Merge branch 'main' into comments

This commit is contained in:
0x01fe 2024-06-26 14:10:02 -05:00
commit ce9c995a50
22 changed files with 435 additions and 33 deletions

7
.gitignore vendored
View File

@ -6,6 +6,8 @@ __pycache__
docker-compose.yaml docker-compose.yaml
*.sh *.sh
*.ini
# Ignore images in posts # Ignore images in posts
*.jpg *.jpg
*.png *.png
@ -13,3 +15,8 @@ docker-compose.yaml
# Flask Data & Config # Flask Data & Config
*.ini *.ini
data data
*.gif
# Writing
writing

View File

@ -4,9 +4,7 @@ FROM python:3.12.2-slim-bookworm
RUN apt-get update && apt-get upgrade -y RUN apt-get update && apt-get upgrade -y
RUN useradd -m app RUN groupadd -r app && useradd -r -g app app
USER app
COPY . . COPY . .
@ -15,4 +13,6 @@ RUN python3 -m pip install -r requirements.txt
WORKDIR ./app WORKDIR ./app
USER app
CMD ["python3", "-u", "app.py"] CMD ["python3", "-u", "app.py"]

View File

@ -2,8 +2,5 @@
Code of the website hosted at https://www.0x01fe.net Code of the website hosted at https://www.0x01fe.net
Could I gitignore the config files? 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!
Yes.
Do I?
no.

View File

@ -1,8 +1,11 @@
import os
import glob import glob
import configparser import configparser
import random import random
import base64 import base64
import datetime
import requests
import flask import flask
import flask_wtf.csrf import flask_wtf.csrf
import flask_session import flask_session
@ -22,6 +25,7 @@ CONFIG_PATH = "./config.ini"
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(CONFIG_PATH) config.read(CONFIG_PATH)
WRITING_FOLDER = 'static/writing/'
POSTS_FOLDER = config['POSTS']['POSTS_FOLDER'] POSTS_FOLDER = config['POSTS']['POSTS_FOLDER']
STATUS_FILE = config['STATUS']['STATUS_FILE'] STATUS_FILE = config['STATUS']['STATUS_FILE']
PORT = int(config['NETWORK']['PORT']) PORT = int(config['NETWORK']['PORT'])
@ -38,6 +42,10 @@ app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './data/.flask_session/' app.config['SESSION_FILE_DIR'] = './data/.flask_session/'
flask_session.Session(app) 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]: def get_posts(category_filter : str | None = None) -> list[Post]:
post_files = glob.glob(f'{POSTS_FOLDER}/*') post_files = glob.glob(f'{POSTS_FOLDER}/*')
try: try:
@ -70,13 +78,36 @@ def get_posts(category_filter : str | None = None) -> list[Post]:
return reversed(ordered_posts) return reversed(ordered_posts)
def get_status() -> str: def read_status_file() -> dict:
with open(STATUS_FILE, 'r', encoding='utf-8') as file: 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'<div title="{selected_key}">{markdown.markdown(selected_status)}</div>'
# Main Page # Main Page
@app.route('/') @app.route('/')
@ -100,6 +131,26 @@ def index():
return flask.render_template('index.html', posts=posts_and_comments, status=status, form=form, user="yes") return flask.render_template('index.html', posts=posts_and_comments, status=status, form=form, user="yes")
# Posts
@app.route('/post/<string:post_name>')
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/<string:post_name>')
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 # Games Page
@app.route('/games/') @app.route('/games/')
def games(): def games():
@ -130,7 +181,25 @@ def music():
# Get status # Get status
status = 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 # Motion Pictures Page
@app.route('/motion-pictures/') @app.route('/motion-pictures/')
@ -164,6 +233,31 @@ def programming():
return flask.render_template('programming.html', posts=post_bodies, status=status) 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 # About Page
@app.route('/about/') @app.route('/about/')
def about(): def about():
@ -173,7 +267,42 @@ def about():
return flask.render_template('about.html', status=status) return flask.render_template('about.html', status=status)
# MISC
@app.route('/albumsquare/<user_id>/<int:rows>')
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__": if __name__ == "__main__":
statuses = read_status_file()
if DEV: if DEV:
app.run(port=PORT) app.run(port=PORT)
else: else:

8
app/data/comments.json Normal file
View File

@ -0,0 +1,8 @@
{
"2" : [
{
"username" : "0x01FE",
"content" : "Hello, this is an example comment!"
}
]
}

5
app/data/users.json Normal file
View File

@ -0,0 +1,5 @@
{
"users" : {
"0x01FE" : "cGFzc3dvcmQ="
}
}

View File

@ -9,6 +9,8 @@ class Post:
body : str body : str
file : str file : str
id : int id : int
title : str
url : str
def __init__(self, file_path): def __init__(self, file_path):
self.file = file_path self.file = file_path
@ -18,11 +20,13 @@ class Post:
self.category = lines[1].split(":")[1].strip() self.category = lines[1].split(":")[1].strip()
self.author = lines[2].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() date = lines[3].split(":")[1].strip()
self.date = datetime.datetime.strptime(date, "%d-%m-%Y") self.date = datetime.datetime.strptime(date, "%d-%m-%Y")
self.id = int(lines[4].split(":")[1].strip()) 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:]))

View File

