您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Replaces the Flash RIP notice on the Neopian Lottery page with a looping MP4 video and hides any lingering SWF embed.
// ==UserScript== // @name Neopian Lottery – Replace Flash RIP with MP4 // @namespace neopets // @version 1.0.0 // @description Replaces the Flash RIP notice on the Neopian Lottery page with a looping MP4 video and hides any lingering SWF embed. // @author SirStroman // @match https://www.neopets.com/games/lottery.phtml // @match http://www.neopets.com/games/lottery.phtml // @run-at document-idle // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; const MP4_URL = 'https://files.catbox.moe/lph5qc.mp4'; /** Poll for an element until it exists, then resolve */ function waitForEl(selector, { interval = 200, timeout = 10_000 } = {}) { return new Promise((resolve, reject) => { const start = Date.now(); const timer = setInterval(() => { const el = document.querySelector(selector); if (el) { clearInterval(timer); resolve(el); } else if (Date.now() - start > timeout) { clearInterval(timer); reject(new Error(`Timed out waiting for ${selector}`)); } }, interval); }); } function hideFlashEmbed() { // Hide obvious SWF/object embeds and the dynamic SWFObject output const swfLike = document.querySelectorAll( 'embed[type*="shockwave"], object[type*="shockwave"], object[data$=".swf"], embed[src$=".swf"], [id^="flash_"]' ); swfLike.forEach((n) => { n.style.display = 'none'; n.style.visibility = 'hidden'; }); } function buildVideo(widthPx = 150, heightPx = 225) { const vid = document.createElement('video'); vid.src = MP4_URL; vid.autoplay = true; vid.muted = true; // required for autoplay vid.loop = true; vid.playsInline = true; // iOS inline playback vid.setAttribute('playsinline', ''); vid.setAttribute('preload', 'auto'); Object.assign(vid.style, { width: `${widthPx}px`, height: `${heightPx}px`, objectFit: 'cover', display: 'block', borderRadius: '6px', boxShadow: '0 1px 3px rgba(0,0,0,.25)', }); return vid; } async function replaceFlashRip() { try { // Flash RIP div is injected by /js/flash_rip.js and has this class const rip = await waitForEl('.flashRIP__2020', { interval: 200, timeout: 10000 }); // Make sure it’s visible and empty it rip.style.display = 'block'; rip.innerHTML = ''; // Some page layouts benefit from a small wrapper to ensure sizing const wrap = document.createElement('div'); Object.assign(wrap.style, { width: '150px', height: '225px', margin: '0 auto', }); wrap.appendChild(buildVideo(150, 225)); rip.appendChild(wrap); } catch (err) { // If the Flash RIP element never appears, try to inject near the SWF slot as a fallback console.warn('[Lottery MP4] FlashRIP not found, falling back:', err); // The SWF was written with a dynamic id 'flash_*' inside the first <td> of the lottery table const swfCell = document.querySelector('table[width="100%"] td[width="160"]') || document.querySelector('object[id^="flash_"], embed[id^="flash_"]')?.parentElement; if (swfCell) { // Clear and insert our video swfCell.innerHTML = ''; swfCell.appendChild(buildVideo(150, 225)); } } } function init() { hideFlashEmbed(); replaceFlashRip(); // If the site’s JS toggles Flash RIP visibility later, keep our video visible const mo = new MutationObserver(() => { const rip = document.querySelector('.flashRIP__2020'); if (rip && rip.style.display === 'none') rip.style.display = 'block'; }); const root = document.body || document.documentElement; if (root) mo.observe(root, { attributes: true, childList: true, subtree: true }); } // Kick off once the DOM is usable if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init, { once: true }); } else { init(); } })();