diff --git a/vigilancia/pi_bot.py b/vigilancia/pi_bot.py
index 4f44558..93bab01 100644
--- a/vigilancia/pi_bot.py
+++ b/vigilancia/pi_bot.py
@@ -94,6 +94,15 @@ def mandar_tv(mensaje, simple):
return False
+def mandar_youtube(url):
+ try:
+ r = requests.get(f"http://127.0.0.1:8600/tv/youtube?url={url}", timeout=10)
+ return r.status_code == 200
+ except Exception as e:
+ log(f"youtube error: {e}")
+ return False
+
+
def procesar(texto, chat_id):
t = texto.lower().strip()
log(f"RECIBIDO chat={chat_id} texto={texto!r}")
@@ -119,7 +128,7 @@ def procesar(texto, chat_id):
ok = mandar_tv(msj, simple=False)
enviar("🚨 Alarma lanzada en la tele ✅" if ok
else "❌ No se pudo lanzar la alarma", chat_id)
- elif t in ("panorama", "/panorama"):
+ elif t.startswith("panorama") or t.startswith("/panorama"):
enviar("📷 Capturando snapshots de las cámaras...", chat_id)
try:
import subprocess as sp
@@ -128,12 +137,20 @@ def procesar(texto, chat_id):
log(f"panorama: {r.stdout.strip()[-200:]}")
except Exception as e:
log(f"panorama error: {e}")
+ elif t.startswith("youtube ") or t.startswith("/youtube "):
+ url = texto.split(" ", 1)[1].strip()
+ if not url:
+ enviar("Uso: youtube <URL>", chat_id)
+ else:
+ ok = mandar_youtube(url)
+ enviar("🎬 YouTube lanzado en la TV ✅" if ok else "❌ No se pudo lanzar YouTube", chat_id)
elif t in ("ayuda", "/ayuda", "help", "/help"):
enviar("Comandos:\n"
"estado — estado de la Pi\n"
"temperatura — temperatura\n"
"tv <mensaje> — mensaje rápido a la tele\n"
"alarma <mensaje> — secuencia completa (sirena x3)\n"
+ "youtube <URL> — reproduce YouTube y apaga al terminar\n"
"panorama — fotos de las cámaras",
chat_id)
diff --git a/vigilancia/tv_api.py b/vigilancia/tv_api.py
index 8083674..1d8510d 100644
--- a/vigilancia/tv_api.py
+++ b/vigilancia/tv_api.py
@@ -9,12 +9,24 @@ import sys
sys.path.insert(0, sys_dir)
import config
-from voz import anuncio_en_teles, anuncio_simple
+from voz import anuncio_en_teles, anuncio_simple, youtube_en_teles
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
q = parse_qs(urlparse(self.path).query)
+ path = urlparse(self.path).path
+
+ if path == "/tv/youtube":
+ url = (q.get("url") or [""])[0]
+ if not url:
+ self._resp(400, {"error": "falta parametro url"})
+ return
+ threading.Thread(target=youtube_en_teles, args=(url,), daemon=True).start()
+ print(f"[TV-API] YouTube lanzado: {url[:80]}")
+ self._resp(200, {"ok": True, "url": url, "modo": "youtube"})
+ return
+
texto = (q.get("texto") or q.get("msg") or [""])[0]
if not texto:
self._resp(400, {"error": "falta parametro texto"})
diff --git a/vigilancia/voz.py b/vigilancia/voz.py
index b7e297f..5f77ab6 100644
--- a/vigilancia/voz.py
+++ b/vigilancia/voz.py
@@ -316,6 +316,53 @@ def reproducir_en_teles(texto):
anuncio_en_teles(texto)
+def youtube_en_teles(url):
+ """Reproduce un video de YouTube en la tele y la apaga al terminar."""
+ import re
+ match = re.search(r"(?:v=|youtu\.be/)([A-Za-z0-9_-]{11})", url)
+ if not match:
+ print("[Voz] URL de YouTube no válida")
+ return
+ video_id = match.group(1)
+ try:
+ import pychromecast
+ from pychromecast.controllers.youtube import YouTubeController
+
+ chromecasts, browser = pychromecast.get_chromecasts(timeout=8)
+ try:
+ if config.GOOGLE_TV_NOMBRES:
+ objetivos = [c for c in chromecasts
+ if c.cast_info.friendly_name in config.GOOGLE_TV_NOMBRES]
+ else:
+ objetivos = chromecasts
+ for c in objetivos:
+ try:
+ c.wait(timeout=10)
+ c.set_volume(config.GOOGLE_TV_VOLUMEN / 100.0)
+ yt = YouTubeController()
+ c.register_handler(yt)
+ print(f"[Voz] Lanzando YouTube en {c.cast_info.friendly_name}: {video_id}")
+ yt.play_video(video_id)
+ # Esperar a que termine el video
+ time.sleep(5)
+ while True:
+ try:
+ state = c.media_controller.status.player_state
+ if state == "IDLE":
+ break
+ except Exception:
+ pass
+ time.sleep(3)
+ apagar_tv_remote()
+ print(f"[Voz] Video terminado, TV apagada")
+ except Exception as e:
+ print(f"[Voz] Error en {c.cast_info.friendly_name}: {e}")
+ finally:
+ pychromecast.discovery.stop_discovery(browser)
+ except Exception as e:
+ print(f"[Voz] Error YouTube: {e}")
+
+
def apagar_tv_remote():
"""Apaga la TV via AndroidTVRemote (protocolo oficial Google)."""
try: