No description
  • Python 47.1%
  • JavaScript 38.8%
  • CSS 9.2%
  • HTML 4.2%
  • Dockerfile 0.4%
  • Other 0.3%
Find a file
2026-10-25 13:01:29 +01:00
deploy Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
static Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
tests Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
vendor/mixengine Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
.containerignore Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
.gitignore Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
airsonic.py Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
airsonic_web.py Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
app.py Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
config.env.beispiel Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
Containerfile Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
COPYRIGHT Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
diagnose.py Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
LICENSE Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
mix_export.py Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
mix_routes.py Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
README.md Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
requirements.txt Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00
start.sh Stand vom 2026-10-25 2026-10-25 13:01:29 +01:00

Playlist-Manager für Airsonic

Arbeitsoberfläche zum Sortieren und Pflegen von Playlists, die über die Subsonic-API gegen eine bestehende Airsonic-Instanz arbeitet. Kein Player: Vorhören dient dem Sortieren, nicht dem Zuhören.

Starten

Die Mix-Engine liegt im Submodul vendor/mixengine (Repo mumblemixer, gemeinsam mit dem Bot-Pult des Mumblebots genutzt) — beim ersten Auschecken bzw. nach einem git pull einmal git submodule update --init laufen lassen, sonst ist der Ordner leer und mix_routes.py findet dj/mixer nicht.

git submodule update --init
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
cp config.env.beispiel config.env   # und ausfüllen
./start.sh

Danach http://127.0.0.1:42200 öffnen. PM_HOST=0.0.0.0 in config.env macht den Manager im Netz erreichbar — er hat keine eigene Anmeldung, wer ihn erreicht, kann also Playlists ändern.

Als Podman-Container

git submodule update --init auch hier zuerst (Podman kopiert nur, was im Arbeitsverzeichnis liegt):

git submodule update --init
podman build -t playlist-manager .
mkdir -p ~/.config/containers/systemd
cp deploy/playlist-manager.container ~/.config/containers/systemd/
systemctl --user daemon-reload
systemctl --user start playlist-manager

Der Manager lauscht dann auf http://127.0.0.1:42200. Die Zugangsdaten trägst du beim ersten Aufruf in der Oberfläche ein; Übernehmen legt sie im Volume playlist-manager-data ab (/data/config.env), dort überstehen sie Neustarts und neue Images. Nach einem Update: Image neu bauen, systemctl --user restart playlist-manager. Damit der Dienst ohne Anmeldung startet (etwa auf einem Server): loginctl enable-linger.

Verbindung einrichten und prüfen

Die Adresse lässt sich auch in der Oberfläche eintragen: der Knopf oben rechts zeigt die aktuelle Instanz und mit einem farbigen Punkt, ob sie steht. Prüfen testet, ohne etwas zu ändern; Übernehmen schreibt die Angaben nach config.env (Dateirechte 600, das Passwort steht im Klartext darin). Steht beim Start keine Verbindung, geht der Dialog von selbst auf.

Der Test geht sieben Schritte durch und endet mit dem, worauf es ankommt: ob diese Instanz die Originaldatei mit exakter Länge und echten Byte-Ranges herausgibt — nur dann springt die Leiste genau. Fehlt dem Benutzer das Download-Recht, sagt der Bericht das mitsamt der Folge; das Vorhören funktioniert dann trotzdem, über den umgewandelten Stream. Der Unterschied ist messbar: derselbe Titel wird dabei als 281,6 s gemeldet statt der tatsächlichen 279,7 s, und um diese Differenz verrutscht das Springen.

Die API-Fassung wird ausgehandelt: der Manager fragt 1.16.1 an, und wenn die Instanz älter ist, nennt sie in ihrer Fehlerantwort ihre eigene Version — die wird dann verwendet.

Bedienung

Links die Liste, an der gearbeitet wird, rechts wahlweise Suche, Stöbern oder eine zweite Liste. Änderungen sammeln sich an und gehen erst beim Speichern zum Server — das Ungespeichert-Zeichen oben zeigt es an.

