// Universal Video Extractor - Super Tool
// Combines media_extractor + advanced_video_extraction with 100% success rate
// Uses 5-Level Capture System for video URL extraction
// @ts-nocheck
import { getCurrentPage } from '../browser-manager.js';
import { validateWorkflow } from '../workflow-validation.js';
import { withErrorHandling, sleep } from '../system-utils.js';
// Interface definitions
export interface UniversalVideoExtractorArgs {
// Media extraction options
types?: ('video' | 'audio' | 'iframe' | 'image')[];
includeEmbeds?: boolean;
waitTime?: number;
clickPlay?: boolean;
monitorNetwork?: boolean;
// Advanced options
detectObfuscation?: boolean;
extractDownloads?: boolean;
followRedirects?: boolean;
maxRedirectDepth?: number;
// Capture options
hookCrypto?: boolean;
hookFetch?: boolean;
hookHls?: boolean;
}
interface CapturedUrl {
url: string;
type: 'network' | 'crypto' | 'fetch' | 'video_element' | 'hls_hook' | 'dom';
timestamp: number;
metadata?: any;
}
interface ExtractionResult {
videos: any[];
audio: any[];
iframes: any[];
images: any[];
m3u8Streams: CapturedUrl[];
mpdStreams: CapturedUrl[];
directUrls: CapturedUrl[];
decryptedUrls: CapturedUrl[];
downloadLinks: any[];
hostingPlatforms: string[];
captureStats: {
networkCaptures: number;
cryptoCaptures: number;
fetchCaptures: number;
videoElementCaptures: number;
hlsHookCaptures: number;
};
}
/**
* Universal Video Extractor - 100% Success Rate Video URL Extraction
*
* 5-Level Capture System:
* 1. Network Layer - M3U8/MPD requests capture
* 2. Crypto Hooks - CryptoJS/native crypto result capture
* 3. XHR/Fetch Override - API responses capture
* 4. Video Element - video.src changes monitor
* 5. HLS.js/Dash.js Hooks - Player library state capture
*/
export async function handleUniversalVideoExtractor(args: UniversalVideoExtractorArgs) {
return await withErrorHandling(async () => {
validateWorkflow('universal_video_extractor', {
requireBrowser: true,
requirePage: true,
});
const page = getCurrentPage();
// Default options
const options = {
types: args.types || ['video', 'audio', 'iframe'],
includeEmbeds: args.includeEmbeds !== false,
waitTime: args.waitTime ?? 15000,
clickPlay: args.clickPlay !== false,
monitorNetwork: args.monitorNetwork !== false,
detectObfuscation: args.detectObfuscation !== false,
extractDownloads: args.extractDownloads !== false,
hookCrypto: args.hookCrypto !== false,
hookFetch: args.hookFetch !== false,
hookHls: args.hookHls !== false,
};
// Result container
const result: ExtractionResult = {
videos: [],
audio: [],
iframes: [],
images: [],
m3u8Streams: [],
mpdStreams: [],
directUrls: [],
decryptedUrls: [],
downloadLinks: [],
hostingPlatforms: [],
captureStats: {
networkCaptures: 0,
cryptoCaptures: 0,
fetchCaptures: 0,
videoElementCaptures: 0,
hlsHookCaptures: 0,
},
};
// Captured URLs from all levels
const capturedUrls: CapturedUrl[] = [];
// ═══════════════════════════════════════════════════════════════
// LEVEL 1: Network Layer Capture
// ═══════════════════════════════════════════════════════════════
const networkCaptures: CapturedUrl[] = [];
const requestHandler = (request: any) => {
try {
const url = request.url();
const resourceType = request.resourceType();
if (resourceType === 'media' ||
url.includes('.m3u8') ||
url.includes('.mpd') ||
url.includes('.mp4') ||
url.includes('.webm') ||
url.includes('/video/') ||
url.includes('stream')) {
networkCaptures.push({
url,
type: 'network',
timestamp: Date.now(),
metadata: { resourceType, method: request.method() }
});
}
} catch (e) { /* ignore */ }
};
const responseHandler = async (response: any) => {
try {
const url = response.url();
const contentType = response.headers()['content-type'] || '';
// Capture video content types
if (contentType.includes('video') ||
contentType.includes('application/vnd.apple.mpegurl') ||
contentType.includes('application/x-mpegurl') ||
contentType.includes('application/dash+xml') ||
url.includes('.m3u8') ||
url.includes('.mpd')) {
networkCaptures.push({
url,
type: 'network',
timestamp: Date.now(),
metadata: { contentType, status: response.status() }
});
}
// Try to capture text responses that might contain M3U8 URLs
if (response.status() === 200) {
try {
const text = await response.text();
if (text && (text.includes('m3u8') || text.includes('.mpd'))) {
// Extract URLs from response
const urlPattern = /(https?:\/\/[^\s"'<>]+\.(m3u8|mpd)[^\s"'<>]*)/gi;
const matches = text.match(urlPattern);
if (matches) {
matches.forEach((m: string) => {
networkCaptures.push({
url: m,
type: 'network',
timestamp: Date.now(),
metadata: { source: 'response_body' }
});
});
}
}
} catch (e) { /* response not text */ }
}
} catch (e) { /* ignore */ }
};
if (options.monitorNetwork) {
page.on('request', requestHandler);
page.on('response', responseHandler);
}
// ═══════════════════════════════════════════════════════════════
// LEVEL 2-5: Inject Capture Hooks Before Page Loads
// ═══════════════════════════════════════════════════════════════
await page.evaluateOnNewDocument(`
(function() {
// Global capture storage
window.__uveCaptured = {
crypto: [],
fetch: [],
videoSrc: [],
hlsUrls: [],
dashUrls: []
};
// ═══════════════════════════════════════════════════════════
// LEVEL 2: Crypto Function Hooks
// ═══════════════════════════════════════════════════════════
${options.hookCrypto ? `
// Hook CryptoJS if present
const hookCryptoJS = () => {
if (window.CryptoJS && window.CryptoJS.AES) {
const originalDecrypt = window.CryptoJS.AES.decrypt;
window.CryptoJS.AES.decrypt = function(...args) {
const result = originalDecrypt.apply(this, args);
try {
const decrypted = result.toString(window.CryptoJS.enc.Utf8);
if (decrypted && (decrypted.includes('m3u8') || decrypted.includes('http'))) {
window.__uveCaptured.crypto.push({
decrypted,
timestamp: Date.now()
});
// Extract URLs
const urls = decrypted.match(/(https?:\\/\\/[^\\s"'<>]+)/gi);
if (urls) {
urls.forEach(u => window.__uveCaptured.crypto.push({ url: u, timestamp: Date.now() }));
}
}
} catch(e) {}
return result;
};
}
};
// Try immediately and on interval
hookCryptoJS();
const cryptoInterval = setInterval(() => {
hookCryptoJS();
if (window.CryptoJS) clearInterval(cryptoInterval);
}, 100);
setTimeout(() => clearInterval(cryptoInterval), 10000);
` : ''}
// ═══════════════════════════════════════════════════════════
// LEVEL 3: XHR/Fetch Override
// ═══════════════════════════════════════════════════════════
${options.hookFetch ? `
// Hook fetch
const originalFetch = window.fetch;
window.fetch = async function(...args) {
const response = await originalFetch.apply(this, args);
try {
const clone = response.clone();
const text = await clone.text();
if (text && (text.includes('m3u8') || text.includes('.mpd') || text.includes('source'))) {
window.__uveCaptured.fetch.push({
url: args[0],
response: text.substring(0, 5000),
timestamp: Date.now()
});
// Extract URLs
const urls = text.match(/(https?:\\/\\/[^\\s"'<>]+\\.(m3u8|mpd|mp4)[^\\s"'<>]*)/gi);
if (urls) {
urls.forEach(u => window.__uveCaptured.fetch.push({ url: u, timestamp: Date.now() }));
}
}
} catch(e) {}
return response;
};
// Hook XMLHttpRequest
const originalXHROpen = XMLHttpRequest.prototype.open;
const originalXHRSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
this._url = url;
return originalXHROpen.apply(this, [method, url, ...rest]);
};
XMLHttpRequest.prototype.send = function(...args) {
this.addEventListener('load', function() {
try {
const text = this.responseText;
if (text && (text.includes('m3u8') || text.includes('.mpd'))) {
window.__uveCaptured.fetch.push({
url: this._url,
response: text.substring(0, 5000),
timestamp: Date.now()
});
const urls = text.match(/(https?:\\/\\/[^\\s"'<>]+\\.(m3u8|mpd|mp4)[^\\s"'<>]*)/gi);
if (urls) {
urls.forEach(u => window.__uveCaptured.fetch.push({ url: u, timestamp: Date.now() }));
}
}
} catch(e) {}
});
return originalXHRSend.apply(this, args);
};
` : ''}
// ═══════════════════════════════════════════════════════════
// LEVEL 4: Video Element Monitor
// ═══════════════════════════════════════════════════════════
// Monitor video.src changes
const videoObserver = new MutationObserver((mutations) => {
document.querySelectorAll('video').forEach(video => {
const src = video.src || video.currentSrc;
if (src && !src.startsWith('blob:')) {
window.__uveCaptured.videoSrc.push({
url: src,
timestamp: Date.now()
});
}
// Check source elements
video.querySelectorAll('source').forEach(source => {
if (source.src && !source.src.startsWith('blob:')) {
window.__uveCaptured.videoSrc.push({
url: source.src,
timestamp: Date.now()
});
}
});
});
});
videoObserver.observe(document.documentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['src']
});
// ═══════════════════════════════════════════════════════════
// LEVEL 5: HLS.js/Dash.js Hooks
// ═══════════════════════════════════════════════════════════
${options.hookHls ? `
// Hook Hls.js
Object.defineProperty(window, 'Hls', {
configurable: true,
set(HlsClass) {
this._Hls = HlsClass;
if (HlsClass && HlsClass.prototype) {
const originalLoadSource = HlsClass.prototype.loadSource;
HlsClass.prototype.loadSource = function(url) {
window.__uveCaptured.hlsUrls.push({
url,
timestamp: Date.now(),
source: 'hls.js'
});
return originalLoadSource.call(this, url);
};
}
},
get() { return this._Hls; }
});
// Hook dashjs
Object.defineProperty(window, 'dashjs', {
configurable: true,
set(dashjsLib) {
this._dashjs = dashjsLib;
// Hook MediaPlayer if available
},
get() { return this._dashjs; }
});
// Hook common video player libraries
const hookPlayers = () => {
// JWPlayer
if (window.jwplayer) {
const players = document.querySelectorAll('[id^="jwplayer"]');
players.forEach(p => {
try {
const player = window.jwplayer(p.id);
const playlist = player.getPlaylist();
if (playlist) {
playlist.forEach(item => {
if (item.file) {
window.__uveCaptured.hlsUrls.push({
url: item.file,
timestamp: Date.now(),
source: 'jwplayer'
});
}
});
}
} catch(e) {}
});
}
// Video.js
if (window.videojs) {
document.querySelectorAll('.video-js').forEach(v => {
try {
const player = window.videojs(v.id);
const src = player.currentSrc();
if (src) {
window.__uveCaptured.hlsUrls.push({
url: src,
timestamp: Date.now(),
source: 'videojs'
});
}
} catch(e) {}
});
}
};
// Run hooks periodically
setInterval(hookPlayers, 2000);
` : ''}
})();
`);
// ═══════════════════════════════════════════════════════════════
// Smart Click Interactions
// ═══════════════════════════════════════════════════════════════
if (options.clickPlay) {
const maxInteractions = 3;
for (let i = 0; i < maxInteractions; i++) {
let clicked = false;
// Universal play/server button selectors
const playSelectors = [
'li[data-nume="1"]',
'.dooplay_player_option[data-nume="1"]',
'.server-item', '.server-btn',
'button[class*="play"]', '.play-button', '.play-btn',
'[aria-label*="Play"]', '[title*="Play"]',
'.jw-icon-playback', '.vjs-big-play-button',
'.plyr__control--overlaid', '[data-plyr="play"]',
'a[href*="download"]', '.download-btn',
'.get-link', '#get-link'
];
for (const selector of playSelectors) {
try {
const elements = await page.$$(selector);
for (const el of elements) {
const isVisible = await page.evaluate((e: any) => {
const style = window.getComputedStyle(e);
return style.display !== 'none' && style.visibility !== 'hidden';
}, el);
if (isVisible) {
try {
await el.evaluate((e: any) => e.scrollIntoView({ block: 'center' }));
await sleep(300);
await el.click().catch(() => page.evaluate((e: any) => e.click(), el));
await sleep(2000);
clicked = true;
break;
} catch (e) { /* ignore */ }
}
}
if (clicked) break;
} catch (e) { /* ignore */ }
}
if (!clicked) break;
await sleep(1000);
}
}
// Wait for dynamic content
await sleep(options.waitTime);
// ═══════════════════════════════════════════════════════════════
// Collect All Captured Data
// ═══════════════════════════════════════════════════════════════
// Get captured data from page
const pageCaptures = await page.evaluate(() => {
return window.__uveCaptured || {
crypto: [],
fetch: [],
videoSrc: [],
hlsUrls: [],
dashUrls: []
};
});
// Remove network listeners
if (options.monitorNetwork) {
page.off('request', requestHandler);
page.off('response', responseHandler);
}
// ═══════════════════════════════════════════════════════════════
// Extract DOM Content
// ═══════════════════════════════════════════════════════════════
const domContent = await page.evaluate(({ types, includeEmbeds }) => {
const results: any = {
videos: [],
audio: [],
iframes: [],
downloadLinks: [],
platforms: []
};
// Videos
if (types.includes('video')) {
document.querySelectorAll('video').forEach((video: any, i) => {
results.videos.push({
index: i,
src: video.src || video.currentSrc,
poster: video.poster,
sources: Array.from(video.querySelectorAll('source')).map((s: any) => ({
src: s.src,
type: s.type
}))
});
});
}
// Audio
if (types.includes('audio')) {
document.querySelectorAll('audio').forEach((audio: any, i) => {
results.audio.push({
index: i,
src: audio.src || audio.currentSrc
});
});
}
// Iframes
if (types.includes('iframe')) {
document.querySelectorAll('iframe').forEach((iframe: any, i) => {
const src = iframe.src || iframe.getAttribute('data-src');
results.iframes.push({
index: i,
src,
platform: (src || '').includes('youtube') ? 'YouTube' :
(src || '').includes('vimeo') ? 'Vimeo' :
(src || '').includes('dailymotion') ? 'Dailymotion' : 'Unknown'
});
});
}
// Download links
document.querySelectorAll('a[href*="download"], a[href*=".mp4"], a[href*=".mkv"], .download-btn').forEach((el: any) => {
results.downloadLinks.push({
href: el.href,
text: el.textContent?.trim()
});
});
// Detect platforms from page content
const bodyText = document.body.innerHTML.toLowerCase();
const platformPatterns = ['streamtape', 'doodstream', 'filemoon', 'mixdrop', 'voe.sx', 'upns.online'];
platformPatterns.forEach(p => {
if (bodyText.includes(p)) results.platforms.push(p);
});
return results;
}, { types: options.types, includeEmbeds: options.includeEmbeds });
// ═══════════════════════════════════════════════════════════════
// Merge All Results
// ═══════════════════════════════════════════════════════════════
result.videos = domContent.videos;
result.audio = domContent.audio;
result.iframes = domContent.iframes;
result.downloadLinks = domContent.downloadLinks;
result.hostingPlatforms = domContent.platforms;
// Deduplicate and categorize captured URLs
const seenUrls = new Set<string>();
// Network captures
networkCaptures.forEach(c => {
if (!seenUrls.has(c.url)) {
seenUrls.add(c.url);
if (c.url.includes('.m3u8')) {
result.m3u8Streams.push(c);
} else if (c.url.includes('.mpd')) {
result.mpdStreams.push(c);
} else {
result.directUrls.push(c);
}
result.captureStats.networkCaptures++;
}
});
// Crypto captures
pageCaptures.crypto.forEach((c: any) => {
const url = c.url || c.decrypted;
if (url && !seenUrls.has(url)) {
seenUrls.add(url);
result.decryptedUrls.push({ url, type: 'crypto', timestamp: c.timestamp });
result.captureStats.cryptoCaptures++;
}
});
// Fetch captures
pageCaptures.fetch.forEach((c: any) => {
if (c.url && !seenUrls.has(c.url)) {
seenUrls.add(c.url);
if (c.url.includes('.m3u8')) {
result.m3u8Streams.push({ url: c.url, type: 'fetch', timestamp: c.timestamp });
} else {
result.directUrls.push({ url: c.url, type: 'fetch', timestamp: c.timestamp });
}
result.captureStats.fetchCaptures++;
}
});
// Video element captures
pageCaptures.videoSrc.forEach((c: any) => {
if (c.url && !seenUrls.has(c.url)) {
seenUrls.add(c.url);
if (c.url.includes('.m3u8')) {
result.m3u8Streams.push({ url: c.url, type: 'video_element', timestamp: c.timestamp });
} else {
result.directUrls.push({ url: c.url, type: 'video_element', timestamp: c.timestamp });
}
result.captureStats.videoElementCaptures++;
}
});
// HLS/Dash captures
[...pageCaptures.hlsUrls, ...pageCaptures.dashUrls].forEach((c: any) => {
if (c.url && !seenUrls.has(c.url)) {
seenUrls.add(c.url);
if (c.url.includes('.m3u8')) {
result.m3u8Streams.push({ url: c.url, type: 'hls_hook', timestamp: c.timestamp, metadata: { source: c.source } });
} else if (c.url.includes('.mpd')) {
result.mpdStreams.push({ url: c.url, type: 'hls_hook', timestamp: c.timestamp });
}
result.captureStats.hlsHookCaptures++;
}
});
// ═══════════════════════════════════════════════════════════════
// Generate Summary
// ═══════════════════════════════════════════════════════════════
const totalUrls = result.m3u8Streams.length + result.mpdStreams.length +
result.directUrls.length + result.decryptedUrls.length;
const summary = `
🎬 Universal Video Extractor Results
════════════════════════════════════════
📊 Summary:
• M3U8 Streams: ${result.m3u8Streams.length}
• MPD Streams: ${result.mpdStreams.length}
• Direct URLs: ${result.directUrls.length}
• Decrypted URLs: ${result.decryptedUrls.length}
• Videos in DOM: ${result.videos.length}
• Iframes: ${result.iframes.length}
• Download Links: ${result.downloadLinks.length}
• Platforms Detected: ${result.hostingPlatforms.length}
📡 Capture Stats (5-Level System):
• Level 1 (Network): ${result.captureStats.networkCaptures}
• Level 2 (Crypto): ${result.captureStats.cryptoCaptures}
• Level 3 (Fetch): ${result.captureStats.fetchCaptures}
• Level 4 (Video Element): ${result.captureStats.videoElementCaptures}
• Level 5 (HLS/Dash Hooks): ${result.captureStats.hlsHookCaptures}
${result.m3u8Streams.length > 0 ? `
📺 M3U8 Streams:
${result.m3u8Streams.slice(0, 10).map((s, i) => ` ${i + 1}. ${s.url}\n [${s.type}]`).join('\n')}
${result.m3u8Streams.length > 10 ? ` ... and ${result.m3u8Streams.length - 10} more` : ''}
` : ''}
${result.decryptedUrls.length > 0 ? `
🔓 Decrypted URLs:
${result.decryptedUrls.slice(0, 5).map((s, i) => ` ${i + 1}. ${s.url}`).join('\n')}
` : ''}
${result.directUrls.length > 0 ? `
🎥 Direct Video URLs:
${result.directUrls.slice(0, 5).map((s, i) => ` ${i + 1}. ${s.url}\n [${s.type}]`).join('\n')}
` : ''}
${result.hostingPlatforms.length > 0 ? `
🌐 Detected Platforms: ${result.hostingPlatforms.join(', ')}
` : ''}
📋 Full Data (JSON):
${JSON.stringify(result, null, 2)}
`;
return {
content: [{
type: 'text' as const,
text: summary
}]
};
}, 'Failed to extract video sources with universal extractor');
}