diff --git a/.tf5_mixer_cache/mixer_ip.json b/.tf5_mixer_cache/mixer_ip.json new file mode 100644 index 0000000..26fd4e5 --- /dev/null +++ b/.tf5_mixer_cache/mixer_ip.json @@ -0,0 +1,4 @@ +{ + "ip": "192.168.1.57", + "timestamp": 1770578444.177839 +} \ No newline at end of file diff --git a/__pycache__/config.cpython-312.pyc b/__pycache__/config.cpython-312.pyc index 86e287c..aa1bf7b 100644 Binary files a/__pycache__/config.cpython-312.pyc and b/__pycache__/config.cpython-312.pyc differ diff --git a/config.py b/config.py index 3256892..82fb038 100644 --- a/config.py +++ b/config.py @@ -1,13 +1,252 @@ +import socket +import ipaddress +from pathlib import Path +from typing import Optional +import json +import threading +from concurrent.futures import ThreadPoolExecutor, as_completed +import time + # Configurazione mixer -DEFAULT_HOST = "192.168.1.57" DEFAULT_PORT = 49280 TF5_INPUT_CHANNELS = 40 TF5_MIX_BUSSES = 20 -from pathlib import Path - - # Configurazione cache CACHE_DIR = Path(".tf5_mixer_cache") CACHE_FILE = CACHE_DIR / "channels_cache.json" -CACHE_DURATION = 3600 # 60 minuti in secondi \ No newline at end of file +IP_CACHE_FILE = CACHE_DIR / "mixer_ip.json" +CACHE_DURATION = 3600 # 60 minuti in secondi +IP_CACHE_DURATION = 300 # 5 minuti per l'IP + +def log(message: str, level: str = "INFO"): + """Stampa log formattato con timestamp""" + timestamp = time.strftime("%H:%M:%S") + symbols = { + "INFO": "ℹ️", + "SUCCESS": "✅", + "ERROR": "❌", + "WARNING": "⚠️", + "SEARCH": "🔍", + "NETWORK": "🌐", + "CACHE": "📍", + "TIME": "⏱️" + } + symbol = symbols.get(level, "•") + print(f"[{timestamp}] {symbol} {message}") + +def get_local_network() -> str: + """Ottiene la rete locale del sistema""" + log("Rilevamento rete locale in corso...", "NETWORK") + try: + # Crea un socket per ottenere l'IP locale + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + local_ip = s.getsockname()[0] + s.close() + + # Converte in network (es: 192.168.1.0/24) + ip_parts = local_ip.split('.') + network = f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.0/24" + + log(f"IP locale rilevato: {local_ip}", "INFO") + log(f"Rete da scansionare: {network}", "NETWORK") + return network + except Exception as e: + log(f"Errore nel rilevare la rete locale: {e}", "ERROR") + network = "192.168.1.0/24" + log(f"Uso rete di fallback: {network}", "WARNING") + return network + +def check_port(ip: str, port: int, timeout: float = 0.5) -> bool: + """Controlla se una porta è aperta su un IP""" + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + result = sock.connect_ex((ip, port)) + sock.close() + return result == 0 + except Exception as e: + # Log solo per debug, commentabile se troppo verbose + # log(f"Errore su {ip}: {e}", "ERROR") + return False + +def scan_network_for_mixer(port: int = DEFAULT_PORT, max_workers: int = 50) -> Optional[str]: + """Scansiona la rete locale per trovare il mixer""" + log(f"Ricerca mixer sulla porta {port}...", "SEARCH") + start_time = time.time() + + network = get_local_network() + + # Genera lista di IP da scansionare + ip_network = ipaddress.ip_network(network, strict=False) + total_hosts = sum(1 for _ in ip_network.hosts()) + log(f"Indirizzi da scansionare: {total_hosts}", "INFO") + log(f"Thread paralleli: {max_workers}", "INFO") + + found_ip = None + scanned = 0 + + # Scansione parallela per velocità + with ThreadPoolExecutor(max_workers=max_workers) as executor: + future_to_ip = { + executor.submit(check_port, str(ip), port): str(ip) + for ip in ip_network.hosts() + } + + log("Scansione in corso...", "SEARCH") + + for future in as_completed(future_to_ip): + ip = future_to_ip[future] + scanned += 1 + + # Log di progresso ogni 50 IP + if scanned % 50 == 0: + log(f"Progresso: {scanned}/{total_hosts} IP scansionati", "INFO") + + try: + if future.result(): + found_ip = ip + elapsed = time.time() - start_time + log(f"MIXER TROVATO su {ip}:{port}", "SUCCESS") + log(f"Tempo di scansione: {elapsed:.2f}s", "TIME") + log(f"IP scansionati: {scanned}/{total_hosts}", "INFO") + # Cancella i task rimanenti + executor.shutdown(wait=False, cancel_futures=True) + break + except Exception as e: + log(f"Errore durante scansione di {ip}: {e}", "ERROR") + + if not found_ip: + elapsed = time.time() - start_time + log(f"Nessun mixer trovato sulla porta {port}", "ERROR") + log(f"Tempo totale di scansione: {elapsed:.2f}s", "TIME") + log(f"IP scansionati: {scanned}/{total_hosts}", "INFO") + + return found_ip + +def load_cached_ip() -> Optional[str]: + """Carica l'IP dalla cache se valido""" + log("Controllo cache IP...", "CACHE") + + if not IP_CACHE_FILE.exists(): + log("Nessuna cache trovata", "INFO") + return None + + try: + with open(IP_CACHE_FILE, 'r') as f: + data = json.load(f) + + cached_ip = data.get('ip') + cache_time = data.get('timestamp', 0) + age = time.time() - cache_time + + log(f"Cache trovata: {cached_ip} (età: {int(age)}s)", "CACHE") + + # Controlla se la cache è ancora valida + if age < IP_CACHE_DURATION: + log(f"Verifica raggiungibilità di {cached_ip}...", "CACHE") + # Verifica che l'IP sia ancora valido + if cached_ip and check_port(cached_ip, DEFAULT_PORT, timeout=1.0): + log(f"IP dalla cache valido: {cached_ip}", "SUCCESS") + return cached_ip + else: + log(f"IP dalla cache non raggiungibile", "WARNING") + else: + log(f"Cache scaduta (max {IP_CACHE_DURATION}s)", "WARNING") + except Exception as e: + log(f"Errore nel leggere cache IP: {e}", "ERROR") + + return None + +def save_ip_to_cache(ip: str): + """Salva l'IP nella cache""" + log(f"Salvataggio IP in cache: {ip}", "CACHE") + CACHE_DIR.mkdir(exist_ok=True) + + try: + with open(IP_CACHE_FILE, 'w') as f: + json.dump({ + 'ip': ip, + 'timestamp': time.time() + }, f, indent=2) + log(f"Cache salvata: {IP_CACHE_FILE}", "SUCCESS") + except Exception as e: + log(f"Errore nel salvare cache IP: {e}", "ERROR") + +def get_mixer_ip() -> str: + """ + Ottiene l'IP del mixer con auto-discovery: + 1. Controlla cache + 2. Scansiona la rete + 3. Fallback su IP predefinito + """ + log("=== INIZIO RICERCA MIXER ===", "INFO") + + # Prova con la cache + cached_ip = load_cached_ip() + if cached_ip: + log("=== RICERCA COMPLETATA (CACHE) ===", "SUCCESS") + return cached_ip + + # Scansiona la rete + log("Avvio scansione di rete...", "SEARCH") + discovered_ip = scan_network_for_mixer() + if discovered_ip: + save_ip_to_cache(discovered_ip) + log("=== RICERCA COMPLETATA (DISCOVERY) ===", "SUCCESS") + return discovered_ip + + # Fallback + fallback_ip = "192.168.1.57" + log(f"Uso IP predefinito di fallback: {fallback_ip}", "WARNING") + log("=== RICERCA COMPLETATA (FALLBACK) ===", "WARNING") + return fallback_ip + +# Variabile globale per l'host (si aggiorna automaticamente) +DEFAULT_HOST = None + +def get_host() -> str: + """Ottiene l'host del mixer (con lazy loading)""" + global DEFAULT_HOST + if DEFAULT_HOST is None: + log("Host mixer non inizializzato, avvio discovery...", "INFO") + DEFAULT_HOST = get_mixer_ip() + else: + log(f"Host mixer già inizializzato: {DEFAULT_HOST}", "INFO") + return DEFAULT_HOST + +def refresh_mixer_ip(): + """Forza un refresh dell'IP del mixer""" + global DEFAULT_HOST + log("=== REFRESH FORZATO IP MIXER ===", "INFO") + log("Cancellazione cache esistente...", "CACHE") + + # Rimuovi cache + if IP_CACHE_FILE.exists(): + try: + IP_CACHE_FILE.unlink() + log("Cache rimossa", "SUCCESS") + except Exception as e: + log(f"Errore rimozione cache: {e}", "ERROR") + + # Nuova scansione + DEFAULT_HOST = scan_network_for_mixer() + if DEFAULT_HOST: + save_ip_to_cache(DEFAULT_HOST) + log(f"Nuovo IP impostato: {DEFAULT_HOST}", "SUCCESS") + else: + log("Refresh fallito, mantengo IP precedente", "ERROR") + + log("=== REFRESH COMPLETATO ===", "INFO") + return DEFAULT_HOST + +# Test rapido +if __name__ == "__main__": + log("=== TEST AUTO-DISCOVERY MIXER ===", "INFO") + host = get_host() + log(f"Host finale: {host}", "SUCCESS") + + # Test refresh + # log("\n=== TEST REFRESH ===", "INFO") + # refresh_mixer_ip() \ No newline at end of file diff --git a/conversations/4762864.json b/conversations/4762864.json index 1decbf6..921c0b0 100644 --- a/conversations/4762864.json +++ b/conversations/4762864.json @@ -1,34 +1,10 @@ { "user_id": 4762864, "username": "unnikked", - "last_updated": 1770577997.6975403, - "last_updated_str": "2026-02-08 19:13:17", + "last_updated": 1770578542.7348943, + "last_updated_str": "2026-02-08 19:22:22", "message_count": 21, "history": [ - { - "role": "user", - "content": "Controlla canali mixer", - "timestamp": 1769455886.9095418, - "timestamp_str": "2026-01-26 19:31:26" - }, - { - "role": "assistant", - "content": "Ok Nicola, ho controllato i canali del mixer! Ecco cosa vedo:\n\n**Canali Attivi e Nominati:**\n* **Gelato (Canale 2):** Acceso, volume a -11.7 dB\n* **Vox1 (Canale 5):** Acceso, volume a 0 dB\n* **Vox2 (Canale 6):** Acceso, volume a 6.3 dB\n* **Basso (Canale 7):** Acceso, volume a -2.15 dB\n* **Kick (Canale 9):** Acceso, volume a -0.35 dB\n* **Snare (Canale 10):** Acceso, volume a -1.6 dB\n* **Tom 1 (Canale 11):** Acceso, volume a -2.8 dB\n* **Tom 2 (Canale 12):** Acceso, volume a -0.8 dB\n* **Tom3 (Canale 13):** Acceso, volume a -3.05 dB\n* **Pan SX (Canale 14):** Acceso, volume a -3.85 dB\n* **Pan dx (Canale 15):** Acceso, volume a -4.3 dB\n* **Archetto (Canale 18):** Acceso, volume a 4.6 dB\n* **Vox 5 (Canale 19):** Acceso, volume a -4.65 dB\n* **Tast (Canale 20):** Acceso, volume a -1.6 dB\n* **Vox3 (Canale 23):** Acceso, volume a 3.05 dB\n* **Chit cnt (Canale 24):** Acceso, volume a -2.35 dB\n* **Chit dx (Canale 25):** Acceso, volume a -0.85 dB\n* **Vox 4 (Canale 27):** Acceso, volume a -120 dB (ma è acceso, strano, forse un errore o un volume bassissimo)\n* **PC (Canale 33 e 34):** Accesi, volume a -43.2 dB\n\n**Canali Spenti o Sconosciuti:**\n* **Canale 1:** Sconosciuto, spento, volume a 0.65 dB\n* **Talkback (Canale 3):** Spento, volume a -120 dB\n* **Canale 4:** Sconosciuto, spento, volume a -120 dB\n* **Canale 8:** Sconosciuto, spento, volume a -120 dB\n* **Canale 16:** Sconosciuto, spento, volume a -120 dB\n* **Canale 17:** Sconosciuto, spento, volume a -120 dB\n* **Canale 21:** Sconosciuto, spento, volume a -120 dB\n* **Canale 22:** Sconosciuto, spento, volume a -120 dB\n* **Canale 26:** Sconosciuto, spento, volume a -120 dB\n* **Canale 28:** Sconosciuto, spento, volume a -120 dB\n* **Pad (Canale 29):** Spento, volume a -120 dB\n* **Canali dal 30 al 32:** Sconosciuti, spenti, volume a -120 dB\n* **Canali dal 35 al 40:** Nominati \"chXX\", accesi ma con volume a -120 dB (praticamente muti)\n\nSembra che ci siano un bel po' di canali attivi con nomi, il che è un buon segno! Però, alcuni canali sono \"accesi\" ma con il volume a -120 dB, il che significa che non si sentiranno.\n\nFammi sapere se vuoi che faccia qualcosa in particolare! 🎛️🎤", - "timestamp": 1769455894.465047, - "timestamp_str": "2026-01-26 19:31:34" - }, - { - "role": "user", - "content": "Refresh cache", - "timestamp": 1769455900.8138618, - "timestamp_str": "2026-01-26 19:31:40" - }, - { - "role": "assistant", - "content": "✅ Fatto, Nicola! Ho ricaricato tutte le informazioni del mixer. Ora siamo pronti a ripartire con i dati freschi! 🎛️✨", - "timestamp": 1769455904.113328, - "timestamp_str": "2026-01-26 19:31:44" - }, { "role": "user", "content": "Controlla ora", @@ -130,6 +106,30 @@ "content": "Ciao Nicola! Tutto bene? Dimmi pure se hai bisogno di qualcosa con il mixer! 🎛️🎤", "timestamp": 1770577997.697525, "timestamp_str": "2026-02-08 19:13:17" + }, + { + "role": "user", + "content": "Ciao pupo", + "timestamp": 1770578526.691519, + "timestamp_str": "2026-02-08 19:22:06" + }, + { + "role": "assistant", + "content": "Ciao Nicola! Tutto bene? Dimmi pure se hai bisogno di qualcosa con il mixer! 🎛️🎤", + "timestamp": 1770578528.1236699, + "timestamp_str": "2026-02-08 19:22:08" + }, + { + "role": "user", + "content": "Check canali", + "timestamp": 1770578537.6022112, + "timestamp_str": "2026-02-08 19:22:17" + }, + { + "role": "assistant", + "content": "Allora, Nicola, ho controllato tutti i canali! Ecco la situazione attuale:\n\n**Canali Attivi (o con volume udibile):**\n* **PC (Canale 33 e 34):** Accesi, volume a -17.5 dB\n\n**Canali che sono accesi ma con volume bassissimo (-120 dB), quindi praticamente muti:**\n* **Gelato (Canale 2)**\n* **Vox1 (Canale 5)**\n* **Vox2 (Canale 6)**\n* **Basso (Canale 7)**\n* **Kick (Canale 9)**\n* **Snare (Canale 10)**\n* **Tom 1 (Canale 11)**\n* **Tom 2 (Canale 12)**\n* **Tom3 (Canale 13)**\n* **Pan SX (Canale 14)**\n* **Pan dx (Canale 15)**\n* **Vox 5 (Canale 19)**\n* **Tast (Canale 20)**\n* **Vox3 (Canale 23)**\n* **Chit cnt (Canale 24)**\n* **Chit dx (Canale 25)**\n* **Vox 4 (Canale 27)**\n* **ch35 (Canale 35)**\n* **ch36 (Canale 36)**\n* **ch37 (Canale 37)**\n* **ch38 (Canale 38)**\n* **ch39 (Canale 39)**\n* **ch40 (Canale 40)**\n\n**Canali spenti o sconosciuti:**\n* **Canale 1:** Sconosciuto, spento, volume a 0.65 dB\n* **Talkback (Canale 3):** Spento, volume a -60 dB\n* **Canale 4:** Sconosciuto, spento, volume a -120 dB\n* **Canale 8:** Sconosciuto, spento, volume a -120 dB\n* **Canale 16:** Sconosciuto, spento, volume a -120 dB\n* **Canale 17:** Sconosciuto, spento, volume a -120 dB\n* **Archetto (Canale 18):** Spento, volume a -76 dB\n* **Canale 21:** Sconosciuto, spento, volume a -120 dB\n* **Canale 22:** Sconosciuto, spento, volume a -120 dB\n* **Canale 26:** Sconosciuto, spento, volume a -120 dB\n* **Canale 28:** Sconosciuto, spento, volume a -120 dB\n* **Pad (Canale 29):** Spento, volume a -120 dB\n* **Canali dal 30 al 32:** Sconosciuti, spenti, volume a -120 dB\n\nLa cache è stata aggiornata circa 10 minuti fa. Sembra che molti canali siano spenti o con volumi molto bassi. Fammi sapere se vuoi che accenda o alzi qualcosa! 🎛️🎤", + "timestamp": 1770578542.7348733, + "timestamp_str": "2026-02-08 19:22:22" } ] } \ No newline at end of file diff --git a/telegram_bot.py b/telegram_bot.py index cbf28df..c19ca97 100644 --- a/telegram_bot.py +++ b/telegram_bot.py @@ -1083,7 +1083,7 @@ def main(): try: bot = TF5TelegramBot( telegram_token=telegram_token, - mixer_host=args.mixer_host, + mixer_host=get_host(), mixer_port=args.mixer_port, conversations_dir=args.conversations_dir, profiles_dir=args.profiles_dir