#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ DIGI Online Authentication & Playlist Generator Extrage token-uri de autentificare și generează playlist M3U funcțional """ import requests import json import sys from datetime import datetime class DigiOnlineAuth: def __init__(self): self.base_url = "https://www.digionline.ro" self.api_url = "https://www.digionline.ro/api" self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'ro-RO,ro;q=0.9,en-US;q=0.8,en;q=0.7', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"' }) self.token = None self.device_id = None self.channels = [] def get_homepage(self): """Accesează homepage-ul pentru a obține cookies""" print(f"🌐 Accesare homepage DIGI Online...") try: response = self.session.get(self.base_url, timeout=10) if response.status_code == 200: print("✅ Homepage accesat cu succes!") return True else: print(f"⚠️ Status homepage: {response.status_code}") return False except Exception as e: print(f"❌ Eroare la accesare homepage: {e}") return False def login(self, email, password): """Autentificare pe DIGI Online""" print(f"\n🔐 Autentificare pe DIGI Online...") print(f"📧 Email: {email}") # Mai întâi accesează homepage-ul pentru cookies self.get_homepage() # Actualizează headers pentru login self.session.headers.update({ 'Origin': 'https://www.digionline.ro', 'Referer': 'https://www.digionline.ro/', 'Content-Type': 'application/json' }) login_url = f"{self.base_url}/api/user/login" payload = { "email": email, "password": password } try: print(f"📡 Trimitere cerere de autentificare...") response = self.session.post(login_url, json=payload, timeout=15) print(f"📊 Status răspuns: {response.status_code}") if response.status_code == 200: try: data = response.json() if 'data' in data and 'token' in data['data']: self.token = data['data']['token'] print("✅ Autentificare reușită!") print(f"🔑 Token obținut: {self.token[:20]}...") # Actualizează header-ul cu token-ul self.session.headers.update({ 'Authorization': f'Bearer {self.token}' }) return True else: print("❌ Răspuns invalid de la server") print(f"Răspuns: {data}") return False except json.JSONDecodeError: print("❌ Răspuns nu este JSON valid") print(f"Răspuns: {response.text[:200]}") return False elif response.status_code == 403: print(f"❌ Acces interzis (403)!") print(f"⚠️ API-ul DIGI blochează cererea automată.") print(f"\n💡 SOLUȚIE ALTERNATIVĂ:") print(f" 1. Deschide browser și mergi pe digionline.ro") print(f" 2. Autentifică-te manual") print(f" 3. Deschide Developer Tools (F12)") print(f" 4. Mergi la Network tab") print(f" 5. Caută cererea 'login' și copiază token-ul") return False else: print(f"❌ Autentificare eșuată! Status: {response.status_code}") print(f"Răspuns: {response.text[:500]}") return False except Exception as e: print(f"❌ Eroare la autentificare: {e}") import traceback traceback.print_exc() return False def get_channels(self): """Obține lista de canale disponibile""" print("\n📺 Obținere listă canale...") channels_url = f"{self.api_url}/channel/list" try: response = self.session.get(channels_url, timeout=10) if response.status_code == 200: data = response.json() if 'data' in data: self.channels = data['data'] print(f"✅ {len(self.channels)} canale găsite!") return True else: print("❌ Răspuns invalid de la server") return False else: print(f"❌ Eroare la obținere canale! Status: {response.status_code}") return False except Exception as e: print(f"❌ Eroare la obținere canale: {e}") return False def get_stream_url(self, channel_id): """Obține URL-ul de stream pentru un canal""" stream_url = f"{self.api_url}/stream/start/{channel_id}" try: response = self.session.get(stream_url, timeout=10) if response.status_code == 200: data = response.json() if 'data' in data and 'stream_url' in data['data']: return data['data']['stream_url'] elif 'data' in data and 'url' in data['data']: return data['data']['url'] return None except Exception as e: print(f"⚠️ Eroare la obținere stream pentru canal {channel_id}: {e}") return None def generate_playlist(self, output_file="digi_authenticated.m3u"): """Generează playlist M3U cu URL-uri autentificate""" print(f"\n📝 Generare playlist: {output_file}") if not self.channels: print("❌ Nu există canale disponibile!") return False try: with open(output_file, 'w', encoding='utf-8') as f: # Header M3U f.write("#EXTM3U\n\n") f.write("# ========================================\n") f.write("# PLAYLIST DIGI ONLINE - AUTENTIFICAT\n") f.write(f"# Generat: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"# Canale: {len(self.channels)}\n") f.write("# ========================================\n\n") # Procesează fiecare canal processed = 0 for channel in self.channels: channel_id = channel.get('id') channel_name = channel.get('name', 'Unknown') channel_logo = channel.get('logo', '') category = channel.get('category', 'General') print(f" 📡 Procesare: {channel_name}...", end='') # Obține URL-ul de stream stream_url = self.get_stream_url(channel_id) if stream_url: # Scrie în playlist f.write(f'#EXTINF:-1 tvg-id="{channel_id}" tvg-name="{channel_name}" ') f.write(f'tvg-logo="{channel_logo}" group-title="{category}",{channel_name}\n') f.write(f'{stream_url}\n\n') processed += 1 print(" ✅") else: print(" ❌ (URL indisponibil)") # Footer f.write("# ========================================\n") f.write(f"# Total canale procesate: {processed}/{len(self.channels)}\n") f.write("# ========================================\n") print(f"\n✅ Playlist generat cu succes!") print(f"📁 Fișier: {output_file}") print(f"📺 Canale funcționale: {processed}/{len(self.channels)}") return True except Exception as e: print(f"❌ Eroare la generare playlist: {e}") return False def main(): """Funcția principală""" print("=" * 60) print("🎬 DIGI ONLINE - EXTRACTOR AUTENTIFICAT") print("=" * 60) print() # Citește credențialele print("📋 Introdu credențialele DIGI Online:") print("⚠️ NOTĂ: Credențialele sunt folosite DOAR pentru autentificare") print("⚠️ pe digionline.ro oficial. Nu sunt trimise nicăieri altundeva!\n") email = input("📧 Email: ").strip() if not email: print("❌ Email-ul este obligatoriu!") sys.exit(1) # Importă getpass pentru parolă ascunsă try: from getpass import getpass password = getpass("🔒 Parolă: ") except: password = input("🔒 Parolă: ").strip() if not password: print("❌ Parola este obligatorie!") sys.exit(1) print("\n" + "=" * 60) # Creează instanța și autentifică digi = DigiOnlineAuth() if not digi.login(email, password): print("\n❌ Autentificare eșuată! Verifică credențialele.") sys.exit(1) # Obține lista de canale if not digi.get_channels(): print("\n❌ Nu s-au putut obține canalele!") sys.exit(1) # Generează playlist-ul output_file = "digi_authenticated.m3u" if digi.generate_playlist(output_file): print("\n" + "=" * 60) print("🎉 SUCCES!") print("=" * 60) print(f"\n📁 Playlist generat: {output_file}") print(f"📺 Folosește acest fișier în Dispatcharr/Jellyfin/VLC") print(f"\n💡 TIP: Token-ul expiră după câteva ore.") print(f" Rulează din nou scriptul pentru a reînnoi token-ul.\n") else: print("\n❌ Eroare la generare playlist!") sys.exit(1) if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\n\n⚠️ Întrerupt de utilizator!") sys.exit(0) except Exception as e: print(f"\n❌ Eroare neașteptată: {e}") sys.exit(1)