Size
7.0 KB
Version
1.1.8
Created
Jan 21, 2026
Updated
about 1 month ago
1// ==UserScript==
2// @name PornoLab Torrent Name Copier
3// @description Copy torrent file name to clipboard with one click
4// @version 1.1.8
5// @match https://*.pornolab.net/*
6// @icon https://static.pornolab.net/favicon.ico
7// @grant GM.setClipboard
8// ==/UserScript==
9(function() {
10 'use strict';
11
12 console.log('PornoLab Torrent File Name Copier loaded');
13
14 // Function to extract just the filename from the file list text
15 function extractFileName(fileListText) {
16 // Remove the file size info (everything after the filename)
17 // The format is: "filename.mp4 <i><s>size</s> (bytes)</i>"
18 const match = fileListText.match(/^(.+?\.mp4)/);
19 return match ? match[1].trim() : fileListText.trim();
20 }
21
22 // Function to wait for the file list to load
23 async function waitForFileList() {
24 const maxAttempts = 20; // Wait up to 10 seconds
25 let attempts = 0;
26
27 while (attempts < maxAttempts) {
28 const fileListElement = document.querySelector('#tor-filelist');
29 if (fileListElement) {
30 const text = fileListElement.textContent.trim();
31 // Check if it's not loading and contains .mp4
32 if (text && !text.includes('загружается') && text.includes('.mp4')) {
33 console.log('File list loaded successfully');
34 return extractFileName(text);
35 }
36 }
37 await new Promise(resolve => setTimeout(resolve, 500));
38 attempts++;
39 }
40
41 console.error('File list did not load in time');
42 return null;
43 }
44
45 // Cross-platform clipboard function
46 async function copyToClipboard(text) {
47 // Try GM.setClipboard first (works in most userscript managers)
48 if (typeof GM !== 'undefined' && GM.setClipboard) {
49 await GM.setClipboard(text);
50 return;
51 }
52
53 // Fallback to navigator.clipboard API
54 if (navigator.clipboard && navigator.clipboard.writeText) {
55 await navigator.clipboard.writeText(text);
56 return;
57 }
58
59 // Last resort: create a temporary textarea
60 const textarea = document.createElement('textarea');
61 textarea.value = text;
62 textarea.style.position = 'fixed';
63 textarea.style.opacity = '0';
64 document.body.appendChild(textarea);
65 textarea.select();
66 document.execCommand('copy');
67 document.body.removeChild(textarea);
68 }
69
70 // Function to initialize the copy button
71 async function init() {
72 // Find the torrent title element at the top of the page
73 const titleElement = document.querySelector('#topic-title');
74
75 if (!titleElement) {
76 console.log('Torrent title not found on this page');
77 return;
78 }
79
80 // Create the copy button immediately
81 const copyButton = document.createElement('button');
82 copyButton.textContent = '📋 Copy File Name';
83 copyButton.style.cssText = `
84 margin-left: 10px;
85 padding: 8px 16px;
86 background-color: #4CAF50;
87 color: white;
88 border: none;
89 border-radius: 4px;
90 cursor: pointer;
91 font-size: 14px;
92 font-weight: bold;
93 transition: background-color 0.3s;
94 `;
95
96 // Add hover effect
97 copyButton.addEventListener('mouseenter', () => {
98 copyButton.style.backgroundColor = '#45a049';
99 });
100
101 copyButton.addEventListener('mouseleave', () => {
102 copyButton.style.backgroundColor = '#4CAF50';
103 });
104
105 // Insert the button next to the title immediately
106 const titleContainer = titleElement.parentElement;
107 if (titleContainer) {
108 titleContainer.appendChild(copyButton);
109 console.log('Copy button added successfully');
110 }
111
112 // Now load the file name in the background
113 const fileListBtn = document.querySelector('#tor-filelist-btn');
114
115 if (!fileListBtn) {
116 console.log('File list button not found on this page');
117 copyButton.textContent = '✗ No Files';
118 copyButton.style.backgroundColor = '#f44336';
119 copyButton.disabled = true;
120 return;
121 }
122
123 // Check if file list is already loaded
124 const fileListElement = document.querySelector('#tor-filelist');
125 const isAlreadyLoaded = fileListElement &&
126 fileListElement.textContent.trim() &&
127 !fileListElement.textContent.includes('загружается') &&
128 fileListElement.textContent.includes('.mp4');
129
130 // Click the button to reveal the file list if not already loaded
131 if (!isAlreadyLoaded) {
132 const fileListWrap = document.querySelector('#tor-fl-wrap');
133 if (!fileListWrap || fileListWrap.style.display === 'none') {
134 fileListBtn.click();
135 console.log('Clicked file list button to reveal files');
136 } else {
137 // File list wrap exists but might be loading, click anyway to ensure it loads
138 fileListBtn.click();
139 console.log('File list wrap exists, clicking button to load files');
140 }
141 }
142
143 // Wait for the file list to load
144 const fileName = await waitForFileList();
145
146 if (!fileName) {
147 console.error('Could not get file name');
148 copyButton.textContent = '✗ Failed to Load';
149 copyButton.style.backgroundColor = '#f44336';
150 copyButton.disabled = true;
151 return;
152 }
153
154 console.log('Found file name:', fileName);
155
156 // Add click handler to copy the file name
157 copyButton.addEventListener('click', async () => {
158 try {
159 await copyToClipboard(fileName);
160 console.log('File name copied to clipboard:', fileName);
161
162 // Visual feedback
163 const originalText = copyButton.textContent;
164 copyButton.textContent = '✓ Copied!';
165 copyButton.style.backgroundColor = '#2196F3';
166
167 setTimeout(() => {
168 copyButton.textContent = originalText;
169 copyButton.style.backgroundColor = '#4CAF50';
170 }, 2000);
171 } catch (error) {
172 console.error('Failed to copy to clipboard:', error);
173 copyButton.textContent = '✗ Failed';
174 copyButton.style.backgroundColor = '#f44336';
175
176 setTimeout(() => {
177 copyButton.textContent = '📋 Copy File Name';
178 copyButton.style.backgroundColor = '#4CAF50';
179 }, 2000);
180 }
181 });
182 }
183
184 // Wait for the page to be fully loaded
185 if (document.readyState === 'loading') {
186 document.addEventListener('DOMContentLoaded', init);
187 } else {
188 init();
189 }
190})();