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();
})();