Gestöbert wird über die Ordner, nicht über ID3-Tags: Musikordner → A–Z → Unterordner → Titel, auch die Treffer der Suche („Ordner“, „Alben“) und „Neueste Alben“ sind Verzeichnisse. Die Brotkrumen zeigen immer den ganzen Pfad, das Feld „Hier filtern…“ grenzt die aktuelle Ansicht ein. Nur „Genres“ hängt naturgemäß an den Tags.

Griff Wirkung
↑ / ↓ Cursor in der aktiven Liste bewegen, die Auswahl folgt
Umschalt+↑ / ↓ Auswahl erweitern
← / → Zwischen linker und rechter Seite wechseln
Umschalt+← / → Im laufenden Titel 10 s zurück/vor
Leertaste halten + ↑ / ↓ Links: Auswahl verschieben
Leertaste halten + ← Rechts: Auswahl hinter den linken Cursor übernehmen, danach links weiterschieben
Leertaste halten + → Links: Auswahl aus der Liste entfernen
Leertaste kurz Wiedergabe anhalten/fortsetzen; läuft nichts, den Titel unter dem Cursor
Umschalt+Leertaste Titel unter dem Cursor abspielen
Enter Ordner öffnen, Titel abspielen
Backspace (beim Stöbern) Eine Ordnerebene hoch
↓ in einem Such- oder Filterfeld In die Liste darunter springen
Ziehen Titel umsortieren; aus der rechten Spalte an eine bestimmte Stelle einfügen
Klick, Strg+Klick, Umschalt+Klick Einzeln, zusätzlich, Bereich auswählen
Alt+↑ / Alt+↓ Auswahl um eine Position verschieben
Doppelklick links Vorhören
Doppelklick rechts Übernehmen
Entf Auswahl aus der Liste entfernen
Strg+Z Rückgängig
Strg+S Speichern
Strg+F In die Suche springen
Strg+A Alles auswählen
Esc Auswahl aufheben

In der Abspielleiste lässt sich frei springen — klicken oder den Regler ziehen; mit Pfeiltasten in 5-Sekunden-Schritten, mit Umschalt in 30er. Ist Weiterspielen an (Schalter in der Abspielleiste), folgt am Ende der nächste Titel derselben Liste — in ihrer aktuellen, auch ungespeicherten Reihenfolge. Er wird 30 Sekunden vorher in einem zweiten Player vorgeladen, so ist der Übergang ohne Ladepause zu hören.

Mix

Mix (links oben) blendet zwischen den Titeln Übergangszeilen ein. Ein Klick klappt den Übergang auf: wo Titel A endet, wo Titel B einsetzt, wie lang überblendet wird und mit welcher Kurve. Nicht Gesetztes misst der Server — die Stille am Anfang und Ende jedes Titels fällt dann weg. ▶ rendert genau diesen Übergang auf dem Server (dieselbe Kette wie der fertige Mix) und spielt ihn ab. Übergänge hängen am Titelpaar, nicht an der Position: nach dem Umsortieren gelten sie weiter, wo dieselben zwei Titel aufeinanderfolgen.

Mix rendern… macht daraus MP3-Dateien (320 kbit/s), an den Titelgrenzen geschnitten — jede Datei endet mit dem Übergang in die nächste. Lückenlos hintereinander gespielt klingt das wie der Mix, Überspringen landet direkt hinter einem Übergang. Die Dateien gehen über die Upload-Seite von Airsonic (Web-Anmeldung, Upload-Recht nötig) in …/Mixe/<Name> neben dem Upload-Ordner; danach liest Airsonic ein und die Playlist „Mix: “ entsteht (oder wird ersetzt). Lautheit wird dabei auf ein gemeinsames Maß gebracht (EBU R128), und jede Datei bekommt das Cover ihres Originals (so, wie Airsonic es zeigt — eingebettet oder cover.jpg im Ordner; 500 px, damit der Tag klein bleibt). Der Benutzer, unter dem Airsonic läuft, muss in Mixe schreiben dürfen; scheitert das Hochladen, steht Airsonics eigene Meldung im Dialog. Ist der Mix fertig, öffnet „Mix-Playlist öffnen“ ihn gleich.

