Echter Discord-Zeit-/Bild-Fix, Cache-Reset nach Update, Windows-Startmenue-Icon
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]>
This commit is contained in:
+54
-2
@@ -28,6 +28,54 @@ MEDIA_PROBE_JS = r"""
|
||||
function ytThumbnailUrl(videoId) {
|
||||
return videoId ? ('https://i.ytimg.com/vi/' + videoId + '/hqdefault.jpg') : null;
|
||||
}
|
||||
// "1:23" oder "1:02:03" -> Sekunden.
|
||||
function parseClock(str) {
|
||||
if (!str) { return null; }
|
||||
var parts = String(str).trim().split(':').map(function(p) { return parseInt(p, 10); });
|
||||
if (!parts.length) { return null; }
|
||||
for (var i = 0; i < parts.length; i++) { if (isNaN(parts[i])) { return null; } }
|
||||
var seconds = 0;
|
||||
for (var j = 0; j < parts.length; j++) { seconds = seconds * 60 + parts[j]; }
|
||||
return seconds;
|
||||
}
|
||||
function numAttr(el, name) {
|
||||
if (!el) { return null; }
|
||||
var raw = el.getAttribute(name);
|
||||
var n = raw !== null ? parseFloat(raw) : NaN;
|
||||
return isFinite(n) ? n : null;
|
||||
}
|
||||
// WICHTIG: video.currentTime/video.duration sind bei YouTube Music NICHT
|
||||
// verlaesslich pro Titel - bei nahtlosem (gapless) Songwechsel laeuft darunter
|
||||
// teils ein durchgehender Buffer weiter, dessen currentTime/duration beim
|
||||
// Songwechsel NICHT auf den neuen Titel zurueckgesetzt wird, sondern einfach ueber
|
||||
// mehrere Songs hinweg weiterzaehlt (empirisch bestaetigt: nach einem Songwechsel
|
||||
// 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). Deshalb wird die sichtbar angezeigte Fortschrittsanzeige ausgelesen
|
||||
// (ARIA-Attribute des Sliders in Sekunden, sonst der Zeit-Text im Player) - die
|
||||
// zeigt garantiert den Fortschritt des GERADE LAUFENDEN Titels, weil der Nutzer sie
|
||||
// ja selbst so sieht.
|
||||
function musicTimeInfo() {
|
||||
var slider = document.querySelector('#progress-bar, tp-yt-paper-slider#progress-bar');
|
||||
var current = numAttr(slider, 'aria-valuenow');
|
||||
var total = numAttr(slider, 'aria-valuemax');
|
||||
if (current !== null && total !== null && total > 0) {
|
||||
return { current: current, total: total };
|
||||
}
|
||||
var el = document.querySelector('.time-info.ytmusic-player-bar, ytmusic-player-bar .time-info');
|
||||
var parts = el ? (el.textContent || '').split('/') : [];
|
||||
if (parts.length === 2) {
|
||||
var c = parseClock(parts[0]), t = parseClock(parts[1]);
|
||||
if (c !== null && t !== null) { return { current: c, total: t }; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function youtubeTimeInfo() {
|
||||
var current = parseClock(txt('.ytp-time-current'));
|
||||
var total = parseClock(txt('.ytp-time-duration'));
|
||||
if (current !== null && total !== null) { return { current: current, total: total }; }
|
||||
return null;
|
||||
}
|
||||
|
||||
var video = document.querySelector('video');
|
||||
var isMusic = location.hostname.indexOf('music.youtube.com') !== -1;
|
||||
@@ -49,6 +97,10 @@ MEDIA_PROBE_JS = r"""
|
||||
thumbnail = (imgY ? imgY.href : null) || ytThumbnailUrl(videoId);
|
||||
}
|
||||
|
||||
var timeInfo = isMusic ? musicTimeInfo() : youtubeTimeInfo();
|
||||
var currentTime = timeInfo ? timeInfo.current : (video ? video.currentTime : 0);
|
||||
var duration = timeInfo ? timeInfo.total : ((video && isFinite(video.duration)) ? video.duration : 0);
|
||||
|
||||
// WICHTIG: QtWebEngine's runJavaScript()-Bruecke liefert bei einem direkt
|
||||
// zurueckgegebenen JS-Objekt zuverlaessig nur einen leeren String statt des
|
||||
// Objekts (Zahlen/Strings funktionieren, Objekte nicht) - deshalb hier als
|
||||
@@ -61,8 +113,8 @@ MEDIA_PROBE_JS = r"""
|
||||
thumbnail: thumbnail,
|
||||
url: location.href,
|
||||
playing: video ? (!video.paused && !video.ended && video.readyState > 2) : false,
|
||||
currentTime: video ? video.currentTime : 0,
|
||||
duration: (video && isFinite(video.duration)) ? video.duration : 0,
|
||||
currentTime: currentTime,
|
||||
duration: duration,
|
||||
hasVideo: !!video
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user