PornXnow Download Manager

Download videos from PornXnow with ease

Size

12.7 KB

Version

1.1.1

Created

Feb 23, 2026

Updated

about 2 months ago

1// ==UserScript==
2// @name		PornXnow Download Manager
3// @description		Download videos from PornXnow with ease
4// @version		1.1.1
5// @match		https://*.pornxnow.me/*
6// @icon		https://pornxnow.me/wp-content/uploads/2019/05/cropped-favicon-pornxnow-32x32.png
7// @grant		GM.xmlhttpRequest
8// @grant		GM.setValue
9// @grant		GM.getValue
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('PornXnow Download Manager initialized');
15
16    // Debounce function to prevent excessive calls
17    function debounce(func, wait) {
18        let timeout;
19        return function executedFunction(...args) {
20            const later = () => {
21                clearTimeout(timeout);
22                func(...args);
23            };
24            clearTimeout(timeout);
25            timeout = setTimeout(later, wait);
26        };
27    }
28
29    // Add custom styles for the download button
30    function addStyles() {
31        const styles = `
32            .pxnow-download-btn {
33                position: relative;
34                display: inline-flex;
35                align-items: center;
36                gap: 8px;
37                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38                color: white;
39                padding: 12px 24px;
40                border: none;
41                border-radius: 8px;
42                font-size: 16px;
43                font-weight: 600;
44                cursor: pointer;
45                transition: all 0.3s ease;
46                box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
47                margin: 20px 0;
48                text-decoration: none;
49            }
50            
51            .pxnow-download-btn:hover {
52                transform: translateY(-2px);
53                box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
54            }
55            
56            .pxnow-download-btn:active {
57                transform: translateY(0);
58            }
59            
60            .pxnow-download-btn.loading {
61                opacity: 0.7;
62                cursor: wait;
63            }
64            
65            .pxnow-download-btn.loading::after {
66                content: '';
67                position: absolute;
68                width: 16px;
69                height: 16px;
70                top: 50%;
71                right: 12px;
72                margin-top: -8px;
73                border: 2px solid white;
74                border-radius: 50%;
75                border-top-color: transparent;
76                animation: spinner 0.6s linear infinite;
77            }
78            
79            @keyframes spinner {
80                to { transform: rotate(360deg); }
81            }
82            
83            .pxnow-download-container {
84                background: #f8f9fa;
85                padding: 20px;
86                border-radius: 12px;
87                margin: 20px 0;
88                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
89            }
90            
91            .pxnow-download-title {
92                font-size: 18px;
93                font-weight: bold;
94                color: #333;
95                margin-bottom: 15px;
96            }
97            
98            .pxnow-quality-option {
99                display: block;
100                padding: 10px 15px;
101                margin: 8px 0;
102                background: white;
103                border: 2px solid #e0e0e0;
104                border-radius: 6px;
105                color: #333;
106                text-decoration: none;
107                transition: all 0.2s ease;
108            }
109            
110            .pxnow-quality-option:hover {
111                border-color: #667eea;
112                background: #f0f4ff;
113                transform: translateX(5px);
114            }
115            
116            .pxnow-status {
117                padding: 10px;
118                margin: 10px 0;
119                border-radius: 6px;
120                font-size: 14px;
121            }
122            
123            .pxnow-status.success {
124                background: #d4edda;
125                color: #155724;
126                border: 1px solid #c3e6cb;
127            }
128            
129            .pxnow-status.error {
130                background: #f8d7da;
131                color: #721c24;
132                border: 1px solid #f5c6cb;
133            }
134            
135            .pxnow-status.info {
136                background: #d1ecf1;
137                color: #0c5460;
138                border: 1px solid #bee5eb;
139            }
140        `;
141        
142        const styleElement = document.createElement('style');
143        styleElement.textContent = styles;
144        document.head.appendChild(styleElement);
145    }
146
147    // Extract video sources from iframe
148    async function extractVideoSources(iframeUrl) {
149        console.log('Extracting video sources from:', iframeUrl);
150        
151        return new Promise((resolve, reject) => {
152            GM.xmlhttpRequest({
153                method: 'GET',
154                url: iframeUrl,
155                onload: function(response) {
156                    console.log('Iframe content loaded');
157                    const html = response.responseText;
158                    const sources = [];
159                    
160                    // Try to find video sources in various formats
161                    // Look for direct video URLs
162                    const videoUrlPatterns = [
163                        /sources:\s*\[([^\]]+)\]/g,
164                        /file:\s*["']([^"']+\.mp4[^"']*)["']/g,
165                        /src:\s*["']([^"']+\.mp4[^"']*)["']/g,
166                        /https?:\/\/[^"'\s]+\.mp4[^"'\s]*/g
167                    ];
168                    
169                    videoUrlPatterns.forEach(pattern => {
170                        let match;
171                        while ((match = pattern.exec(html)) !== null) {
172                            const url = match[1] || match[0];
173                            if (url && url.includes('.mp4')) {
174                                sources.push(url.replace(/['"]/g, ''));
175                            }
176                        }
177                    });
178                    
179                    // Look for m3u8 streams
180                    const m3u8Pattern = /https?:\/\/[^"'\s]+\.m3u8[^"'\s]*/g;
181                    let m3u8Match;
182                    while ((m3u8Match = m3u8Pattern.exec(html)) !== null) {
183                        sources.push(m3u8Match[0]);
184                    }
185                    
186                    console.log('Found sources:', sources);
187                    
188                    if (sources.length > 0) {
189                        resolve([...new Set(sources)]); // Remove duplicates
190                    } else {
191                        reject('No video sources found');
192                    }
193                },
194                onerror: function(error) {
195                    console.error('Error fetching iframe:', error);
196                    reject('Failed to fetch video sources');
197                }
198            });
199        });
200    }
201
202    // Create download button and container
203    function createDownloadUI() {
204        const videoSection = document.querySelector('.single-video-player');
205        if (!videoSection) {
206            console.log('Video section not found');
207            return;
208        }
209
210        // Check if UI already exists
211        if (document.querySelector('.pxnow-download-container')) {
212            console.log('Download UI already exists');
213            return;
214        }
215
216        const container = document.createElement('div');
217        container.className = 'pxnow-download-container';
218        container.innerHTML = `
219            <div class="pxnow-download-title">📥 Download Video</div>
220            <button class="pxnow-download-btn" id="pxnow-fetch-btn">
221                <span>🎬 Get Download Links</span>
222            </button>
223            <div id="pxnow-download-links"></div>
224        `;
225
226        // Insert right after the video player, before video title
227        const videoPlayer = videoSection.querySelector('.responsive-player');
228        if (videoPlayer && videoPlayer.parentNode) {
229            videoPlayer.parentNode.insertBefore(container, videoPlayer.nextSibling);
230            console.log('Download UI created after video player');
231        } else {
232            // Fallback: insert after video wrapper
233            const videoWrapper = videoSection.querySelector('.video-wrapper');
234            if (videoWrapper) {
235                videoWrapper.parentNode.insertBefore(container, videoWrapper.nextSibling);
236                console.log('Download UI created after video wrapper');
237            }
238        }
239
240        // Add click handler
241        const fetchBtn = document.getElementById('pxnow-fetch-btn');
242        if (fetchBtn) {
243            fetchBtn.addEventListener('click', handleDownloadClick);
244        }
245    }
246
247    // Handle download button click
248    async function handleDownloadClick(e) {
249        const btn = e.currentTarget;
250        const linksContainer = document.getElementById('pxnow-download-links');
251        
252        // Prevent multiple clicks
253        if (btn.classList.contains('loading')) {
254            return;
255        }
256        
257        btn.classList.add('loading');
258        btn.querySelector('span').textContent = 'Fetching video sources...';
259        linksContainer.innerHTML = '<div class="pxnow-status info">🔍 Searching for video sources...</div>';
260
261        try {
262            // Get iframe URL
263            const iframe = document.querySelector('.video-player iframe');
264            if (!iframe || !iframe.src) {
265                throw new Error('Video iframe not found');
266            }
267
268            const iframeUrl = iframe.src;
269            console.log('Processing iframe:', iframeUrl);
270
271            // Extract video sources
272            const sources = await extractVideoSources(iframeUrl);
273            
274            if (sources.length === 0) {
275                throw new Error('No video sources found');
276            }
277
278            // Display download links
279            let linksHTML = '<div class="pxnow-status success">✅ Found video sources!</div>';
280            
281            sources.forEach((source, index) => {
282                const isM3U8 = source.includes('.m3u8');
283                const quality = isM3U8 ? 'HLS Stream' : `Quality ${index + 1}`;
284                const icon = isM3U8 ? '📺' : '🎥';
285                
286                linksHTML += `
287                    <a href="${source}" 
288                       class="pxnow-quality-option" 
289                       download 
290                       target="_blank">
291                        ${icon} ${quality} - Click to Download
292                    </a>
293                `;
294            });
295            
296            linksContainer.innerHTML = linksHTML;
297            btn.querySelector('span').textContent = '✅ Download Links Ready';
298            
299            // Save to history
300            await saveDownloadHistory(window.location.href, sources);
301            
302        } catch (error) {
303            console.error('Error:', error);
304            linksContainer.innerHTML = `
305                <div class="pxnow-status error">
306${error.message || 'Failed to fetch video sources'}
307                    <br><small>Try refreshing the page or check if the video is loaded</small>
308                </div>
309            `;
310            btn.querySelector('span').textContent = '🔄 Try Again';
311        } finally {
312            btn.classList.remove('loading');
313        }
314    }
315
316    // Save download history
317    async function saveDownloadHistory(pageUrl, sources) {
318        try {
319            const history = await GM.getValue('download_history', []);
320            history.unshift({
321                url: pageUrl,
322                sources: sources,
323                timestamp: Date.now(),
324                title: document.title
325            });
326            
327            // Keep only last 50 entries
328            if (history.length > 50) {
329                history.splice(50);
330            }
331            
332            await GM.setValue('download_history', history);
333            console.log('Download history saved');
334        } catch (error) {
335            console.error('Error saving history:', error);
336        }
337    }
338
339    // Initialize the extension
340    function init() {
341        console.log('Initializing PornXnow Download Manager');
342        
343        // Add styles
344        addStyles();
345        
346        // Wait for page to load
347        if (document.readyState === 'loading') {
348            document.addEventListener('DOMContentLoaded', createDownloadUI);
349        } else {
350            createDownloadUI();
351        }
352        
353        // Also try after a delay to ensure video player is loaded
354        setTimeout(createDownloadUI, 2000);
355        
356        // Watch for dynamic content changes
357        const observer = new MutationObserver(debounce(() => {
358            if (document.querySelector('.single-video-player') && !document.querySelector('.pxnow-download-container')) {
359                createDownloadUI();
360            }
361        }, 1000));
362        
363        observer.observe(document.body, {
364            childList: true,
365            subtree: true
366        });
367    }
368
369    // Start the extension
370    init();
371})();
PornXnow Download Manager | Robomonkey