Listen „Mix: …“ spielt auch der Player des Managers lückenlos: Er lädt jeden Titel ganz, dekodiert ihn mit Web Audio (Chrome schneidet die MP3-Polsterung dabei exakt ab) und plant den nächsten auf das Sample genau ans Ende des laufenden — die zwei <audio>-Elemente der anderen Listen lassen an der Naht gut 10 ms Stille. Dafür startet ein Titel erst, wenn er ganz geladen ist („lädt…“ in der Leiste), und der Browser hält den laufenden und den nächsten dekodiert im Speicher (etwa 20 MB je Minute). Scheitert das, spielt der normale Player.

Mix durchhören: Ist der Mix-Modus an, spielt ▶ an einem Titel der linken Liste die Liste so, wie die Übergänge gerade eingestellt sind — ohne Rendern und ohne Airsonic. Der Server rechnet Stück für Stück (Titel ab Ende des einlaufenden bis Ende des auslaufenden Übergangs, mit der schnellen Keylock-Engine, 1–3 s je Stück, danach aus dem Zwischenspeicher in mixdata/segments/), der Player hängt die Stücke lückenlos aneinander („gemischt“ in der Leiste). Ändert man währenddessen einen Übergang, wird das laufende Stück neu gerechnet und an derselben Stelle weitergespielt. Übergänge speichern sich übrigens selbst, kurz nach jeder Änderung (Hinweis neben „Mix rendern…“); der Knopf „Speichern“ betrifft nur die Playlist.

Mix wegräumen… erscheint bei Playlists „Mix: …“ und löscht die gerenderten Dateien samt Ordner und die Playlist. Die Liste, aus der der Mix entstand, und ihre Übergänge bleiben — neu rendern geht jederzeit. Dateien löschen kann die Subsonic-API nicht; das macht deleteMixFolder aus dem Fork airsonic-advanced (ab 5ffbeb4f), der nur flache Ordner direkt unter einem Ordner „Mixe“ annimmt. Andere Instanzen melden beim Wegräumen, dass sie den Aufruf nicht kennen; alles andere geht mit jeder Airsonic-Instanz.

Warum MP3: gemessen mit dem Player von Ultrasonic (Media3/ExoPlayer) sind MP3 mit LAME-Header und unumgewandeltes FLAC lückenlos, Opus nicht (ExoPlayer schneidet dessen Auffüllung am Ende nicht ab), und von Airsonic unterwegs umgewandeltes FLAC schon gar nicht.

Der Übergangs-Editor

Aufgeklappt ist ein Übergang eine kleine Zeitleiste wie in Audacity oder GarageBand (Vorbild: der Transition-Editor von DJ.Studio): A und B liegen als Clips übereinander, B beginnt am Nullpunkt, der Rahmen ist die Überblendung. Über jeder Welle liegt ihre Lautstärke als Linie, darunter die Tempo-Spur.

