In den Einstellungen (Gruppe "Audioausgabe", Felder "YouTube" und "YouTube Musik") laesst
sich getrennt waehlen, ueber welches Ausgabegeraet der Ton jedes Tabs laeuft - z.B. auf
getrennte Sonar-Kanaele. Die Auswahl gilt sofort, auch fuer bereits geoeffnete Seiten.
Warum ueber die Seite: QtWebEngine spielt beide Tabs ueber einen gemeinsamen Audio-Prozess
ab, Windows kann sie daher nicht einzeln routen. Chromium kann aber pro Medienelement ein
Geraet waehlen (setSinkId).
- audio_routing.py (neu): Router-Skript (findet das Geraet ueber seinen Namen, kennt den
Hardware-ID-Suffix von Chromium, behandelt dynamisch erzeugte Elemente, Zielwechsel,
Zuruecksetzen und fehlende Geraete), Geraeteliste (QMediaDevices), Freigabe der
Geraetenamen (Chromium blendet sie ohne Mikrofon-Berechtigung aus)
- Freigabe nur solange ein Tab ein eigenes Geraet nutzt, nur fuer die beiden YouTube-
Seiten, nur fuer die laufende Sitzung (Qt speichert sie nicht) - bei jedem Start und nach
jedem Seitenaufbau neu erteilt, weil sie auf der YouTube-Startseite sonst nicht greift
- browser: BrowserTab.set_audio_output (Skript pro Seite; ohne Auswahl wird die Seite gar
nicht angefasst)
- settings_tab: neue Gruppe, Hot-Plug-Aktualisierung, fehlendes Geraet bleibt als "nicht
verfuegbar" gespeichert, Discord-Anzeige nennt das bearbeitete Feld
- config: audio.youtube_output / audio.music_output (leer = Systemstandard)
- README: Abschnitt inkl. Hinweis, dass Windows weiter einen Eintrag "Playtube" zeigt
Solange der Einstellungen-Tab offen ist, zeigt Discord "In den Einstellungen" mit dem
Feld, das gerade den Fokus hat (z.B. "Bearbeitet: Discord Rich Presence > Client-ID").
Es werden nur Feldnamen uebermittelt, nie Inhalte (z.B. nicht die Client-ID selbst).
- discord_rpc: build_settings_payload + DiscordRPCWorker.submit_settings_activity
- settings_tab: Signal activityChanged, verfolgt den Fokus (auch bei Spinner/Combobox,
deren Fokus auf einem internen Kind-Widget liegt)
- mainwindow: _update_discord_presence waehlt zwischen Einstellungen, Wiedergabe und
Leerlauf; Einstellungs-Status folgt der Option "Status anzeigen, wenn gerade nichts
laeuft" (show_idle_presence); bei Tab-Wechsel und nach dem Speichern aktualisiert
- README: Hinweis zur neuen Anzeige
Ursache: Der Installer beendete laufende Playtube-Prozesse per "taskkill /F /T". Der
Updater startet ihn aus Playtube.exe heraus, er ist also ein Kindprozess - solange
Playtube noch beendet wurde, schoss "/T" den Installer selbst mit ab, bevor er etwas
installiert hatte (kein Kopieren, kein Neustart, nur der Download blieb im Temp-Ordner).
- playtube.iss: taskkill ohne /T; Setup wartet per /WAITPID=<PID> (max. 20 s) darauf, dass
sich die alte App selbst beendet; uebrig gebliebene QtWebEngine-Prozesse aus dem
Installationsordner werden gezielt nach Pfad beendet
- updater: uebergibt /WAITPID und /LOG (Setup-Protokoll nach %TEMP%); robocopy im
ZIP-Fallback mit /R:3 /W:2, damit gesperrte Dateien das Update nicht endlos haengen
- mainwindow: hartes Beenden nach 8 s, falls Qt/QtWebEngine beim Beenden haengt
(sonst wartet der Update-Helfer ewig und die alte Version bleibt laufen)
- Inno-Setup-Installer (packaging/playtube.iss): installiert pro Benutzer nach
%LOCALAPPDATA%\Programs\Playtube, feste AppId -> jede neue Version ueberschreibt die
vorhandene Installation an Ort und Stelle, raeumt den alten _internal-Ordner auf und
beendet laufende Playtube-Prozesse vor dem Kopieren
- Updater: installierte Kopie nimmt das kleine Patch (Versionseintrag in "Apps &
Features" wird nachgezogen), portable Kopie wechselt per stillem Setup in die
regulaere Installation; Patch nur bei passender PySide6-Version (steht im Dateinamen),
sonst Setup; Aufraeumen des heruntergeladenen Installers
- Einzelinstanz-Schutz (playtube/single_instance.py): zwei Prozesse auf demselben
Browser-Profil liessen auf YouTube alle Icons verschwinden; ein zweiter Start holt jetzt
das laufende Fenster nach vorn (auch .play-Patchdateien werden weitergereicht)
- build.ps1 baut den Installer mit, Release-Pipeline haengt ihn an jedes Release
- README: Installation, Update-Ablauf, Troubleshooting fuer fehlende Icons
Windows-Patch-Pakete heissen jetzt Playtube-vX.Y.Z-win64-patch.play statt .zip
(technisch weiterhin ein ganz normales ZIP-Archiv - Windows/Python schauen beim
Entpacken auf die Magic Bytes, nicht auf die Endung). Playtube registriert .play
beim ersten Start als Windows-Dateizuordnung (HKCU, keine Admin-Rechte noetig),
sodass eine manuell heruntergeladene Patchdatei per Doppelklick installiert
werden kann, ohne dass Playtube selbst etwas herunterladen muss:
- shortcuts.py: ensure_play_file_association() registriert ProgID +
DefaultIcon + shell/open/command und stoesst SHChangeNotify an, damit die
Zuordnung sofort greift.
- updater.py: UpdateInstaller akzeptiert jetzt optional local_archive_path
statt einer download_url und ueberspringt dann den Download komplett.
- main.py: erkennt eine .play-Datei als Kommandozeilenargument (Doppelklick-
Start) und uebergibt sie an MainWindow.install_local_patch().
- release.yml: Windows-Patch wird als .zip gepackt und anschliessend zu .play
umbenannt; _find_platform_asset() sucht fuer Windows-Patches jetzt nach .play
statt .zip.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher lief der Datei-Austausch (Skript wartet auf Prozessende, kopiert/robocopy,
startet App neu) nach dem Schliessen des Hauptfensters komplett unsichtbar im
Hintergrund - bei einem vollen Paket-Update konnte das mehrere Sekunden dauern,
in denen es aussah, als waere die App abgestuerzt oder haenge.
- Windows: PowerShell-Skript zeigt jetzt ein kleines WinForms-Fenster mit
Marquee-Fortschrittsbalken und Statustext (Warten auf Prozessende / Kopieren /
Fertig - Neustart), robocopy laeuft dafuer per Start-Process+Polling statt
-Wait, damit die Fensternachrichtenschleife per DoEvents() nicht einfriert.
- Linux: optional dasselbe ueber zenity --progress (best effort, falls
installiert - ohne zenity laeuft es wie bisher unsichtbar durch).
- App zeigt vor dem Neustart noch kurz eine Statusmeldung im Einstellungen-Tab.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Einstellungen-Tab: 'Jetzt nach Updates suchen'-Button, Status-Text (aktuell/verfuegbar/
fehlgeschlagen), Fortschrittsbalken fuer den Download (Prozent bei bekannter Groesse,
unbestimmt waehrend Entpacken/Installieren), 'Update installieren'-Button erscheint bei Fund.
- updater.py/UpdateInstaller: laedt Download jetzt in Chunks (statt copyfileobj) und meldet
echten Fortschritt in Prozent ueber ein neues progress_percent-Signal.
- Patch-Updates: CI baut zusaetzlich zum vollen Release-Paket ein kleines '-patch'-Paket,
das nur die ausfuehrbare Datei (Playtube.exe/Playtube, ~2-3 MB) enthaelt - der riesige
PySide6/QtWebEngine-Laufzeitordner _internal/ (~200 MB) bleibt unangetastet, da er sich
zwischen normalen Code-Patches nicht aendert. updater.py bevorzugt das Patch-Paket und
faellt nur auf das volle Paket zurueck, wenn kein Patch-Asset gefunden wird.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Settings-Tab in der App (Discord/Update/Start-Tab live editierbar, kein config.json-Handbearbeiten noetig)
- updater.py: plattformabhaengige Asset-Auswahl + Installation (Windows .zip/robocopy, Linux .tar.gz/Shell-Skript)
- browser.py/chrome_shim.py: Sec-CH-UA + navigator.userAgentData jetzt je nach sys.platform (Windows/Linux/macOS)
- app_id.py: robustere Suche nach umbenanntem QtWebEngine-Hilfsprozess (rglob statt fixer Pfade)
- packaging/playtube.spec: icon/version nur unter Windows setzen (Linux-Build faehig)
- packaging/install-linux.sh: Installationsskript fuer native Linux-Version (Desktop-Eintrag, Icon, PATH)
- .github/workflows/release.yml: baut bei Tag-Push automatisch Windows-.exe UND Linux-Binary und veroeffentlicht beide als GitHub Release
Co-Authored-By: Claude Sonnet 5 <[email protected]>