Files
LXC-Dispatcharr-modificado-…/scripts/link_backup_streams_boss_javi.py
T
root f56b088643
Base Image Build / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
Frontend Tests / test (push) Has been cancelled
Base Image Build / docker (amd64, ubuntu-24.04) (push) Has been cancelled
Base Image Build / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
Base Image Build / create-manifest (push) Has been cancelled
Proyecto LCX Dispatcharr multicuenta
2026-05-09 21:24:50 +02:00

94 lines
2.6 KiB
Python

"""
Enlaza streams de la cuenta secundaria (Javi) como respaldo en canales que solo tienen la principal (Boss).
Uso (después de refrescar las listas M3U en Dispatcharr):
cd /opt/dispatcharr && set -a && . ./.env && set +a && \\
./.venv/bin/python manage.py shell < scripts/link_backup_streams_boss_javi.py
Empareja por tvg-id; si falta, por nombre normalizado. Idempotente (no duplica enlaces).
IDs de cuenta: revisa en UI M3U Accounts si cambian (por defecto Boss=2, Javi=4).
"""
import re
from collections import defaultdict
from apps.channels.models import Channel, ChannelStream, Stream
BOSS_ACCOUNT_ID = 2
BACKUP_ACCOUNT_ID = 4
def norm_name(s):
if not s:
return ""
return re.sub(r"\s+", " ", str(s).strip().lower())
def run():
by_tvg = {}
by_name = defaultdict(list)
javi_count = 0
for s in Stream.objects.filter(
m3u_account_id=BACKUP_ACCOUNT_ID, is_stale=False
).iterator(chunk_size=500):
javi_count += 1
tid = (s.tvg_id or "").strip()
if tid and tid not in by_tvg:
by_tvg[tid] = s
by_name[norm_name(s.name)].append(s)
linked = 0
skipped_has_backup = 0
skipped_primary_not_boss = 0
missing = 0
for ch in Channel.objects.prefetch_related("channelstream_set__stream").iterator(
chunk_size=400
):
css = sorted(ch.channelstream_set.all(), key=lambda x: x.order)
if not css:
continue
if any(cs.stream.m3u_account_id == BACKUP_ACCOUNT_ID for cs in css):
skipped_has_backup += 1
continue
boss = css[0].stream
if boss.m3u_account_id != BOSS_ACCOUNT_ID:
skipped_primary_not_boss += 1
continue
match = None
tid = (boss.tvg_id or "").strip()
if tid and tid in by_tvg:
match = by_tvg[tid]
if match is None:
cands = by_name.get(norm_name(boss.name))
if cands:
match = cands[0]
if match:
max_order = max(cs.order for cs in css)
_, created = ChannelStream.objects.get_or_create(
channel=ch,
stream=match,
defaults={"order": max_order + 1},
)
if created:
linked += 1
else:
missing += 1
print(
"[link_backup_streams] Javi streams indexados:",
javi_count,
"| nuevos enlaces:",
linked,
"| ya tenían backup:",
skipped_has_backup,
"| primer stream no es Boss:",
skipped_primary_not_boss,
"| sin pareja:",
missing,
)
run()