Size
8.1 KB
Version
1.1.4
Created
Feb 25, 2026
Updated
about 2 months ago
1// ==UserScript==
2// @name Kufirc Thumbnail Display
3// @description Displays thumbnails for torrents on Kufirc browse pages
4// @version 1.1.4
5// @match https://*.kufirc.com/*
6// @icon https://kufirc.com/favicon.ico?v=1756621831
7// @grant GM.xmlHttpRequest
8// ==/UserScript==
9(function() {
10 'use strict';
11
12 console.log('Kufirc Thumbnail Display extension loaded');
13
14 // Add styles for thumbnails
15 GM_addStyle(`
16 .thumbnail-container {
17 display: inline-block;
18 margin-left: 10px;
19 vertical-align: middle;
20 position: relative;
21 }
22
23 .thumbnail-preview {
24 max-width: 250px;
25 max-height: 170px;
26 border: 2px solid #444;
27 border-radius: 4px;
28 cursor: pointer;
29 transition: transform 0.2s, box-shadow 0.2s;
30 }
31
32 .thumbnail-preview:hover {
33 transform: scale(1.05);
34 box-shadow: 0 4px 8px rgba(0,0,0,0.3);
35 border-color: #666;
36 }
37
38 .thumbnail-loading {
39 display: inline-block;
40 width: 250px;
41 height: 170px;
42 background: #2a2a2a;
43 border: 2px solid #444;
44 border-radius: 4px;
45 text-align: center;
46 line-height: 170px;
47 color: #888;
48 font-size: 12px;
49 }
50
51 .thumbnail-error {
52 display: inline-block;
53 width: 250px;
54 height: 170px;
55 background: #3a2a2a;
56 border: 2px solid #644;
57 border-radius: 4px;
58 text-align: center;
59 line-height: 170px;
60 color: #a66;
61 font-size: 11px;
62 }
63
64 .thumbnail-modal {
65 display: none;
66 position: fixed;
67 z-index: 10000;
68 left: 0;
69 top: 0;
70 width: 100%;
71 height: 100%;
72 background-color: rgba(0,0,0,0.9);
73 justify-content: center;
74 align-items: center;
75 }
76
77 .thumbnail-modal.active {
78 display: flex;
79 }
80
81 .thumbnail-modal img {
82 max-width: 90%;
83 max-height: 90%;
84 border: 3px solid #666;
85 border-radius: 8px;
86 }
87
88 .thumbnail-modal-close {
89 position: absolute;
90 top: 20px;
91 right: 40px;
92 color: #fff;
93 font-size: 40px;
94 font-weight: bold;
95 cursor: pointer;
96 z-index: 10001;
97 }
98
99 .thumbnail-modal-close:hover {
100 color: #ccc;
101 }
102 `);
103
104 // Create modal for full-size image viewing
105 const modal = document.createElement('div');
106 modal.className = 'thumbnail-modal';
107 modal.innerHTML = '<span class="thumbnail-modal-close">×</span><img src="" alt="Full size thumbnail">';
108 document.body.appendChild(modal);
109
110 const modalImg = modal.querySelector('img');
111 const closeBtn = modal.querySelector('.thumbnail-modal-close');
112
113 closeBtn.addEventListener('click', () => {
114 modal.classList.remove('active');
115 });
116
117 modal.addEventListener('click', (e) => {
118 if (e.target === modal) {
119 modal.classList.remove('active');
120 }
121 });
122
123 // Function to fetch torrent page and extract thumbnail
124 async function fetchThumbnail(torrentId) {
125 try {
126 console.log(`Fetching thumbnail for torrent ID: ${torrentId}`);
127
128 const response = await GM.xmlhttpRequest({
129 method: 'GET',
130 url: `https://kufirc.com/torrents.php?id=${torrentId}`
131 });
132
133 const parser = new DOMParser();
134 const doc = parser.parseFromString(response.responseText, 'text/html');
135
136 // Look for images in the torrent page
137 const allImages = Array.from(doc.querySelectorAll('img')).filter(img => {
138 const src = img.src;
139 return src &&
140 src.startsWith('http') &&
141 !src.includes('icon') &&
142 !src.includes('arrow') &&
143 !src.includes('snatched') &&
144 !src.includes('logo') &&
145 !src.includes('seeders') &&
146 !src.includes('leechers') &&
147 !src.includes('favicon') &&
148 !src.includes('freedownload');
149 });
150
151 if (allImages.length > 0) {
152 const thumbnailUrl = allImages[0].src;
153 console.log(`Found thumbnail: ${thumbnailUrl}`);
154 return thumbnailUrl;
155 }
156
157 console.log(`No thumbnail found for torrent ID: ${torrentId}`);
158 return null;
159 } catch (error) {
160 console.error(`Error fetching thumbnail for torrent ${torrentId}:`, error);
161 return null;
162 }
163 }
164
165 // Function to add thumbnail to torrent row
166 async function addThumbnailToRow(link) {
167 // Check if thumbnail already added
168 if (link.dataset.thumbnailAdded === 'true') {
169 return;
170 }
171 link.dataset.thumbnailAdded = 'true';
172
173 // Extract torrent ID from link
174 const match = link.href.match(/id=(\d+)/);
175 if (!match) {
176 console.log('Could not extract torrent ID from link:', link.href);
177 return;
178 }
179
180 const torrentId = match[1];
181
182 // Create thumbnail container
183 const container = document.createElement('div');
184 container.className = 'thumbnail-container';
185
186 // Add loading indicator
187 const loading = document.createElement('div');
188 loading.className = 'thumbnail-loading';
189 loading.textContent = 'Loading...';
190 container.appendChild(loading);
191
192 // Insert after the link
193 link.parentNode.appendChild(container);
194
195 // Fetch thumbnail
196 const thumbnailUrl = await fetchThumbnail(torrentId);
197
198 if (thumbnailUrl) {
199 // Replace loading with actual thumbnail
200 const img = document.createElement('img');
201 img.className = 'thumbnail-preview';
202 img.src = thumbnailUrl;
203 img.alt = 'Torrent thumbnail';
204
205 img.addEventListener('click', () => {
206 modalImg.src = thumbnailUrl;
207 modal.classList.add('active');
208 });
209
210 img.addEventListener('error', () => {
211 container.innerHTML = '<div class="thumbnail-error">Failed to load</div>';
212 });
213
214 container.innerHTML = '';
215 container.appendChild(img);
216 } else {
217 // No thumbnail found
218 container.innerHTML = '<div class="thumbnail-error">No thumbnail</div>';
219 }
220 }
221
222 // Function to process all torrent links on the page
223 function processTorrentLinks() {
224 const torrentLinks = document.querySelectorAll('a[href*="/torrents.php?id="]');
225 console.log(`Found ${torrentLinks.length} torrent links`);
226
227 torrentLinks.forEach((link, index) => {
228 // Add a small delay between requests to avoid overwhelming the server
229 setTimeout(() => {
230 addThumbnailToRow(link);
231 }, index * 500);
232 });
233 }
234
235 // Initialize when page is ready
236 function init() {
237 console.log('Initializing Kufirc Thumbnail Display');
238
239 // Wait for the torrent table to be present
240 const checkTable = setInterval(() => {
241 const torrentTable = document.querySelector('#torrent_table, .torrent_table');
242 if (torrentTable) {
243 clearInterval(checkTable);
244 console.log('Torrent table found, processing links');
245 processTorrentLinks();
246 }
247 }, 500);
248
249 // Stop checking after 10 seconds
250 setTimeout(() => clearInterval(checkTable), 10000);
251 }
252
253 // Run when DOM is ready
254 if (document.readyState === 'loading') {
255 document.addEventListener('DOMContentLoaded', init);
256 } else {
257 init();
258 }
259})();