Rework my page and add info from listenbrainz

This commit is contained in:
2026-01-22 23:55:58 +03:00
parent e97985b624
commit ea5156aa6c
18 changed files with 336 additions and 227 deletions
+25 -12
View File
@@ -1,7 +1,19 @@
import os
import magic
from pathlib import Path
from htmlmin import minify
from flask import Blueprint, render_template, send_from_directory, send_file, abort
from datetime import datetime, timedelta
from musicbrainzngs import get_image_front
from flask import (
Blueprint,
render_template,
send_file,
send_from_directory,
make_response,
abort,
)
from .modules.api.lb import listens, listening
bp = Blueprint(
"risdeveau",
@@ -11,10 +23,10 @@ bp = Blueprint(
static_folder=None
)
def render_tmpl(filename: str) -> str:
def render_tmpl(filename: str, **kwargs) -> str:
template_path = os.path.join("risdeveau/templates", filename)
return minify(
render_template(template_path),
render_template(template_path, **kwargs),
remove_empty_space=True
)
@@ -26,14 +38,15 @@ def static(filename: str):
return send_file(path)
return abort(404)
@bp.route("/asset/mb/<mbid>")
def mb_cover(mbid):
r = make_response(image := get_image_front(mbid, "250"))
r.headers['Content-Type'] = magic.from_buffer(image[:2048], mime=True)
r.headers['Cache-Control'] = 'public, max-age=86400'
r.headers['Expires'] = (datetime.now() + timedelta(days=1)) \
.strftime('%a, %d %b %Y %H:%M:%S GMT')
return r
@bp.route("/")
def index():
return render_tmpl('index.html')
@bp.route("/contacts")
def contacts():
return render_tmpl('contacts.html')
@bp.route("/donate")
def donate():
return render_tmpl('donate.html')
return render_tmpl('index.html', lb=listens, lb_now=listening)
+89
View File
@@ -0,0 +1,89 @@
from flask import Flask, jsonify
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
import requests
from datetime import datetime
import atexit
import re
from urllib.parse import urlparse, parse_qs
listens = {}
listening = {}
def yt_cover(youtube_url):
parsed_url = urlparse(youtube_url)
if parsed_url.netloc in ("youtube.com", "music.youtube.com"):
query_params = parse_qs(parsed_url.query)
video_id = query_params.get('v', [None])[0]
elif parsed_url.netloc == 'youtu.be':
video_id = parsed_url.path[1:]
if not video_id:
return
return f"http://img.youtube.com/vi/{video_id}/sddefault.jpg"
def parse_listens(data: dict) -> dict:
new_data = {
"count": data["count"],
"listens": []
}
for track in data["listens"]:
track = track["track_metadata"]
new_track = {
"artist_name": track["artist_name"],
"track_name": track["track_name"]
}
if mb := track.get("mbid_mapping"):
new_track["id"] = mb.get("caa_release_mbid", mb["release_mbid"])
new_track["artist_name"] = mb["artists"][0]["artist_credit_name"]
new_track["track_name"] = mb["recording_name"]
elif info := track.get("additional_info"):
if info \
.get("music_service_name", "") \
.lower() in ("youtube", "youtube music"):
if cover := yt_cover(track["additional_info"]["origin_url"]):
new_track["cover_url"] = cover
if "cover_url" not in new_track.keys() and "id" in new_track.keys():
new_track["cover_url"] = "/asset/mb/" + new_track["id"]
new_data["listens"].append(new_track)
return new_data
def api_request(url: str, cache):
try:
response = requests.get(url, timeout=10)
if response.status_code == 200:
cache.update({
'data': parse_listens(response.json().get("payload")),
'last_updated': datetime.now().isoformat(),
'status': 'success'
})
else:
cache['status'] = f'error: {response.status_code}'
except Exception as e:
cache['status'] = f'error: {str(e)}'
scheduler = BackgroundScheduler()
scheduler.add_job(
func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/listens?count=5", listens),
trigger=IntervalTrigger(minutes=1),
id='risdeveau.listenbrainz.listens',
replace_existing=True
)
scheduler.add_job(
func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/playing-now", listening),
trigger=IntervalTrigger(seconds=15),
id='risdeveau.listenbrainz.playing-now',
replace_existing=True
)
scheduler.start()
atexit.register(lambda: scheduler.shutdown())
Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 13 KiB

@@ -1,29 +1,5 @@
@use "sass:color";
// Palette: Catppuccin Mocha
// https://catppuccin.com/palette/
$base: #1e1e2e;
$text: #cdd6f4;
$mantle: #181825;
$crust: #11111b;
$overlay0: #6c7086;
$overlay1: #7f849c;
$overlay2: #9399b2;
$surface0: #313244;
$surface1: #45475a;
$surface2: #585b70;
$subtext0: #a6adc8;
$subtext1: #bac2de;
$red: #f38ba8;
$green: #a6e3a1;
$peach: #fab387;
$blue: #89b4fa;
$mauve: #8839ef;
@use "../../../root/static/style/catppuccin" as theme;
h3 {
margin-block-end: 0;
@@ -58,6 +34,20 @@ h3 {
}
}
.track {
display: flex;
&.active {
box-shadow: theme.$green 0 0 5px 0;
}
img {
width: 5rem;
height: 5rem;
border-radius: .5rem;
}
}
table, tbody {
vertical-align: baseline;
border-collapse: collapse;
@@ -66,7 +56,7 @@ table, tbody {
border-radius: 10px;
&:hover {
background-color: color.change($surface1, $alpha:75%);
background-color: color.change(theme.$surface1, $alpha:75%);
}
th {
+16
View File
@@ -0,0 +1,16 @@
<div>
<div class="88-31">
<a href="https://chest.lair.moe" class="disabled">
<img src="/static/img/88x31/gf.png"/>
</a>
<a href="https://preview.about.akarpov.ru" id="pie">
<img src="/static/img/88x31/withpie.gif"/>
</a>
</div>
<div class="88-31">
<a href="https://g.lair.moe/Sweetbread/nixos-config">
<img src="/static/img/88x31/nixos.webp"/>
</a>
<img src="/static/img/88x31/teto.webp"/>
</div>
</div>
-24
View File
@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Sweet Bread</title>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="stylesheet" href="/static/style/risdeveau.css">
<link rel="icon" type="image/webp" href="/static/icon/us/risdeveau.webp" />
<script
src="https://track.lair.moe/api/script.js"
data-site-id="1"
defer
></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block head %}{% endblock %}
</head>
<body>
{% include 'risdeveau/templates/header.tmpl' %}
<main>
{% block content %}{% endblock %}
</main>
</body>
</html>
@@ -1,14 +1,4 @@
{% extends 'risdeveau/templates/base.tmpl' %}
{% block head %}
<style>
main {
width: -webkit-fill-available;
}
</style>
{% endblock %}
{% block content %}
<div class="block">
<h3>Development</h3>
<div class="blocks badges">
<a class="block" href="//g.lair.moe/Sweetbread">
@@ -55,4 +45,4 @@
GameBanana
</a>
</div>
{% endblock %}
</div>
+19
View File
@@ -0,0 +1,19 @@
<div>
<h3>Wallets</h3>
<div class="blocks qr">
<div class="block qr">
<p>POL, BNB</p>
<img src="/static/img/wallets/evm.webp">
</div>
<div class="block qr">
<p>TON</p>
<img src="/static/img/wallets/ton.webp">
</div>
<div class="block qr">
<p>XMR</p>
<img src="/static/img/wallets/xmr.webp">
</div>
</div>
</div>
@@ -1,21 +0,0 @@
{% extends 'risdeveau/templates/base.tmpl' %}
{% block content %}
<h3>Wallets</h3>
<div class="blocks qr">
<div class="block qr">
<p>POL, BNB</p>
<img src="/static/img/wallets/evm.webp">
</div>
<div class="block qr">
<p>TON</p>
<img src="/static/img/wallets/ton.webp">
</div>
<div class="block qr">
<p>XMR</p>
<img src="/static/img/wallets/xmr.webp">
</div>
</div>
{% endblock %}
@@ -1,20 +0,0 @@
<header>
{%- if request.path != url_for('.index') %}
<a href="{{ url_for('.index') }}">Main</a>
{%- else %}
<a href="{{ url_for('root.index') }}">Lair</a>
{%- endif %}
<div class="header-links">
{%- for (l, t) in (
('.contacts', _('contacts')),
('.donate', _('donate'))
) %}
{%- if url_for(l) == request.path %}
<strong>{{ t }}</strong>
{%- else %}
<a href="{{ url_for(l) }}">{{ t }}</a>
{%- endif %}
{%- endfor %}
</div>
</header>
+31 -67
View File
@@ -1,69 +1,33 @@
{% extends 'risdeveau/templates/base.tmpl' %}
<!DOCTYPE html>
<html>
<head>
<title>Sweet Bread</title>
{% block content %}
<div class="block">
<table>
<tr>
<th>DoB</th>
<td>2005-01-13</td>
</tr>
<tr>
<th>Languages</th>
<td>
<table>
<tr>
<td>Russian</td>
<td>Native</td>
</tr>
<tr>
<td>English</td>
<td>B2</td>
</tr>
<tr>
<td>French</td>
<td>A1?</td>
</tr>
<tr>
<td>German</td>
<td>A2?</td>
</tr>
<tr>
<td>Japanese</td>
<td>Beginner</td>
</tr>
</table>
</td>
</tr>
<tr>
<th>Student</th>
<td>
<table>
<tr>
<td>Programmer</td>
<td>2/4yr.</td>
</tr>
<tr>
<td>Translator</td>
<td>2/3yr.</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="stylesheet" href="/static/style/risdeveau.css">
<link rel="icon" type="image/webp" href="/static/icon/us/risdeveau.webp" />
<script
src="https://track.lair.moe/api/script.js"
data-site-id="1"
defer
></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<header>
<a href="{{ url_for('root.index') }}">Lair</a>
</header>
<div class="88-31">
<a href="https://chest.lair.moe" class="disabled">
<img src="/static/img/88x31/gf.png"/>
</a>
<a href="https://preview.about.akarpov.ru" id="pie">
<img src="/static/img/88x31/withpie.gif"/>
</a>
</div>
<div class="88-31">
<a href="https://g.lair.moe/Sweetbread/nixos-config">
<img src="/static/img/88x31/nixos.webp"/>
</a>
<img src="/static/img/88x31/teto.webp"/>
</div>
{% endblock %}
<main>
{% for m in (
'info',
'contacts',
'listenbrainz',
'donate',
'88x31'
) %}
{% include 'risdeveau/templates/%s.htm' % m %}
{% endfor %}
</main>
</body>
</html>
+50
View File
@@ -0,0 +1,50 @@
<div class="block">
<table>
<tr>
<th>DoB</th>
<td>2005-01-13</td>
</tr>
<tr>
<th>Languages</th>
<td>
<table>
<tr>
<td>Russian</td>
<td>Native</td>
</tr>
<tr>
<td>English</td>
<td>B2</td>
</tr>
<tr>
<td>French</td>
<td>A1?</td>
</tr>
<tr>
<td>German</td>
<td>A2?</td>
</tr>
<tr>
<td>Japanese</td>
<td>Beginner</td>
</tr>
</table>
</td>
</tr>
<tr>
<th>Student</th>
<td>
<table>
<tr>
<td>Programmer</td>
<td>2/4yr.</td>
</tr>
<tr>
<td>Translator</td>
<td>2/3yr.</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
@@ -0,0 +1,23 @@
{% macro track_block(track, is_active=false) %}
<div class="block track{% if is_active %} active{% endif %}">
{% if track.cover_url %}
<img src="{{ track.cover_url }}"/>
{% endif %}
<div>
<p><b>{{ track.artist_name }}</b></p>
<p>{{ track.track_name }}</p>
</div>
</div>
{% endmacro %}
<div class="block">
<h2><a href="https://listenbrainz.org/user/risdeveau/">Listenbrainz</a></h2>
{% if lb_now.data and lb_now.data.listens.0 %}
{{ track_block(lb_now.data.listens.0, is_active=true) }}
{% endif %}
{% if lb.data and lb.data.listens %}
{% for track in lb.data.listens %}
{{ track_block(track) }}
{% endfor %}
{% endif %}
</div>