您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
View Original Avatar, Banner, Video and Shorts Thumbnails.
// ==UserScript== // @name YouTube Enhancer (Thumbnail Preview) // @description View Original Avatar, Banner, Video and Shorts Thumbnails. // @icon https://raw.githubusercontent.com/exyezed/youtube-enhancer/refs/heads/main/extras/youtube-enhancer.png // @version 1.8 // @author exyezed // @namespace https://github.com/exyezed/youtube-enhancer/ // @supportURL https://github.com/exyezed/youtube-enhancer/issues // @license MIT // @match https://www.youtube.com/* // @match https://youtube.com/* // @match https://m.youtube.com/* // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; function extractVideoId(thumbnailSrc) { const match = thumbnailSrc.match(/\/vi\/([^\/]+)\//); return match ? match[1] : null; } function extractShortsId(href) { const match = href.match(/\/shorts\/([^\/\?]+)/); return match ? match[1] : null; } async function checkImageExists(url) { try { const corsTest = await fetch(url, { method: 'HEAD' }).catch(() => null); if (corsTest) { return corsTest.ok; } else { return true; } } catch (error) { return new Promise((resolve) => { const img = document.createElement('img'); img.style.display = 'none'; const timeout = setTimeout(() => { document.body.removeChild(img); resolve(false); }, 2000); img.onload = () => { clearTimeout(timeout); document.body.removeChild(img); resolve(true); }; img.onerror = () => { clearTimeout(timeout); document.body.removeChild(img); resolve(false); }; document.body.appendChild(img); img.src = url; }); } } function createSpinner() { const spinner = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); spinner.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); spinner.setAttribute('width', '16'); spinner.setAttribute('height', '16'); spinner.setAttribute('viewBox', '0 0 24 24'); spinner.setAttribute('fill', 'none'); spinner.setAttribute('stroke', 'white'); spinner.setAttribute('stroke-width', '2'); spinner.setAttribute('stroke-linecap', 'round'); spinner.setAttribute('stroke-linejoin', 'round'); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', 'M21 12a9 9 0 1 1-6.219-8.56'); spinner.appendChild(path); spinner.style.animation = 'spin 1s linear infinite'; if (!document.querySelector('#spinner-keyframes')) { const style = document.createElement('style'); style.id = 'spinner-keyframes'; style.textContent = ` @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } `; document.head.appendChild(style); } return spinner; } async function openThumbnail(videoId, isShorts, overlayElement) { if (isShorts) { const originalSvg = overlayElement.querySelector('svg'); const spinner = createSpinner(); overlayElement.replaceChild(spinner, originalSvg); try { const oardefaultUrl = `https://i.ytimg.com/vi/${videoId}/oardefault.jpg`; const isOarDefaultAvailable = await checkImageExists(oardefaultUrl); if (isOarDefaultAvailable) { window.open(oardefaultUrl, '_blank'); } else { window.open(`https://i.ytimg.com/vi/${videoId}/oar2.jpg`, '_blank'); } } finally { overlayElement.replaceChild(originalSvg, spinner); } } else { window.open(`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`, '_blank'); } } let thumbnailPreviewCurrentVideoId = ""; let thumbnailPreviewClosed = false; let thumbnailInsertionAttempts = 0; const MAX_ATTEMPTS = 10; const RETRY_DELAY = 500; function isWatchPage() { const url = new URL(window.location.href); return url.pathname === "/watch" && url.searchParams.has("v"); } function addOrUpdateThumbnailImage() { if (!isWatchPage()) return; const newVideoId = new URLSearchParams(window.location.search).get("v"); if (newVideoId !== thumbnailPreviewCurrentVideoId) { thumbnailPreviewClosed = false; } if (!newVideoId || newVideoId === thumbnailPreviewCurrentVideoId || thumbnailPreviewClosed) { return; } thumbnailPreviewCurrentVideoId = newVideoId; function attemptInsertion() { const targetElement = document.querySelector("#secondary-inner #panels"); const existingContainer = document.getElementById("thumbnailPreview-custom-container"); if (existingContainer) { const existingImg = existingContainer.querySelector("img"); if (existingImg) { existingImg.src = `https://i.ytimg.com/vi/${thumbnailPreviewCurrentVideoId}/mqdefault.jpg`; } thumbnailInsertionAttempts = 0; return; } if (!targetElement) { thumbnailInsertionAttempts++; if (thumbnailInsertionAttempts < MAX_ATTEMPTS) { setTimeout(attemptInsertion, RETRY_DELAY); } else { thumbnailInsertionAttempts = 0; } return; } const container = document.createElement("div"); container.id = "thumbnailPreview-custom-container"; container.style.cssText = ` position: relative; width: 100%; margin-bottom: 10px; box-sizing: border-box; `; const img = document.createElement("img"); img.src = `https://i.ytimg.com/vi/${thumbnailPreviewCurrentVideoId}/mqdefault.jpg`; img.style.cssText = ` width: 100%; height: auto; border-radius: 10px; cursor: pointer; display: block; `; img.addEventListener("click", function (e) { e.preventDefault(); e.stopPropagation(); const maxResUrl = `https://i.ytimg.com/vi/${thumbnailPreviewCurrentVideoId}/maxresdefault.jpg`; window.open(maxResUrl, '_blank'); }); const closeButton = document.createElement("div"); closeButton.style.cssText = ` position: absolute; top: 8px; right: 8px; background: rgba(0, 0, 0, 0.7); color: white; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 1001; transition: all 0.2s ease; `; const closeSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); closeSvg.setAttribute('width', '20'); closeSvg.setAttribute('height', '20'); closeSvg.setAttribute('viewBox', '0 0 24 24'); closeSvg.setAttribute('fill', 'none'); closeSvg.setAttribute('stroke', 'currentColor'); closeSvg.setAttribute('stroke-width', '2'); closeSvg.setAttribute('stroke-linecap', 'round'); closeSvg.setAttribute('stroke-linejoin', 'round'); const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('cx', '12'); circle.setAttribute('cy', '12'); circle.setAttribute('r', '10'); closeSvg.appendChild(circle); const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path1.setAttribute('d', 'm15 9-6 6'); closeSvg.appendChild(path1); const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path2.setAttribute('d', 'm9 9 6 6'); closeSvg.appendChild(path2); closeButton.appendChild(closeSvg); closeButton.onmouseenter = () => closeSvg.style.stroke = '#f50057'; closeButton.onmouseleave = () => closeSvg.style.stroke = 'currentColor'; closeButton.addEventListener("click", function(e) { e.preventDefault(); e.stopPropagation(); thumbnailPreviewClosed = true; container.remove(); }); container.appendChild(img); container.appendChild(closeButton); targetElement.parentNode.insertBefore(container, targetElement); thumbnailInsertionAttempts = 0; } attemptInsertion(); } function createThumbnailOverlay(videoId, container) { const overlay = document.createElement('div'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '16'); svg.setAttribute('height', '16'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('fill', 'none'); svg.setAttribute('stroke', 'white'); svg.setAttribute('stroke-width', '2'); svg.setAttribute('stroke-linecap', 'round'); svg.setAttribute('stroke-linejoin', 'round'); svg.style.transition = 'stroke 0.2s ease'; const mainRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); mainRect.setAttribute('width', '18'); mainRect.setAttribute('height', '18'); mainRect.setAttribute('x', '3'); mainRect.setAttribute('y', '3'); mainRect.setAttribute('rx', '2'); mainRect.setAttribute('ry', '2'); svg.appendChild(mainRect); const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('cx', '9'); circle.setAttribute('cy', '9'); circle.setAttribute('r', '2'); svg.appendChild(circle); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', 'm21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'); svg.appendChild(path); overlay.appendChild(svg); overlay.style.cssText = ` position: absolute; bottom: 8px; left: 8px; background: rgba(0, 0, 0, 0.7); width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 4px; cursor: pointer; z-index: 1000; opacity: 0; transition: all 0.2s ease; `; overlay.onmouseenter = () => { overlay.style.background = 'rgba(0, 0, 0, 0.9)'; svg.style.stroke = '#f50057'; }; overlay.onmouseleave = () => { overlay.style.background = 'rgba(0, 0, 0, 0.7)'; svg.style.stroke = 'white'; }; overlay.onclick = async (e) => { e.preventDefault(); e.stopPropagation(); const isShorts = container.closest('ytm-shorts-lockup-view-model') || container.closest('.shortsLockupViewModelHost') || container.closest('[class*="shortsLockupViewModelHost"]') || container.querySelector('a[href*="/shorts/"]'); await openThumbnail(videoId, !!isShorts, overlay); }; return overlay; } function addThumbnailOverlay(container) { if (container.querySelector('.thumb-overlay')) return; let videoId = null; let thumbnailContainer = null; const img = container.querySelector('img[src*="ytimg.com"]'); if (img?.src) { videoId = extractVideoId(img.src); thumbnailContainer = img.closest('yt-thumbnail-view-model') || img.parentElement; } if (!videoId) { const link = container.querySelector('a[href*="/shorts/"]'); if (link?.href) { videoId = extractShortsId(link.href); const shortsImg = container.querySelector('img[src*="ytimg.com"]'); if (shortsImg) { thumbnailContainer = shortsImg.closest('.ytCoreImageHost') || shortsImg.closest('[class*="ThumbnailContainer"]') || shortsImg.closest('[class*="ImageHost"]') || shortsImg.parentElement; } } } if (!videoId || !thumbnailContainer) return; if (getComputedStyle(thumbnailContainer).position === 'static') { thumbnailContainer.style.position = 'relative'; } const overlay = createThumbnailOverlay(videoId, container); overlay.className = 'thumb-overlay'; thumbnailContainer.appendChild(overlay); // Add hover effect to show/hide overlay thumbnailContainer.onmouseenter = () => overlay.style.opacity = '1'; thumbnailContainer.onmouseleave = () => overlay.style.opacity = '0'; } function createAvatarOverlay() { const overlay = document.createElement('div'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '16'); svg.setAttribute('height', '16'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('fill', 'none'); svg.setAttribute('stroke', 'white'); svg.setAttribute('stroke-width', '2'); svg.setAttribute('stroke-linecap', 'round'); svg.setAttribute('stroke-linejoin', 'round'); svg.style.transition = 'stroke 0.2s ease'; const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('cx', '12'); circle.setAttribute('cy', '8'); circle.setAttribute('r', '5'); svg.appendChild(circle); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', 'M20 21a8 8 0 0 0-16 0'); svg.appendChild(path); overlay.appendChild(svg); overlay.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0, 0, 0, 0.7); width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 50%; cursor: pointer; z-index: 1000; opacity: 0; transition: all 0.2s ease; `; overlay.onmouseenter = () => { overlay.style.background = 'rgba(0, 0, 0, 0.9)'; svg.style.stroke = '#f50057'; }; overlay.onmouseleave = () => { overlay.style.background = 'rgba(0, 0, 0, 0.7)'; svg.style.stroke = 'white'; }; return overlay; } function addAvatarOverlay(img) { const container = img.parentElement; if (container.querySelector('.avatar-overlay')) return; if (getComputedStyle(container).position === 'static') { container.style.position = 'relative'; } const overlay = createAvatarOverlay(); overlay.className = 'avatar-overlay'; overlay.onclick = (e) => { e.preventDefault(); e.stopPropagation(); const highResUrl = img.src.replace(/=s\d+-c-k-c0x00ffffff-no-rj.*/, '=s0'); window.open(highResUrl, '_blank'); }; container.appendChild(overlay); container.onmouseenter = () => overlay.style.opacity = '1'; container.onmouseleave = () => overlay.style.opacity = '0'; } function createBannerOverlay() { const overlay = document.createElement('div'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '16'); svg.setAttribute('height', '16'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('fill', 'none'); svg.setAttribute('stroke', 'white'); svg.setAttribute('stroke-width', '2'); svg.setAttribute('stroke-linecap', 'round'); svg.setAttribute('stroke-linejoin', 'round'); svg.style.transition = 'stroke 0.2s ease'; const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', '3'); rect.setAttribute('y', '3'); rect.setAttribute('width', '18'); rect.setAttribute('height', '18'); rect.setAttribute('rx', '2'); rect.setAttribute('ry', '2'); svg.appendChild(rect); const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('cx', '9'); circle.setAttribute('cy', '9'); circle.setAttribute('r', '2'); svg.appendChild(circle); const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline'); polyline.setAttribute('points', '21,15 16,10 5,21'); svg.appendChild(polyline); overlay.appendChild(svg); overlay.style.cssText = ` position: absolute; bottom: 8px; left: 8px; background: rgba(0, 0, 0, 0.7); width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 4px; cursor: pointer; z-index: 1000; opacity: 0; transition: all 0.2s ease; `; overlay.onmouseenter = () => { overlay.style.background = 'rgba(0, 0, 0, 0.9)'; svg.style.stroke = '#f50057'; }; overlay.onmouseleave = () => { overlay.style.background = 'rgba(0, 0, 0, 0.7)'; svg.style.stroke = 'white'; }; return overlay; } function addBannerOverlay(img) { const container = img.parentElement; if (container.querySelector('.banner-overlay')) return; if (getComputedStyle(container).position === 'static') { container.style.position = 'relative'; } const overlay = createBannerOverlay(); overlay.className = 'banner-overlay'; overlay.onclick = (e) => { e.preventDefault(); e.stopPropagation(); const highResUrl = img.src.replace(/=w\d+-.*/, '=s0'); window.open(highResUrl, '_blank'); }; container.appendChild(overlay); container.onmouseenter = () => overlay.style.opacity = '1'; container.onmouseleave = () => overlay.style.opacity = '0'; } function processAvatars() { const avatarSelectors = [ 'yt-avatar-shape img', '#avatar img', 'ytd-channel-avatar-editor img', '.ytd-video-owner-renderer img[src*="yt"]' ]; avatarSelectors.forEach(selector => { document.querySelectorAll(selector).forEach(img => { if (img.src && img.src.includes('yt') && !img.closest('.avatar-overlay')) { addAvatarOverlay(img); } }); }); } function processBanners() { const bannerSelectors = [ 'yt-image-banner-view-model img', 'ytd-c4-tabbed-header-renderer img[src*="yt"]', '#channel-header img[src*="banner"]' ]; bannerSelectors.forEach(selector => { document.querySelectorAll(selector).forEach(img => { if (img.src && (img.src.includes('banner') || img.src.includes('yt')) && !img.closest('.banner-overlay')) { addBannerOverlay(img); } }); }); } function processThumbnails() { document.querySelectorAll('yt-thumbnail-view-model').forEach(addThumbnailOverlay); document.querySelectorAll('.ytd-thumbnail').forEach(addThumbnailOverlay); document.querySelectorAll('ytm-shorts-lockup-view-model').forEach(addThumbnailOverlay); document.querySelectorAll('.shortsLockupViewModelHost').forEach(addThumbnailOverlay); document.querySelectorAll('[class*="shortsLockupViewModelHost"]').forEach(addThumbnailOverlay); } function processAll() { processThumbnails(); processAvatars(); processBanners(); addOrUpdateThumbnailImage(); } function setupMutationObserver() { const observer = new MutationObserver(() => { setTimeout(processAll, 50); }); observer.observe(document.body, { childList: true, subtree: true }); } function setupUrlChangeDetection() { let currentUrl = location.href; const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = function () { originalPushState.apply(history, arguments); setTimeout(() => { if (location.href !== currentUrl) { currentUrl = location.href; setTimeout(addOrUpdateThumbnailImage, 500); } }, 100); }; history.replaceState = function () { originalReplaceState.apply(history, arguments); setTimeout(() => { if (location.href !== currentUrl) { currentUrl = location.href; setTimeout(addOrUpdateThumbnailImage, 500); } }, 100); }; window.addEventListener("popstate", function () { setTimeout(() => { if (location.href !== currentUrl) { currentUrl = location.href; setTimeout(addOrUpdateThumbnailImage, 500); } }, 100); }); setInterval(function () { if (location.href !== currentUrl) { currentUrl = location.href; setTimeout(addOrUpdateThumbnailImage, 300); } }, 500); } function initialize() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { setTimeout(init, 100); }); } else { setTimeout(init, 100); } } function init() { setupUrlChangeDetection(); setupMutationObserver(); processAll(); setTimeout(processAll, 500); setTimeout(processAll, 1000); setTimeout(processAll, 2000); } initialize(); })();