diff --git a/src/viewer/index.js b/src/viewer/index.js index 2c5e70f..b59727c 100644 --- a/src/viewer/index.js +++ b/src/viewer/index.js @@ -41,8 +41,11 @@ function renderList(items) { for (const item of items) { const link = document.createElement('a'); link.className = 'video-item'; - link.href = item.url; - link.textContent = item.label ? `${item.label}: ${item.url}` : item.url; + let url = item.url; + if (typeof url === 'string' && item.src) url = item.src; + if (typeof url === 'object' && url.src) url = url.src; + link.href = url; + link.textContent = item.label ? `${item.label}: ${url}` : url; link.target = '_blank'; listEl.appendChild(link); } @@ -52,7 +55,7 @@ function renderList(items) { copyBtn.className = 'copy-btn'; copyBtn.textContent = 'Copy All URLs'; copyBtn.addEventListener('click', () => { - const urls = items.map(v => v.url); + const urls = items.map(v => (typeof v === 'object' && v.src) ? v.src : (typeof v === 'object' ? v.url : v)); navigator.clipboard.writeText(urls.join('\n')).then(() => { copyBtn.textContent = 'Copied!'; setTimeout(() => { copyBtn.textContent = 'Copy All URLs'; }, 1500); @@ -66,7 +69,11 @@ function showActions() { btnRow.style.display = 'flex'; loadVideos().then(({ urls, tags }) => { if (urls.length > 0) { - const items = urls.map((url, i) => ({ url, label: tags[i] })); + const items = urls.map((url, i) => { + const entry = { url: url.src || url, label: tags[i] }; + if (typeof url === 'object' && url.src) entry.src = url.src; + return entry; + }); renderList(items); setStatus(`Using ${urls.length} video(s) from last search.`); } else { @@ -103,14 +110,27 @@ findBtn.addEventListener('click', async () => { try { // Execute scraping on all tabs in parallel const scrapeFn = () => { - const videos = Array.from(document.querySelectorAll('video')).map(v => ({ - src: v.currentSrc || v.src || null, - poster: v.poster || null, - })); - const videoCount = videos.length; + const dataKeys = ['src', 'video', 'mp4', 'webm', 'poster']; + // Collect all visible video elements, measure by rendered pixel area + const allVideos = Array.from(document.querySelectorAll('video')).filter(v => { + const style = window.getComputedStyle(v); + return style.display !== 'none' && v.clientWidth > 0 && v.clientHeight > 0; + }).map(v => { + const area = v.clientWidth * v.clientHeight; + const src = dataKeys.map(k => v.getAttribute('data-' + k)).find(Boolean) + || (v.currentSrc || v.src || '') + || null; + const poster = (v.poster || '') + || dataKeys.filter(k => k !== 'poster').map(k => v.getAttribute('data-' + k)).find(Boolean) + || v.getAttribute('data-poster') || null; + return { src, poster, area, width: v.clientWidth, height: v.clientHeight }; + }); + // Sort by displayed size descending, pick the largest + allVideos.sort((a, b) => b.area - a.area); + const largest = allVideos.length > 0 ? allVideos[0] : null; const sources = Array.from(document.querySelectorAll('video source[src]')).map(s => s.src); const audios = Array.from(document.querySelectorAll('audio')).length; - return { videos, videoCount, sources, audios }; + return { videos: largest ? [largest] : [], videoCount: largest ? 1 : 0, sources, audios }; }; const results = await Promise.all( tabsToScan.map(async t => { @@ -142,24 +162,30 @@ findBtn.addEventListener('click', async () => { totalFound++; const key = (v.src || '(empty)') + '||' + (v.poster || '(none)'); if (!seen.has(key)) { - seen.set(key, { url: v.src || v.poster || '', tab: group.tabTitle }); + const item = { url: v.src || v.poster || '', poster: v.poster || null, tab: group.tabTitle }; + if (v.src) item.src = v.src; + seen.set(key, item); } } } } - const items = [...seen.values()]; + const items = [...seen.values()].filter(v => { + const url = v.src || v.url || ''; + return url.startsWith('http://') || url.startsWith('https://'); + }); console.log('[goon] ===== Found', totalFound, 'video elements across', tabsToScan.length, 'tabs, unique:', items.length); // Replace the entire list (fresh scan) + const storedItems = items.map(v => ({ url: v.url, src: v.src || v.url, poster: v.poster, tab: v.tab })); await chrome.storage.local.set({ - [STORAGE_KEY]: items.map(v => v.url), + [STORAGE_KEY]: storedItems, [TAGGED_KEY]: items.map(v => v.tab), }); setStatus(`Found ${items.length} video(s) across ${scanned} tab(s).`); - renderList(items.map(v => ({ url: v.url, label: v.tab }))); + renderList(storedItems.map(v => ({ url: v, label: v.tab }))); btnRow.style.display = 'flex'; } catch (e) { setStatus(`Scan failed: ${e.message}`); diff --git a/src/viewer/viewer.js b/src/viewer/viewer.js index 5445fe2..d4915bf 100644 --- a/src/viewer/viewer.js +++ b/src/viewer/viewer.js @@ -38,9 +38,10 @@ async function init() { if (i < videoUrls.length && videoUrls[i]) { const video = document.createElement('video'); - video.src = videoUrls[i]; + video.src = (typeof videoUrls[i] === 'object') ? videoUrls[i].src : videoUrls[i]; video.autoplay = true; video.muted = true; + video.loop = true; video.playsInline = true; console.log('[goon-viewer] panel', i + '/4:', videoUrls[i]); panel.appendChild(video);