mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-21 01:05:30 +00:00
commit
02ac0d8de5
3 changed files with 47 additions and 143 deletions
|
|
@ -879,6 +879,8 @@ def parse_channels_only(source):
|
|||
display_name = child.text.strip()
|
||||
elif child.tag == 'icon':
|
||||
icon_url = child.get('src', '').strip()
|
||||
if display_name and icon_url:
|
||||
break # No need to continue if we have both
|
||||
|
||||
if not display_name:
|
||||
display_name = tvg_id
|
||||
|
|
|
|||
|
|
@ -1008,31 +1008,11 @@ def xc_get_vod_categories(user):
|
|||
|
||||
response = []
|
||||
|
||||
# Filter categories based on user's M3U accounts
|
||||
if user.user_level == 0:
|
||||
# For regular users, get categories from their accessible M3U accounts
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
# Get M3U accounts accessible through user's profiles
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
else:
|
||||
m3u_accounts = []
|
||||
|
||||
# Get categories that have movie relations with these accounts
|
||||
categories = VODCategory.objects.filter(
|
||||
category_type='movie',
|
||||
m3umovierelation__m3u_account__in=m3u_accounts
|
||||
).distinct().order_by(Lower("name"))
|
||||
else:
|
||||
# Admins can see all categories that have active movie relations
|
||||
categories = VODCategory.objects.filter(
|
||||
category_type='movie',
|
||||
m3umovierelation__m3u_account__is_active=True
|
||||
).distinct().order_by(Lower("name"))
|
||||
# All authenticated users get access to VOD from all active M3U accounts
|
||||
categories = VODCategory.objects.filter(
|
||||
category_type='movie',
|
||||
m3umovierelation__m3u_account__is_active=True
|
||||
).distinct().order_by(Lower("name"))
|
||||
|
||||
for category in categories:
|
||||
response.append({
|
||||
|
|
@ -1051,22 +1031,9 @@ def xc_get_vod_streams(request, user, category_id=None):
|
|||
|
||||
streams = []
|
||||
|
||||
# Build filters for movies based on user access
|
||||
# All authenticated users get access to VOD from all active M3U accounts
|
||||
filters = {"m3u_relations__m3u_account__is_active": True}
|
||||
|
||||
if user.user_level == 0:
|
||||
# For regular users, filter by accessible M3U accounts
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
filters["m3u_relations__m3u_account__in"] = m3u_accounts
|
||||
else:
|
||||
return [] # No accessible accounts
|
||||
|
||||
if category_id:
|
||||
filters["m3u_relations__category_id"] = category_id
|
||||
|
||||
|
|
@ -1127,28 +1094,11 @@ def xc_get_series_categories(user):
|
|||
|
||||
response = []
|
||||
|
||||
# Similar filtering as VOD categories but for series
|
||||
if user.user_level == 0:
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
else:
|
||||
m3u_accounts = []
|
||||
|
||||
# Get categories that have series relations with these accounts
|
||||
categories = VODCategory.objects.filter(
|
||||
category_type='series',
|
||||
m3useriesrelation__m3u_account__in=m3u_accounts
|
||||
).distinct().order_by(Lower("name"))
|
||||
else:
|
||||
categories = VODCategory.objects.filter(
|
||||
category_type='series',
|
||||
m3useriesrelation__m3u_account__is_active=True
|
||||
).distinct().order_by(Lower("name"))
|
||||
# All authenticated users get access to series from all active M3U accounts
|
||||
categories = VODCategory.objects.filter(
|
||||
category_type='series',
|
||||
m3useriesrelation__m3u_account__is_active=True
|
||||
).distinct().order_by(Lower("name"))
|
||||
|
||||
for category in categories:
|
||||
response.append({
|
||||
|
|
@ -1166,21 +1116,9 @@ def xc_get_series(request, user, category_id=None):
|
|||
|
||||
series_list = []
|
||||
|
||||
# Build filters based on user access
|
||||
# All authenticated users get access to series from all active M3U accounts
|
||||
filters = {"m3u_account__is_active": True}
|
||||
|
||||
if user.user_level == 0:
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
filters["m3u_account__in"] = m3u_accounts
|
||||
else:
|
||||
return []
|
||||
|
||||
if category_id:
|
||||
filters["category_id"] = category_id
|
||||
|
||||
|
|
@ -1228,21 +1166,9 @@ def xc_get_series_info(request, user, series_id):
|
|||
if not series_id:
|
||||
raise Http404()
|
||||
|
||||
# Get series relation with user access filtering
|
||||
# All authenticated users get access to series from all active M3U accounts
|
||||
filters = {"id": series_id, "m3u_account__is_active": True}
|
||||
|
||||
if user.user_level == 0:
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
filters["m3u_account__in"] = m3u_accounts
|
||||
else:
|
||||
raise Http404()
|
||||
|
||||
try:
|
||||
series_relation = M3USeriesRelation.objects.select_related('series', 'series__logo').get(**filters)
|
||||
series = series_relation.series
|
||||
|
|
@ -1439,21 +1365,9 @@ def xc_get_vod_info(request, user, vod_id):
|
|||
if not vod_id:
|
||||
raise Http404()
|
||||
|
||||
# Get movie relation with user access filtering - use movie ID instead of relation ID
|
||||
# All authenticated users get access to VOD from all active M3U accounts
|
||||
filters = {"movie_id": vod_id, "m3u_account__is_active": True}
|
||||
|
||||
if user.user_level == 0:
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
filters["m3u_account__in"] = m3u_accounts
|
||||
else:
|
||||
raise Http404()
|
||||
|
||||
try:
|
||||
# Order by account priority to get the best relation when multiple exist
|
||||
movie_relation = M3UMovieRelation.objects.select_related('movie', 'movie__logo').filter(**filters).order_by('-m3u_account__priority', 'id').first()
|
||||
|
|
@ -1602,22 +1516,9 @@ def xc_movie_stream(request, username, password, stream_id, extension):
|
|||
if custom_properties["xc_password"] != password:
|
||||
return JsonResponse({"error": "Invalid credentials"}, status=401)
|
||||
|
||||
# Get movie relation based on user access level - use movie ID instead of relation ID
|
||||
# All authenticated users get access to VOD from all active M3U accounts
|
||||
filters = {"movie_id": stream_id, "m3u_account__is_active": True}
|
||||
|
||||
if user.user_level < 10:
|
||||
# For regular users, filter by accessible M3U accounts
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
filters["m3u_account__in"] = m3u_accounts
|
||||
else:
|
||||
return JsonResponse({"error": "No accessible content"}, status=403)
|
||||
|
||||
try:
|
||||
# Order by account priority to get the best relation when multiple exist
|
||||
movie_relation = M3UMovieRelation.objects.select_related('movie').filter(**filters).order_by('-m3u_account__priority', 'id').first()
|
||||
|
|
@ -1652,22 +1553,9 @@ def xc_series_stream(request, username, password, stream_id, extension):
|
|||
if custom_properties["xc_password"] != password:
|
||||
return JsonResponse({"error": "Invalid credentials"}, status=401)
|
||||
|
||||
# Get episode relation based on user access level - use episode ID instead of stream_id
|
||||
# All authenticated users get access to series/episodes from all active M3U accounts
|
||||
filters = {"episode_id": stream_id, "m3u_account__is_active": True}
|
||||
|
||||
if user.user_level < 10:
|
||||
# For regular users, filter by accessible M3U accounts
|
||||
if user.channel_profiles.count() > 0:
|
||||
channel_profiles = user.channel_profiles.all()
|
||||
from apps.m3u.models import M3UAccount
|
||||
m3u_accounts = M3UAccount.objects.filter(
|
||||
is_active=True,
|
||||
profiles__in=channel_profiles
|
||||
).distinct()
|
||||
filters["m3u_account__in"] = m3u_accounts
|
||||
else:
|
||||
return JsonResponse({"error": "No accessible content"}, status=403)
|
||||
|
||||
try:
|
||||
episode_relation = M3UEpisodeRelation.objects.select_related('episode').get(**filters)
|
||||
except M3UEpisodeRelation.DoesNotExist:
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ def refresh_vod_content(account_id):
|
|||
|
||||
logger.info(f"Batch VOD refresh completed for account {account.name} in {duration:.2f} seconds")
|
||||
|
||||
# Cleanup orphaned VOD content after refresh
|
||||
logger.info("Starting cleanup of orphaned VOD content")
|
||||
cleanup_result = cleanup_orphaned_vod_content(scan_start_time=start_time)
|
||||
# Cleanup orphaned VOD content after refresh (scoped to this account only)
|
||||
logger.info(f"Starting cleanup of orphaned VOD content for account {account.name}")
|
||||
cleanup_result = cleanup_orphaned_vod_content(account_id=account_id, scan_start_time=start_time)
|
||||
logger.info(f"VOD cleanup completed: {cleanup_result}")
|
||||
|
||||
# Send completion notification
|
||||
|
|
@ -1308,7 +1308,7 @@ def batch_refresh_series_episodes(account_id, series_ids=None):
|
|||
|
||||
|
||||
@shared_task
|
||||
def cleanup_orphaned_vod_content(stale_days=0, scan_start_time=None):
|
||||
def cleanup_orphaned_vod_content(stale_days=0, scan_start_time=None, account_id=None):
|
||||
"""Clean up VOD content that has no M3U relations or has stale relations"""
|
||||
from datetime import timedelta
|
||||
|
||||
|
|
@ -1318,30 +1318,44 @@ def cleanup_orphaned_vod_content(stale_days=0, scan_start_time=None):
|
|||
# Calculate cutoff date for stale relations
|
||||
cutoff_date = reference_time - timedelta(days=stale_days)
|
||||
|
||||
# Build base query filters
|
||||
base_filters = {'last_seen__lt': cutoff_date}
|
||||
if account_id:
|
||||
base_filters['m3u_account_id'] = account_id
|
||||
logger.info(f"Cleaning up stale VOD content for account {account_id}")
|
||||
else:
|
||||
logger.info("Cleaning up stale VOD content across all accounts")
|
||||
|
||||
# Clean up stale movie relations (haven't been seen in the specified days)
|
||||
stale_movie_relations = M3UMovieRelation.objects.filter(last_seen__lt=cutoff_date)
|
||||
stale_movie_relations = M3UMovieRelation.objects.filter(**base_filters)
|
||||
stale_movie_count = stale_movie_relations.count()
|
||||
stale_movie_relations.delete()
|
||||
|
||||
# Clean up stale series relations
|
||||
stale_series_relations = M3USeriesRelation.objects.filter(last_seen__lt=cutoff_date)
|
||||
stale_series_relations = M3USeriesRelation.objects.filter(**base_filters)
|
||||
stale_series_count = stale_series_relations.count()
|
||||
stale_series_relations.delete()
|
||||
|
||||
# Clean up stale episode relations
|
||||
stale_episode_relations = M3UEpisodeRelation.objects.filter(last_seen__lt=cutoff_date)
|
||||
stale_episode_relations = M3UEpisodeRelation.objects.filter(**base_filters)
|
||||
stale_episode_count = stale_episode_relations.count()
|
||||
stale_episode_relations.delete()
|
||||
|
||||
# Clean up movies with no relations (orphaned)
|
||||
orphaned_movies = Movie.objects.filter(m3u_relations__isnull=True)
|
||||
orphaned_movie_count = orphaned_movies.count()
|
||||
orphaned_movies.delete()
|
||||
# Clean up movies with no relations (orphaned) - only if no account_id specified (global cleanup)
|
||||
if not account_id:
|
||||
orphaned_movies = Movie.objects.filter(m3u_relations__isnull=True)
|
||||
orphaned_movie_count = orphaned_movies.count()
|
||||
orphaned_movies.delete()
|
||||
|
||||
# Clean up series with no relations (orphaned)
|
||||
orphaned_series = Series.objects.filter(m3u_relations__isnull=True)
|
||||
orphaned_series_count = orphaned_series.count()
|
||||
orphaned_series.delete()
|
||||
# Clean up series with no relations (orphaned) - only if no account_id specified (global cleanup)
|
||||
orphaned_series = Series.objects.filter(m3u_relations__isnull=True)
|
||||
orphaned_series_count = orphaned_series.count()
|
||||
orphaned_series.delete()
|
||||
else:
|
||||
# When cleaning up for specific account, we don't remove orphaned content
|
||||
# as other accounts might still reference it
|
||||
orphaned_movie_count = 0
|
||||
orphaned_series_count = 0
|
||||
|
||||
# Episodes will be cleaned up via CASCADE when series are deleted
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue