Proyecto LCX Dispatcharr multicuenta
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
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
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user