diff --git a/TESTED_SERVICES.md b/TESTED_SERVICES.md index 4f7fba0..21bd81d 100644 --- a/TESTED_SERVICES.md +++ b/TESTED_SERVICES.md @@ -11,7 +11,7 @@ This document tracks which streaming platforms and media servers have been teste | **Jellyfin** | ✅ Full | ✅ Full | ✅ Full | Self-hosted. Full HTML5 player access. | | **Plex** | Not tested | Not tested | Not tested | Community reports indicate compatibility via HTML5 player mode. | | **Disney+** | Not tested | Not tested | Not tested | Widevine DRM may restrict title detection similar to Netflix. | -| **Prime Video** | ❌ None | ❌ None | ❌ | Extension cannot detect video elements. Play/Pause do not work. Media title detection fails. DRM and custom player prevent script access. | +| **Prime Video** | ⚠️ Partial | ⚠️ Partial | ❌ | Video elements detected (2 on page, picks larger one). Playback state + time readable. However, the preview/trailer video may be selected instead of the main content. Play/Pause commands may not reach the correct player. Title detection from MediaSession API may work for some content. | | **HBO Max / Max** | Not tested | Not tested | Not tested | — | | **Crunchyroll** | Not tested | Not tested | Not tested | — | | **Vimeo** | Not tested | Not tested | Not tested | — | diff --git a/extension/content.js b/extension/content.js index 0bf7fb4..0ca68e0 100644 --- a/extension/content.js +++ b/extension/content.js @@ -78,21 +78,41 @@ } // --- Helper: find the best video element on the page --- + // Prefers larger, visible videos over tiny preview/trailer elements. function findVideo(root = document) { - const video = root.querySelector('video'); - if (video) return video; - - // Optimize: scan only potential player, video, media, and stream hosts by matching typical keywords (case-insensitive) - // or common custom element tags. This prevents recursive scanning of thousands of standard DOM nodes (div, span, a, etc.) - // while guaranteeing 100% airtight compatibility with all video web components in the wild. - const potentialHosts = root.querySelectorAll('[id*="player" i], [class*="player" i], [id*="video" i], [class*="video" i], [id*="media" i], [class*="media" i], [id*="stream" i], [class*="stream" i], ytd-player, netflix-player, emby-player, jellyfin-player, video-player'); - for (const el of potentialHosts) { - if (el.shadowRoot) { - const found = findVideo(el.shadowRoot); - if (found) return found; + const allVideos = root.querySelectorAll('video'); + if (allVideos.length === 0) { + // Optimize: scan only potential player, video, media, and stream hosts by matching typical keywords (case-insensitive) + // or common custom element tags. This prevents recursive scanning of thousands of standard DOM nodes (div, span, a, etc.) + // while guaranteeing 100% airtight compatibility with all video web components in the wild. + const potentialHosts = root.querySelectorAll('[id*="player" i], [class*="player" i], [id*="video" i], [class*="video" i], [id*="media" i], [class*="media" i], [id*="stream" i], [class*="stream" i], ytd-player, netflix-player, emby-player, jellyfin-player, video-player'); + for (const el of potentialHosts) { + if (el.shadowRoot) { + const found = findVideo(el.shadowRoot); + if (found) return found; + } + } + return null; + } + + // Multiple videos found → pick the best one + if (allVideos.length === 1) return allVideos[0]; + + let best = null; + let bestScore = -1; + for (const v of allVideos) { + if (v.tagName !== 'VIDEO') continue; + // Score: visible area + bonus for unmuted + bonus for longer duration + const area = (v.videoWidth || v.offsetWidth || 0) * (v.videoHeight || v.offsetHeight || 0); + const unmutedBonus = v.muted ? 0 : 100000; + const durationBonus = (v.duration && isFinite(v.duration) ? v.duration : 0) * 100; + const score = area + unmutedBonus + durationBonus; + if (score > bestScore) { + bestScore = score; + best = v; } } - return null; + return best; } // --- Episode Auto-Sync: Detection --- diff --git a/extension/popup.js b/extension/popup.js index 70040ea..4b1e28f 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -1541,7 +1541,7 @@ elements.copyLogs.addEventListener('click', () => { for (const h of recent) { if (!h) continue; const ts = safe(h.timestamp, ''); - const evt = safe(h.event, safe(h.type, '?')); + const evt = safe(h.action, '?'); const from = h.senderId ? ` (${h.senderId})` : (h.peerId ? ` (${h.peerId})` : ''); const extra = h.detail ? ` \u2192 ${h.detail}` : ''; lines.push(`[${ts}] ${evt}${from}${extra}`);