Die Folgen eines YouTube-Kanals werden gehört wie Podcasts; unterbrochen wird man
darin von der Werbung und vom Schluss. Beides markieren andere Hörer bei
SponsorBlock: podcasts/sponsor.py fragt je Folge einmal danach (nur sponsor und
outro, nur Teile, die übersprungen werden, kein „full“) und legt die Antwort an
der Folge ab (PodcastEpisode.sponsor); GET /podcasts/episodes/<id>/sponsor/
antwortet damit. Eine Antwort gilt eine Woche, ein Fehlschlag eine Stunde.
Der Player springt über solche Teile (podcasts-web.js für Browser und Desktop,
in der App später der eigene Player); der Schalter heißt skip_sponsor, steht bei
„Stille überspringen“ im Abspiel- und Tempomenü, ist an und wirkt nur bei
YouTube-Folgen (default on). e2e/sponsor.spec.js spielt es in Chromium durch;
sw v155
Eine App mit alter Bücherliste (Desktop während des langsamen Syncs) hat beim Öffnen fünf
MEW-Bände mit ihrem alten Stand überschrieben – Titel, Autor, Ordner weg. base_iv sagt dem
Server, von welchem Stand eine Änderung ausgeht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ein MEW-Band mit 1000 Seiten bereitete vorher jede Seite vor und zeichnete alle, bevor er sich
zeigte – Minuten und Gigabytes. e2e/pdf.spec.js mit einem 400-Seiten-PDF (e2e/make_pdf.py, pypdf).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Icons: eigene SVGs, kräftig und geometrisch (2,4 px, eckige Enden), in
nav.js für alle Leisten (DioraNav.icon, sections()/groups() .svg); der
aktive Bereich gefüllt.
- Hochladen: mehrere Dateien auf einmal (Auswahl oder auf die Bibliothek
ziehen) und aus der Cloud per Häkchen („Alle auswählen“, „n importieren“);
nacheinander mit Fortschritt, ein schon vorhandenes Buch (Titel und Autor)
wird übersprungen.
- Pro Buch: „Generiertes Cover verwenden“ statt des eigenen (im verschlüsselten
Meta, cover: 'generated').
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ein neuer Abschnitt (docs/sources.md, static/js/sources.js) für Podcasts,
YouTube-Kanäle, Hörbücher, Nachrichten und Blogs:
- ein Feld zum Hinzufügen: Adresse (Feed, Seite, YouTube) oder Name eines
Podcasts; die Art ist wählbar (Podcast, Hörbuch, Nachrichten, Blog);
/feeds/discover/ erkennt dafür Podcasts (Folgen mit Ton oder Video);
- eine Liste aller Abos mit Filtern (auch „Probleme“) und Suche;
- je Abo: Inhalt öffnen, Einstellungen (die vorhandenen Editoren), Art ändern,
abbestellen; OPML-Import und -Export.
In der Seitenleiste unten, auf dem Telefon im App-Menü; ⚙ in den Feeds führt
hierher. Abschnitte, die beim Laden schon gezeigt werden, füllen sich jetzt
auch (nav.js zeigt sie nach dem Laden aller Skripte noch einmal).
Podcast-UI aus diora-android 50c6f9c.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Bereiche nach dem, was man tut (docs/navigation.md): Home; Lesen mit
Bücher, Zeitschriften, Nachrichten, Blogs; Hören mit Hörbücher, Podcasts,
Radio, Ambient. static/js/nav.js ist die eine Definition für alle Plattformen
(DioraNav: Abschnitte, Gruppen, go, Hash, zuletzt gewählter Abschnitt je
Gruppe). Die Webseite zeichnet ihre Leiste daraus: breit alle Abschnitte unter
ihrer Gruppe, schmal Home · Lesen · Hören mit einer Abschnittszeile oben.
- Hörbücher haben ein eigenes Panel (#tab-audiobooks), nicht mehr über den E-Books.
- Zeitschriften: die Bücher im Ordner „Zeitschriften“ (oder „Magazine“).
- Nachrichten/Blogs wählt die Navigation; der eigene Umschalter verschwindet dann.
- Ein Link auf einen Abschnitt (#news …) schlägt die Startseite.
Die Apps zeichnen ihre Leiste (native-radio.js, diora-android) bald ebenfalls
daraus; bis dahin bleibt das hier unveröffentlicht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Leiste nimmt ihre Breite links weg; dieselbe Breite kommt rechts als
Abstand dazu, soweit Platz ist (die Spalte wird dafür nie schmaler). Beides
gleitet gleichzeitig, der Text bleibt stehen. Neu berechnet beim Öffnen und
Schließen der Leiste, bei Fenstergröße und Zeilenlänge/Schrift.
e2e: Test dafür (breit: Spalte bleibt, schmal: weicht aus, bleibt gleich
breit, liegt nicht unter der Leiste); Service Worker in den Tests aus (sein
Neuladen störte mitten im Test).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- e2e/reader.spec.js: ein Test-EPUB (e2e/make_epub.py) hochladen, öffnen ohne
zu senden, lesen und Lesestand nach Neuladen, Fußnote, Markierung und
Notizleiste, Hell/Dunkel samt Reader, alle Tabs ohne Seitenfehler.
- e2e/env.js: E2E_PORT und E2E_PYTHON; nie einen laufenden Server
wiederverwenden (dahinter läge eine echte Datenbank).
- CI: eigener Job e2e (Playwright + Chromium); blockiert den Docker-Build nicht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Books: Reader sprang beim Scroll+sofortigem Tap auf die alte Position
zurück (Anker-Tracking lief nur alle 2s über den Save-Debounce, jetzt
eigener 150ms-Tracker unabhängig davon)
- Books: +/- Buttons neben den Reader-Slidern (Font/Zeilenhöhe/Breite)
- Books: Sicherheitsnetz-Toast bei plötzlichen großen Scroll-Sprüngen
(Fling, aus Versehen 'G' gedrückt) mit Zurückspringen-Option; bewusste
Sprünge (TOC, Lesezeichen, Fortschritts-Eingabe, Suche) lösen ihn nicht aus
- Radio: Donation-Hinweis kam bei vielen Lieblingssendern gefühlt ständig —
jetzt zusätzlich auf ~1-von-10 Plays gedrosselt
- UI: farbige Emoji-Icons (🔍📻⏪⏩💡 etc.) durch monochrome Unicode-Symbole
ersetzt, die nicht mehr je nach OS/Browser-Font unterschiedlich aussehen;
Lesezeichen-Icon war zudem fast identisch zum TOC-Icon
- UI: native alert()/confirm()/prompt() durch eigenes Modal-System ersetzt
- UI: Hash-basiertes URL-Routing für Tabs (#radio/saved, #podcasts/feeds, …)
— Browser-Zurück/Vor und Deep-Links funktionieren jetzt
- Tests: Playwright e2e-Setup gegen isolierte Test-DB (DIORA_DB_NAME),
Smoke- und Auth-Specs
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>