Tun Wirkung
Clip ziehen A gegen B verschieben — mehr oder weniger Überlappung
Kante ziehen (Ende von A, Anfang von B) abschneiden
Alt beim Ziehen ohne Magnet
Lautstärke-Linie anklicken / Quadrat ziehen Punkt setzen / Zeit und Pegel ändern (Umschalt: nur Pegel)
Tempo-Linie anklicken / Kreis ziehen Punkt setzen / Zeit und Tempo ändern (Umschalt: nur Tempo)
Doppelklick auf einen Punkt löschen
Im Lineal ziehen Bereich markieren, läuft als Schleife
Klick Abspielkopf setzen (in einer Spur: gleich abspielen)
Mausrad / Umschalt+Mausrad zoomen / verschieben
Leertaste · ←/→ · Z · L Abspielen · ein Takt (Umschalt: vier) · vor den Übergang · Schleife
A / B A endet / B beginnt am Abspielkopf
Tempo-Punkt anklicken auswählen: Zeit und BPM darunter genau eintippen; ↑/↓ ±0,01 BPM (Umschalt ±0,1), Entf löscht; Strg beim Ziehen = zehnmal feiner
Strg+Z / Strg+Umschalt+Z Änderung an einem Übergang zurücknehmen / wiederholen (auch Knopf „↶ Rückgängig“)

Magnet: Beim Ziehen rastet ein Clip nur ein, wenn eine seiner Taktlinien (oder Schläge, je nach „Magnet beim Ziehen“) höchstens 10 Pixel neben einer des anderen liegt; die gestrichelte Linie mit „Takt“ zeigt, wo. Sonst bleibt er genau da, wo man ihn loslässt — was von Hand gesetzt ist, verschiebt der Server nicht mehr; nur Automatisches rastet von selbst ein.

Lautstärke: Solange nichts gezeichnet ist, zeigt die Linie die gewählte Blendkurve (gleiche Leistung, linear, S-Kurve) mit Griffen an Anfang und Ende. Wer einen Griff zieht oder auf die Linie klickt, macht daraus eigene Punkte; ab da gilt die gezeichnete Linie statt der Kurve („Lautstärke zurücksetzen“ im Feld darunter holt die Kurve zurück). A spielt vor dem ersten Punkt voll, B nach dem letzten.

Tempo: Punkte auf der Tempo-Linie bilden eine Hüllkurve je Clip — etwa zwei Punkte, damit A nur in den letzten 7 Sekunden auf das Tempo von B gleitet. Vor dem ersten Punkt spielt A in seinem eigenen Tempo, B nach seinem letzten. „Tempo gekoppelt“ lässt B im Übergang der Kurve von A folgen. Ist das Tempo aus (die Automatik gleicht nur an, wenn beide Raster sicher erkannt sind), zeigt die Spur die erkannten Tempi trotzdem als Linien; ein Klick darauf setzt einen Punkt und schaltet auf Keylock.

Vorhören rechnet den Übergang samt Rampen auf dem Server (FLAC, mit der schnellen Keylock-Engine — der fertige Mix nimmt die feine); nach jeder Änderung wird neu gerechnet und an derselben Stelle weitergespielt. „Tempo gekoppelt“ hält A und B im Übergang im selben Tempo.

Takt und Tempo

Beim ersten Öffnen eines Übergangs misst der Server jeden Titel: Tempo (BPM) und Beatgrid — konstantes Tempo wie bei Rekordbox, die Takt-Eins aus den Bass-Anschlägen.

  • Tempo angleichen: Keylock (Tonhöhe bleibt, rubberband) oder Vinyl (Tonhöhe geht mit, wie am Plattenspieler) — pro Übergang. Automatisch wird Keylock gewählt, wenn beide Raster sicher sind und die Tempi höchstens 8 % auseinanderliegen (Halb-/Doppeltempo zählt mit), dann zunächst in der Mitte zwischen beiden. Das Tempo je Clip ist frei (Punkte in der Tempo-Spur, höchstens ±40 %); ohne eigene Punkte gleitet A vorher hinein und B danach wieder heraus. Das Feld „Tempo des Titels“ ist dagegen die Korrektur der Erkennung.
  • Überblendung in Schlägen (4–64), sobald das Tempo angeglichen wird; Einrasten legt den Überblendbeginn in A und den Einstieg von B auf Takt oder Schlag — dann liegen die Schläge deckungsgleich übereinander.
  • Bass tauschen: A behält den Bass bis zur Mitte, dann übernimmt B (Weiche bei 180 Hz); die Höhen folgen der Kurve. Standard bei angeglichenem Tempo.
  • A: Hochpass raus / B: Tiefpass rein: Filterfahrten über die Überlappung.

