您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
On-hover Steam thumbnail, description, and community tags for 1337x torrent titles
当前为
// ==UserScript== // @name 1337x - Steam Hover Preview // @namespace https://greasyfork.org/users/DeonHolo // @version 1.8 // @description On-hover Steam thumbnail, description, and community tags for 1337x torrent titles // @icon https://greasyfork.s3.us-east-2.amazonaws.com/x432yc9hx5t6o2gbe9ccr7k5l6u8 // @author DeonHolo // @license MIT // @match *://*.1337x.to/* // @match *://*.1337x.ws/* // @match *://*.1337x.is/* // @match *://*.1337x.gd/* // @match *://*.x1337x.cc/* // @match *://*.1337x.st/* // @match *://*.x1337x.ws/* // @match *://*.1337x.eu/* // @match *://*.1337x.se/* // @match *://*.x1337x.eu/* // @match *://*.x1337x.se/* // @match https://www.1337x.to/* // @match http://l337xdarkkaqfwzntnfk5bmoaroivtl6xsbatabvlb52umg6v3ch44yd.onion/* // @grant GM_xmlhttpRequest // @connect store.steampowered.com // @run-at document-idle // ==/UserScript== ;(function(){ 'use strict'; // create tooltip element const tip = document.createElement('div'); Object.assign(tip.style, { position : 'fixed', padding : '8px', background : 'rgba(255,255,255,0.95)', border : '1px solid #444', borderRadius : '4px', boxShadow : '0 2px 6px rgba(0,0,0,0.2)', zIndex : 2147483647, maxWidth : '300px', fontSize : '12px', lineHeight : '1.3', display : 'none', pointerEvents : 'none' }); document.body.appendChild(tip); let hoverCounter = 0; const cache = new Map(); function gmFetch(url, responseType = 'json') { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url, responseType, onload: res => resolve(res.response), onerror: err => reject(err) }); }); } // fetch search + details from Steam API async function fetchSteam(name) { if (cache.has(name) && cache.get(name).apiData) { return cache.get(name).apiData; } let search; try { search = await gmFetch( `https://store.steampowered.com/api/storesearch/?cc=us&l=en&term=${encodeURIComponent(name)}` ); } catch { return null; } const id = search.items?.[0]?.id; if (!id) return null; let details; try { const resp = await gmFetch( `https://store.steampowered.com/api/appdetails?appids=${id}&cc=us&l=en` ); details = resp[id]?.data; } catch { return null; } cache.set(name, { appid: id, apiData: details }); return details; } // scrape community tags from store page HTML async function fetchTags(appid) { const key = `tags:${appid}`; if (cache.has(key)) return cache.get(key); let html; try { html = await gmFetch(`https://store.steampowered.com/app/${appid}/?l=en`, 'text'); } catch { return []; } const doc = new DOMParser().parseFromString(html, 'text/html'); const els = doc.querySelectorAll('.glance_tags.popular_tags a.app_tag'); const tags = Array.from(els).slice(0,5).map(a => a.textContent.trim()); cache.set(key, tags); return tags; } // clean up torrent title function cleanName(raw) { let name = raw.trim(); name = name.split(/(?:[-\/\(\[]|Update|Edition|Deluxe)/i)[0].trim(); name = name.replace(/ v[\d.].*$/i, '').trim(); return name; } // position tooltip, keep in viewport function positionTip(e) { let x = e.clientX + 12; let y = e.clientY + 12; const w = tip.offsetWidth, h = tip.offsetHeight; if (x + w > window.innerWidth) x = window.innerWidth - w - 8; if (y + h > window.innerHeight) y = window.innerHeight - h - 8; tip.style.left = x + 'px'; tip.style.top = y + 'px'; } // show tooltip with image, description, tags async function showTip(e) { const thisHover = ++hoverCounter; const raw = e.target.textContent; const name = cleanName(raw); tip.innerHTML = `<p>Loading <strong>${name}</strong>…</p>`; tip.style.display = 'block'; positionTip(e); // short debounce await new Promise(r => setTimeout(r, 100)); if (thisHover !== hoverCounter) return; const data = await fetchSteam(name); if (!data || thisHover !== hoverCounter) { tip.innerHTML = `<p>No Steam info for<br><strong>${name}</strong>.</p>`; return; } // once we have API data, load tags const tags = await fetchTags(data.steam_appid || data.appid); if (thisHover !== hoverCounter) return; // build tag HTML const tagHtml = tags.length ? `<p style="margin-top:6px"><strong>Tags:</strong> ${tags.join(', ')}</p>` : ''; tip.innerHTML = ` <img src="${data.header_image}" style="width:100%;margin-bottom:6px"> <p>${data.short_description}</p> ${tagHtml} `; } function hideTip() { hoverCounter++; tip.style.display = 'none'; } // delegate event listeners const SEL = 'td.coll-1 a[href^="/torrent/"]'; document.addEventListener('mouseover', e => { if (e.target.matches(SEL)) showTip(e); }); document.addEventListener('mousemove', e => { if (e.target.matches(SEL) && tip.style.display === 'block') { positionTip(e); } }); document.addEventListener('mouseout', e => { if (e.target.matches(SEL)) hideTip(); }); })();