diff --git a/videoclub/global_buscar.py b/videoclub/global_buscar.py
index 3507ebd..bf973b5 100644
--- a/videoclub/global_buscar.py
+++ b/videoclub/global_buscar.py
@@ -247,7 +247,7 @@ def formatear_titulos(resultados):
if not resultados:
return ["No se encontraron resultados para ese termino."]
lineas = [f"🎬 Resultados globales ({len(resultados)}):",
- "Responde /bajar <numero> para ver torrents.", ""]
+ "Responde /torrents <numero> para ver torrents.", ""]
for i, r in enumerate(resultados, 1):
icono = "📺" if r["type"] == "series" else "🎬"
y = f" ({r['year']})" if r.get("year") else ""
diff --git a/videoclub/listados/2026-09-06.md b/videoclub/listados/2026-09-06.md
new file mode 100644
index 0000000..bf2b081
--- /dev/null
+++ b/videoclub/listados/2026-09-06.md
@@ -0,0 +1,60 @@
+# Videoclub — 2026-09-06
+
+**Total disponibles: 51** | Novedades: 0
+
+## Películas (37)
+
+- Backrooms 2160p 4K WEB x265 10bit AAC5 1 (2026) `https://real-debrid.com/d/WC7MIGNKYMMEAFED`
+- Disclosure Day 1080p ViruseProject (2026) `https://real-debrid.com/d/7AKRWAMVG2A7OFA6`
+- Disclosure Day NO-ADS 1080p x265 MD-AAC5 1+2 0 ITA-ENG MmTRaXx DD-CREW-IlCosaro (2026) `https://real-debrid.com/d/ZWPJNGU5EKGA61D4`
+- Downloads
+- El dia de la revelacion Disclosure Day (2026) `https://real-debrid.com/d/AHBLKPLNL56KOBBC`
+- El día de la revelacion Disclosure Day (2026) `https://real-debrid.com/d/NSHXB2IFNLNEK7C8`
+- El Pasajero Nocturno (2026) `https://real-debrid.com/d/52MMX6GHV6U5639B`
+- El Pasajero Nocturno (2026) `https://real-debrid.com/d/MBLS4EMXARKVM5C4`
+- Fiasco total La tragedia del festival Astroworld (2025) `https://real-debrid.com/d/YCBMS3HYQPLU27E1`
+- Fiasco total La tragedia del festival Astroworld (2025) `https://real-debrid.com/d/YCBMS3HYQPLU27E1`
+- Fiasco total La tragedia del festival Astroworld (2025) `https://real-debrid.com/d/YCBMS3HYQPLU27E1`
+- Greenland `https://real-debrid.com/d/LUZ3G5KBQZYES397`
+- Greenland 2 `https://real-debrid.com/d/FS4OAHZSNYHFK568`
+- Greenland El Ultimo Refugio (2020) `https://real-debrid.com/d/MJR44YRCTRDMY2C9`
+- He-Man y los Masters del Universo (2026) `https://real-debrid.com/d/APGDE3Z7ADR3U58B`
+- Iron Lung 2026 1080p `https://real-debrid.com/d/I6BVHXX7IFSUE1DB`
+- La maldicion de Shelby Oaks (2026) `https://real-debrid.com/d/T4FFNHSB2XBV4D92`
+- La momia de Lee Cronin Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5 1 BD-Rip hd 1080p `https://real-debrid.com/d/QDPUO2UWMDWX6C6E`
+- Luger (2026) `https://real-debrid.com/d/VWUUZIQGVLO76357`
+- Obsession 2160p UHD x265 10bit DV HDR r00t (2026) `https://real-debrid.com/d/XFJULZ3HFQ6VG8A4`
+- Obsession 2160p UHD x265 10bit DV HDR TrueHD Atmos 7 1 r00t (2026) `https://real-debrid.com/d/LMJHM23CEYXZOA66`
+- Obsession Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5 1 BD-Rip hd 1080p `https://real-debrid.com/d/LESH2XGOLRWYKEC8`
+- Posesion infernal En llamas (2026) `https://real-debrid.com/d/RF2IRCGKIKISI174`
+- Project Hail Mary 2160p KinoRip h265 En Es Dual YG (2026) `https://real-debrid.com/d/OMCP4MAMM775Q17A`
+- Project Hail Mary 2160p KinoRip h265 En Es Dual YG (2026) `https://real-debrid.com/d/OMCP4MAMM775Q17A`
+- Project Hail Mary 2160p KinoRip h265 En Es Dual YG (2026) `https://real-debrid.com/d/OMCP4MAMM775Q17A`
+- Resident Evil `https://real-debrid.com/d/6VMIEUSOVVIXYBD2`
+- Salvacion (2026) `https://real-debrid.com/d/BF3FGPVABGL6A610`
+- Salvacion (2026) `https://real-debrid.com/d/4Q6AFXH6KSKRO2AF`
+- Scary Movie (2026) `https://real-debrid.com/d/7FHGHGOXV7ELY3E6`
+- Spider-Man No Way Home 4Kremux2160 atomixhq link `https://real-debrid.com/d/S7GR3CYFAWOWC7AC`
+- Steven Spielberg el rey midas de Hollywood wolfmax4k com (2024) `https://real-debrid.com/d/WWCMHPUY4FPFAF67`
+- Super Mario Galaxy La película (2026) `https://real-debrid.com/d/VNTK5JCJGRHJOF0E`
+- super mario galaxy la película Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5 1 BD-Rip hd 1080p `https://real-debrid.com/d/3GQUITYMNB4TUE1C`
+- The End of Oak Street 1080p HC V2 x264-DKS (2026) `https://real-debrid.com/d/JI3KPXS4HEY7Y234`
+- TheAdventuresOfTomSawyer `https://real-debrid.com/d/XJVUAD7LIIMFKDCC`
+- Twilight Saga 2008-2012 2160p H265 HDR10 AC3 5 1 ITA ENG sub ita eng Sp33dy94-MIRCrew `https://real-debrid.com/d/II6EYH6KIMNUI10A`
+
+## Series (14)
+
+- Euphoria `https://real-debrid.com/d/YOFHJHFSKN6HOB11`
+- From - S02E01 - Strangers in a Strange Land - WEBDL-1080p - Spanish 2x01 - audio - sub `https://real-debrid.com/d/B64L3AL7NWVN41D1`
+- Heidi Girl of the Alps Alps no Shoujo Heidi Season 1 BD 1080p HEVC x265 10bit Eng-Subs -Judas `https://real-debrid.com/d/3V5DNKCHKQOPGF89`
+- Monarch El Legado De Los Monstruos wolfmax4k com `https://real-debrid.com/d/LRB4AEEJCYOCU1E0`
+- Star Trek Strange New Worlds `https://real-debrid.com/d/UCVH7W3HSXDKS4E5`
+- Stargate Sg-1 05x09 Entre Dos Fuegos `https://real-debrid.com/d/TYLADWGS6AEMQ28C`
+- Stargate Sg-1 05x10 2001 `https://real-debrid.com/d/LHQ7LEN7VCRSS1C4`
+- Stargate Sg-1 05x12 Agujero X-Tremo `https://real-debrid.com/d/7BTWUVXH2KH7KCC5`
+- Supergirl (2026) `https://real-debrid.com/d/65RUKRSI3YERQDCB`
+- Supergirl (2026) `https://real-debrid.com/d/ZKB3MUWMEM52G885`
+- The Studio `https://real-debrid.com/d/6AQCY2YCPY6FE9A9`
+- The Studio `https://real-debrid.com/d/L7DDTFXUCCPF47A5`
+- The Studio `https://real-debrid.com/d/P3J5H2OCFG76WC67`
+- The Studio wolfmax4k com `https://real-debrid.com/d/KHLUHJ4W7JMKA663`
diff --git a/videoclub/snapshots/2026-09-06.json b/videoclub/snapshots/2026-09-06.json
new file mode 100644
index 0000000..cbcfde8
--- /dev/null
+++ b/videoclub/snapshots/2026-09-06.json
@@ -0,0 +1,413 @@
+{
+ "fecha": "2026-09-06",
+ "items": [
+ {
+ "id": "realdebrid:Downloads",
+ "name": "Downloads",
+ "clean": "Downloads",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": null
+ },
+ {
+ "id": "realdebrid:O47SZPHDEIJD4",
+ "name": "Posesion infernal En llamas (2026) [4k 2160p][Esp].mkv",
+ "clean": "Posesion infernal En llamas",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/RF2IRCGKIKISI174"
+ },
+ {
+ "id": "realdebrid:5DLXRYNWASICQ",
+ "name": "The.End.of.Oak.Street.2026.1080p.HC.V2.x264-DKS.mkv",
+ "clean": "The End of Oak Street 1080p HC V2 x264-DKS",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/JI3KPXS4HEY7Y234"
+ },
+ {
+ "id": "realdebrid:TEGQKYCCQBXXO",
+ "name": "Supergirl (2026) [Bluray 720p][Esp].mkv",
+ "clean": "Supergirl",
+ "year": "2026",
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/65RUKRSI3YERQDCB"
+ },
+ {
+ "id": "realdebrid:HARMOP47F3AP2",
+ "name": "Obsession Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5.1 BD-Rip hd 1080p.mkv",
+ "clean": "Obsession Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5 1 BD-Rip hd 1080p",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/LESH2XGOLRWYKEC8"
+ },
+ {
+ "id": "realdebrid:V7XUZQ6APSG4Q",
+ "name": "Scary Movie (2026) [4k 2160p][Esp].mkv",
+ "clean": "Scary Movie",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/7FHGHGOXV7ELY3E6"
+ },
+ {
+ "id": "realdebrid:MBGEYHZC4MKYU",
+ "name": "Star Trek Strange New Worlds [HDTV 1080p][Cap.401].mkv",
+ "clean": "Star Trek Strange New Worlds",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/UCVH7W3HSXDKS4E5"
+ },
+ {
+ "id": "realdebrid:HEIP5O2XB5V66",
+ "name": "He-Man y los Masters del Universo (2026) [Bluray 1080p][Esp].mkv",
+ "clean": "He-Man y los Masters del Universo",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/APGDE3Z7ADR3U58B"
+ },
+ {
+ "id": "realdebrid:SLJ2UJGPDFZLW",
+ "name": "Supergirl (2026) [Bluray 1080p][Esp].mkv",
+ "clean": "Supergirl",
+ "year": "2026",
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/ZKB3MUWMEM52G885"
+ },
+ {
+ "id": "realdebrid:FC5FZS2J4HUFS",
+ "name": "El dia de la revelacion (Disclosure Day) (2026) [Bluray 1080p][Esp].mkv",
+ "clean": "El dia de la revelacion Disclosure Day",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/AHBLKPLNL56KOBBC"
+ },
+ {
+ "id": "realdebrid:A5XIYLPNAZNZM",
+ "name": "El día de la revelacion (Disclosure Day) (2026) [4k 2160p][Esp].mkv",
+ "clean": "El día de la revelacion Disclosure Day",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/NSHXB2IFNLNEK7C8"
+ },
+ {
+ "id": "realdebrid:7XL55PFQOE4OO",
+ "name": "El Pasajero Nocturno (2026) [Bluray 1080p][Esp].mkv",
+ "clean": "El Pasajero Nocturno",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/52MMX6GHV6U5639B"
+ },
+ {
+ "id": "realdebrid:5IHX4PFCFP5QY",
+ "name": "El Pasajero Nocturno (2026) [Bluray][Esp].avi",
+ "clean": "El Pasajero Nocturno",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/MBLS4EMXARKVM5C4"
+ },
+ {
+ "id": "realdebrid:S52E6GZH2FSNK",
+ "name": "Disclosure.Day.(2026).(NO-ADS).1080p.x265.MD-AAC5.1+2.0.ITA-ENG.MmTRaXx(DD-CREW-IlCosaro).mkv",
+ "clean": "Disclosure Day NO-ADS 1080p x265 MD-AAC5 1+2 0 ITA-ENG MmTRaXx DD-CREW-IlCosaro",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/ZWPJNGU5EKGA61D4"
+ },
+ {
+ "id": "realdebrid:FOTT5OF2CNCQO",
+ "name": "Disclosure.Day.2026.1080p.CAMRip.ViruseProject.mkv",
+ "clean": "Disclosure Day 1080p ViruseProject",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/7AKRWAMVG2A7OFA6"
+ },
+ {
+ "id": "realdebrid:FEWY5OUINFE6I",
+ "name": "Obsession (2026) (2160p UHD BluRay x265 10bit DV HDR r00t).mkv",
+ "clean": "Obsession 2160p UHD x265 10bit DV HDR r00t",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/XFJULZ3HFQ6VG8A4"
+ },
+ {
+ "id": "realdebrid:GE3KLARBGACYC",
+ "name": "Obsession (2026) (2160p UHD BluRay x265 10bit DV HDR TrueHD Atmos 7.1 r00t)",
+ "clean": "Obsession 2160p UHD x265 10bit DV HDR TrueHD Atmos 7 1 r00t",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/LMJHM23CEYXZOA66"
+ },
+ {
+ "id": "realdebrid:REQOOWL7R3X5M",
+ "name": "Backrooms.2026.2160p.4K.WEB.x265.10bit.AAC5.1-[YTS.GG - YTS.BZ].mkv",
+ "clean": "Backrooms 2160p 4K WEB x265 10bit AAC5 1",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/WC7MIGNKYMMEAFED"
+ },
+ {
+ "id": "realdebrid:HEVMDYWAXLSLM",
+ "name": "Luger (2026) [Bluray 720p][Esp].mkv",
+ "clean": "Luger",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/VWUUZIQGVLO76357"
+ },
+ {
+ "id": "realdebrid:MBSDHRJMTC3S2",
+ "name": "Spider-Man No Way Home 4Kremux2160.atomixhq.link.mkv",
+ "clean": "Spider-Man No Way Home 4Kremux2160 atomixhq link",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/S7GR3CYFAWOWC7AC"
+ },
+ {
+ "id": "realdebrid:YVLXIF6ILFL2U",
+ "name": "Iron Lung 2026 1080p.mkv",
+ "clean": "Iron Lung 2026 1080p",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/I6BVHXX7IFSUE1DB"
+ },
+ {
+ "id": "realdebrid:DLUAAXNZJ2ZHW",
+ "name": "From - S02E01 - Strangers in a Strange Land - WEBDL-1080p - Spanish 2x01 - audio [ES+EN] - sub [ES+EN].mkv",
+ "clean": "From - S02E01 - Strangers in a Strange Land - WEBDL-1080p - Spanish 2x01 - audio - sub",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/B64L3AL7NWVN41D1"
+ },
+ {
+ "id": "realdebrid:UP7DPBWVMH7JS",
+ "name": "La maldicion de Shelby Oaks (2026) [4k 2160p][Esp].mkv",
+ "clean": "La maldicion de Shelby Oaks",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/T4FFNHSB2XBV4D92"
+ },
+ {
+ "id": "realdebrid:PMBQI365H7PU6",
+ "name": "Steven Spielberg el rey midas de Hollywood (2024) [HDTV 1080p][Esp](wolfmax4k.com).mkv",
+ "clean": "Steven Spielberg el rey midas de Hollywood wolfmax4k com",
+ "year": "2024",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/WWCMHPUY4FPFAF67"
+ },
+ {
+ "id": "realdebrid:OWWSTBTFG4ZFO",
+ "name": "Fiasco total La tragedia del festival Astroworld (2025) [HDTV 1080p][Esp].mkv",
+ "clean": "Fiasco total La tragedia del festival Astroworld",
+ "year": "2025",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/YCBMS3HYQPLU27E1"
+ },
+ {
+ "id": "realdebrid:M4UVGSNUKTLA6",
+ "name": "Fiasco total La tragedia del festival Astroworld (2025) [HDTV 1080p][Esp].mkv",
+ "clean": "Fiasco total La tragedia del festival Astroworld",
+ "year": "2025",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/YCBMS3HYQPLU27E1"
+ },
+ {
+ "id": "realdebrid:7HQN7ELMLWTDI",
+ "name": "Fiasco total La tragedia del festival Astroworld (2025) [HDTV 1080p][Esp].mkv",
+ "clean": "Fiasco total La tragedia del festival Astroworld",
+ "year": "2025",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/YCBMS3HYQPLU27E1"
+ },
+ {
+ "id": "realdebrid:BRNWEZP2TGOEQ",
+ "name": "La momia de Lee Cronin Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5.1 BD-Rip hd 1080p.mkv",
+ "clean": "La momia de Lee Cronin Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5 1 BD-Rip hd 1080p",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/QDPUO2UWMDWX6C6E"
+ },
+ {
+ "id": "realdebrid:3MNHGJ3UM73VY",
+ "name": "super mario galaxy la película Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5.1 BD-Rip hd 1080p.mkv",
+ "clean": "super mario galaxy la película Castellano-Ingles+Subt Castellano-Ingles H264 E-AC3 5 1 BD-Rip hd 1080p",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/3GQUITYMNB4TUE1C"
+ },
+ {
+ "id": "realdebrid:PKZ3B7VEZXWZQ",
+ "name": "Super Mario Galaxy La película (2026) [4k 2160p][Esp].mkv",
+ "clean": "Super Mario Galaxy La película",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/VNTK5JCJGRHJOF0E"
+ },
+ {
+ "id": "realdebrid:6RE4EY5ZP2ILA",
+ "name": "Proyecto Salvacion (2026) [Bluray 1080p][Esp].mkv",
+ "clean": "Salvacion",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/BF3FGPVABGL6A610"
+ },
+ {
+ "id": "realdebrid:ASX6FSY2ZZD36",
+ "name": "Heidi Girl of the Alps (Alps no Shoujo Heidi) (Season 1) (BD 1080p)(HEVC x265 10bit)(Eng-Subs)-Judas[TGx]",
+ "clean": "Heidi Girl of the Alps Alps no Shoujo Heidi Season 1 BD 1080p HEVC x265 10bit Eng-Subs -Judas",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/3V5DNKCHKQOPGF89"
+ },
+ {
+ "id": "realdebrid:K4CJIWAJF3NKS",
+ "name": "Greenland El Ultimo Refugio (2020) [BluRay Rip][AC3 5.1 Castellano][www.PctFenix.com].avi",
+ "clean": "Greenland El Ultimo Refugio",
+ "year": "2020",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/MJR44YRCTRDMY2C9"
+ },
+ {
+ "id": "realdebrid:KDWFL34NA3MXE",
+ "name": "Greenland [4K UHDremux][2160p][HDR10][AC3 5.1 Castellano-True HD 7.1-Ingles+Subs][ES-EN]",
+ "clean": "Greenland",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/LUZ3G5KBQZYES397"
+ },
+ {
+ "id": "realdebrid:KW4WNKPELJM5O",
+ "name": "Greenland 2 [4k 2160p][Esp].mkv",
+ "clean": "Greenland 2",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/FS4OAHZSNYHFK568"
+ },
+ {
+ "id": "realdebrid:WEFMCETRL5BZM",
+ "name": "Resident Evil [FullUHD 2160p][Castellano AC3 5.1-Ingles DolbyTrueHD 7.1+Subs]",
+ "clean": "Resident Evil",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/6VMIEUSOVVIXYBD2"
+ },
+ {
+ "id": "realdebrid:CFPM3BI4C7EXO",
+ "name": "Proyecto Salvacion (2026) [4k 2160p][Esp].mkv",
+ "clean": "Salvacion",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/4Q6AFXH6KSKRO2AF"
+ },
+ {
+ "id": "realdebrid:5W6E6YBRA7V22",
+ "name": "Project.Hail.Mary.2026.2160p.KinoRip.h265.En.Es.Dual YG.mkv",
+ "clean": "Project Hail Mary 2160p KinoRip h265 En Es Dual YG",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/OMCP4MAMM775Q17A"
+ },
+ {
+ "id": "realdebrid:3GJHZMZQUQ544",
+ "name": "Project.Hail.Mary.2026.2160p.KinoRip.h265.En.Es.Dual YG.mkv",
+ "clean": "Project Hail Mary 2160p KinoRip h265 En Es Dual YG",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/OMCP4MAMM775Q17A"
+ },
+ {
+ "id": "realdebrid:YAFM2WGO4IR64",
+ "name": "Project.Hail.Mary.2026.2160p.KinoRip.h265.En.Es.Dual YG.mkv",
+ "clean": "Project Hail Mary 2160p KinoRip h265 En Es Dual YG",
+ "year": "2026",
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/OMCP4MAMM775Q17A"
+ },
+ {
+ "id": "realdebrid:RBESCUG7LBCH2",
+ "name": "Twilight Saga (2008-2012) 2160p H265 HDR10 AC3 5.1 ITA.ENG sub ita.eng Sp33dy94-MIRCrew",
+ "clean": "Twilight Saga 2008-2012 2160p H265 HDR10 AC3 5 1 ITA ENG sub ita eng Sp33dy94-MIRCrew",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/II6EYH6KIMNUI10A"
+ },
+ {
+ "id": "realdebrid:ZYLMP5J4H3VE6",
+ "name": "Monarch El Legado De Los Monstruos [4k 2160p][Cap.101](wolfmax4k.com).mkv",
+ "clean": "Monarch El Legado De Los Monstruos wolfmax4k com",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/LRB4AEEJCYOCU1E0"
+ },
+ {
+ "id": "realdebrid:37ZFJ63K6W7PM",
+ "name": "Stargate_Sg-1_05x12_Agujero_X-Tremo.avi",
+ "clean": "Stargate Sg-1 05x12 Agujero X-Tremo",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/7BTWUVXH2KH7KCC5"
+ },
+ {
+ "id": "realdebrid:6JJIFVQ5MZQEI",
+ "name": "TheAdventuresOfTomSawyer",
+ "clean": "TheAdventuresOfTomSawyer",
+ "year": null,
+ "tipo": "pelicula",
+ "enlace": "https://real-debrid.com/d/XJVUAD7LIIMFKDCC"
+ },
+ {
+ "id": "realdebrid:5KFSC2OVN37MO",
+ "name": "The Studio [HDTV 1080p][Cap.105]",
+ "clean": "The Studio",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/6AQCY2YCPY6FE9A9"
+ },
+ {
+ "id": "realdebrid:3AS7OJ3EXXKMC",
+ "name": "Stargate_Sg-1_05x10_2001.avi",
+ "clean": "Stargate Sg-1 05x10 2001",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/LHQ7LEN7VCRSS1C4"
+ },
+ {
+ "id": "realdebrid:UYIBLKOIL5HD6",
+ "name": "The Studio [HDTV 1080p][Cap.104]",
+ "clean": "The Studio",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/L7DDTFXUCCPF47A5"
+ },
+ {
+ "id": "realdebrid:CQ5CWIAKCM3ZS",
+ "name": "The Studio [HDTV 1080p][Cap.103]",
+ "clean": "The Studio",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/P3J5H2OCFG76WC67"
+ },
+ {
+ "id": "realdebrid:TMZRDVHVHUHRQ",
+ "name": "The Studio [HDTV 1080p][cap.102](wolfmax4k.com).mkv",
+ "clean": "The Studio wolfmax4k com",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/KHLUHJ4W7JMKA663"
+ },
+ {
+ "id": "realdebrid:S5HO3BW6ADQYI",
+ "name": "Euphoria [4k 2160p][Cap.302].mkv",
+ "clean": "Euphoria",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/YOFHJHFSKN6HOB11"
+ },
+ {
+ "id": "realdebrid:CCDJGDZJK3FRA",
+ "name": "Stargate_Sg-1_05x09_Entre_Dos_Fuegos.avi",
+ "clean": "Stargate Sg-1 05x09 Entre Dos Fuegos",
+ "year": null,
+ "tipo": "serie",
+ "enlace": "https://real-debrid.com/d/TYLADWGS6AEMQ28C"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/videoclub/videoclub_buscador.py b/videoclub/videoclub_buscador.py
index a088dd2..42f3f57 100644
--- a/videoclub/videoclub_buscador.py
+++ b/videoclub/videoclub_buscador.py
@@ -252,20 +252,29 @@ def formatear_peliculas(resultados):
calidad = "4K" if "4k" in (it.get("name") or "").lower() or \
"2160p" in (it.get("name") or "").lower() else "HD"
idioma = "cast." if it.get("castellano") else "ing."
- enlace = it.get("enlace") or ""
lineas.append(f"{i}. {it['clean']}{y} — {calidad}, {idioma}")
- if enlace:
- lineas.append(f" descargar {enlace}")
lineas.append("")
- lineas.append("Responde con el numero para descargar.")
+ lineas.append("Responde /torrents NUMERO para ver opciones y descargar.")
return trocear_texto(lineas)
+def aplanar_series(grupos):
+ """Devuelve lista plana de episodios en el mismo orden de visualizacion
+ (grupos ordenados, episodios ordenados). La usa el bot para que el numero
+ elegido con /torrents coincida con lo mostrado."""
+ planos = []
+ for base in sorted(grupos, key=lambda x: x.lower()):
+ for it in grupos[base]:
+ planos.append(it)
+ return planos
+
+
def formatear_series(grupos):
"""Formatea resultados de series como lista de mensajes Telegram numerados."""
if not grupos:
return ["No se encontraron series con ese termino."]
lineas = []
+ num_global = 1
for base in sorted(grupos, key=lambda x: x.lower()):
eps = grupos[base]
temp_max = max(parsear_episodio(e["name"])[0] for e in eps)
@@ -273,7 +282,6 @@ def formatear_series(grupos):
lineas.append("")
temp_actual = 0
- num_global = 1
for it in eps:
temp, cap = parsear_episodio(it["name"])
if temp != temp_actual:
@@ -282,18 +290,15 @@ def formatear_series(grupos):
lineas.append(f"Temporada {temp}:")
resto = _limpiar_titulo_ep(it["name"][SERIE_EP_RE.search(it["name"]).end():]) \
if SERIE_EP_RE.search(it["name"]) else it["clean"]
- enlace = it.get("enlace") or ""
if temp > 0:
etiqueta = f"S{temp:02d}E{cap:02d}"
else:
etiqueta = it["clean"]
lineas.append(f" {num_global}. {etiqueta} — {resto}")
- if enlace:
- lineas.append(f" descargar {enlace}")
num_global += 1
lineas.append("")
- lineas.append("Responde con el numero de episodio para descargar.")
+ lineas.append("Responde /torrents NUMERO de episodio para ver opciones y descargar.")
return trocear_texto(lineas)
@@ -330,10 +335,9 @@ def formatear_novedades(items):
y = f" ({it['year']})" if it["year"] else ""
tipo = "📺" if it["tipo"] == "serie" else "🎬"
idioma = "cast." if it.get("castellano") else "ing."
- enlace = it.get("enlace") or ""
lineas.append(f"{tipo} {i}. {it['clean']}{y} — {idioma}")
- if enlace:
- lineas.append(f" descargar {enlace}")
+ lineas.append("")
+ lineas.append("Responde /torrents NUMERO para ver opciones y descargar.")
return trocear_texto(lineas)
diff --git a/vigilancia/asus_api_control.py b/vigilancia/asus_api_control.py
index c871c71..ad19ea8 100644
--- a/vigilancia/asus_api_control.py
+++ b/vigilancia/asus_api_control.py
@@ -106,12 +106,39 @@ def parental_status():
return json.dumps(data, ensure_ascii=False, indent=2, default=str)
+def _mac_en_vivo(pistas):
+ """Busca en los leases DHCP actuales un dispositivo cuyo hostname
+ contenga alguna pista. Devuelve (ip, mac, hostname) o None.
+ Sirve para tablets con MAC privada aleatoria (la MAC guardada rota)."""
+ try:
+ from router_control import _inventario
+ except Exception:
+ return None
+ try:
+ devices, _by_mac = _inventario()
+ except Exception:
+ return None
+ for ip, mac, nombre in devices:
+ n = normalizar_nombre(nombre)
+ for p in pistas:
+ if p and (p in n or n in p):
+ return ip, mac, nombre
+ return None
+
+
def cambiar_bloqueo(nombre, blocked):
device = resolver_dispositivo(nombre)
if not device:
raise ValueError(f"Dispositivo no reconocido: {nombre}")
- asyncio.run(_set_block(device["mac"], device["name"], blocked))
- return f"{'Bloqueado' if blocked else 'Activado'}: {device['name']}"
+ mac = device["mac"]
+ etiqueta = device["name"]
+ vivo = _mac_en_vivo((normalizar_nombre(nombre),
+ normalizar_nombre(etiqueta)))
+ if vivo and vivo[1].upper() != mac.upper():
+ mac = vivo[1]
+ etiqueta = f"{etiqueta} [{vivo[2]} {vivo[0]}]"
+ asyncio.run(_set_block(mac, device["name"], blocked))
+ return f"{'Bloqueado' if blocked else 'Activado'}: {etiqueta} ({mac})"
async def _aimesh_data():
diff --git a/vigilancia/pi_bot.py b/vigilancia/pi_bot.py
index 93fceac..e33cd3e 100644
--- a/vigilancia/pi_bot.py
+++ b/vigilancia/pi_bot.py
@@ -19,6 +19,7 @@ temporizadores_parental = {} # alias normalizado -> Timer de desbloqueo
menu_pendiente = {} # chat_id -> accion de texto libre esperada (menu botones)
menu_pausa_nombre = {} # chat_id -> nombre elegido en flujo de pausa
historial_chat = {} # chat_id -> [message_id...] enviados por el bot (para /limpiar)
+entrantes_chat = {} # chat_id -> [message_id...] enviados por el usuario (para /limpiar)
borrar_pend = {} # chat_id -> lista de tareas NAS esperando numero a borrar
BASE = os.path.dirname(os.path.abspath(__file__))
@@ -278,8 +279,10 @@ def borrar(chat_id, message_id):
def limpiar_pantalla(chat_id):
- """Borra los mensajes que el bot ha enviado en este chat (/limpiar)."""
+ """Borra TODO el chat visible: mensajes del bot y del usuario (/limpiar).
+ Limite de Telegram: solo mensajes de menos de 48h se pueden borrar."""
lista = historial_chat.pop(chat_id, None) or []
+ lista += entrantes_chat.pop(chat_id, None) or []
borrados = 0
for mid in reversed(lista):
try:
@@ -292,7 +295,7 @@ def limpiar_pantalla(chat_id):
borrados += 1
except Exception:
pass
- aviso = enviar(f"🧹 Pantalla limpia ({borrados} mensajes borrados).", chat_id)
+ aviso = enviar(f"🧹 Chat limpio ({borrados} mensajes borrados).", chat_id)
if aviso:
threading.Timer(6.0, borrar, args=(chat_id, aviso)).start()
@@ -943,6 +946,8 @@ def procesar_buscador_pelicula(nombre, chat_id):
for m in mensajes:
enviar(m, chat_id)
if resultados:
+ ultima_titulos[chat_id] = {"query": nombre, "results": resultados,
+ "origen": "catalogo"}
log(f"BUSCADOR pelis '{nombre}': {len(resultados)} resultados")
@@ -967,6 +972,9 @@ def procesar_buscador_serie(nombre, chat_id):
enviar(m, chat_id)
if grupos:
total_eps = sum(len(v) for v in grupos.values())
+ ultima_titulos[chat_id] = {"query": nombre,
+ "results": vcb.aplanar_series(grupos),
+ "origen": "catalogo"}
log(f"BUSCADOR series '{nombre}': {len(grupos)} series, {total_eps} capitulos")
@@ -989,6 +997,10 @@ def procesar_novedades(chat_id):
return
for m in mensajes:
enviar(m, chat_id)
+ if items:
+ ultima_titulos[chat_id] = {"query": "novedades", "results": items,
+ "origen": "catalogo"}
+ log(f"NOVEDADES: {len(items)} items")
def _int_arg(texto):
@@ -1071,11 +1083,31 @@ def _mostrar_catalogo_genero(chat_id, tipo, genero, categoria):
def procesar_torrents(n, chat_id):
- """Muestra los torrents (Torrentio) del titulo numero n de la ultima busqueda."""
+ """Muestra las opciones de descarga del numero n de la ultima busqueda
+ (/busca, /pelicula, /serie, /novedades o /genero)."""
estado = ultima_titulos.get(chat_id)
if not estado or n is None or n < 1 or n > len(estado["results"]):
- enviar("Primero usa /busca <nombre> y luego "
- "/torrents <numero>.", chat_id)
+ enviar("Primero usa /busca, /pelicula, /serie, "
+ "/novedades o /genero y luego "
+ "/torrents <numero>.", chat_id)
+ return
+ r = estado["results"][n - 1]
+ if not r.get("imdb_id") and r.get("enlace"):
+ # Item de catalogo: ya trae enlace directo, sin paso por Torrentio.
+ nombre = r.get("clean") or r.get("name") or "titulo"
+ ultimos_torrents[chat_id] = {
+ "titulo": nombre,
+ "torrents": [{"filename": nombre, "calidad": "directo",
+ "size": None, "enlace": r["enlace"]}],
+ }
+ enviar(f"🧲 {nombre} — enlace directo disponible:\n"
+ "1. Descarga directa al NAS\n\n"
+ "Responde /bajar 1 para descargarlo.", chat_id)
+ log(f"TORRENTS catalogo '{nombre}': enlace directo")
+ return
+ if not r.get("imdb_id"):
+ enviar("❌ Ese resultado no tiene enlace de descarga. "
+ "Prueba con /busca <nombre>.", chat_id)
return
try:
gol = _import_global_buscar()
@@ -1083,7 +1115,6 @@ def procesar_torrents(n, chat_id):
log(f"global_buscar import error: {e}")
enviar("❌ No se pudo cargar el modulo", chat_id)
return
- r = estado["results"][n - 1]
enviar(f"🧲 Buscando torrents de {r['name']}...", chat_id)
try:
torrents = gol.torrents_de(r["imdb_id"], r["type"])
@@ -1104,8 +1135,25 @@ def procesar_bajar(n, chat_id):
"""Descarga el torrent numero n al NAS (Download Station via magnet)."""
estado = ultimos_torrents.get(chat_id)
if not estado or n is None or n < 1 or n > len(estado["torrents"]):
- enviar("Primero usa /busca <nombre> y luego "
- "/torrents <numero>.", chat_id)
+ enviar("Primero usa /busca, /pelicula, /serie, "
+ "/novedades o /genero, luego "
+ "/torrents <numero>.", chat_id)
+ return
+ t = estado["torrents"][n - 1]
+ if t.get("enlace") and not t.get("info_hash"):
+ # Enlace directo de catalogo: al NAS sin magnet.
+ try:
+ import nas_dl
+ ok = nas_dl.add_torrent(t["enlace"])
+ except Exception as e:
+ log(f"bajar error: {e}")
+ enviar(f"❌ Error al anadir al NAS: {e}", chat_id)
+ return
+ if ok:
+ enviar(f"📥 Añadido al NAS: {t.get('filename') or estado['titulo']}.",
+ chat_id)
+ else:
+ enviar("❌ No se pudo añadir al NAS.", chat_id)
return
try:
gol = _import_global_buscar()
@@ -1113,7 +1161,6 @@ def procesar_bajar(n, chat_id):
log(f"global_buscar import error: {e}")
enviar("❌ No se pudo cargar el modulo", chat_id)
return
- t = estado["torrents"][n - 1]
magnet = gol.magnet_de(t)
log(f"BAJAR '{estado['titulo']}' torrent {n}: {magnet[:60]}...")
try:
@@ -1167,6 +1214,11 @@ def _atender_update(upd):
return
texto = msg.get("text")
chat_id = msg["chat"]["id"]
+ if msg.get("message_id"):
+ lista = entrantes_chat.setdefault(chat_id, [])
+ lista.append(msg["message_id"])
+ if len(lista) > 300:
+ entrantes_chat[chat_id] = lista[-300:]
if texto:
procesar(texto, chat_id)
except Exception as e:
diff --git a/vps_opencode_bot/opencode_bot.py b/vps_opencode_bot/opencode_bot.py
index 5d669e6..d0b2f85 100644
--- a/vps_opencode_bot/opencode_bot.py
+++ b/vps_opencode_bot/opencode_bot.py
@@ -53,6 +53,7 @@ bloqueos = {} # chat_id -> True (procesando mensaje)
sesiones = {} # chat_id -> {'repo': slug, 'session': id, 'model': obj|None}
repos_cache = [] # lista de {'slug','dir'}
sentidos = {} # chat_id -> [message_id...] enviados por el bot (para /limpiar)
+entrantes = {} # chat_id -> [message_id...] enviados por el usuario (para /limpiar)
menu_msg = {} # chat_id -> message_id del menu abierto
@@ -560,8 +561,10 @@ def cmd_salir(chat):
def cmd_limpiar(chat):
- """Borra los mensajes que el bot ha enviado en este chat."""
+ """Borra TODO el chat visible: mensajes del bot y del usuario.
+ Limite de Telegram: solo mensajes de menos de 48h se pueden borrar."""
lista = sentidos.get(str(chat)) or []
+ lista += entrantes.get(str(chat)) or []
borrados = 0
for mid in reversed(lista):
try:
@@ -573,7 +576,8 @@ def cmd_limpiar(chat):
except Exception:
pass
sentidos[str(chat)] = []
- enviar(chat, f"🧹 Pantalla limpia ({borrados} mensajes borrados).")
+ entrantes[str(chat)] = []
+ enviar(chat, f"🧹 Chat limpio ({borrados} mensajes borrados).")
# borra tambien este aviso al cabo de unos segundos
threading.Timer(6.0, _autolimpia, args=(chat,)).start()
@@ -887,6 +891,11 @@ def main():
log(f"Bloqueado chat {chat}")
continue
texto = msg.get("text")
+ if msg.get("message_id"):
+ lista = entrantes.setdefault(chat, [])
+ lista.append(msg["message_id"])
+ if len(lista) > 300:
+ entrantes[chat] = lista[-300:]
if texto:
threading.Thread(target=procesar, args=(texto, chat),
daemon=True).start()