from .base import BaseVideoPlayer from bs4 import BeautifulSoup import re import asyncio class LpayerDownloader(BaseVideoPlayer): """Downloader for lpayer.embed4me.com video player""" def can_handle(self, url: str) -> bool: return 'lpayer.embed4me.com' in url.lower() async def get_download_link(self, url: str) -> tuple[str, str]: """ Extract download link from Lpayer video page Lpayer uses a React app with dynamic JavaScript - requires Playwright """ try: print(f"[LPAYER] Extracting link from: {url}") # Try using Playwright to extract video URL video_url = await self._extract_with_playwright(url) if not video_url: raise Exception("Could not find video URL in Lpayer page") print(f"[LPAYER] Found video URL: {video_url[:80]}...") # Generate filename filename = "lpayer_video.mp4" return video_url, filename except Exception as e: raise Exception(f"Error extracting Lpayer link: {str(e)}") async def _extract_with_playwright(self, url: str) -> str | None: """Extract video URL using Playwright with network interception""" try: from playwright.async_api import async_playwright print("[LPAYER] Launching browser with network interception...") video_urls = [] async with async_playwright() as p: browser = await p.chromium.launch( headless=True, args=['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'] ) context = await browser.new_context( user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' ) page = await context.new_page() # Set up request interception async def handle_request(route): req_url = route.request.url # Look for video files if any(ext in req_url.lower() for ext in ['.m3u8', '.mp4', '.mkv']): if 'lpayer' not in req_url.lower(): print(f"[LPAYER] 🎥 Captured video URL: {req_url[:100]}...") video_urls.append(req_url) await route.continue_() await page.route('**', handle_request) print("[LPAYER] Navigating to page...") try: await page.goto(url, wait_until='domcontentloaded', timeout=30000) except Exception as e: print(f"[LPAYER] Navigation warning: {e}") # Wait for page to load print("[LPAYER] Waiting for video player to load...") await asyncio.sleep(5) # Try to find and click play button try: play_selectors = [ 'button[aria-label="Play"]', '.play-button', 'video', ] for selector in play_selectors: try: element = await page.query_selector(selector) if element: print(f"[LPAYER] Found element: {selector}") if 'button' in selector: await element.click() await asyncio.sleep(3) break except: continue except Exception as e: print(f"[LPAYER] Play button interaction: {e}") # Wait more for network requests await asyncio.sleep(3) # Try JavaScript extraction try: js_result = await page.evaluate(""" () => { // Check all video elements const videos = document.querySelectorAll('video'); for (let v of videos) { if (v.src) { return v.src; } const sources = v.querySelectorAll('source'); for (let s of sources) { if (s.src && (s.src.includes('.m3u8') || s.src.includes('.mp4'))) { return s.src; } } } // Check window object for video URLs for (let key in window) { if (typeof window[key] === 'string') { const str = window[key]; if ((str.includes('.m3u8') || str.includes('.mp4')) && str.startsWith('http')) { return str; } } } return null; } """) if js_result and ('.m3u8' in js_result or '.mp4' in js_result): print(f"[LPAYER] Found video URL via JavaScript") video_urls.append(js_result) except Exception as e: print(f"[LPAYER] JS extraction error: {e}") # Parse page HTML for video URLs try: content = await page.content() patterns = [ r'"file"\s*:\s*"([^"]+\.m3u8[^"]*)"', r'"file"\s*:\s*"([^"]+\.mp4[^"]*)"', r'(https?://[^\s"\'<>]+\.m3u8[^\s"\'<>]*)', r'(https?://[^\s"\'<>]+\.mp4[^\s"\'<>]*)', ] for pattern in patterns: matches = re.findall(pattern, content) for match in matches: match = match.replace('\\', '').replace('\/', '/') if 'http' in match and 'lpayer' not in match: print(f"[LPAYER] Found in HTML: {match[:100]}...") video_urls.append(match) except Exception as e: print(f"[LPAYER] HTML parsing error: {e}") await browser.close() # Return first valid video URL if video_urls: seen = set() unique_urls = [] for url in video_urls: if url not in seen: seen.add(url) unique_urls.append(url) if unique_urls: print(f"[LPAYER] ✅ Found {len(unique_urls)} video URL(s)") return unique_urls[0] print("[LPAYER] ❌ No video URLs found") return None except ImportError: print("[LPAYER] Playwright not installed") return None except Exception as e: print(f"[LPAYER] Playwright error: {e}") import traceback traceback.print_exc() return None