diff --git a/.gitignore b/.gitignore
index 170b585..0db4e3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,8 @@ __pycache__
docker-compose.yaml
*.sh
+*.ini
+
# Ignore images in posts
*.jpg
*.png
@@ -13,3 +15,8 @@ docker-compose.yaml
# Flask Data & Config
*.ini
data
+*.gif
+
+# Writing
+writing
+
diff --git a/Dockerfile b/Dockerfile
index 67b613a..9360969 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,9 +4,7 @@ FROM python:3.12.2-slim-bookworm
RUN apt-get update && apt-get upgrade -y
-RUN useradd -m app
-
-USER app
+RUN groupadd -r app && useradd -r -g app app
COPY . .
@@ -15,4 +13,6 @@ RUN python3 -m pip install -r requirements.txt
WORKDIR ./app
+USER app
+
CMD ["python3", "-u", "app.py"]
diff --git a/README.md b/README.md
index d8282e3..c9fa882 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,5 @@
Code of the website hosted at https://www.0x01fe.net
-Could I gitignore the config files?
-Yes.
-Do I?
-no.
+One might ask why my pretty simple website is written in Python. The answer is so that I can just drop markdown files in a folder and have them automatically formatted and uploaded. This is done using the fact that markdown translates to HTML perfectly and that Flask / Jinja2 templates are really easy to use!
diff --git a/app/app.py b/app/app.py
index e7d9301..b672af8 100644
--- a/app/app.py
+++ b/app/app.py
@@ -1,8 +1,11 @@
+import os
import glob
import configparser
import random
import base64
+import datetime
+import requests
import flask
import flask_wtf.csrf
import flask_session
@@ -22,6 +25,7 @@ CONFIG_PATH = "./config.ini"
config = configparser.ConfigParser()
config.read(CONFIG_PATH)
+WRITING_FOLDER = 'static/writing/'
POSTS_FOLDER = config['POSTS']['POSTS_FOLDER']
STATUS_FILE = config['STATUS']['STATUS_FILE']
PORT = int(config['NETWORK']['PORT'])
@@ -38,6 +42,10 @@ app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './data/.flask_session/'
flask_session.Session(app)
+MUSIC_API_TOKEN = config['AUTH']['MUSIC_API_TOKEN']
+MUSIC_API_URL = config['NETWORK']['MUSIC_API_URL']
+statuses = {}
+
def get_posts(category_filter : str | None = None) -> list[Post]:
post_files = glob.glob(f'{POSTS_FOLDER}/*')
try:
@@ -70,13 +78,36 @@ def get_posts(category_filter : str | None = None) -> list[Post]:
return reversed(ordered_posts)
-def get_status() -> str:
+def read_status_file() -> dict:
with open(STATUS_FILE, 'r', encoding='utf-8') as file:
- statuses = file.readlines()
+ data = file.readlines()
- status = random.randint(0, len(statuses) - 1)
+ result = {}
+ current_key = None
+ for line in data:
+ if line[0] == '#':
- return markdown.markdown(statuses[status])
+ # Empty Key-Value pairs will cause errors
+ if current_key:
+ if not result[current_key]:
+ result.pop(current_key)
+
+ current_key = line.replace('#', '').strip()
+ result[current_key] = []
+ elif not (line == '\n'):
+ result[current_key].append(line)
+
+ return result
+
+def get_status() -> str:
+ keys = list(statuses.keys())
+
+ selected_key = keys[random.randint(0, len(keys) - 1)]
+ section: list = statuses[selected_key]
+
+ selected_status = section[random.randint(0, len(section) - 1)]
+
+ return f'
{markdown.markdown(selected_status)}
'
# Main Page
@app.route('/')
@@ -100,6 +131,26 @@ def index():
return flask.render_template('index.html', posts=posts_and_comments, status=status, form=form, user="yes")
+# Posts
+@app.route('/post/')
+def post(post_name: str):
+
+ for post in get_posts():
+ if post.title.replace(' ', '-') == post_name:
+ return flask.render_template('index.html', posts=[post.body], status=get_status())
+
+ flask.abort(404)
+
+# Posts
+@app.route('/post/')
+def post(post_name: str):
+
+ for post in get_posts():
+ if post.title.replace(' ', '-') == post_name:
+ return flask.render_template('index.html', posts=[post.body], status=get_status())
+
+ flask.abort(404)
+
# Games Page
@app.route('/games/')
def games():
@@ -130,7 +181,25 @@ def music():
# Get status
status = get_status()
- return flask.render_template('music.html', posts=post_bodies, status=status)
+ # Get top albums
+ r = requests.get(
+ MUSIC_API_URL +'/top/albums',
+ headers={
+ 'token' : MUSIC_API_TOKEN,
+ 'user' : '1',
+ 'limit' : '9'
+ })
+
+ top_albums = r.json()['top']
+ for album_index in range(0, len(top_albums)):
+ album = top_albums[album_index]
+
+ time = int(album['listen_time'])
+ hours = round(time/1000/60/60, 1)
+
+ top_albums[album_index]['listen_time'] = hours
+
+ return flask.render_template('music.html', posts=post_bodies, status=status, top_albums=top_albums)
# Motion Pictures Page
@app.route('/motion-pictures/')
@@ -164,6 +233,31 @@ def programming():
return flask.render_template('programming.html', posts=post_bodies, status=status)
+@app.route('/writing/')
+def writing():
+
+ works = []
+
+ # Get all works in writing folder
+ files = glob.glob(WRITING_FOLDER + '*')
+
+ for path in files:
+
+ date: str = datetime.datetime.fromtimestamp(os.path.getctime(path)).strftime("%B %d, %Y")
+ name: str = path.split('/')[-1]
+
+ works.append({
+ 'date' : date,
+ 'name' : name,
+ 'path' : path
+ })
+
+ return flask.render_template('writing.html', works=works)
+
+
+
+
+
# About Page
@app.route('/about/')
def about():
@@ -173,7 +267,42 @@ def about():
return flask.render_template('about.html', status=status)
+# MISC
+
+@app.route('/albumsquare//')
+def album_square(user_id, rows : int):
+
+ limit = rows ** 2
+
+ res = (1080/(rows))-rows
+
+ # Get top albums
+ r = requests.get(
+ MUSIC_API_URL +'/top/albums',
+ headers={
+ 'token' : MUSIC_API_TOKEN,
+ 'user' : user_id,
+ 'limit' : str(limit)
+ })
+
+ top_albums = r.json()['top']
+ for album_index in range(0, len(top_albums)):
+ album = top_albums[album_index]
+
+ time = int(album['listen_time'])
+ hours = round(time/1000/60/60, 1)
+
+ top_albums[album_index]['listen_time'] = hours
+
+
+ return flask.render_template('album_square.html', top_albums=top_albums, limit=rows, res=res)
+
+
+
if __name__ == "__main__":
+
+ statuses = read_status_file()
+
if DEV:
app.run(port=PORT)
else:
diff --git a/app/data/.flask_session/2029240f6d1128be89ddc32729463129 b/app/data/.flask_session/2029240f6d1128be89ddc32729463129
new file mode 100644
index 0000000..7f5741f
Binary files /dev/null and b/app/data/.flask_session/2029240f6d1128be89ddc32729463129 differ
diff --git a/app/data/.flask_session/aa43147407c8a8c678cd91f678f2a023 b/app/data/.flask_session/aa43147407c8a8c678cd91f678f2a023
new file mode 100644
index 0000000..d818306
Binary files /dev/null and b/app/data/.flask_session/aa43147407c8a8c678cd91f678f2a023 differ
diff --git a/app/data/comments.json b/app/data/comments.json
new file mode 100644
index 0000000..964e9aa
--- /dev/null
+++ b/app/data/comments.json
@@ -0,0 +1,8 @@
+{
+ "2" : [
+ {
+ "username" : "0x01FE",
+ "content" : "Hello, this is an example comment!"
+ }
+ ]
+}
diff --git a/app/data/users.json b/app/data/users.json
new file mode 100644
index 0000000..c3227f9
--- /dev/null
+++ b/app/data/users.json
@@ -0,0 +1,5 @@
+{
+ "users" : {
+ "0x01FE" : "cGFzc3dvcmQ="
+ }
+}
diff --git a/app/post.py b/app/post.py
index f087a29..92dce5d 100644
--- a/app/post.py
+++ b/app/post.py
@@ -9,6 +9,8 @@ class Post:
body : str
file : str
id : int
+ title : str
+ url : str
def __init__(self, file_path):
self.file = file_path
@@ -18,11 +20,13 @@ class Post:
self.category = lines[1].split(":")[1].strip()
self.author = lines[2].split(":")[1].strip()
+ self.title = lines[6][2:-1]
+ self.url = '/post/' + self.title.replace(' ', '-')
date = lines[3].split(":")[1].strip()
self.date = datetime.datetime.strptime(date, "%d-%m-%Y")
self.id = int(lines[4].split(":")[1].strip())
- self.body = markdown.markdown(''.join(lines[7:]))
+ self.body = markdown.markdown(f'# [{self.title}]({self.url})\n' + ''.join(lines[7:]))
diff --git a/app/resources/status.text b/app/resources/status.text
index c258209..0fece64 100644
--- a/app/resources/status.text
+++ b/app/resources/status.text
@@ -1,31 +1,112 @@
-Catchy Right?
-Everybody's lazy when they're tired
+# Project Moon
+Needles
+Sally forth Rocinante!
+The multitude tightens its hold.
+
+# Misc
+Check out [NEUPINK](https://neupink.bandcamp.com/album/swordflower-hills-killer-2)!
+Solar Sect of Mystic Wisdom
+~ Nuclear Fusion
+His name really is Tim.
+Just wait until you see the 1 in 1000 message.
+I'm open to suggestions on how to improve the look of the website
As long as there is delusion, there is hope
It's 510.
+Catchy Right?
+
+## TV / Movie Quotes
+
+# Monogatari
+I don't know everything, I only know what I know.
+
+## Song Lyrics
+
+# I’m in Your Mind by King Gizzard & The Lizard Wizard
+Everybody's lazy when they're tired
+
+# Straws In The Wind by King Gizzard & The Lizard Wizard
Mindful of the weary inkling that is lurking
Mortal traffic lights signaling when to stay or go
+
+# Automation by King Gizzard & The Lizard Wizard
Cyber surgeon, Javascript person
+
+# Gilgamesh by King Gizzard & The Lizard Wizard
Bone-dried swamplands swallow me
House of dust, land of bone
I ate dirt, I drank stone
Come on, snake, punish me
+
+# The Dripping Tap by King Gizzard & The Lizard Wizard
Drip, drip from the tap, don't slip on the drip
-His name really is Tim.
-Just wait until you see the 1 in 1000 message.
-I'm open to suggestions on how to improve the look of the website
-Open the curtains
-Don't miss a moment of this experiment
-Needles
-Sally forth Rocinante!
-The multitude tightens its hold.
+
+# Face to Face by Daft Punk
It's amazing what you'll find face to face
It's not hard to go the distance / When you finally get involved face to face
+
+# Touch by Daft Punk
A tourist in a dream / A visitor, it seems / A half-forgotten song / Where do I belong?
+
+# Magenta Mountian by King Gizzard & The Lizard Wizard
What do you mean ... You can't see it?
I don't believe you / your eyes deceive you / better check yourself in
You will say I'm crazy / I will go on my way 'cause it's what I need
I'd cross a thousand seas just to prove I'm not mad
I thought I saw a statue blink, and a bird with no head, Land on a golden thread, I rub my eyes, What am I saying? There's nothing there
-Solar Sect of Mystic Wisdom
-~ Nuclear Fusion
-Check out [NEUPINK](https://neupink.bandcamp.com/album/swordflower-hills-killer-2)!
\ No newline at end of file
+
+# Armor-clad Faith by NAOKI, Arc System Works
+I'm a fool, I know nothing / I take the role of a silly clown
+All I do is embrace the wounded soul
+
+# Love the Subhuman Self by AISHA, Jamison Boaz, Arc System Works (Guilty Gear Strive)
+So carry on, love the subhuman self
+Break yourself inside out, she told me
+
+# Symphony by NAOKI, Arc System Works (Guilty Gear Strive)
+We're just a quirky note in the symphony
+
+# White Whale by Shadow Academy
+So, silent tide / Tell me which face do I show the world / And which one do I hide?
+
+# Intrasport by King Gizzard & The Lizard Wizard
+Dreams that sew me up like sleeping with a needle
+Those feelings that I had are building up to something
+I feel a schism in the rhythm, now I'm running
+My hair is liquifying
+My taste buds are igniting
+
+# Set by King Gizzard & The Lizard Wizard
+Cut the cord, kill the king and reset
+Squeezing day into night with supernatural pressure
+Right eye is the sun and left the moon's light
+
+# Swan Song by King Gizzard & The Lizard Wizard
+Score the music // Of your essence
+Stars fall from their lofty places
+Earth has been put through her paces
+Cosmic surgeons cut the cable
+Make a new world if you're able
+
+# String Theocracy by Mili
+Open the curtains
+Don't miss a moment of this experiment
+If you're going to replace me // At least have the audacity to kill me thoroughly
+What's the color of the electric sheep you see?
+Maybe we're all cold machines
+
+# Change by King Gizzard & The Lizard Wizard
+We're changing pace // Higher stakes
+So called heroes wearing fake capes
+Buildings that you know // People come and go // Are a certain way
+And then you get the news that obliterates your view // Amputate your truths // The signifiance has changed
+Hospital inane // Meaningless and grey // But lie within the walls and the signifiance will change
+What would it take for us to change the game? // Maybe our existence is signifiance in vain
+
+# Candles by King Gizzard & The Lizard Wizard
+This little man is too hot to handle // Set the funeral on fire with the candles
+Praying to the gods at the top of a mountian // Better throwing all your pennies in a fountian
+My little heart, as cold as a morgue // Let the weight of it drop like an iceberg
+
+# Presumptuous by King Gizzard & The Lizard Wizard
+Eggshell, landmine, stepping stones // Kindred spirits at a crossroads
+The world we built is on a tilt // Bottled up inside and filled with guilt
diff --git a/app/static/albumsquare.css b/app/static/albumsquare.css
new file mode 100644
index 0000000..1044b3d
--- /dev/null
+++ b/app/static/albumsquare.css
@@ -0,0 +1,19 @@
+.albums {
+ height: 100%;
+
+ line-height: 0;
+ font-size: 0;
+}
+
+.albums img {
+ padding: 0 0;
+ margin: 0 0;
+ border: 0 0;
+}
+
+
+.body {
+ height: 100%;
+ padding: 0 0;
+ margin: 0 0;
+}
diff --git a/app/static/programming/vscode_extensions.txt b/app/static/programming/vscode_extensions.txt
new file mode 100644
index 0000000..a0edf1d
--- /dev/null
+++ b/app/static/programming/vscode_extensions.txt
@@ -0,0 +1,12 @@
+EOF Mark,
+Glassit-VSC,
+JSON formatter,
+Pylance,
+Remote - SSH,
+Synthwave '84 Blues,
+Trailing Spaces,
+Helm Intellisense,
+background,
+Helium Icon Theme,
+SQLite Viewer,
+Docker
\ No newline at end of file
diff --git a/app/static/style.css b/app/static/style.css
index 68cbe2c..6e4dab4 100644
--- a/app/static/style.css
+++ b/app/static/style.css
@@ -107,6 +107,39 @@ a:hover {
text-decoration: none;
}
+.rightbar {
+ height: fit-content;
+ align-self: flex-start;
+ top: 10px;
+
+ padding: 20pt;
+
+ margin: 5em 0;
+ margin-right: 2em;
+
+ border-style: var(--borders-style);
+ border-radius: var(--border-radius);
+ border-color: #1E2022;
+ background-color: var(--main-background);
+
+ opacity: 0.9;
+
+ /* box-shadow: -10px 10px var(--accent); */
+
+ /* Text Settings */
+ font-weight: bold;
+ line-height: 30pt;
+}
+
+.rightbar a {
+ text-decoration: none;
+}
+
+.rightbar h2 {
+ font-family: Georgia, 'Times New Roman', Times, serif;
+ line-height: normal;
+}
+
.dlog {
flex: 3;
@@ -158,7 +191,7 @@ a:hover {
text-decoration: underline;
text-decoration-style: solid;
text-decoration-thickness: 0.25em;
- text-underline-offset: 6px;
+ text-underline-offset: 7px;
text-decoration-color: var(--primary);
}
@@ -195,3 +228,49 @@ a:hover {
.comment-editor textarea:focus {
border: 3px solid var(--accent);
}
+
+/* MUSIC */
+.albums {
+ height: fit-content;
+ align-self: flex-start;
+ top: 10px;
+
+ padding: 20pt;
+
+ margin: 5em 0;
+ margin-right: 2em;
+
+ border-style: var(--borders-style);
+ border-radius: var(--border-radius);
+ border-color: #1E2022;
+ background-color: var(--main-background);
+
+ /* Text Settings
+ font-weight: bold;
+ line-height: 30pt; */
+}
+
+
+.real-albums img {
+ height: 100px;
+ width: 100px;
+ padding: 0 0;
+ margin: 0 0;
+ border: 0 0;
+}
+
+.real-albums {
+ line-height: 0;
+ font-size: 0;
+ padding: 0 0;
+ margin: 0 0;
+}
+
+.albums h1 {
+ font-size: 2em;
+ text-align: center;
+ padding: 0 0;
+ margin: 15pt 0;
+ margin-top: -5pt;
+}
+
diff --git a/app/templates/about.html b/app/templates/about.html
index a2663fc..ce7774c 100644
--- a/app/templates/about.html
+++ b/app/templates/about.html
@@ -18,6 +18,7 @@
Music
Motion Picture
Programming
+ Writing
About
diff --git a/app/templates/album_square.html b/app/templates/album_square.html
new file mode 100644
index 0000000..ca6d024
--- /dev/null
+++ b/app/templates/album_square.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ {% for album in top_albums %}
+
+
+
+ {% if loop.index % limit == 0 %}
+
+ {% endif %}
+ {% endfor %}
+
+
+
diff --git a/app/templates/games.html b/app/templates/games.html
index d023f8b..0ffded7 100644
--- a/app/templates/games.html
+++ b/app/templates/games.html
@@ -18,6 +18,7 @@
Music
Motion Picture
Programming
+ Writing
About
diff --git a/app/templates/index.html b/app/templates/index.html
index d349f43..4c79bc5 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -14,11 +14,12 @@
diff --git a/app/templates/motion-pictures.html b/app/templates/motion-pictures.html
index 459f655..87d36f9 100644
--- a/app/templates/motion-pictures.html
+++ b/app/templates/motion-pictures.html
@@ -18,6 +18,7 @@
Music
Motion Picture
Programming
+ Writing
About
diff --git a/app/templates/music.html b/app/templates/music.html
index 9a00a11..5ea89f3 100644
--- a/app/templates/music.html
+++ b/app/templates/music.html
@@ -18,6 +18,7 @@
Music
Motion Picture
Programming
+ Writing
About
@@ -28,6 +29,20 @@
{{ post|safe }}
{% endfor %}
+
+
+
Top Albums
+
+ {% for album in top_albums %}
+
+
+
+ {% if loop.index % 3 == 0 %}
+
+ {% endif %}
+ {% endfor %}
+
+