SimpCity Video & Image Link Copier

Collect and copy video/image links across current or all XenForo thread pages, one page at a time, using localStorage clipboard workaround (Cloudflare safe). Supports separate video/image modes with domain matching.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==UserScript==
// @name         SimpCity Video & Image Link Copier
// @version      2.0
// @namespace    RiisDevScripts
// @description  Collect and copy video/image links across current or all XenForo thread pages, one page at a time, using localStorage clipboard workaround (Cloudflare safe). Supports separate video/image modes with domain matching.
// @author       https://github.com/RiisDev/
// @match        *https://simpcity.cr/threads/*
// @grant        GM_setClipboard
// @icon         https://simpcity.cr/data/assets/logo/favicon.png
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function () {
	'use strict';

	function showChoiceDialog(autoCopy) {
		const overlay = document.createElement('div');
		overlay.style.cssText = `
        	position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
			background: rgba(0,0,0,0.3);
			backdrop-filter: blur(5px);
			-webkit-backdrop-filter: blur(5px);
			display: flex; align-items: center; justify-content: center;
			z-index: 10000;
		`;

		const modal = document.createElement('div');
		modal.className = 'p-body-background p-body-background--main';
		modal.style.cssText = `
			background: var(--xf-palette-pureWhite);
			border-radius: 6px;
			padding: 20px;
			max-width: 320px;
			text-align: center;
			box-shadow: 0 4px 12px rgba(0,0,0,0.15);
		`;

		const title = document.createElement('h3');
		title.textContent = 'Auto Copy Links';
		title.style.marginBottom = '12px';

		const prompt = document.createElement('p');
		prompt.textContent = 'Which links do you want to auto copy across all pages?';
		prompt.style.marginBottom = '20px';

		const btnContainer = document.createElement('div');
		btnContainer.style.display = 'flex';
		btnContainer.style.justifyContent = 'space-between';
		btnContainer.style.gap = '10px';

		function createOptionBtn(text, type) {
			const btn = document.createElement('button');
			btn.className = 'button--primary button rippleButton';
			btn.textContent = text;
			btn.style.flex = '1';
			if (autoCopy){
				btn.addEventListener('click', () => {
					document.body.removeChild(overlay);
					startAutoCopy(type);
				});
			}
			else {
				btn.addEventListener('click', () => {
					const links = extractLinks(type);
					if (links.length > 0) {
						GM_setClipboard(links.join('\n'));
						showXenforoNotice(`✅ Copied ${links.length} ${type} link(s)!`);
					} else {
						showXenforoNotice(`⚠️ No ${type} links found.`);
					}
					document.body.removeChild(overlay);
					
					localStorage.removeItem(XF_LINKS_TYPE);
					localStorage.removeItem(STORAGE_KEY);
				});
			}
			return btn;
		}

		const btnVideo = createOptionBtn('Video', 'video');
		const btnImage = createOptionBtn('Image', 'image');
		const btnBoth = createOptionBtn('Both', 'all');

		const btnCancel = document.createElement('button');
		btnCancel.className = 'button--link button rippleButton';
		btnCancel.textContent = 'Cancel';
		btnCancel.style.flex = '1';
		btnCancel.addEventListener('click', () => {
			document.body.removeChild(overlay);
			if (autoCopy) {
				showXenforoNotice('Auto copy cancelled.', 'warning');
			} else {
				showXenforoNotice('Copy cancelled.', 'warning');
			}
		});

		btnContainer.appendChild(btnVideo);
		btnContainer.appendChild(btnImage);
		btnContainer.appendChild(btnBoth);
		btnContainer.appendChild(btnCancel);

		modal.appendChild(title);
		modal.appendChild(prompt);
		modal.appendChild(btnContainer);
		overlay.appendChild(modal);
		document.body.appendChild(overlay);
	}

	function showXenforoNotice(message, type = 'success', duration = 3000) {
		const notice = document.createElement('div');
		notice.className = `p-notice p-notice--${type}`;
		notice.style.cssText = `
            position: fixed;
            top: 80px;
            right: 30px;
            z-index: 9999;
            max-width: 300px;
            padding: 10px 15px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.3);
            border-radius: 5px;
            font-size: 14px;
            opacity: 0;
            border: 2px solid hsla(var(--xf-textColorEmphasized));
            animation: fadeInOut 0.3s forwards;
        `;
		notice.innerHTML = `<div class="p-notice__content">${message}</div>`;
		document.body.appendChild(notice);

		setTimeout(() => {
			notice.style.animation = 'fadeOut 0.3s forwards';
			setTimeout(() => notice.remove(), 300);
		}, duration);
	}

	const style = document.createElement('style');
	style.textContent = `
        @keyframes fadeInOut {
            from { opacity: 0; transform: translateY(-10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        @keyframes fadeOut {
            from { opacity: 1; }
            to { opacity: 0; transform: translateY(-10px); }
        }
    `;
	document.head.appendChild(style);

	const XF_LINKS_TYPE = 'xf_links_type';
	const STORAGE_KEY = 'xf_links_collector';
	const imageDomains = ['bunkr', 'cyberdrop', 'pixeldrain', 'ibb.co', 'postimg', 'jpg5.su'];
	const videoDomains = ['gofile', 'pixeldrain', 'mega', 'mediafire', 'xhamster', 'pornhub', 'bunkr', 'cyberdrop', 'cyberfile', 'saint2', 'pvvstream', 'noodlemagazine.com', 'xvideos', 'vk'];

	const isVideoLink = url => { try { return videoDomains.some(domain => new URL(url).hostname.includes(domain)); } catch { return false; } };
	const isImageLink = url => { try { return imageDomains.some(domain => new URL(url).hostname.includes(domain)); } catch { return false; } };
	function GetStorageLinks() { return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]'); }
	function GetType() { return localStorage.getItem(XF_LINKS_TYPE); }

	function extractLinks(type) {
		if (!GetType()) { localStorage.setItem(XF_LINKS_TYPE, type);}

		const links = new Set();

		const anchors = document.querySelectorAll('.message--post a[href]');
		anchors.forEach(a => {
			const href = a.href.trim();
			if (
				href &&
				(
					(type === 'video' && isVideoLink(href)) ||
					(type === 'image' && isImageLink(href)) ||
					(type === 'all' && (isVideoLink(href) || isImageLink(href)))
				)
			) {
				links.add(href);
			}
		});

		const iframes = document.querySelectorAll('iframe.saint-iframe[src]');
		if (type !== 'image') {
			iframes.forEach(iframe => {
				const src = iframe.src.trim();
				if (src && isVideoLink(src)) {
					links.add(src);
				}
			});
		}

		return Array.from(links);
	};

	function getNextPageUrl() {
		const nextBtn = document.querySelector('.pageNav-jump--next');
		return nextBtn ? nextBtn.href : null;
	};

	function saveLinks(newLinks) {
		const existing = GetStorageLinks();
		const merged = [...new Set([...existing, ...newLinks])];
		localStorage.setItem(STORAGE_KEY, JSON.stringify(merged));
		return merged;
	};

	function copyAndFinish(type) {
		const allLinks = GetStorageLinks();
		if (allLinks.length > 0) {
			GM_setClipboard(allLinks.join('\n'));
			showXenforoNotice(`✅ Copied ${allLinks.length} ${type} link(s) from all pages!`);
		} else {
			showXenforoNotice(`⚠️ No ${type} links were found.`);
		}

		localStorage.removeItem(STORAGE_KEY);
		localStorage.removeItem(XF_LINKS_TYPE);
	};

	function startAutoCopy(type) {
		localStorage.removeItem(STORAGE_KEY);
		localStorage.removeItem(XF_LINKS_TYPE);

		const links = extractLinks(type);
		saveLinks(links);

		const nextPage = getNextPageUrl();
		if (nextPage) {
			window.location.href = nextPage;
		} else {
			copyAndFinish(type);
		}
	}
	
	function autoContinueIfNeeded() {
		const linksExist = GetStorageLinks();
		const type = GetType();
		if (!linksExist || !type) return;

		const links = extractLinks(type);
		saveLinks(links);

		const nextPage = getNextPageUrl();
		if (nextPage) {
			setTimeout(() => {
				window.location.href = nextPage;
			}, 1000);
		} else {
			copyAndFinish(type);
		}
	};

	function addButton(label, clickHandler) {
		const buttonGroup = document.querySelector('.buttonGroup');
		if (!buttonGroup) return;

		const btn = document.createElement('a');
		btn.href = '#';
		btn.className = 'button--link button rippleButton';
		btn.innerHTML = `<span class="button-text">${label}</span>`;
		btn.addEventListener('click', e => { e.preventDefault(); clickHandler(); });
		buttonGroup.prepend(btn);
	};

	function addButtons() {
		addButton('📋 Start Auto Copy', () => {
			showChoiceDialog(true);
		});

		addButton('📋 Copy Links', () => {
			showChoiceDialog(false);
		});
	};

	window.addEventListener('load', () => {
		addButtons();
		autoContinueIfNeeded();
	});
})();