您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show image preview next to the titles by hovering the mouse, with caching and cleanup.
// ==UserScript== // @name oxtorrent preview Image with Cache Management // @namespace http://tampermonkey.net/ // @version 1.2 // @description Show image preview next to the titles by hovering the mouse, with caching and cleanup. // @author dr.bobo0 // @match https://www.oxtorrent.co/* // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAAAAAAeW/F+AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAACYktHRAD/h4/MvwAAAAd0SU1FB+cFERYzNsSqEXsAAADBSURBVCjPY7RiwAeYGGgozQKhPHjiUcUXvjjCwMDAwGjFwMCgUi6BqfFC5xcGBmZZBgaefiEs5krwnIbY7cGD1V4PCYi0NQ532UCcpgLhHVl7ByocD3cKC1zti04Y68iXZkx/H0FyNJZg+Ypk6wvqBCqdpLkRgjwSmNI2CGkDLLolyqGBy+CBiHsWBgaGOxBxGyT9yLovMGAHRyDSO79gld3xApJavtzVwpIgLkz9BU1rDAwh4h6okshJkfaBihUAAMGoJCE4fyJaAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIzLTA1LTE3VDIyOjUxOjUzKzAwOjAwF57XXQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMy0wNS0xN1QyMjo1MTo1MyswMDowMGbDb+EAAAAodEVYdGRhdGU6dGltZXN0YW1wADIwMjMtMDUtMTdUMjI6NTE6NTQrMDA6MDD0cXCwAAAAAElFTkSuQmCC // @grant none // ==/UserScript== (function() { 'use strict'; const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // Cache Time To Live: 7 days // Function to remove old cache entries that do not have expiration timestamps function cleanOldCache() { for (let i = 0; i < localStorage.length; i++) { let key = localStorage.key(i); if (key.startsWith("oxtorrent_cache_")) { let cacheEntry = JSON.parse(localStorage.getItem(key)); if (!cacheEntry.timestamp) { localStorage.removeItem(key); } } } } // Function to fetch from cache with expiration check function getFromCache(url) { let cacheKey = "oxtorrent_cache_" + url; let cachedData = localStorage.getItem(cacheKey); if (cachedData) { let cacheEntry = JSON.parse(cachedData); if (Date.now() - cacheEntry.timestamp < CACHE_TTL) { return cacheEntry.data; } else { localStorage.removeItem(cacheKey); // Remove expired cache } } return null; } // Function to save to cache with timestamp function saveToCache(url, data) { let cacheKey = "oxtorrent_cache_" + url; let cacheEntry = { data: data, timestamp: Date.now() }; localStorage.setItem(cacheKey, JSON.stringify(cacheEntry)); } cleanOldCache(); document.querySelectorAll("td > a[href^='/torrent/']").forEach(link => { link.addEventListener("mouseover", function(event) { let previewContainer = document.createElement("div"); previewContainer.style.position = "fixed"; previewContainer.style.display = "none"; previewContainer.style.transition = "opacity 0.1s ease-in-out"; previewContainer.style.opacity = 0; previewContainer.style.width = "216px"; previewContainer.style.height = "307px"; previewContainer.style.overflow = "hidden"; document.body.appendChild(previewContainer); let url = this.href; let cachedImage = getFromCache(url); if (cachedImage) { previewContainer.innerHTML = `<img style="width: 100%; height: 100%;" src="${cachedImage}"/>`; showPreview(previewContainer); } else { var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = "document"; xhr.onload = function() { let preview = xhr.response.querySelector("#torrentsimage img"); if (preview) { let imgSrc = preview.getAttribute("src"); previewContainer.innerHTML = `<img style="width: 100%; height: 100%;" src="${imgSrc}"/>`; saveToCache(url, imgSrc); } showPreview(previewContainer); }; xhr.send(); } link.addEventListener("mouseout", function() { previewContainer.style.opacity = 0; setTimeout(function () { previewContainer.style.display = "none"; previewContainer.remove(); }, 300); }); }); }); function showPreview(previewContainer) { document.addEventListener("mousemove", function (event) { previewContainer.style.top = event.clientY + 20 + "px"; previewContainer.style.left = event.clientX + 20 + "px"; if (previewContainer.getBoundingClientRect().right > window.innerWidth) { previewContainer.style.left = (window.innerWidth - previewContainer.offsetWidth - 20) + "px"; } if (previewContainer.getBoundingClientRect().bottom > window.innerHeight) { previewContainer.style.top = (window.innerHeight - previewContainer.offsetHeight - 20) + "px"; } }); previewContainer.style.display = "block"; setTimeout(function () { previewContainer.style.opacity = 1; }, 0); } })();