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
94 lines
2.6 KiB
Python
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()
|