update music api to listenbrainz
Deploy website / deploy (push) Successful in 3m1s

This commit is contained in:
2026-06-15 21:56:41 +01:00
parent af5116d931
commit cb7ec029eb
12 changed files with 215 additions and 81 deletions
-2
View File
@@ -14,5 +14,3 @@ conn = psycopg2.connect(
password = env("PG_PASSWORD") password = env("PG_PASSWORD")
) )
cursor = conn.cursor() cursor = conn.cursor()
+31 -11
View File
@@ -1,10 +1,14 @@
# Imports # Imports
from flask import Blueprint, render_template, abort, request from flask import Blueprint, render_template, abort
import os, markdown import os, importlib, logging
# Logging
log = logging.getLogger("__main__")
# Create blueprint # Create blueprint
bp = Blueprint('dynamic_routes', __name__) bp = Blueprint('dynamic', __name__)
template_folder = "templates" template_folder = "templates"
@@ -25,6 +29,23 @@ def ListFiles(path):
return files 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 # Catch-all route for generic pages
@bp.route('/<path:filename>') @bp.route('/<path:filename>')
def catch_all(filename): def catch_all(filename):
@@ -36,18 +57,17 @@ def catch_all(filename):
pages=ListFiles(filename) pages=ListFiles(filename)
) )
if filename.split('.')[-1] in handlers.keys():
return handlers[filename.split('.')[-1]](filename)
return render_template(f'pages/{filename}') return render_template(f'pages/{filename}')
elif os.path.exists(get_path(filename + '.html')): elif os.path.exists(get_path(filename + '.html')):
return render_template(f'pages/{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: 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") abort(404, f"'{filename}' not found")
+10
View File
@@ -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
)
+11 -5
View File
@@ -4,11 +4,9 @@ from os import getenv as env
import logging import logging
try: try:
import src.dynamic_routes as dynamic_routes
import src.errors as errors
import src.pg_log as pg_log import src.pg_log as pg_log
except ImportError: except ImportError:
import dynamic_routes, errors, pg_log import pg_log
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv() load_dotenv()
@@ -42,6 +40,14 @@ werkzeug_logger.addHandler(stream_log_handler)
log.info("Logging initialized.") 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 # CREATE FLASK APP
app = Flask( app = Flask(
__name__, __name__,
@@ -53,7 +59,8 @@ log.info("Flask initialized.")
# BLUEPRINTS # BLUEPRINTS
app.register_blueprint(errors.bp, url_prefix="/errors") 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.") log.info("Blueprints registered.")
@@ -71,7 +78,6 @@ def terminal():
return render_template("terminal.html") return render_template("terminal.html")
# DEBUG (DONT RUN LIKE THIS IN PROD) # DEBUG (DONT RUN LIKE THIS IN PROD)
if __name__ == "__main__": if __name__ == "__main__":
log.warning(f"RUNNING IN DEBUG MODE DO NOT USE FOR PRODUCTION!") log.warning(f"RUNNING IN DEBUG MODE DO NOT USE FOR PRODUCTION!")
+25
View File
@@ -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")
+7
View File
@@ -40,6 +40,8 @@
--smileos2-box: url(/static/content/smileos/SmileOS_2_Box.webp) 17 3 3 fill / 51px 9px 9px; --smileos2-box: url(/static/content/smileos/SmileOS_2_Box.webp) 17 3 3 fill / 51px 9px 9px;
--smileos2-font: 'Ultrafont2'; --smileos2-font: 'Ultrafont2';
--smileos2-emphasis: #FF4343; --smileos2-emphasis: #FF4343;
--line-height: normal;
--header-line-height: normal;
} }
body { body {
@@ -48,6 +50,7 @@ body {
color: var(--text-color); color: var(--text-color);
font-size: var(--font-size); font-size: var(--font-size);
font-family: var(--font-family); font-family: var(--font-family);
line-height: var(--line-height);
display: grid; display: grid;
grid-template-columns: auto auto; grid-template-columns: auto auto;
grid-template-rows: 1fr; grid-template-rows: 1fr;
@@ -58,6 +61,10 @@ body {
width: 940px; width: 940px;
} }
h1, h2, h3, h4, h5, h6 {
line-height: var(--header-line-height);
}
#sidebar { #sidebar {
grid-area: sidebar; grid-area: sidebar;
display: flex; display: flex;
+19 -5
View File
@@ -43,7 +43,7 @@
transform: scale(1.1) rotate(-5deg); transform: scale(1.1) rotate(-5deg);
} }
#spotify { #listenbrainz {
background-image: none; background-image: none;
backdrop-filter: blur(2px) brightness(0.6); backdrop-filter: blur(2px) brightness(0.6);
border: var(--secondary-background-color) 2px solid; border: var(--secondary-background-color) 2px solid;
@@ -58,8 +58,8 @@
flex-direction: column; flex-direction: column;
} }
#spotify-title { #listenbrainz-title {
font-size: 1.5rem; font-size: 1.2rem;
font-weight: 900; font-weight: 900;
margin: 0; margin: 0;
padding: 0; padding: 0;
@@ -67,15 +67,29 @@
color: white; color: white;
} }
#spotify-artist { #listenbrainz-artist {
color: white; color: white;
font-size: 1rem; font-size: 0.7rem;
font-weight: 900; font-weight: 900;
margin: 0; margin: 0;
padding: 0; padding: 0;
mix-blend-mode: difference; 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 { #button-collection {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
+12 -52
View File
@@ -76,72 +76,32 @@ let last15Chars = "";
document.addEventListener('keydown', function(event) { document.addEventListener('keydown', function(event) {
last15Chars += event.key; last15Chars += event.key;
if (last15Chars.includes("furry")) { if (last15Chars.includes("owo")) {
console.log("owo, whats this?"); console.log("owo, whats this?");
document.getElementById('furry').style.display = 'block'; document.getElementById('furry').style.display = 'block';
last15Chars = ""; last15Chars = "";
} }
if (last15Chars.includes("irken")) { if (last15Chars.includes("doom")) {
console.log("doom doom doom!"); console.log("Im gonna sing the doom song now");
document.querySelector(":root").style.setProperty('--font-family', 'Irken'); 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('--title-font', '1.5em');
document.querySelector(":root").style.setProperty('--line-height', 'default');
document.querySelector(":root").style.setProperty('--header-line-height', 'default');
last15Chars = ""; last15Chars = "";
} }
if (last15Chars.includes("scratch")) { if (last15Chars.includes("kfc")) {
console.log("space chicken"); console.log("space chicken");
document.querySelector(":root").style.setProperty('--font-family', 'Scratch'); document.querySelector(":root").style.setProperty('--font-family', 'Scratch');
document.querySelector(":root").style.setProperty('--title-font', '1em'); 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 = ""; last15Chars = "";
} }
while (last15Chars.length >= 15) { while (last15Chars.length >= 15) {
last15Chars = last15Chars.slice(1); 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();
}
+57
View File
@@ -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);
+11
View File
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Gallery - Toasters's basement{% endblock %}</title>
</head>
<body>
</body>
</html>
+9 -4
View File
@@ -38,10 +38,11 @@
<img src="https://s1nez.nekoweb.org/img/7dcd20d4.gif" alt=""> <img src="https://s1nez.nekoweb.org/img/7dcd20d4.gif" alt="">
</section> </section>
<div class="flex-row"> <div class="flex-row">
<a href="https://www.last.fm/user/acetheking987" id="spotify-link"> <a href="https://listenbrainz.org/user/acetheking987/" id="listenbrainz-link">
<div id="spotify"> <div id="listenbrainz">
<h1 id="spotify-title"></h1> <h1 id="listenbrainz-title">Loading...</h1>
<h2 id="spotify-artist"></h2> <h2 id="listenbrainz-artist">be patient, listenbrainz is slow :P</h2>
<h3 id="listenbrainz-live">Not Live :<</h3>
</div> </div>
</a> </a>
<section class="stamps"> <section class="stamps">
@@ -160,3 +161,7 @@
</section> </section>
<iframe src="https://john.citrons.xyz/embed?ref=alfieking.dev" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe> <iframe src="https://john.citrons.xyz/embed?ref=alfieking.dev" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe>
{% endblock %} {% endblock %}
{% block scripts %}
<script src="/static/js/index.js"></script>
{% endblock %}
+21
View File
@@ -0,0 +1,21 @@
{% extends "bases/base.html" %}
{% block content %}
<section>
<h1>Test</h1>
<img src="static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="toaster" id="img1">
<p id="makeAndModel"></p>
<script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
<script>
window.onload=getExif;
function getExif() {
var img1 = document.getElementById("img1");
EXIF.getData(img1, function() {
var make = EXIF.pretty(this);
makeAndModel.innerHTML = `${make}`;
});
}
</script>
</section>
{% endblock %}