diff --git a/src/blog.py b/src/blog.py index 1d409c5..e320378 100644 --- a/src/blog.py +++ b/src/blog.py @@ -13,6 +13,4 @@ conn = psycopg2.connect( user= env("PG_USER"), password = env("PG_PASSWORD") ) -cursor = conn.cursor() - - +cursor = conn.cursor() \ No newline at end of file diff --git a/src/dynamic_routes.py b/src/dynamic.py similarity index 52% rename from src/dynamic_routes.py rename to src/dynamic.py index 3df4cc1..608d1ad 100644 --- a/src/dynamic_routes.py +++ b/src/dynamic.py @@ -1,10 +1,14 @@ # Imports -from flask import Blueprint, render_template, abort, request -import os, markdown +from flask import Blueprint, render_template, abort +import os, importlib, logging + + +# Logging +log = logging.getLogger("__main__") # Create blueprint -bp = Blueprint('dynamic_routes', __name__) +bp = Blueprint('dynamic', __name__) template_folder = "templates" @@ -25,6 +29,23 @@ def ListFiles(path): return files +# Import handlers +handlers_unloaded = os.listdir("src/handlers") +handlers_unloaded = [handler for handler in handlers_unloaded if handler.endswith(".py")] +handlers = {} + +for handler in handlers_unloaded: + try: + try: module = importlib.import_module(f'src.handlers.{handler[:-3]}') + except ImportError: module = importlib.import_module(f'handlers.{handler[:-3]}') + handlers[handler[:-3]] = module.callback + log.info(f"Loaded handler {handler}: {module.callback}") + + except Exception as e: + log.error(f"Failed to load handler {handler}: {e}") + continue + + # Catch-all route for generic pages @bp.route('/') def catch_all(filename): @@ -36,18 +57,17 @@ def catch_all(filename): pages=ListFiles(filename) ) + if filename.split('.')[-1] in handlers.keys(): + return handlers[filename.split('.')[-1]](filename) + return render_template(f'pages/{filename}') elif os.path.exists(get_path(filename + '.html')): return render_template(f'pages/{filename}.html') - elif os.path.exists(get_path(filename + '.md')): - output = markdown.markdown(open(get_path(filename + '.md'), "r").read()) - return render_template( - f'bases/md.html', - title = filename.split("/")[-1], - markdown = output - ) - else: + for ext in handlers.keys(): + if os.path.exists(get_path(filename + f".{ext}")): + return handlers[ext](filename + f".{ext}") + abort(404, f"'{filename}' not found") \ No newline at end of file diff --git a/src/handlers/md.py b/src/handlers/md.py new file mode 100644 index 0000000..7c8c772 --- /dev/null +++ b/src/handlers/md.py @@ -0,0 +1,10 @@ +from flask import render_template +import markdown, os + +def callback(filename): + output = markdown.markdown(open(os.path.join("templates", "pages", filename), "r").read()) + return render_template( + f'bases/md.html', + title = filename.split("/")[-1], + markdown = output + ) \ No newline at end of file diff --git a/src/main.py b/src/main.py index 8e0fdf4..4c29880 100644 --- a/src/main.py +++ b/src/main.py @@ -4,11 +4,9 @@ from os import getenv as env import logging try: - import src.dynamic_routes as dynamic_routes - import src.errors as errors import src.pg_log as pg_log except ImportError: - import dynamic_routes, errors, pg_log + import pg_log from dotenv import load_dotenv load_dotenv() @@ -42,6 +40,14 @@ werkzeug_logger.addHandler(stream_log_handler) log.info("Logging initialized.") +try: + import src.dynamic as dynamic + import src.errors as errors + import src.music_metadata as music_metadata +except ImportError: + import dynamic, errors, music_metadata + + # CREATE FLASK APP app = Flask( __name__, @@ -53,7 +59,8 @@ log.info("Flask initialized.") # BLUEPRINTS app.register_blueprint(errors.bp, url_prefix="/errors") -app.register_blueprint(dynamic_routes.bp, url_prefix="/") +app.register_blueprint(music_metadata.bp, url_prefix="/music") +app.register_blueprint(dynamic.bp, url_prefix="/") log.info("Blueprints registered.") @@ -71,7 +78,6 @@ def terminal(): return render_template("terminal.html") - # DEBUG (DONT RUN LIKE THIS IN PROD) if __name__ == "__main__": log.warning(f"RUNNING IN DEBUG MODE DO NOT USE FOR PRODUCTION!") diff --git a/src/music_metadata.py b/src/music_metadata.py new file mode 100644 index 0000000..60b81c2 --- /dev/null +++ b/src/music_metadata.py @@ -0,0 +1,25 @@ +from flask import Blueprint, request, abort +from os import getenv as env +from urllib.parse import quote +import requests + +bp = Blueprint("music", __name__) + +@bp.route("/metadata") +def metadata(): + if not request.args.get("recording_name"): + abort(400, "Recording name is required") + if not request.args.get("artist_name"): + abort(400, "Artist name is required") + + data = requests.get( + f"https://api.listenbrainz.org/1/metadata/lookup/?recording_name={quote(request.args.get("recording_name"))}&artist_name={quote(request.args.get("artist_name"))}&metadata=true&inc=artist+tag+release", + headers={ + "Authorization": f"Token {env("LISTENBRAINZ_TOKEN")}" + } + ) + + if data.status_code == 200: + return data.json() + else: + abort(500, "Failed to retrieve metadata") \ No newline at end of file diff --git a/static/css/bases/base.css b/static/css/bases/base.css index 536d500..fa99a87 100644 --- a/static/css/bases/base.css +++ b/static/css/bases/base.css @@ -40,6 +40,8 @@ --smileos2-box: url(/static/content/smileos/SmileOS_2_Box.webp) 17 3 3 fill / 51px 9px 9px; --smileos2-font: 'Ultrafont2'; --smileos2-emphasis: #FF4343; + --line-height: normal; + --header-line-height: normal; } body { @@ -48,6 +50,7 @@ body { color: var(--text-color); font-size: var(--font-size); font-family: var(--font-family); + line-height: var(--line-height); display: grid; grid-template-columns: auto auto; grid-template-rows: 1fr; @@ -58,6 +61,10 @@ body { width: 940px; } +h1, h2, h3, h4, h5, h6 { + line-height: var(--header-line-height); +} + #sidebar { grid-area: sidebar; display: flex; diff --git a/static/css/index.css b/static/css/index.css index 8077b43..27bba6d 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -43,7 +43,7 @@ transform: scale(1.1) rotate(-5deg); } -#spotify { +#listenbrainz { background-image: none; backdrop-filter: blur(2px) brightness(0.6); border: var(--secondary-background-color) 2px solid; @@ -58,8 +58,8 @@ flex-direction: column; } -#spotify-title { - font-size: 1.5rem; +#listenbrainz-title { + font-size: 1.2rem; font-weight: 900; margin: 0; padding: 0; @@ -67,15 +67,29 @@ color: white; } -#spotify-artist { +#listenbrainz-artist { color: white; - font-size: 1rem; + font-size: 0.7rem; font-weight: 900; margin: 0; padding: 0; mix-blend-mode: difference; } +#listenbrainz-live { + color: white; + font-size: 0.6rem; + font-weight: 900; + margin: 0; + padding: 0; + margin-top: auto; + margin-left: auto; + background-color: gray; + border-radius: 30px; + padding: 2px 6px; + font-family: var(--ultrafont-font); +} + #button-collection { display: flex; flex-direction: row; diff --git a/static/js/base.js b/static/js/base.js index c8a246f..2d287c6 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -76,72 +76,32 @@ let last15Chars = ""; document.addEventListener('keydown', function(event) { last15Chars += event.key; - if (last15Chars.includes("furry")) { + if (last15Chars.includes("owo")) { console.log("owo, whats this?"); document.getElementById('furry').style.display = 'block'; last15Chars = ""; } - if (last15Chars.includes("irken")) { - console.log("doom doom doom!"); + if (last15Chars.includes("doom")) { + console.log("Im gonna sing the doom song now"); document.querySelector(":root").style.setProperty('--font-family', 'Irken'); + document.querySelector(":root").style.setProperty('--ultrafont-font', 'Irken'); + document.querySelector(":root").style.setProperty('--smileos2-font', 'Irken'); document.querySelector(":root").style.setProperty('--title-font', '1.5em'); + document.querySelector(":root").style.setProperty('--line-height', 'default'); + document.querySelector(":root").style.setProperty('--header-line-height', 'default'); last15Chars = ""; } - if (last15Chars.includes("scratch")) { + if (last15Chars.includes("kfc")) { console.log("space chicken"); document.querySelector(":root").style.setProperty('--font-family', 'Scratch'); document.querySelector(":root").style.setProperty('--title-font', '1em'); + document.querySelector(":root").style.setProperty('--line-height', '120%'); + document.querySelector(":root").style.setProperty('--header-line-height', '150%'); + document.querySelector(":root").style.setProperty('--ultrafont-font', 'Scratch'); + document.querySelector(":root").style.setProperty('--smileos2-font', 'Scratch'); last15Chars = ""; } while (last15Chars.length >= 15) { last15Chars = last15Chars.slice(1); } -}); - -// Spotify API (now lastfm) - -function getSpotify() { - fetch('https://api.alfieking.dev/spotify/nowplaying/xz02oolstlvwxqu1pfcua9exz').then(response => { - return response.json(); - }).then(data => { - if (data.item == null) { - document.getElementById('spotify').style.backgroundImage = "none"; - document.getElementById('spotify-title').innerHTML = "Spotify is not playing anything"; - document.getElementById('spotify-artist').innerHTML = ":("; - document.getElementById('spotify-link').href = "https://open.spotify.com/"; - return; - } - document.getElementById('spotify').style.backgroundImage = "url(" + data.item.album.images[0].url + ")"; - document.getElementById('spotify-title').innerHTML = data.item.name; - document.getElementById('spotify-artist').innerHTML = data.item.artists[0].name; - document.getElementById('spotify-link').href = data.item.external_urls.spotify; - }); -} - -if (document.getElementById('spotify')) { - getSpotify(); - setInterval(getSpotify, 15000); -} - - -// load buttons - -function loadButtons() { - fetch('/static/content/buttons/non_link_buttons.txt').then(response => { - return response.text(); - }).then(data => { - container = document.getElementById('button-collection'); - for (let line of data.split('\n')) { - if (line == "") { - continue; - } - let img = document.createElement('img'); - img.src = line; - container.appendChild(img); - } - }); -} - -if (document.getElementById('button-collection')) { - loadButtons(); -} \ No newline at end of file +}); \ No newline at end of file diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 0000000..f779b6c --- /dev/null +++ b/static/js/index.js @@ -0,0 +1,57 @@ +function loadButtons() { + fetch('/static/content/buttons/non_link_buttons.txt').then(response => { + return response.text(); + }).then(data => { + container = document.getElementById('button-collection'); + for (let line of data.split('\n')) { + if (line == "") { + continue; + } + let img = document.createElement('img'); + img.src = line; + container.appendChild(img); + } + }); +} + + +function getAlbumArt(songName, artistName) { + fetch("/music/metadata?recording_name=" + encodeURIComponent(songName) + "&artist_name=" + encodeURIComponent(artistName)).then(response => response.json()).then(data => { + if (Object.keys(data).length > 0) { + document.getElementById('listenbrainz').style.backgroundImage = "url(https://coverartarchive.org/release/" + data.release_mbid + "/front)"; + } else { + console.log("No album art found for the given song and artist"); + document.getElementById('listenbrainz').style.backgroundImage = "url(https://placehold.co/512x512/transparent/777?text=[Insert%20art%20here])"; + } + }); +} + +function getMusic() { + fetch("https://api.listenbrainz.org/1/user/acetheking987/playing-now").then(response => response.json()).then(data => { + if (data.payload.count != 0) { + let song_data = data.payload.listens[0].track_metadata; + getAlbumArt(song_data.track_name, song_data.artist_name); + document.getElementById('listenbrainz-title').innerHTML = song_data.track_name; + document.getElementById('listenbrainz-artist').innerHTML = song_data.artist_name; + document.getElementById('listenbrainz-link').href = "https://listenbrainz.org/user/acetheking987/"; + document.getElementById('listenbrainz-live').style.backgroundColor = "red"; + document.getElementById('listenbrainz-live').innerHTML = "Live"; + } else { + fetch("https://api.listenbrainz.org/1/user/acetheking987/listens?count=1").then(response => response.json()).then(data => { + if (data.payload.count != 0) { + let song_data = data.payload.listens[0].track_metadata; + getAlbumArt(song_data.track_name, song_data.artist_name); + document.getElementById('listenbrainz-title').innerHTML = song_data.track_name; + document.getElementById('listenbrainz-artist').innerHTML = song_data.artist_name; + document.getElementById('listenbrainz-link').href = "https://listenbrainz.org/user/acetheking987/"; + document.getElementById('listenbrainz-live').style.backgroundColor = "grey"; + document.getElementById('listenbrainz-live').innerHTML = "Not Live :<"; + } + }); + } + }); +} + +loadButtons(); +getMusic(); +setInterval(getMusic, 15000); \ No newline at end of file diff --git a/templates/bases/gallery.html b/templates/bases/gallery.html new file mode 100644 index 0000000..7647132 --- /dev/null +++ b/templates/bases/gallery.html @@ -0,0 +1,11 @@ + + + + + + {% block title %}Gallery - Toasters's basement{% endblock %} + + + + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index f4b59fa..f9dc0b1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -38,10 +38,11 @@
- -
-

-

+
+
+

Loading...

+

be patient, listenbrainz is slow :P

+

Not Live :<

@@ -159,4 +160,8 @@
+{% endblock %} + +{% block scripts %} + {% endblock %} \ No newline at end of file diff --git a/templates/pages/test.html b/templates/pages/test.html new file mode 100644 index 0000000..4a048d0 --- /dev/null +++ b/templates/pages/test.html @@ -0,0 +1,21 @@ +{% extends "bases/base.html" %} + +{% block content %} +
+

Test

+ toaster +

+ + +
+{% endblock %} \ No newline at end of file