diff --git a/extension/content.js b/extension/content.js index 22412db..a36cc7f 100644 --- a/extension/content.js +++ b/extension/content.js @@ -62,6 +62,7 @@ let lastKnownDisneyPlusDuration = 0; let lastKnownDisneyPlusScale = 1; let lastKnownDisneyPlusStart = 0; + let videoEventsLog = []; function hostMatchesUrl(host, url) { const normalized = String(url || '') @@ -1445,6 +1446,8 @@ platform, siteQuirk: getSiteQuirkDebug(video), mediaSessionPosition: window.__koalaLastCapturedMediaPosition || null, + scrapedTimestamps: getScrapedTimestamps(), + videoEventsLog: videoEventsLog, allVideos }); } else { @@ -1456,7 +1459,9 @@ allVideos, url: window.location.href, pageTitle: document.title, - mediaSessionPosition: window.__koalaLastCapturedMediaPosition || null, + mediaSessionPosition: window.__koalaLastCapturedMediaPosition || null, + scrapedTimestamps: getScrapedTimestamps(), + videoEventsLog: videoEventsLog, metadata: (navigator.mediaSession && navigator.mediaSession.metadata) ? { title: navigator.mediaSession.metadata.title, artist: navigator.mediaSession.metadata.artist, @@ -1674,6 +1679,46 @@ checkEpisodeTransition(); }; + function getScrapedTimestamps() { + if (typeof document === 'undefined') return []; + try { + const elms = Array.from(document.querySelectorAll('div,span,p,button,a,[role="button"]')); + const unique = new Set(); + const results = []; + for (const el of elms) { + if (el.children.length > 3) continue; + const txt = (el.textContent || '').trim(); + if (!txt || txt.length > 50) continue; + if (unique.has(txt)) continue; + const match = txt.match(/(\d{1,2}:)?\d{1,2}:\d{2}/); + if (match) { + unique.add(txt); + const tag = el.tagName.toLowerCase(); + const cls = el.className ? `.${el.className.split(' ')[0]}` : ''; + results.push(`${tag}${cls}: "${txt}"`); + } + } + return results.slice(0, 15); + } catch (_e) { + return []; + } + } + + function logVideoEvent(name, video) { + try { + const time = Number.isFinite(video?.currentTime) ? video.currentTime.toFixed(2) : '?'; + const dur = Number.isFinite(video?.duration) ? video.duration.toFixed(2) : '?'; + const timeStr = new Date().toTimeString().split(' ')[0]; + const msg = `[${timeStr}] ${name} (t=${time}s, d=${dur}s)`; + videoEventsLog.unshift(msg); + if (videoEventsLog.length > 15) { + videoEventsLog.pop(); + } + } catch (_e) { + // safe + } + } + function setupListeners() { const video = findVideo(); if (video) { @@ -1688,7 +1733,14 @@ video.removeEventListener('loadeddata', existing.loadeddata); if (existing.waiting) video.removeEventListener('waiting', existing.waiting); } - video._koalaHandlers = { play: handlePlay, pause: handlePause, seeked: handleSeeked, loadeddata: handleLoadedData, waiting: handleWaiting }; + video._koalaHandlers = { play: handlePlay, pause: handlePause, seeked: handleSeeked, loadeddata: handleLoadedData, waiting: handleWaiting }; + if (!video._koalaLoggingAttached) { + video._koalaLoggingAttached = true; + const logEvents = ['play', 'pause', 'seeking', 'seeked', 'durationchange', 'ratechange', 'volumechange', 'waiting', 'playing']; + logEvents.forEach(evt => { + video.addEventListener(evt, () => logVideoEvent(evt.toUpperCase(), video)); + }); + } video.addEventListener('play', handlePlay); video.addEventListener('pause', handlePause); diff --git a/extension/popup.html b/extension/popup.html index df2188c..b84debb 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -700,6 +700,18 @@ +
+ +
+ No timestamps scraped. +
+
+
+ +
+ No events logged. +
+
Build: __BUILD_TIMESTAMP__
diff --git a/extension/popup.js b/extension/popup.js index cd183f5..765a64e 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -2296,6 +2296,18 @@ function refreshDebugInfo() { const buttons = Array.isArray(quirk.seekButtons) ? quirk.seekButtons.slice(0, 4).join(' | ') : ''; if (buttons) addField(`${label} Buttons`, buttons); } + const domScraperEl = document.getElementById('devtoolsDomScraperList'); + const eventLogEl = document.getElementById('devtoolsVideoEventLogList'); + if (domScraperEl && state.scrapedTimestamps) { + domScraperEl.textContent = state.scrapedTimestamps.length > 0 + ? state.scrapedTimestamps.join('\n') + : 'No timestamps scraped.'; + } + if (eventLogEl && state.videoEventsLog) { + eventLogEl.textContent = state.videoEventsLog.length > 0 + ? state.videoEventsLog.join('\n') + : 'No events logged.'; + } addSection('Properties'); addField('Seeking', String(state.seeking));