import asyncio
import itertools
import string
import os
from collections import Counter
from playwright.async_api import async_playwright

# --- KONFIGURACJA ---
BASE_URL = "https://magictube.net/?v="
WORKING_FILE = "dzialajace.txt"
FAILED_FILE = "nieaktywne.txt"
CHARS = string.ascii_lowercase
LENGTH = 5

# Ile przeglądarek naraz. Na VPS z 1-2GB RAM ustaw 2 lub 3.
CONCURRENT_BROWSERS = 20 

class Crawler:
    def __init__(self):
        self.checked = self.load_checked()
        self.counter = 0
        self.found_count = 0

    def load_checked(self):
        checked = set()
        for f_name in [WORKING_FILE, FAILED_FILE]:
            if os.path.exists(f_name):
                with open(f_name, 'r', encoding='utf-8') as f:
                    checked.update(line.strip() for line in f)
        print(f"[*] Wczytano {len(checked)} sprawdzonych kodów.")
        return checked

    def is_valid_pattern(self, code_tuple):
        """Filtr: Max 2 takie same litery w całym kodzie i brak potrójnych obok siebie."""
        code = "".join(code_tuple)
        counts = Counter(code)
        if any(char_count > 2 for char_count in counts.values()):
            return False
        
        # Dodatkowy check na 3 litery obok siebie (dla pewności)
        for i in range(len(code) - 2):
            if code[i] == code[i+1] == code[i+2]:
                return False
        return True

    def save_result(self, filename, code):
        with open(filename, "a", encoding='utf-8') as f:
            f.write(f"{code}\n")

    async def check_url(self, browser, code):
        url = f"{BASE_URL}{code}"
        context = await browser.new_context(
            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"
        )
        page = await context.new_page()
        
        # Flaga sukcesu dla tego konkretnego linku
        is_video_found = {"status": False}

        # Szpieg sieciowy
        def handle_request(request):
            # Jeśli w sieci pojawi się Vimeo lub pliki wideo - link jest dobry
            u = request.url.lower()
            if "vimeo" in u or "vimeocdn" in u or "videoplayback" in u:
                is_video_found["status"] = True

        page.on("request", handle_request)
        self.counter += 1

        try:
            # Wchodzimy na stronę
            await page.goto(url, timeout=20000, wait_until="networkidle")
            # Dajemy 2 sekundy na doładowanie skryptów wideo
            await asyncio.sleep(2)

            if is_video_found["status"]:
                self.found_count += 1
                print(f"\n[+] TRAFIONY ({self.found_count}): {url}")
                self.save_result(WORKING_FILE, code)
            else:
                self.save_result(FAILED_FILE, code)
                print(f"\rSprawdzono: {self.counter} | Ostatni: {code} | Znaleziono: {self.found_count}", end="", flush=True)

        except Exception:
            # W razie błędu (np. timeout) nie zapisujemy do żadnego pliku, by spróbować później
            pass
        finally:
            await context.close()

    async def run(self):
        # Generator z filtrami
        raw_gen = itertools.product(CHARS, repeat=LENGTH)
        valid_gen = ("".join(p) for p in raw_gen if self.is_valid_pattern(p))

        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True)
            
            tasks = []
            print(f"[*] Rozpoczynam masowe skanowanie metodą Network Sniffing...")

            for code in valid_gen:
                if code in self.checked:
                    continue
                
                tasks.append(self.check_url(browser, code))

                if len(tasks) >= CONCURRENT_BROWSERS:
                    await asyncio.gather(*tasks)
                    tasks = []
                    # Krótka pauza dla procesora między paczkami
                    await asyncio.sleep(0.5)
            
            if tasks:
                await asyncio.gather(*tasks)
            
            await browser.close()

if __name__ == "__main__":
    crawler = Crawler()
    try:
        asyncio.run(crawler.run())
    except KeyboardInterrupt:
        print("\n\n[!] Zatrzymano ręcznie. Postęp zapisany w plikach.")