@ -1,31 +1,112 @@
Catchy Right? # Project Moon
Everybody's lazy when they're tired 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 As long as there is delusion, there is hope
It's 510. It's 510.
Catchy Right?
## TV / Movie Quotes
# Monogatari
I don't know everything, I only know what I know.
## Song Lyrics
# Im 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 Mindful of the weary inkling that is lurking
Mortal traffic lights signaling when to stay or go Mortal traffic lights signaling when to stay or go
# Automation by King Gizzard & The Lizard Wizard
Cyber surgeon, Javascript person Cyber surgeon, Javascript person
# Gilgamesh by King Gizzard & The Lizard Wizard
Bone-dried swamplands swallow me Bone-dried swamplands swallow me
House of dust, land of bone House of dust, land of bone
I ate dirt, I drank stone I ate dirt, I drank stone
Come on, snake, punish me 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 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. # Face to Face by Daft Punk
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.
It's amazing what you'll find face to face 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 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? 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? What do you mean ... You can't see it?
I don't believe you / your eyes deceive you / better check yourself in 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 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'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 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 # Armor-clad Faith by NAOKI, Arc System Works
Check out [NEUPINK](https://neupink.bandcamp.com/album/swordflower-hills-killer-2)! 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

View File

@ -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;
}

View File

@ -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

View File

@ -107,6 +107,39 @@ a:hover {
text-decoration: none; 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 { .dlog {
flex: 3; flex: 3;
@ -158,7 +191,7 @@ a:hover {
text-decoration: underline; text-decoration: underline;
text-decoration-style: solid; text-decoration-style: solid;
text-decoration-thickness: 0.25em; text-decoration-thickness: 0.25em;
text-underline-offset: 6px; text-underline-offset: 7px;
text-decoration-color: var(--primary); text-decoration-color: var(--primary);
} }
@ -195,3 +228,49 @@ a:hover {
.comment-editor textarea:focus { .comment-editor textarea:focus {
border: 3px solid var(--accent); 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;
}

View File

@ -18,6 +18,7 @@
<a href="../music/">Music</a><br> <a href="../music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="../motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br> <a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="."><u>About</u></a> <a href="."><u>About</u></a>
</div> </div>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<header>
<link rel="shortcut icon" href="index_favicon.ico">
<link rel="stylesheet" href="{{ url_for('static', filename='albumsquare.css') }}">
<title>Album Square</title>
</header>
<body>
<div class="albums">
{% for album in top_albums %}
<a title="{{ album.album_name}} by {{ album.artist_name }} - {{ album.listen_time }} Hours">
<img src="{{ album.album_cover }}" style="width: {{ res }}px; height: {{ res }}px;">
</a>
{% if loop.index % limit == 0 %}
<br>
{% endif %}
{% endfor %}
</div>
</body>
</html>

View File

@ -18,6 +18,7 @@
<a href="../music/">Music</a><br> <a href="../music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="../motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br> <a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a> <a href="../about/">About</a>
</div> </div>

View File

@ -14,11 +14,12 @@
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="."><u>Home</u></a><br> <a href="."><u>Home</u></a><br>
<a href="./games/">Games</a><br> <a href="/games/">Games</a><br>
<a href="./music/">Music</a><br> <a href="/music/">Music</a><br>
<a href="./motion-pictures/">Motion Picture</a><br> <a href="/motion-pictures/">Motion Picture</a><br>
<a href="./programming/">Programming</a><br> <a href="/programming/">Programming</a><br>
<a href="./about/">About</a> <a href="/writing/">Writing</a><br>
<a href="/about/">About</a>
</div> </div>
<!-- Main Page --> <!-- Main Page -->

View File

@ -18,6 +18,7 @@
<a href="../music/">Music</a><br> <a href="../music/">Music</a><br>
<a href="."><u>Motion Picture</u></a><br> <a href="."><u>Motion Picture</u></a><br>
<a href="../programming/">Programming</a><br> <a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a> <a href="../about/">About</a>
</div> </div>

View File

@ -18,6 +18,7 @@
<a href="."><u>Music</u></a><br> <a href="."><u>Music</u></a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="../motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br> <a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a> <a href="../about/">About</a>
</div> </div>
@ -28,6 +29,20 @@
<div class="post">{{ post|safe }}</div> <div class="post">{{ post|safe }}</div>
{% endfor %} {% endfor %}
</div> </div>
<div class="albums">
<h1>Top Albums</h1>
<div class="real-albums">
{% for album in top_albums %}
<a title="{{ album.album_name}} by {{ album.artist_name }} - {{ album.listen_time }} Hours">
<img src="{{ album.album_cover }}">
</a>
{% if loop.index % 3 == 0 %}
<br>
{% endif %}
{% endfor %}
</div>
</div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -18,6 +18,7 @@
<a href="../music/">Music</a><br> <a href="../music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="../motion-pictures/">Motion Picture</a><br>
<a href="."><u>Programming</u></a><br> <a href="."><u>Programming</u></a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a> <a href="../about/">About</a>
</div> </div>
@ -28,6 +29,12 @@
<div class="post">{{ post|safe }}</div> <div class="post">{{ post|safe }}</div>
{% endfor %} {% endfor %}
</div> </div>
<!-- Other Sidear -->
<div class="rightbar">
<h2>Other</h2>
<a href="">Technologies I Use</a>
</div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<body>
<a href="/">home</a>
<p>
This is just a little page where I post stuff I write. I was kind of unsure if I wanted this stuff out here but I think to those who know me it could serve as an interesting view into some thoughts that I don't often express elsewhere.
</p>
<br>
<br>
{% for work in works %}
<a href="/{{ work.path }}">{{ work.name }}</a> {{ work.date }}
{% endfor %}
</body>
</html>

View File

@ -3,4 +3,5 @@ Flask==2.2.3
waitress==2.1.2 waitress==2.1.2
Werkzeug==2.2.3 Werkzeug==2.2.3
Flask-Session==0.5.0 Flask-Session==0.5.0
Flask-WTF==1.1.1 Flask-WTF==1.1.1
requests==2.31.0