您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Extract images and videos from X.com (Twitter) media gallery and play slideshow with controls, countdown timer and pause on spacebar
// ==UserScript== // @name X.com Media Gallery Slideshow with Timer and Video Support + Pause // @namespace http://tampermonkey.net/ // @version 1.7 // @description Extract images and videos from X.com (Twitter) media gallery and play slideshow with controls, countdown timer and pause on spacebar // @author OpenAI // @match https://twitter.com/* // @match https://x.com/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; let slideshowOverlay = null; let slideshowMedia = []; // Array of objects {type: 'image'|'video', src: URL} let currentIndex = 0; let slideshowTimeout = null; let countdownInterval = null; let countdownSeconds = 10; let isPaused = false; let currentVideo = null; // Extract media URLs (images and videos) from X.com media gallery function extractMedia() { const seen = new Set(); const media = []; // Images const imgElements = document.querySelectorAll('img[src*="pbs.twimg.com/media/"]'); imgElements.forEach(img => { const baseUrl = img.src.split('?')[0]; if (!seen.has(baseUrl)) { seen.add(baseUrl); // Images full size media.push({ type: 'image', src: baseUrl + '?format=jpg&name=large' }); } }); // Videos const videoElements = document.querySelectorAll('video'); videoElements.forEach(video => { let src = video.currentSrc || video.src; if (src && !seen.has(src)) { seen.add(src); media.push({ type: 'video', src: src }); } }); return media; } function clearTimers() { clearTimeout(slideshowTimeout); clearInterval(countdownInterval); } // Create and show slideshow overlay function showSlideshow(mediaArray) { if (mediaArray.length === 0) { alert('No media found!'); return; } if (slideshowOverlay) { slideshowOverlay.remove(); clearTimers(); document.removeEventListener('keydown', keyHandler); } slideshowMedia = mediaArray; currentIndex = 0; countdownSeconds = 10; isPaused = false; currentVideo = null; slideshowOverlay = document.createElement('div'); slideshowOverlay.style.position = 'fixed'; slideshowOverlay.style.top = '0'; slideshowOverlay.style.left = '0'; slideshowOverlay.style.width = '100vw'; slideshowOverlay.style.height = '100vh'; slideshowOverlay.style.backgroundColor = 'rgba(0,0,0,0.9)'; slideshowOverlay.style.display = 'flex'; slideshowOverlay.style.alignItems = 'center'; slideshowOverlay.style.justifyContent = 'center'; slideshowOverlay.style.flexDirection = 'column'; slideshowOverlay.style.zIndex = '100000'; const mediaContainer = document.createElement('div'); mediaContainer.style.maxWidth = '90%'; mediaContainer.style.maxHeight = '90%'; mediaContainer.style.borderRadius = '10px'; mediaContainer.style.boxShadow = '0 0 20px rgba(255, 255, 255, 0.7)'; mediaContainer.style.display = 'flex'; mediaContainer.style.alignItems = 'center'; mediaContainer.style.justifyContent = 'center'; slideshowOverlay.appendChild(mediaContainer); const timerDisplay = document.createElement('div'); timerDisplay.style.color = 'white'; timerDisplay.style.fontSize = '18px'; timerDisplay.style.marginTop = '10px'; timerDisplay.style.fontFamily = 'Arial, sans-serif'; timerDisplay.textContent = `Next media in: ${countdownSeconds} seconds`; slideshowOverlay.appendChild(timerDisplay); const closeBtn = document.createElement('button'); closeBtn.innerText = '✕'; closeBtn.style.position = 'fixed'; closeBtn.style.top = '20px'; closeBtn.style.right = '20px'; closeBtn.style.fontSize = '30px'; closeBtn.style.background = 'transparent'; closeBtn.style.color = 'white'; closeBtn.style.border = 'none'; closeBtn.style.cursor = 'pointer'; closeBtn.style.zIndex = '100001'; closeBtn.title = 'Close Slideshow'; closeBtn.addEventListener('click', () => { clearTimers(); slideshowOverlay.remove(); slideshowOverlay = null; document.removeEventListener('keydown', keyHandler); }); slideshowOverlay.appendChild(closeBtn); function loadMedia(index) { mediaContainer.innerHTML = ''; currentVideo = null; const mediaObj = slideshowMedia[index]; if (!mediaObj) return; if (mediaObj.type === 'image') { const img = document.createElement('img'); img.src = mediaObj.src; img.style.maxWidth = '100%'; img.style.maxHeight = '100%'; img.style.borderRadius = '10px'; mediaContainer.appendChild(img); countdownSeconds = 10; timerDisplay.textContent = `Next media in: ${countdownSeconds} seconds`; resetInterval(10000); } else if (mediaObj.type === 'video') { const video = document.createElement('video'); video.src = mediaObj.src; video.style.maxWidth = '100%'; video.style.maxHeight = '100%'; video.style.borderRadius = '10px'; video.autoplay = true; video.controls = true; video.loop = false; mediaContainer.appendChild(video); currentVideo = video; video.addEventListener('loadedmetadata', () => { countdownSeconds = Math.ceil(video.duration); timerDisplay.textContent = `Next media in: ${countdownSeconds} seconds`; resetInterval(countdownSeconds * 1000); if (isPaused) video.pause(); }); video.addEventListener('ended', () => { nextMedia(); }); } } function showMedia(index) { currentIndex = (index + slideshowMedia.length) % slideshowMedia.length; loadMedia(currentIndex); } function nextMedia() { showMedia(currentIndex + 1); } function prevMedia() { showMedia(currentIndex - 1); } function resetInterval(duration) { clearTimers(); countdownSeconds = Math.floor(duration / 1000); timerDisplay.textContent = `Next media in: ${countdownSeconds} seconds`; if (!isPaused) { slideshowTimeout = setTimeout(() => { nextMedia(); }, duration); countdownInterval = setInterval(() => { if (!isPaused) { countdownSeconds--; if (countdownSeconds < 0) countdownSeconds = 0; timerDisplay.textContent = `Next media in: ${countdownSeconds} seconds`; } }, 1000); } } function togglePause() { isPaused = !isPaused; if (isPaused) { clearTimers(); if (currentVideo && !currentVideo.paused) currentVideo.pause(); } else { if (currentVideo && currentVideo.paused) currentVideo.play(); resetInterval(countdownSeconds * 1000); } } function keyHandler(e) { if (!slideshowOverlay) return; if (e.key === 'ArrowRight') { nextMedia(); } else if (e.key === 'ArrowLeft') { prevMedia(); } else if (e.key === 'Escape') { closeBtn.click(); } else if (e.code === 'Space') { e.preventDefault(); // prevent page scroll togglePause(); } } document.addEventListener('keydown', keyHandler); showMedia(0); document.body.appendChild(slideshowOverlay); } function addButton() { if (document.getElementById('extract-media-btn')) return; const btn = document.createElement('button'); btn.innerText = 'Start X.com Slideshow'; btn.id = 'extract-media-btn'; btn.style.position = 'fixed'; btn.style.top = '10px'; btn.style.right = '10px'; btn.style.zIndex = '9999'; btn.style.padding = '10px'; btn.style.background = '#1da1f2'; btn.style.color = 'white'; btn.style.border = 'none'; btn.style.borderRadius = '5px'; btn.style.cursor = 'pointer'; btn.title = 'Start slideshow'; btn.addEventListener('click', () => { const media = extractMedia(); showSlideshow(media); }); document.body.appendChild(btn); } const observer = new MutationObserver(() => { addButton(); }); observer.observe(document.body, { childList: true, subtree: true }); addButton(); })();