Anhand der neuen Debug-Logs (siehe vorheriger Commit) konnte der Bug endlich anhand echter Daten diagnostiziert werden: video.currentTime/video.duration sind bei YouTube Music beim Songwechsel NICHT verlaesslich - wegen nahtloser (gapless) Wiedergabe laeuft darunter ein durchgehender Buffer, dessen currentTime/duration nicht pro Titel zurueckgesetzt wird. Log-Beweis: beim Wechsel zu einem neuen Titel wurde die verbleibende Spielzeit des VORHERIGEN Titels als Start-Offset des neuen uebernommen, und die Dauer wuchs bei jedem Poll weiter statt konstant zu bleiben. - media_probe.py: liest Fortschritt/Gesamtlaenge jetzt aus der sichtbar angezeigten Fortschrittsanzeige (ARIA-Attribute des YT-Music-Sliders in Sekunden, sonst Zeit-Text im Player; bei YouTube .ytp-time-current/.ytp-time-duration) statt aus den unzuverlaessigen <video>-Eigenschaften - diese Anzeige MUSS pro Titel stimmen, weil der Nutzer sie selbst so sieht. - config.py/main.py: Cache (webprofile/cache) wird automatisch geleert, wenn seit dem letzten Start ein Update installiert wurde - Login (webprofile/storage) bleibt unangetastet. - shortcuts.py/main.py: legt beim ersten Start der gepackten .exe automatisch eine Windows-Startmenue-Verknuepfung an (Playtube wird als portables ZIP ohne Installer ausgeliefert, haette sonst nie einen Startmenue-Eintrag). Co-Authored-By: Claude Sonnet 5 <[email protected]>
53 lines
1.9 KiB
Python
53 lines
1.9 KiB
Python
"""Erstellt bei Bedarf eine Windows-Startmenue-Verknuepfung.
|
|
|
|
Playtube wird als portables ZIP ausgeliefert (kein MSI/Installer) - ohne das gaebe es
|
|
also nie einen Eintrag im Windows-Startmenue, wie man ihn von "richtig installierten"
|
|
Programmen kennt. Wird beim Start der gepackten .exe einmalig nachgeholt (idempotent -
|
|
prueft vorher, ob die Verknuepfung schon existiert)."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def _find_icon(exe_dir: Path) -> Path | None:
|
|
matches = list(exe_dir.rglob("icon.ico"))
|
|
return matches[0] if matches else None
|
|
|
|
|
|
def ensure_start_menu_shortcut(app_name: str) -> None:
|
|
if sys.platform != "win32" or not getattr(sys, "frozen", False):
|
|
return
|
|
try:
|
|
appdata = os.environ.get("APPDATA")
|
|
if not appdata:
|
|
return
|
|
start_menu = Path(appdata) / "Microsoft" / "Windows" / "Start Menu" / "Programs"
|
|
shortcut_path = start_menu / f"{app_name}.lnk"
|
|
if shortcut_path.exists():
|
|
return
|
|
|
|
exe_path = Path(sys.executable).resolve()
|
|
icon_path = _find_icon(exe_path.parent) or exe_path
|
|
|
|
ps_script = (
|
|
'$WshShell = New-Object -ComObject WScript.Shell\n'
|
|
f'$Shortcut = $WshShell.CreateShortcut("{shortcut_path}")\n'
|
|
f'$Shortcut.TargetPath = "{exe_path}"\n'
|
|
f'$Shortcut.WorkingDirectory = "{exe_path.parent}"\n'
|
|
f'$Shortcut.IconLocation = "{icon_path}"\n'
|
|
f'$Shortcut.Description = "{app_name}"\n'
|
|
'$Shortcut.Save()\n'
|
|
)
|
|
subprocess.run(
|
|
["powershell", "-NoProfile", "-WindowStyle", "Hidden", "-Command", ps_script],
|
|
capture_output=True,
|
|
timeout=15,
|
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
|
)
|
|
except Exception:
|
|
# Kein Startmenue-Eintrag ist kein Grund, den App-Start scheitern zu lassen.
|
|
pass
|