Size
5.8 KB
Version
1.1.2
Created
Jan 17, 2026
Updated
18 days ago
1// ==UserScript==
2// @name Kufirc Thumbnail Display
3// @description Shows torrent thumbnails directly on the browse page
4// @version 1.1.2
5// @match https://*.kufirc.com/*
6// @icon https://kufirc.com/favicon.ico?v=1756621831
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Kufirc Thumbnail Display: Starting...');
12
13 // Add CSS styles for thumbnails
14 TM_addStyle(`
15 .thumbnail-container {
16 display: inline-block;
17 margin-left: 10px;
18 vertical-align: middle;
19 }
20
21 .thumbnail-container img {
22 max-width: 250px;
23 max-height: 250px;
24 border: 2px solid #444;
25 border-radius: 4px;
26 box-shadow: 0 2px 8px rgba(0,0,0,0.3);
27 cursor: pointer;
28 transition: transform 0.2s;
29 }
30
31 .thumbnail-container img:hover {
32 transform: scale(1.05);
33 border-color: #666;
34 }
35
36 .thumbnail-loading {
37 display: inline-block;
38 margin-left: 10px;
39 color: #888;
40 font-size: 11px;
41 }
42 `);
43
44 // Parse overlay data from script tags
45 function parseOverlayData() {
46 const overlayData = {};
47 const scripts = document.querySelectorAll('script');
48
49 scripts.forEach(script => {
50 const content = script.textContent;
51 // Match overlay variables: var overlay12345 = "..."
52 const overlayMatches = content.matchAll(/var\s+overlay(\d+)\s*=\s*"(.+?)"\s*(?:var|<\/script>|$)/gs);
53
54 for (const match of overlayMatches) {
55 const torrentId = match[1];
56 const overlayHtml = match[2];
57 overlayData[torrentId] = overlayHtml;
58 }
59 });
60
61 console.log(`Parsed ${Object.keys(overlayData).length} overlay entries`);
62 return overlayData;
63 }
64
65 function extractThumbnailFromOverlay(overlayHtml) {
66 // Extract image URL from overlay HTML
67 const imgMatch = overlayHtml.match(/src=\\"([^"]+)\\"/);
68 if (imgMatch && imgMatch[1]) {
69 // Unescape the URL
70 return imgMatch[1].replace(/\\\//g, '/');
71 }
72 return null;
73 }
74
75 function addThumbnailToTorrent(torrentLink, overlayData) {
76 // Check if thumbnail already added
77 if (torrentLink.dataset.thumbnailAdded) {
78 return;
79 }
80 torrentLink.dataset.thumbnailAdded = 'true';
81
82 // Get the torrent ID from the link
83 const torrentId = torrentLink.href.match(/id=(\d+)/)?.[1];
84 if (!torrentId) {
85 console.log('No torrent ID found for link:', torrentLink.href);
86 return;
87 }
88
89 // Get overlay HTML from parsed data
90 const overlayHtml = overlayData[torrentId];
91
92 if (!overlayHtml) {
93 console.log(`No overlay found for torrent ${torrentId}`);
94 return;
95 }
96
97 // Extract thumbnail URL
98 const thumbnailUrl = extractThumbnailFromOverlay(overlayHtml);
99
100 if (!thumbnailUrl) {
101 console.log(`No thumbnail URL found in overlay for torrent ${torrentId}`);
102 return;
103 }
104
105 console.log(`Adding thumbnail for torrent ${torrentId}:`, thumbnailUrl);
106
107 // Create thumbnail container
108 const thumbnailContainer = document.createElement('div');
109 thumbnailContainer.className = 'thumbnail-container';
110
111 const img = document.createElement('img');
112 img.src = thumbnailUrl;
113 img.alt = 'Torrent thumbnail';
114 img.title = 'Click to view full size';
115
116 // Add click handler to open image in new tab
117 img.addEventListener('click', (e) => {
118 e.preventDefault();
119 e.stopPropagation();
120 window.open(thumbnailUrl, '_blank');
121 });
122
123 thumbnailContainer.appendChild(img);
124
125 // Insert thumbnail after the torrent link
126 torrentLink.parentNode.appendChild(thumbnailContainer);
127 }
128
129 function processTorrents() {
130 // Parse overlay data from scripts
131 const overlayData = parseOverlayData();
132
133 // Find all torrent links with onmouseover overlay
134 const torrentLinks = document.querySelectorAll('a[href*="/torrents.php?id="][onmouseover*="overlay"]');
135
136 console.log(`Found ${torrentLinks.length} torrent links to process`);
137
138 torrentLinks.forEach(link => {
139 addThumbnailToTorrent(link, overlayData);
140 });
141 }
142
143 // Wait for page to be ready
144 TM_runBody(() => {
145 console.log('Kufirc Thumbnail Display: Page ready, processing torrents...');
146
147 // Initial processing
148 processTorrents();
149
150 // Watch for dynamic content changes (pagination, filtering, etc.)
151 const observer = new MutationObserver((mutations) => {
152 let shouldProcess = false;
153
154 mutations.forEach(mutation => {
155 if (mutation.addedNodes.length > 0) {
156 mutation.addedNodes.forEach(node => {
157 if (node.nodeType === 1 && (node.matches('tr.torrent') || node.querySelector('tr.torrent'))) {
158 shouldProcess = true;
159 }
160 });
161 }
162 });
163
164 if (shouldProcess) {
165 console.log('New torrents detected, processing...');
166 processTorrents();
167 }
168 });
169
170 // Observe the torrent table for changes
171 const torrentTable = document.getElementById('torrent_table');
172 if (torrentTable) {
173 observer.observe(torrentTable, {
174 childList: true,
175 subtree: true
176 });
177 console.log('Watching for dynamic content changes');
178 }
179 });
180})();