From 68019352e21ea57b374a2181e2036ddef3aff7ce Mon Sep 17 00:00:00 2001 From: bernd Date: Tue, 29 Sep 2026 12:17:10 +0200 Subject: [PATCH] neue Sortierung nach mp3-tags --- recorder.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/recorder.py b/recorder.py index 1c40b9d..af4d867 100644 --- a/recorder.py +++ b/recorder.py @@ -2,6 +2,7 @@ import os import signal import subprocess import threading +import json import time from datetime import datetime from pathlib import Path @@ -137,6 +138,51 @@ def format_duration(seconds): return f"{minutes}:{seconds:02d}" +def read_metadata(path): + """Read common ID3/FFmpeg metadata from an MP3.""" + try: + result = subprocess.run( + ["ffprobe", "-v", "error", "-show_entries", + "format_tags=date,artist,title,album", "-of", "json", str(path)], + capture_output=True, text=True, timeout=10, + ) + if result.returncode != 0: + return {} + data = json.loads(result.stdout) + tags = data.get("format", {}).get("tags", {}) or {} + return {str(k).lower(): str(v) for k, v in tags.items() if v is not None} + except Exception: + return {} + + +def metadata_datetime(path): + tags = read_metadata(path) + value = tags.get("date", "") + if value: + try: + dt = datetime.fromisoformat(value.replace("Z", "+00:00")) + if dt.tzinfo is None: + dt = dt.replace(tzinfo=TIMEZONE) + return dt.astimezone(TIMEZONE).strftime("%d.%m.%Y %H:%M") + except ValueError: + pass + return format_datetime(path.stat().st_mtime) + + +def metadata_sort_key(path): + tags = read_metadata(path) + value = tags.get("date", "") + if value: + try: + dt = datetime.fromisoformat(value.replace("Z", "+00:00")) + if dt.tzinfo is None: + dt = dt.replace(tzinfo=TIMEZONE) + return dt.timestamp() + except ValueError: + pass + return path.stat().st_mtime + + def get_duration(filename, directory=RECORDINGS_DIR): path = directory / filename @@ -741,9 +787,10 @@ a.button:hover { - - - + + + + @@ -757,9 +804,11 @@ a.button:hover { - + - + + + @@ -855,17 +904,21 @@ def render_index(): for path in FINISHED_DIR.glob("*.mp3"): try: stat = path.stat() + tags = read_metadata(path) files.append({ "filename": path.name, - "datetime": format_datetime(stat.st_mtime), + "datetime": metadata_datetime(path), + "artist": tags.get("artist", ""), + "title": tags.get("title", ""), + "album": tags.get("album", ""), "size": format_size(stat.st_size), "duration": format_duration(get_duration(path.name, FINISHED_DIR)), - "mtime": stat.st_mtime, + "sort_date": metadata_sort_key(path), }) except FileNotFoundError: continue - files.sort(key=lambda item: item["mtime"], reverse=True) + files.sort(key=lambda item: item["sort_date"], reverse=True) with state_lock: process = ffmpeg_process
StartDateiGrößeZeitpunktRednerBeschreibungVeranstaltung Dauer Wiedergabe {{ item.datetime }}{{ item.filename }}{{ item.artist or "–" }}{{ item.size }}{{ item.title or "–" }}{{ item.album or "–" }} {{ item.duration }}