| import asyncio |
| import urllib.parse |
| import json |
| from playwright.async_api import async_playwright |
| from bs4 import BeautifulSoup |
| import re |
| from xray_manager import setup_and_start_xray |
|
|
| DOMENA = "https://mrkaj.me" |
|
|
| class XrayBrowserManager: |
| _instance = None |
| def __init__(self): |
| self.playwright = None |
| self.context = None |
| self._setup_done = False |
| self._lock = asyncio.Lock() |
|
|
| @classmethod |
| def get_instance(cls): |
| if cls._instance is None: cls._instance = cls() |
| return cls._instance |
|
|
| async def start(self): |
| async with self._lock: |
| if self._setup_done: return |
| setup_and_start_xray() |
| |
| self.playwright = await async_playwright().start() |
| self.context = await self.playwright.chromium.launch_persistent_context( |
| "/tmp/xray_profile", |
| headless=True, |
| proxy={"server": "socks5://127.0.0.1:10808"}, |
| user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" |
| ) |
| |
| |
| test_page = await self.context.new_page() |
| try: |
| print("[DEBUG] Overujem IP cez tunel...") |
| await test_page.goto("https://api.ipify.org", timeout=15000) |
| ip = await test_page.inner_text("body") |
| print(f"[DEBUG] Tvoja IP v tuneli je: {ip}") |
| except Exception as e: |
| print(f"[DEBUG ERROR] Tunel nefunguje: {e}") |
| finally: |
| await test_page.close() |
| |
|
|
| self._setup_done = True |
|
|
|
|
|
|
| async def get_page(self): |
| if not self._setup_done: await self.start() |
| return await self.context.new_page() |
|
|
| manager = XrayBrowserManager.get_instance() |
|
|
| async def search_movies(query): |
| page = await manager.get_page() |
| try: |
| url = f"{DOMENA}/se/j/json?q={urllib.parse.quote(query)}" |
| print(f"[TUNNEL] Vyhľadávam: {query}") |
| |
| |
| await page.goto(url, wait_until="networkidle", timeout=30000) |
| |
| |
| raw_content = await page.content() |
| print(f"[DEBUG] Surová dĺžka obsahu: {len(raw_content)}") |
| |
| if len(raw_content) < 200: |
| print(f"[DEBUG] POZOR! Web vrátil podozrivo málo dát: {raw_content}") |
|
|
| content = await page.evaluate("() => document.body.innerText") |
| return json.loads(content) |
| except Exception as e: |
| print(f"[SEARCH ERROR] {e}") |
| return [] |
| finally: await page.close() |
|
|
|
|
| async def get_details(slug, media_type): |
| page = await manager.get_page() |
| url = f"{DOMENA}/p/{slug}" if media_type in ["movie", "film"] else f"{DOMENA}/tv/{slug}/S01E01" |
| res = {"languages": [], "seasons": []} |
| try: |
| await page.goto(url, timeout=30000) |
| soup = BeautifulSoup(await page.content(), "html.parser") |
| kw = soup.find("div", class_="movie-keyword") |
| if kw: res["languages"] = [p.get_text(strip=True) for p in kw.find_all(recursive=False)] |
| matches = re.findall(r'Séria\s+(\d+)', soup.get_text()) |
| for s in sorted(set(matches), key=int): res["seasons"].append({"season": int(s), "episodes": 0}) |
| except: pass |
| finally: await page.close() |
| return res |
|
|
| async def get_stream_url(slug, media_type, season=None, episode=None, lang=None, source_idx=0): |
| print(f"[STREAM] Skenujem stream: {slug} (Zdroj: {source_idx})") |
| page = await manager.get_page() |
| |
| |
| url = f"{DOMENA}/p/{slug}" if media_type in ["movie", "film"] else f"{DOMENA}/tv/{slug}/S{int(season):02d}E{int(episode):02d}" |
| url += f"?source={source_idx}" |
| if lang: url += f"&lng={urllib.parse.quote(lang)}" |
| |
| found = {"stream": None, "vtt": None} |
|
|
| |
| async def handle_request(request): |
| u = request.url |
| if (".m3u8" in u or ".mp4" in u) and not found["stream"]: |
| if "master.m3u8" not in u: |
| |
| if "ads" not in u and "google" not in u: |
| print(f"[ZACHYTENÉ VIDEO] {u[:80]}...") |
| found["stream"] = u |
| if u.endswith(".vtt") and not found["vtt"]: |
| found["vtt"] = u |
|
|
| page.on("request", handle_request) |
| |
| try: |
| |
| await page.goto(url, wait_until="domcontentloaded", timeout=60000) |
| |
| |
| for _ in range(15): |
| if found["stream"]: break |
| await asyncio.sleep(1) |
| |
| |
| if not found["stream"]: |
| print("[STREAM] Video sa nenačítalo samo, skúšam KLIK na stred...") |
| |
| locators = ["iframe#frm", "iframe[src*='api']", "video", ".play-button"] |
| for loc in locators: |
| target = page.locator(loc).first |
| if await target.count() > 0: |
| try: |
| |
| await target.click(force=True, timeout=5000) |
| await asyncio.sleep(2) |
| if found["stream"]: break |
| except: continue |
|
|
| |
| for _ in range(15): |
| if found["stream"]: break |
| await asyncio.sleep(1) |
|
|
| except Exception as e: |
| print(f"[STREAM ERROR] {e}") |
| finally: |
| await page.close() |
| |
| return found |
|
|
|
|
| def zachyt(req, found): |
| if ".m3u8" in req.url and not found["stream"]: |
| print("[Zachytený stream neoverený]",req.url) |
| print("[stav zoznamu]",found) |
| if "master.m3u8" not in req.url: |
| found["stream"] = req.url |
| if req.url.endswith(".vtt") and not found["vtt"]: found["vtt"] = req.url |
|
|