CoolFace
Apppublic

Inksday/eventstest

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app.py545 linesDownload Raw Back to root
1from flask import Flask, request, Response2import requests3from urllib.parse import urlparse, urljoin, quote, unquote4import re5import traceback6import os7 8app = Flask(__name__)9 10def detect_m3u_type(content):11    """Rileva se è un M3U (lista IPTV) o un M3U8 (flusso HLS)"""12    if "#EXTM3U" in content and "#EXTINF" in content:13        return "m3u8"14    return "m3u"15 16def replace_key_uri(line, headers_query):17    """Sostituisce l'URI della chiave AES-128 con il proxy"""18    match = re.search(r'URI="([^"]+)"', line)19    if match:20        key_url = match.group(1)21        proxied_key_url = f"/proxy/key?url={quote(key_url)}&{headers_query}"22        return line.replace(key_url, proxied_key_url)23    return line24 25def resolve_m3u8_link(url, headers=None):26    """27    Tenta di risolvere un URL M3U8.28    Prova prima la logica specifica per iframe (tipo Daddylive), inclusa la lookup della server_key.29    Se fallisce, verifica se l'URL iniziale era un M3U8 diretto e lo restituisce.30    """31    if not url:32        print("Errore: URL non fornito.")33        return {"resolved_url": None, "headers": {}}34 35    print(f"Tentativo di risoluzione URL: {url}")36    # Utilizza gli header forniti, altrimenti usa un User-Agent di default37    current_headers = headers if headers else {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0+Safari/537.36'}38 39    initial_response_text = None40    final_url_after_redirects = None41 42    # Verifica se è un URL di vavoo.to43    is_vavoo = "vavoo.to" in url.lower()44 45    try:46        with requests.Session() as session:47            print(f"Passo 1: Richiesta a {url}")48            response = session.get(url, headers=current_headers, allow_redirects=True, timeout=(5, 15))49            response.raise_for_status()50            initial_response_text = response.text51            final_url_after_redirects = response.url52            print(f"Passo 1 completato. URL finale dopo redirect: {final_url_after_redirects}")53 54            # Se è un URL di vavoo.to, salta la logica dell'iframe55            if is_vavoo:56                if initial_response_text and initial_response_text.strip().startswith('#EXTM3U'):57                    return {58                        "resolved_url": final_url_after_redirects,59                        "headers": current_headers60                    }61                else:62                    # Se non è un M3U8 diretto, restituisci l'URL originale per vavoo63                    print(f"URL vavoo.to non è un M3U8 diretto: {url}")64                    return {65                        "resolved_url": url,66                        "headers": current_headers67                    }68 69            # Prova la logica dell'iframe per gli altri URL70            print("Tentativo con logica iframe...")71            try:72                # Secondo passo (Iframe): Trova l'iframe src nella risposta iniziale73                iframes = re.findall(r'iframe src="([^"]+)"', initial_response_text)74                if not iframes:75                    raise ValueError("Nessun iframe src trovato.")76 77                url2 = iframes[0]78                print(f"Passo 2 (Iframe): Trovato iframe URL: {url2}")79 80                # Terzo passo (Iframe): Richiesta all'URL dell'iframe81                referer_raw = urlparse(url2).scheme + "://" + urlparse(url2).netloc + "/"82                origin_raw = urlparse(url2).scheme + "://" + urlparse(url2).netloc83                current_headers['Referer'] = referer_raw84                current_headers['Origin'] = origin_raw85                print(f"Passo 3 (Iframe): Richiesta a {url2}")86                response = session.get(url2, headers=current_headers, timeout=(5, 15))87                response.raise_for_status()88                iframe_response_text = response.text89                print("Passo 3 (Iframe) completato.")90 91                # Quarto passo (Iframe): Estrai parametri dinamici dall'iframe response92                channel_key_match = re.search(r'(?s) channelKey = \"([^\"]*)"', iframe_response_text)93                auth_ts_match = re.search(r'(?s) authTs\s*= \"([^\"]*)"', iframe_response_text)94                auth_rnd_match = re.search(r'(?s) authRnd\s*= \"([^\"]*)"', iframe_response_text)95                auth_sig_match = re.search(r'(?s) authSig\s*= \"([^\"]*)"', iframe_response_text)96                auth_host_match = re.search(r'\}\s*fetchWithRetry\(\s*\'([^\']*)\'', iframe_response_text)97                server_lookup_match = re.search(r'n fetchWithRetry\(\s*\'([^\']*)\'', iframe_response_text)98 99                if not all([channel_key_match, auth_ts_match, auth_rnd_match, auth_sig_match, auth_host_match, server_lookup_match]):100                    raise ValueError("Impossibile estrarre tutti i parametri dinamici dall'iframe response.")101                102                channel_key = channel_key_match.group(1)103                auth_ts = auth_ts_match.group(1)104                auth_rnd = auth_rnd_match.group(1)105                auth_sig = quote(auth_sig_match.group(1))106                auth_host = auth_host_match.group(1)107                server_lookup = server_lookup_match.group(1)108 109                print("Passo 4 (Iframe): Parametri dinamici estratti.")110 111                # Quinto passo (Iframe): Richiesta di autenticazione112                auth_url = f'{auth_host}{channel_key}&ts={auth_ts}&rnd={auth_rnd}&sig={auth_sig}'113                print(f"Passo 5 (Iframe): Richiesta di autenticazione a {auth_url}")114                auth_response = session.get(auth_url, headers=current_headers, timeout=(5, 15))115                auth_response.raise_for_status()116                print("Passo 5 (Iframe) completato.")117 118                # Sesto passo (Iframe): Richiesta di server lookup per ottenere la server_key119                server_lookup_url = f"https://{urlparse(url2).netloc}{server_lookup}{channel_key}"120                print(f"Passo 6 (Iframe): Richiesta server lookup a {server_lookup_url}")121                server_lookup_response = session.get(server_lookup_url, headers=current_headers, timeout=(5, 15))122                server_lookup_response.raise_for_status()123                server_lookup_data = server_lookup_response.json()124                print("Passo 6 (Iframe) completato.")125 126                # Settimo passo (Iframe): Estrai server_key dalla risposta di server lookup127                server_key = server_lookup_data.get('server_key')128                if not server_key:129                    raise ValueError("'server_key' non trovato nella risposta di server lookup.")130                print(f"Passo 7 (Iframe): Estratto server_key: {server_key}")131 132                # Ottavo passo (Iframe): Costruisci il link finale133                host_match = re.search('(?s)m3u8 =.*?:.*?:.*?".*?".*?"([^"]*)"', iframe_response_text)134                if not host_match:135                    raise ValueError("Impossibile trovare l'host finale per l'm3u8.")136                host = host_match.group(1)137                print(f"Passo 8 (Iframe): Trovato host finale per m3u8: {host}")138 139                # Costruisci l'URL finale del flusso140                final_stream_url = (141                    f'https://{server_key}{host}{server_key}/{channel_key}/mono.m3u8'142                )143 144                # Prepara gli header per lo streaming145                stream_headers = {146                    'User-Agent': current_headers.get('User-Agent', ''),147                    'Referer': referer_raw,148                    'Origin': origin_raw149                }150                151                return {152                    "resolved_url": final_stream_url,153                    "headers": stream_headers154                }155 156            except (ValueError, requests.exceptions.RequestException) as e:157                print(f"Logica iframe fallita: {e}")158                print("Tentativo fallback: verifica se l'URL iniziale era un M3U8 diretto...")159 160                # Fallback: Verifica se la risposta iniziale era un file M3U8 diretto161                if initial_response_text and initial_response_text.strip().startswith('#EXTM3U'):162                    print("Fallback riuscito: Trovato file M3U8 diretto.")163                    return {164                        "resolved_url": final_url_after_redirects,165                        "headers": current_headers166                    }167                else:168                    print("Fallback fallito: La risposta iniziale non era un M3U8 diretto.")169                    return {170                        "resolved_url": url,171                        "headers": current_headers172                    }173 174    except requests.exceptions.RequestException as e:175        print(f"Errore durante la richiesta HTTP iniziale: {e}")176        return {"resolved_url": url, "headers": current_headers}177    except Exception as e:178        print(f"Errore generico durante la risoluzione: {e}")179        return {"resolved_url": url, "headers": current_headers}180 181@app.route('/proxy')182def proxy():183    """Proxy per liste M3U che aggiunge automaticamente /proxy/m3u?url= con IP prima dei link"""184    m3u_url = request.args.get('url', '').strip()185    if not m3u_url:186        return "Errore: Parametro 'url' mancante", 400187 188    try:189        # Ottieni l'IP del server190        server_ip = request.host191        192        # Scarica la lista M3U originale193        response = requests.get(m3u_url, timeout=(10, 30)) # Timeout connessione 10s, lettura 30s194        response.raise_for_status()195        m3u_content = response.text196        197        # Modifica solo le righe che contengono URL (non iniziano con #)198        modified_lines = []199        for line in m3u_content.splitlines():200            line = line.strip()201            if line and not line.startswith('#'):202                # Per tutti i link, usa il proxy normale203                modified_line = f"http://{server_ip}/proxy/m3u?url={line}"204                modified_lines.append(modified_line)205            else:206                # Mantieni invariate le righe di metadati207                modified_lines.append(line)208        209        modified_content = '\n'.join(modified_lines)210 211        # Estrai il nome del file dall'URL originale212        parsed_m3u_url = urlparse(m3u_url)213        original_filename = os.path.basename(parsed_m3u_url.path)214        215        return Response(modified_content, content_type="application/vnd.apple.mpegurl", headers={'Content-Disposition': f'attachment; filename="{original_filename}"'})216        217    except requests.RequestException as e:218        return f"Errore durante il download della lista M3U: {str(e)}", 500219    except Exception as e:220        return f"Errore generico: {str(e)}", 500221 222@app.route('/proxy/m3u')223def proxy_m3u():224    """Proxy per file M3U e M3U8 con supporto per redirezioni e header personalizzati"""225    m3u_url = request.args.get('url', '').strip()226    if not m3u_url:227        return "Errore: Parametro 'url' mancante", 400228 229    default_headers = {230        "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/33.0 Mobile/15E148 Safari/605.1.15",231        "Referer": "https://vavoo.to/",232        "Origin": "https://vavoo.to"233    }234 235    # Estrai gli header dalla richiesta, sovrascrivendo i default236    request_headers = {237        unquote(key[2:]).replace("_", "-"): unquote(value).strip()238        for key, value in request.args.items()239        if key.lower().startswith("h_")240    }241    headers = {**default_headers, **request_headers}242 243    # --- Logica per trasformare l'URL se necessario ---244    processed_url = m3u_url245    246    # Trasforma /stream/ in /embed/ per Daddylive247    if '/stream/stream-' in m3u_url and 'daddylive.dad' in m3u_url:248        processed_url = m3u_url.replace('/stream/stream-', '/embed/stream-')249        print(f"URL {m3u_url} trasformato da /stream/ a /embed/: {processed_url}")250    match_premium_m3u8 = re.search(r'/premium(\d+)/mono\.m3u8$', m3u_url)251 252    if match_premium_m3u8:253        channel_number = match_premium_m3u8.group(1)254        transformed_url = f"https://daddylive.dad/embed/stream-{channel_number}.php"255        print(f"URL {m3u_url} corrisponde al pattern premium. Trasformato in: {transformed_url}")256        processed_url = transformed_url257    else:258        print(f"URL {processed_url} processato per la risoluzione.")259 260    try:261        print(f"Chiamata a resolve_m3u8_link per URL processato: {processed_url}")262        result = resolve_m3u8_link(processed_url, headers)263 264        if not result["resolved_url"]:265            return "Errore: Impossibile risolvere l'URL in un M3U8 valido.", 500266 267        resolved_url = result["resolved_url"]268        current_headers_for_proxy = result["headers"]269 270        print(f"Risoluzione completata. URL M3U8 finale: {resolved_url}")271 272        # Fetchare il contenuto M3U8 effettivo dall'URL risolto273        print(f"Fetching M3U8 content from resolved URL: {resolved_url}")274        m3u_response = requests.get(resolved_url, headers=current_headers_for_proxy, allow_redirects=True, timeout=(10, 20)) # Timeout connessione 10s, lettura 20s275        m3u_response.raise_for_status()276        m3u_content = m3u_response.text277        final_url = m3u_response.url278 279        # Processa il contenuto M3U8280        file_type = detect_m3u_type(m3u_content)281 282        if file_type == "m3u":283            return Response(m3u_content, content_type="application/vnd.apple.mpegurl")284 285        # Processa contenuto M3U8286        parsed_url = urlparse(final_url)287        base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path.rsplit('/', 1)[0]}/"288 289        # Prepara la query degli header per segmenti/chiavi proxati290        headers_query = "&".join([f"h_{quote(k)}={quote(v)}" for k, v in current_headers_for_proxy.items()])291 292        modified_m3u8 = []293        for line in m3u_content.splitlines():294            line = line.strip()295            if line.startswith("#EXT-X-KEY") and 'URI="' in line:296                line = replace_key_uri(line, headers_query)297            elif line and not line.startswith("#"):298                segment_url = urljoin(base_url, line)299                line = f"/proxy/ts?url={quote(segment_url)}&{headers_query}"300            modified_m3u8.append(line)301 302        modified_m3u8_content = "\n".join(modified_m3u8)303        return Response(modified_m3u8_content, content_type="application/vnd.apple.mpegurl")304 305    except requests.RequestException as e:306        print(f"Errore durante il download o la risoluzione del file: {str(e)}")307        return f"Errore durante il download o la risoluzione del file M3U/M3U8: {str(e)}", 500308    except Exception as e:309        print(f"Errore generico nella funzione proxy_m3u: {str(e)}")310        return f"Errore generico durante l'elaborazione: {str(e)}", 500311 312@app.route('/proxy/resolve')313def proxy_resolve():314    """Proxy per risolvere e restituire un URL M3U8"""315    url = request.args.get('url', '').strip()316    if not url:317        return "Errore: Parametro 'url' mancante", 400318 319    headers = {320        unquote(key[2:]).replace("_", "-"): unquote(value).strip()321        for key, value in request.args.items()322        if key.lower().startswith("h_")323    }324 325    try:326        result = resolve_m3u8_link(url, headers)327        328        if not result["resolved_url"]:329            return "Errore: Impossibile risolvere l'URL", 500330            331        headers_query = "&".join([f"h_{quote(k)}={quote(v)}" for k, v in result["headers"].items()])332        333        return Response(334            f"#EXTM3U\n"335            f"#EXTINF:-1,Canale Risolto\n"336            f"/proxy/m3u?url={quote(result['resolved_url'])}&{headers_query}",337            content_type="application/vnd.apple.mpegurl"338        )339        340    except Exception as e:341        return f"Errore durante la risoluzione dell'URL: {str(e)}", 500342 343@app.route('/proxy/ts')344def proxy_ts():345    """Proxy per segmenti .TS con headers personalizzati - SENZA CACHE"""346    ts_url = request.args.get('url', '').strip()347    if not ts_url:348        return "Errore: Parametro 'url' mancante", 400349 350    headers = {351        unquote(key[2:]).replace("_", "-"): unquote(value).strip()352        for key, value in request.args.items()353        if key.lower().startswith("h_")354    }355 356    try:357        # Stream diretto senza cache per evitare freezing358        response = requests.get(ts_url, headers=headers, stream=True, allow_redirects=True, timeout=(10, 30)) # Timeout di connessione 10s, lettura 30s359        response.raise_for_status()360        361        def generate():362            for chunk in response.iter_content(chunk_size=8192):363                if chunk:364                    yield chunk365        366        return Response(generate(), content_type="video/mp2t")367    368    except requests.RequestException as e:369        return f"Errore durante il download del segmento TS: {str(e)}", 500370 371@app.route('/proxy/key')372def proxy_key():373    """Proxy per la chiave AES-128 con header personalizzati"""374    key_url = request.args.get('url', '').strip()375    if not key_url:376        return "Errore: Parametro 'url' mancante per la chiave", 400377 378    headers = {379        unquote(key[2:]).replace("_", "-"): unquote(value).strip()380        for key, value in request.args.items()381        if key.lower().startswith("h_")382    }383 384    try:385        response = requests.get(key_url, headers=headers, allow_redirects=True, timeout=(5, 15)) # Timeout connessione 5s, lettura 15s386        response.raise_for_status()387        388        return Response(response.content, content_type="application/octet-stream")389    390    except requests.RequestException as e:391        return f"Errore durante il download della chiave AES-128: {str(e)}", 500392 393@app.route('/playlist/channels.m3u8')394def playlist_channels():395    """Gibt eine modifizierte Playlist mit Proxy-Links zurück"""396    playlist_url = "https://raw.githubusercontent.com/eAzTeA123/channel-events/refs/heads/main/channels.m3u8"397    398    try:399        host_url = request.host_url.rstrip('/')400        response = requests.get(playlist_url, timeout=10)401        response.raise_for_status()402        playlist_content = response.text403        404        modified_lines = []405        for line in playlist_content.splitlines():406            stripped_line = line.strip()407            if stripped_line and not stripped_line.startswith('#'):408                proxy_line = f"{host_url}/proxy/m3u?url={quote(stripped_line)}"409                modified_lines.append(proxy_line)410            else:411                modified_lines.append(line)412        413        modified_content = '\n'.join(modified_lines)414        return Response(modified_content, content_type="application/vnd.apple.mpegurl")415 416    except requests.RequestException as e:417        return f"Fehler beim Laden der Playlist: {str(e)}", 500418    except Exception as e:419        return f"Allgemeiner Fehler: {str(e)}", 500420 421 422@app.route('/playlist/events.m3u8')423def playlist_events():424    """Generiert die Events-Playlist mit Proxy-Links bei jedem Aufruf"""425    try:426        # Hole die aktuelle Host-URL427        host_url = request.host_url.rstrip('/')428        429        # Lade die Sendeplandaten430        schedule_data = fetch_schedule_data()431        if not schedule_data:432            return "Fehler beim Abrufen der Sendeplandaten", 500433        434        # Konvertiere JSON in M3U mit Proxy-Links435        m3u_content = json_to_m3u(schedule_data, host_url)436        if not m3u_content:437            return "Fehler beim Generieren der Playlist", 500438            439        return Response(m3u_content, content_type="application/vnd.apple.mpegurl")440    441    except Exception as e:442        print(f"Fehler in /playlist/events: {str(e)}")443        return f"Interner Serverfehler: {str(e)}", 500444 445def fetch_schedule_data():446    """Holt die aktuellen Sendeplandaten von der Website"""447    url = "https://daddylive.dad/schedule/schedule-generated.php"448    headers = {449        "authority": "daddylive.dad",450        "accept": "*/*",451        "accept-encoding": "gzip, deflate, br, zstd",452        "accept-language": "de-DE,de;q=0.9",453        "priority": "u=1, i",454        "referer": "https://daddylive.dad/",455        "sec-ch-ua": '"Brave";v="137", "Chromium";v="137", "Not/A)Brand";v="24"',456        "sec-ch-ua-mobile": "?0",457        "sec-ch-ua-platform": '"Windows"',458        "sec-fetch-dest": "empty",459        "sec-fetch-mode": "cors",460        "sec-fetch-site": "same-origin",461        "sec-gpc": "1",462        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"463    }464    465    try:466        response = requests.get(url, headers=headers, timeout=30)467        if response.status_code == 200:468            return response.json()469        else:470            print(f"Fehler beim Abrufen der Daten: Status-Code {response.status_code}")471            return None472    except Exception as e:473        print(f"Fehler beim Abrufen der Daten: {e}")474        return None475 476def json_to_m3u(data, host_url):477    """Konvertiert JSON-Daten in M3U-Format mit Proxy-Links im gewünschten Format"""478    if not data:479        return None480        481    m3u_content = '#EXTM3U\n\n'482    483    try:484        main_key = list(data.keys())[0]485        categories = data[main_key]486    except Exception as e:487        print(f"Fehler beim Verarbeiten der JSON-Daten: {e}")488        return None489 490    for category_name, events in categories.items():491        if not isinstance(events, list):492            continue493            494        for event in events:495            if not isinstance(event, dict):496                continue497                498            group_title = event.get("event", "Unknown Event")499            channels_list = []500            501            for channel_key in ["channels", "channels2"]:502                channels = event.get(channel_key, [])503                if isinstance(channels, dict):504                    channels_list.extend(channels.values())505                elif isinstance(channels, list):506                    channels_list.extend(channels)507            508            for channel in channels_list:509                if not isinstance(channel, dict):510                    continue511                    512                channel_name = channel.get("channel_name", "Unknown Channel")513                channel_id = channel.get("channel_id", "0")514                515                # Generiere die Stream-URL basierend auf der ID516                try:517                    channel_id_int = int(channel_id)518                    if channel_id_int > 999:519                        stream_url = f"https://daddylive.dad/stream/bet.php?id=bet{channel_id}"520                    else:521                        stream_url = f"https://daddylive.dad/stream/stream-{channel_id}.php"522                except (ValueError, TypeError):523                    stream_url = f"https://daddylive.dad/stream/stream-{channel_id}.php"524                525                # Generiere den Proxy-Link im gewünschten Format526                proxy_url = f"{host_url}/proxy/m3u?url={stream_url}"527                528                m3u_content += (529                    f'#EXTINF:-1 tvg-id="{channel_name}" group-title="{group_title}",{channel_name}\n'530                    '#EXTVLCOPT:http-referrer=https://lefttoplay.xyz/\n'531                    '#EXTVLCOPT:http-origin=https://lefttoplay.xyz\n'532                    '#EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1\n'533                    f'{proxy_url}\n\n'534                )535    536    return m3u_content537 538@app.route('/')539def index():540    """Pagina principale che mostra un messaggio di benvenuto"""541    return "Proxy started!"542 543if __name__ == '__main__':544    print("Proxy started!")545    app.run(host="0.0.0.0", port=7860, debug=False)