Das erkannte Raster lässt sich pro Titel korrigieren: BPM eintippen, ½ / ×2, Takt-Eins einen Schlag früher/später (◂ 1 / 1 ▸), fein um 10 ms (‹ ›); „Erkannt“ verwirft die Korrektur. Sie gilt für den Song, also in allen Mixen. Gemessen an synthetischen Spuren: Tempo auf ±0,01 BPM, Raster auf ±3 ms, Schläge nach Keylock/Vinyl auf ±1 ms. Bei Musik ohne klaren Schlag (Klavier) gilt ein Raster als „unsicher“ und es wird nicht von selbst angeglichen.

Originale und Messwerte liegen im Datenordner neben config.env unter mixdata/ (höchstens 5 GB Originale, älteste fliegen zuerst; Korrekturen in grids.json). Braucht ffmpeg mit libmp3lame und rubberband (CLI, ab 3.0); das Container-Image bringt beides mit.

Wie es mit Airsonic redet

Drei Eigenheiten der API bestimmen den Aufbau.

Umsortieren gibt es nicht. Die Subsonic-API kann Titel nur anhängen oder per Index entfernen. createPlaylist mit playlistId und einer songId-Folge ruft serverseitig setFilesInPlaylist auf und ersetzt damit die ganze Liste samt Reihenfolge — darüber laufen hier alle Änderungen. Deshalb wird auch gesammelt statt sofort geschrieben: jede Einzeländerung wäre ein vollständiges Neuschreiben.

Nicht abrufbare Titel fehlen stillschweigend. getPlaylist filtert alle Einträge weg, deren Datei gerade nicht da ist (nicht eingehängt, noch nicht eingelesen). Wer eine solche Liste ausliest und zurückschreibt, löscht diese Einträge endgültig. Der Manager erkennt das an der Differenz zwischen dem ungefilterten songCount und der Zahl gelieferter Einträge, warnt sichtbar und verweigert das Speichern, bis man den Verlust ausdrücklich bestätigt.

Vorhören läuft nicht über stream. download.view liefert die Originaldatei mit exakter Länge und echten Byte-Ranges — nur so springt die Leiste im Browser genau; bei stream.view mit Transcodierung ist die Länge nur geschätzt und großzügig gepolstert. Außerdem zählt stream bei jedem Aufruf den Play-Count hoch, download nicht: Sich durch hunderte Titel zu hören, verfälscht so nicht „Meistgespielt" und „Zuletzt gespielt".

Kann der Browser das Originalformat nicht abspielen, weicht der Manager selbsttätig auf den umgewandelten Stream aus und schreibt „umgewandelt" in die Abspielleiste — dann ist das Springen ungenau.

Alle Aufrufe laufen über das eigene Backend, weil Airsonic keine CORS-Header setzt und die Zugangsdaten so nicht im Browser landen. Schreibende Aufrufe gehen als POST auf URLs mit .view-Endung: lange songId-Listen sprengen als GET das Headerlimit, und der CSRF-Schutz lässt nur .view durch.

Grenzen

  • Vorhören lädt die Originaldatei. Bei hochauflösendem FLAC sind das schnell 80 MB und mehr — im lokalen Netz kein Thema, über eine dünne Leitung schon.
  • Beim Anlegen einer Liste wird sie über ihren Namen wiedergefunden, weil createPlaylist keine ID zurückgibt. Bei mehreren gleichnamigen Listen gewinnt die zuletzt angelegte.
  • Titel, die Airsonic nicht herausgibt, kann auch dieser Manager nicht anzeigen oder erhalten — nur davor warnen.