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,149 @@
|
||||
"""VOD catalog: optional single M3U account for library listings (env DISPATCHARR_VOD_CATALOG_ACCOUNT_ID).
|
||||
|
||||
Plus per-user playback / catalog policies stored in User.custom_properties:
|
||||
|
||||
custom_properties = {
|
||||
"vod_playback_mode": "strict" | "prefer" | "auto",
|
||||
"vod_playback_account_ids": [10, 11],
|
||||
"allowed_movie_category_ids": [3, 7, 12], # empty/missing = all
|
||||
"allowed_series_category_ids": [4, 9], # empty/missing = all
|
||||
}
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def get_vod_catalog_account_id():
|
||||
raw = (os.environ.get("DISPATCHARR_VOD_CATALOG_ACCOUNT_ID") or "").strip()
|
||||
if raw.isdigit():
|
||||
return int(raw)
|
||||
return None
|
||||
|
||||
|
||||
def get_vod_playback_allowed_account_ids():
|
||||
"""
|
||||
Optional comma-separated M3U account IDs used only for VOD stream selection (failover).
|
||||
Example: DISPATCHARR_VOD_PLAYBACK_ACCOUNT_IDS=10,11,12
|
||||
When unset, any active M3U account with a relation may be used (default).
|
||||
"""
|
||||
raw = (os.environ.get("DISPATCHARR_VOD_PLAYBACK_ACCOUNT_IDS") or "").strip()
|
||||
if not raw:
|
||||
return None
|
||||
out = []
|
||||
for part in raw.split(","):
|
||||
part = part.strip()
|
||||
if part.isdigit():
|
||||
out.append(int(part))
|
||||
return out if out else None
|
||||
|
||||
|
||||
def filter_m3u_relation_queryset_for_playback(qs):
|
||||
"""
|
||||
Apply DISPATCHARR_VOD_PLAYBACK_ACCOUNT_IDS allowlist to an M3U relation queryset.
|
||||
Used by VOD proxy and Xtream stream redirects so failover matches playback policy.
|
||||
"""
|
||||
allowed = get_vod_playback_allowed_account_ids()
|
||||
if allowed is not None:
|
||||
return qs.filter(m3u_account_id__in=allowed, m3u_account__is_active=True)
|
||||
return qs.filter(m3u_account__is_active=True)
|
||||
|
||||
|
||||
def _coerce_int_list(raw):
|
||||
out = []
|
||||
if not raw:
|
||||
return out
|
||||
if isinstance(raw, (list, tuple)):
|
||||
items = raw
|
||||
elif isinstance(raw, str):
|
||||
items = raw.split(",")
|
||||
else:
|
||||
return out
|
||||
for x in items:
|
||||
try:
|
||||
out.append(int(str(x).strip()))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
return out
|
||||
|
||||
|
||||
def get_user_vod_prefs(user):
|
||||
"""Return a normalized dict of per-user VOD policies. Safe with None / anonymous user."""
|
||||
if not user or not getattr(user, "is_authenticated", False):
|
||||
return {
|
||||
"playback_mode": "auto",
|
||||
"playback_account_ids": [],
|
||||
"allowed_movie_category_ids": None,
|
||||
"allowed_series_category_ids": None,
|
||||
}
|
||||
cp = getattr(user, "custom_properties", None) or {}
|
||||
accounts = _coerce_int_list(cp.get("vod_playback_account_ids"))
|
||||
mode = (cp.get("vod_playback_mode") or "").strip().lower()
|
||||
if mode not in ("strict", "prefer", "auto"):
|
||||
mode = "auto"
|
||||
movie_cats = _coerce_int_list(cp.get("allowed_movie_category_ids"))
|
||||
series_cats = _coerce_int_list(cp.get("allowed_series_category_ids"))
|
||||
return {
|
||||
"playback_mode": mode,
|
||||
"playback_account_ids": accounts,
|
||||
"allowed_movie_category_ids": movie_cats or None,
|
||||
"allowed_series_category_ids": series_cats or None,
|
||||
}
|
||||
|
||||
|
||||
def filter_relation_qs_for_user_playback(qs, user):
|
||||
"""Restrict a relation queryset based on the user's playback prefs.
|
||||
|
||||
Returns (queryset, prefer_account_id).
|
||||
- mode=strict: only the user's accounts (queryset further restricted).
|
||||
- mode=prefer: queryset unchanged, returns the first account as preference for tie-breaking.
|
||||
- mode=auto (or no accounts): no per-user filter; the global allowlist already applies upstream.
|
||||
"""
|
||||
prefs = get_user_vod_prefs(user)
|
||||
accounts = prefs.get("playback_account_ids") or []
|
||||
mode = prefs.get("playback_mode") or "auto"
|
||||
if accounts and mode == "strict":
|
||||
qs = qs.filter(m3u_account_id__in=accounts)
|
||||
prefer = accounts[0]
|
||||
elif accounts and mode == "prefer":
|
||||
prefer = accounts[0]
|
||||
else:
|
||||
prefer = None
|
||||
return qs, prefer
|
||||
|
||||
|
||||
def get_user_allowed_movie_category_ids(user):
|
||||
return get_user_vod_prefs(user).get("allowed_movie_category_ids")
|
||||
|
||||
|
||||
def get_user_allowed_series_category_ids(user):
|
||||
return get_user_vod_prefs(user).get("allowed_series_category_ids")
|
||||
|
||||
|
||||
def filter_movie_qs_for_user(qs, user):
|
||||
"""Restrict a Movie queryset to only categories the user is allowed to see."""
|
||||
cats = get_user_allowed_movie_category_ids(user)
|
||||
if cats:
|
||||
return qs.filter(m3u_relations__category_id__in=cats).distinct()
|
||||
return qs
|
||||
|
||||
|
||||
def filter_series_qs_for_user(qs, user):
|
||||
"""Restrict a Series queryset to only categories the user is allowed to see."""
|
||||
cats = get_user_allowed_series_category_ids(user)
|
||||
if cats:
|
||||
return qs.filter(m3u_relations__category_id__in=cats).distinct()
|
||||
return qs
|
||||
|
||||
|
||||
def filter_m3u_movie_relation_qs_for_user(qs, user):
|
||||
cats = get_user_allowed_movie_category_ids(user)
|
||||
if cats:
|
||||
return qs.filter(category_id__in=cats)
|
||||
return qs
|
||||
|
||||
|
||||
def filter_m3u_series_relation_qs_for_user(qs, user):
|
||||
cats = get_user_allowed_series_category_ids(user)
|
||||
if cats:
|
||||
return qs.filter(category_id__in=cats)
|
||||
return qs
|
||||
Reference in New Issue
Block a user