From db11fabe1a645fa684123c9869917415a050c01b Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Fri, 6 Feb 2026 23:24:41 +0300 Subject: [PATCH] Refactoring --- blueprints/risdeveau/__init__.py | 50 +++++-------- blueprints/risdeveau/modules/api/lb.py | 70 ++++++++++++------- blueprints/risdeveau/modules/api/steam.py | 59 +++++++++++----- .../risdeveau/templates/listenbrainz.htm | 14 ++-- blueprints/risdeveau/templates/steam.htm | 16 ++--- 5 files changed, 120 insertions(+), 89 deletions(-) diff --git a/blueprints/risdeveau/__init__.py b/blueprints/risdeveau/__init__.py index 2933e0d..765d0f3 100644 --- a/blueprints/risdeveau/__init__.py +++ b/blueprints/risdeveau/__init__.py @@ -1,24 +1,22 @@ import os -import magic -from pathlib import Path -from htmlmin import minify -from time import time from datetime import datetime, timedelta -from hashlib import md5 -from json import dumps -from musicbrainzngs import get_image_front +from pathlib import Path +from time import time + from flask import ( Blueprint, - request, - render_template, - send_file, - send_from_directory, - make_response, abort, + make_response, + render_template, + request, + send_file, ) +import magic +from htmlmin import minify +from musicbrainzngs import get_image_front -from .modules.api.lb import listens, listening -from .modules.api.steam import recent, owned +from .modules.api.lb import data as lb_data +from .modules.api.steam import data as steam_data def tmsmp(sec: int) -> str: if sec == 0: @@ -43,12 +41,6 @@ def utmsmp(unix: int) -> str: def rtmsmp(unix: int) -> str: return tmsmp(int(time() - unix)) -def lb_etag(): - return md5((dumps(listens.get('data')) + dumps(listening.get('data'))).encode()).hexdigest() - -def steam_etag(): - return md5((dumps(recent.get('data')) + dumps(owned.get('data'))).encode()).hexdigest() - bp = Blueprint( "risdeveau", __name__, @@ -82,12 +74,8 @@ def mb_cover(mbid): return r args = { - "lb_etag": lb_etag, - "steam_etag": steam_etag, - "lb": listens, - "lb_now": listening, - "recent": recent, - "owned": owned, + "lb": lb_data, + "steam": steam_data, "tmsmp": tmsmp, "utmsmp": utmsmp, "rtmsmp": rtmsmp @@ -106,15 +94,15 @@ def module(module): if any((modified_since, none_match)): match module: case "listenbrainz": - if modified_since >= int(max((x.get('last_updated', 0) for x in (listens, listening)))): + if modified_since >= int(lb_data['last_updated']): return '', 304 - if none_match == lb_etag(): + if none_match == lb_data['etag']: return '', 304 case "steam": - if modified_since >= int(max((x.get('last_updated', 0) for x in (recent, owned)))): - return "Not updated yet", 304 - if none_match == steam_etag(): + if modified_since >= int(steam_data['last_updated']): + return '', 304 + if none_match == steam_data['etag']: return '', 304 return render_tmpl(f'{module}.htm', **args) diff --git a/blueprints/risdeveau/modules/api/lb.py b/blueprints/risdeveau/modules/api/lb.py index 8f5dc7a..10b4491 100644 --- a/blueprints/risdeveau/modules/api/lb.py +++ b/blueprints/risdeveau/modules/api/lb.py @@ -1,14 +1,31 @@ -from flask import Flask, jsonify +import atexit +import re +from dataclasses import dataclass +from hashlib import md5 +from json import dumps +from time import time +from urllib.parse import parse_qs, urlparse + from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.interval import IntervalTrigger import requests -from time import time -import atexit -import re -from urllib.parse import urlparse, parse_qs +from flask import Flask, jsonify -listens = {} -listening = {} + +@dataclass +class Cache: + data = {} + last_updated = time() + status = None + +data = { + "caches": { + "now": Cache(), + "listens": Cache() + }, + "last_updated": time(), + "etag": "" +} def yt_cover(youtube_url): parsed_url = urlparse(youtube_url) @@ -23,15 +40,15 @@ def yt_cover(youtube_url): if not video_id: return - return f"http://img.youtube.com/vi/{video_id}/sddefault.jpg" + return f"https://img.youtube.com/vi/{video_id}/sddefault.jpg" -def parse_listens(data: dict) -> dict: - new_data = { - "count": data["count"], +def parse_listens(json: dict) -> dict: + new_json = { + "count": json["count"], "listens": [] } - for track in data["listens"]: + for track in json["listens"]: track = track["track_metadata"] new_track = { @@ -53,33 +70,38 @@ def parse_listens(data: dict) -> dict: 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) + new_json["listens"].append(new_track) - return new_data + return new_json -def api_request(url: str, cache): +def api_request(url: str, cache: Cache): try: response = requests.get(url, timeout=10) if response.status_code == 200: - cache.update({ - 'data': parse_listens(response.json().get("payload")), - 'last_updated': time(), - 'status': 'success' - }) + json = parse_listens(response.json().get("payload")) + cache.status = 'success' + + if cache.data != json: + cache.data = json + cache.last_updated = time() + data['last_updated'] = time() + data['etag'] = md5(''.join( + ( dumps(data['caches'][x].data) for x in data['caches'] ) + ).encode()).hexdigest() else: - cache['status'] = f'error: {response.status_code}' + cache.status = f'error: {response.status_code}' except Exception as e: - cache['status'] = f'error: {str(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), + func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/listens?count=5", data['caches']['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), + func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/playing-now", data['caches']['now']), trigger=IntervalTrigger(seconds=15), id='risdeveau.listenbrainz.playing-now', replace_existing=True diff --git a/blueprints/risdeveau/modules/api/steam.py b/blueprints/risdeveau/modules/api/steam.py index 6f45c77..5061d33 100644 --- a/blueprints/risdeveau/modules/api/steam.py +++ b/blueprints/risdeveau/modules/api/steam.py @@ -1,18 +1,35 @@ +import atexit +import re +from dataclasses import dataclass +from hashlib import md5 +from json import dumps from os import environ -from flask import Flask, jsonify +from time import time +from urllib.parse import parse_qs, urlparse + from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.interval import IntervalTrigger import requests -from time import time -import atexit -import re -from urllib.parse import urlparse, parse_qs +from flask import Flask + TOKEN = environ.get("STEAM_TOKEN") MY_ID = 76561198826355942 -recent = {} -owned = {} +@dataclass +class Cache: + data = {} + last_updated = time() + status = None + +data = { + "caches": { + "recent": Cache(), + "owned": Cache() + }, + "last_updated": time(), + "etag": "" +} def modify_game_list(json: dict) -> dict: if 'games' in json.keys(): @@ -37,34 +54,40 @@ def api_request(cache, *args, **kwargs): try: response = steam_request(*args, **kwargs) if response.status_code == 200: - cache.update({ - 'data': modify_game_list(response.json().get("response")), - 'last_updated': time(), - 'status': 'success' - }) + json = modify_game_list(response.json().get("response")) + cache.status = 'success' + + if cache.data != json: + cache.data = json + cache.last_updated = time() + data['last_updated'] = time() + data['etag'] = md5(''.join( + ( dumps(data['caches'][x].data) for x in data['caches'] ) + ).encode()).hexdigest() else: - cache['status'] = f'error: {response.status_code}' + cache.status = f'error: {response.status_code}' + print("x") except Exception as e: - cache['status'] = f'error: {str(e)}' + cache.status = f'error: {str(e)}' if TOKEN: scheduler = BackgroundScheduler() scheduler.add_job( - func=lambda: api_request(recent, "IPlayerService", "GetRecentlyPlayedGames", steamid=76561198826355942), + func=lambda: api_request(data['caches']['recent'], "IPlayerService", "GetRecentlyPlayedGames", steamid=76561198826355942), trigger=IntervalTrigger(minutes=15), id='risdeveau.steam.recent', replace_existing=True ) scheduler.add_job( - func=lambda: api_request(owned, "IPlayerService", "GetOwnedGames", steamid=76561198826355942, include_appinfo=1, include_played_free_games=1), + func=lambda: api_request(data['caches']['owned'], "IPlayerService", "GetOwnedGames", steamid=76561198826355942, include_appinfo=1, include_played_free_games=1), trigger=IntervalTrigger(minutes=60), id='risdeveau.steam.owned', replace_existing=True ) scheduler.start() - api_request(recent, "IPlayerService", "GetRecentlyPlayedGames", steamid=76561198826355942) - api_request(owned, "IPlayerService", "GetOwnedGames", steamid=76561198826355942, include_appinfo=1, include_played_free_games=1) + api_request(data['caches']['recent'], "IPlayerService", "GetRecentlyPlayedGames", steamid=76561198826355942) + api_request(data['caches']['owned'], "IPlayerService", "GetOwnedGames", steamid=76561198826355942, include_appinfo=1, include_played_free_games=1) atexit.register(lambda: scheduler.shutdown()) else: diff --git a/blueprints/risdeveau/templates/listenbrainz.htm b/blueprints/risdeveau/templates/listenbrainz.htm index 83ce5d8..b48b260 100644 --- a/blueprints/risdeveau/templates/listenbrainz.htm +++ b/blueprints/risdeveau/templates/listenbrainz.htm @@ -10,25 +10,23 @@ {% endmacro %} -{% if lb_now.data and lb.data %}

Listenbrainz

- {% if lb_now.data and lb_now.data.listens.0 %} - {{ track_block(lb_now.data.listens.0, is_active=true) }} + {% if lb.caches.now.data and lb.caches.now.data.listens.0 %} + {{ track_block(lb.caches.now.data.listens.0, is_active=true) }} {% endif %} - {% if lb.data and lb.data.listens %} - {% for track in lb.data.listens %} + {% if lb.caches.listens.data and lb.caches.listens.data.listens %} + {% for track in lb.caches.listens.data.listens %} {{ track_block(track) }} {% endfor %} {% endif %}
-{% endif %} diff --git a/blueprints/risdeveau/templates/steam.htm b/blueprints/risdeveau/templates/steam.htm index 1a181aa..f9735c0 100644 --- a/blueprints/risdeveau/templates/steam.htm +++ b/blueprints/risdeveau/templates/steam.htm @@ -4,15 +4,15 @@ hx-trigger="every 1m" hx-swap="outerHTML" hx-headers='{ - "If-Modified-Since": {{ (recent.last_updated, owned.last_updated) | max | int }}, - "If-None-Match": "{{ steam_etag() }}" + "If-Modified-Since": {{ steam.last_updated | int }}, + "If-None-Match": "{{ steam.etag }}" }' >

Steam

- {% if recent.data.games %} + {% if steam.caches.recent.data.games %}

Recently played:

- {% for g in recent.data.games %} + {% for g in steam.caches.recent.data.games %} @@ -31,12 +31,12 @@ {% endfor %} -

Last updated: {{ rtmsmp(recent.last_updated) }} ago

+

Last updated: {{ rtmsmp(steam.caches.recent.last_updated) }} ago

{% endif %} - {% if owned.data.games %} + {% if steam.caches.owned.data.games %}

Top played games:

- {% set owned_games = owned.data.games | sort(attribute="playtime_forever", reverse=true) %} + {% set owned_games = steam.caches.owned.data.games | sort(attribute="playtime_forever", reverse=true) %} {% for g in owned_games[:5] %} @@ -58,6 +58,6 @@ {% endfor %} -

Last updated: {{ rtmsmp(owned.last_updated) }} ago

+

Last updated: {{ rtmsmp(steam.caches.owned.last_updated) }} ago

{% endif %}