mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-07-26 12:08:15 +00:00
fix: prioritize largest video element, fix history action field in debug report
- findVideo() now scores all video elements by size + unmuted + duration - Fixes Prime Video selecting 0x0 placeholder instead of actual player - Fix history entries showing '?' by using h.action instead of h.event/h.type - Update Prime Video status in TESTED_SERVICES.md to partial support
This commit is contained in:
+1
-1
@@ -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 | — |
|
||||
|
||||
+32
-12
@@ -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 ---
|
||||
|
||||
+1
-1
@@ -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}`);
|
||||
|
||||
Reference in New Issue
Block a user