mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Add ability to scan for vods during m3u refresh.
This commit is contained in:
parent
386a03381c
commit
bcebcadfaa
15 changed files with 315 additions and 27 deletions
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from .models import M3UAccount, M3UFilter, ServerGroup, UserAgent
|
||||
import json
|
||||
|
||||
class M3UFilterInline(admin.TabularInline):
|
||||
model = M3UFilter
|
||||
|
|
@ -10,8 +11,8 @@ class M3UFilterInline(admin.TabularInline):
|
|||
|
||||
@admin.register(M3UAccount)
|
||||
class M3UAccountAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'server_url', 'server_group', 'max_streams', 'is_active', 'user_agent_display', 'uploaded_file_link', 'created_at', 'updated_at')
|
||||
list_filter = ('is_active', 'server_group')
|
||||
list_display = ('name', 'server_url', 'server_group', 'max_streams', 'is_active', 'user_agent_display', 'vod_enabled_display', 'uploaded_file_link', 'created_at', 'updated_at')
|
||||
list_filter = ('is_active', 'server_group', 'account_type')
|
||||
search_fields = ('name', 'server_url', 'server_group__name')
|
||||
inlines = [M3UFilterInline]
|
||||
actions = ['activate_accounts', 'deactivate_accounts']
|
||||
|
|
@ -25,6 +26,18 @@ class M3UAccountAdmin(admin.ModelAdmin):
|
|||
return "None"
|
||||
user_agent_display.short_description = "User Agent(s)"
|
||||
|
||||
def vod_enabled_display(self, obj):
|
||||
"""Display whether VOD is enabled for this account"""
|
||||
if obj.custom_properties:
|
||||
try:
|
||||
custom_props = json.loads(obj.custom_properties)
|
||||
return "Yes" if custom_props.get('enable_vod', False) else "No"
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
return "No"
|
||||
vod_enabled_display.short_description = "VOD Enabled"
|
||||
vod_enabled_display.boolean = True
|
||||
|
||||
def uploaded_file_link(self, obj):
|
||||
if obj.uploaded_file:
|
||||
return format_html("<a href='{}' target='_blank'>Download M3U</a>", obj.uploaded_file.url)
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ from .serializers import (
|
|||
)
|
||||
|
||||
from .tasks import refresh_single_m3u_account, refresh_m3u_accounts
|
||||
from django.core.files.storage import default_storage
|
||||
from django.core.files.base import ContentFile
|
||||
import json
|
||||
|
||||
|
||||
class M3UAccountViewSet(viewsets.ModelViewSet):
|
||||
|
|
@ -78,15 +77,33 @@ class M3UAccountViewSet(viewsets.ModelViewSet):
|
|||
# Now call super().create() to create the instance
|
||||
response = super().create(request, *args, **kwargs)
|
||||
|
||||
print(response.data.get("account_type"))
|
||||
if response.data.get("account_type") == M3UAccount.Types.XC:
|
||||
refresh_m3u_groups(response.data.get("id"))
|
||||
account_type = response.data.get("account_type")
|
||||
account_id = response.data.get("id")
|
||||
|
||||
if account_type == M3UAccount.Types.XC:
|
||||
refresh_m3u_groups(account_id)
|
||||
|
||||
# Check if VOD is enabled
|
||||
enable_vod = request.data.get("enable_vod", False)
|
||||
if enable_vod:
|
||||
from apps.vod.tasks import refresh_vod_content
|
||||
|
||||
refresh_vod_content.delay(account_id)
|
||||
|
||||
# After the instance is created, return the response
|
||||
return response
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
old_vod_enabled = False
|
||||
|
||||
# Check current VOD setting
|
||||
if instance.custom_properties:
|
||||
try:
|
||||
custom_props = json.loads(instance.custom_properties)
|
||||
old_vod_enabled = custom_props.get("enable_vod", False)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
# Handle file upload first, if any
|
||||
file_path = None
|
||||
|
|
@ -122,6 +139,18 @@ class M3UAccountViewSet(viewsets.ModelViewSet):
|
|||
# Now call super().update() to update the instance
|
||||
response = super().update(request, *args, **kwargs)
|
||||
|
||||
# Check if VOD setting changed and trigger refresh if needed
|
||||
new_vod_enabled = request.data.get("enable_vod", old_vod_enabled)
|
||||
|
||||
if (
|
||||
instance.account_type == M3UAccount.Types.XC
|
||||
and not old_vod_enabled
|
||||
and new_vod_enabled
|
||||
):
|
||||
from apps.vod.tasks import refresh_vod_content
|
||||
|
||||
refresh_vod_content.delay(instance.id)
|
||||
|
||||
# After the instance is updated, return the response
|
||||
return response
|
||||
|
||||
|
|
@ -143,6 +172,46 @@ class M3UAccountViewSet(viewsets.ModelViewSet):
|
|||
# Continue with regular partial update
|
||||
return super().partial_update(request, *args, **kwargs)
|
||||
|
||||
@action(detail=True, methods=["post"], url_path="refresh-vod")
|
||||
def refresh_vod(self, request, pk=None):
|
||||
"""Trigger VOD content refresh for XtreamCodes accounts"""
|
||||
account = self.get_object()
|
||||
|
||||
if account.account_type != M3UAccount.Types.XC:
|
||||
return Response(
|
||||
{"error": "VOD refresh is only available for XtreamCodes accounts"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
# Check if VOD is enabled
|
||||
vod_enabled = False
|
||||
if account.custom_properties:
|
||||
try:
|
||||
custom_props = json.loads(account.custom_properties)
|
||||
vod_enabled = custom_props.get("enable_vod", False)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
if not vod_enabled:
|
||||
return Response(
|
||||
{"error": "VOD is not enabled for this account"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
try:
|
||||
from apps.vod.tasks import refresh_vod_content
|
||||
|
||||
refresh_vod_content.delay(account.id)
|
||||
return Response(
|
||||
{"message": f"VOD refresh initiated for account {account.name}"},
|
||||
status=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{"error": f"Failed to initiate VOD refresh: {str(e)}"},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
@action(detail=True, methods=["patch"], url_path="group-settings")
|
||||
def update_group_settings(self, request, pk=None):
|
||||
"""Update auto channel sync settings for M3U account groups"""
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@ from .models import M3UAccount, M3UFilter
|
|||
import re
|
||||
|
||||
class M3UAccountForm(forms.ModelForm):
|
||||
enable_vod = forms.BooleanField(
|
||||
required=False,
|
||||
initial=False,
|
||||
label="Enable VOD Content",
|
||||
help_text="Parse and import VOD (movies/series) content for XtreamCodes accounts"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = M3UAccount
|
||||
fields = [
|
||||
|
|
@ -13,8 +20,44 @@ class M3UAccountForm(forms.ModelForm):
|
|||
'server_group',
|
||||
'max_streams',
|
||||
'is_active',
|
||||
'enable_vod',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Set initial value for enable_vod from custom_properties
|
||||
if self.instance and self.instance.custom_properties:
|
||||
try:
|
||||
import json
|
||||
custom_props = json.loads(self.instance.custom_properties)
|
||||
self.fields['enable_vod'].initial = custom_props.get('enable_vod', False)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = super().save(commit=False)
|
||||
|
||||
# Handle enable_vod field
|
||||
enable_vod = self.cleaned_data.get('enable_vod', False)
|
||||
|
||||
# Parse existing custom_properties
|
||||
custom_props = {}
|
||||
if instance.custom_properties:
|
||||
try:
|
||||
import json
|
||||
custom_props = json.loads(instance.custom_properties)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
custom_props = {}
|
||||
|
||||
# Update VOD preference
|
||||
custom_props['enable_vod'] = enable_vod
|
||||
instance.custom_properties = json.dumps(custom_props)
|
||||
|
||||
if commit:
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
def clean_uploaded_file(self):
|
||||
uploaded_file = self.cleaned_data.get('uploaded_file')
|
||||
if uploaded_file:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from apps.channels.serializers import (
|
|||
ChannelGroupSerializer,
|
||||
)
|
||||
import logging
|
||||
import json
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -83,6 +84,7 @@ class M3UAccountSerializer(serializers.ModelSerializer):
|
|||
allow_null=True,
|
||||
validators=[validate_flexible_url],
|
||||
)
|
||||
enable_vod = serializers.BooleanField(required=False, write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = M3UAccount
|
||||
|
|
@ -109,6 +111,7 @@ class M3UAccountSerializer(serializers.ModelSerializer):
|
|||
"stale_stream_days",
|
||||
"status",
|
||||
"last_message",
|
||||
"enable_vod",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"password": {
|
||||
|
|
@ -117,7 +120,37 @@ class M3UAccountSerializer(serializers.ModelSerializer):
|
|||
},
|
||||
}
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
|
||||
# Parse custom_properties to get VOD preference
|
||||
custom_props = {}
|
||||
if instance.custom_properties:
|
||||
try:
|
||||
custom_props = json.loads(instance.custom_properties)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
custom_props = {}
|
||||
|
||||
data["enable_vod"] = custom_props.get("enable_vod", False)
|
||||
return data
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# Handle enable_vod preference
|
||||
enable_vod = validated_data.pop("enable_vod", None)
|
||||
|
||||
if enable_vod is not None:
|
||||
# Parse existing custom_properties
|
||||
custom_props = {}
|
||||
if instance.custom_properties:
|
||||
try:
|
||||
custom_props = json.loads(instance.custom_properties)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
custom_props = {}
|
||||
|
||||
# Update VOD preference
|
||||
custom_props["enable_vod"] = enable_vod
|
||||
validated_data["custom_properties"] = json.dumps(custom_props)
|
||||
|
||||
# Pop out channel group memberships so we can handle them manually
|
||||
channel_group_data = validated_data.pop("channel_group", [])
|
||||
|
||||
|
|
@ -149,6 +182,24 @@ class M3UAccountSerializer(serializers.ModelSerializer):
|
|||
|
||||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
# Handle enable_vod preference during creation
|
||||
enable_vod = validated_data.pop("enable_vod", False)
|
||||
|
||||
# Parse existing custom_properties or create new
|
||||
custom_props = {}
|
||||
if validated_data.get("custom_properties"):
|
||||
try:
|
||||
custom_props = json.loads(validated_data["custom_properties"])
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
custom_props = {}
|
||||
|
||||
# Set VOD preference
|
||||
custom_props["enable_vod"] = enable_vod
|
||||
validated_data["custom_properties"] = json.dumps(custom_props)
|
||||
|
||||
return super().create(validated_data)
|
||||
|
||||
|
||||
class ServerGroupSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for Server Group"""
|
||||
|
|
|
|||
|
|
@ -1265,6 +1265,16 @@ def refresh_single_m3u_account(account_id):
|
|||
account.save(update_fields=['status'])
|
||||
|
||||
filters = list(account.filters.all())
|
||||
|
||||
# Check if VOD is enabled for this account
|
||||
vod_enabled = False
|
||||
if account.custom_properties:
|
||||
try:
|
||||
custom_props = json.loads(account.custom_properties)
|
||||
vod_enabled = custom_props.get('enable_vod', False)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
vod_enabled = False
|
||||
|
||||
except M3UAccount.DoesNotExist:
|
||||
# The M3U account doesn't exist, so delete the periodic task if it exists
|
||||
logger.warning(f"M3U account with ID {account_id} not found, but task was triggered. Cleaning up orphaned task.")
|
||||
|
|
@ -1531,6 +1541,16 @@ def refresh_single_m3u_account(account_id):
|
|||
streams_deleted=streams_deleted,
|
||||
message=account.last_message
|
||||
)
|
||||
|
||||
# Trigger VOD refresh if enabled and account is XtreamCodes type
|
||||
if vod_enabled and account.account_type == M3UAccount.Types.XC:
|
||||
logger.info(f"VOD is enabled for account {account_id}, triggering VOD refresh")
|
||||
try:
|
||||
from apps.vod.tasks import refresh_vod_content
|
||||
refresh_vod_content.delay(account_id)
|
||||
logger.info(f"VOD refresh task queued for account {account_id}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to queue VOD refresh for account {account_id}: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing M3U for account {account_id}: {str(e)}")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from django.views import View
|
|||
from django.utils.decorators import method_decorator
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.http import JsonResponse
|
||||
from apps.m3u.models import M3UAccount
|
||||
import json
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ from .models import VOD, Series, VODCategory, VODConnection
|
|||
|
||||
@admin.register(VODCategory)
|
||||
class VODCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'm3u_account', 'created_at']
|
||||
list_filter = ['m3u_account', 'created_at']
|
||||
list_display = ['name', 'category_type', 'm3u_account', 'created_at']
|
||||
list_filter = ['category_type', 'm3u_account', 'created_at']
|
||||
search_fields = ['name']
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -120,12 +120,23 @@ class SeriesViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
return Response(serializer.data)
|
||||
|
||||
|
||||
class VODCategoryFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(lookup_expr="icontains")
|
||||
category_type = django_filters.ChoiceFilter(choices=VODCategory.CATEGORY_TYPE_CHOICES)
|
||||
m3u_account = django_filters.NumberFilter(field_name="m3u_account__id")
|
||||
|
||||
class Meta:
|
||||
model = VODCategory
|
||||
fields = ['name', 'category_type', 'm3u_account']
|
||||
|
||||
|
||||
class VODCategoryViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for VOD Categories"""
|
||||
queryset = VODCategory.objects.all()
|
||||
serializer_class = VODCategorySerializer
|
||||
|
||||
filter_backends = [SearchFilter, OrderingFilter]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_class = VODCategoryFilter
|
||||
search_fields = ['name']
|
||||
ordering = ['name']
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 5.2.4 on 2025-08-02 15:33
|
||||
# Generated by Django 5.2.4 on 2025-08-02 16:59
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
|
@ -45,6 +45,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True)),
|
||||
('category_type', models.CharField(choices=[('movie', 'Movie'), ('series', 'Series')], default='movie', help_text='Type of content this category contains', max_length=10)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('m3u_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='vod_categories', to='m3u.m3uaccount')),
|
||||
|
|
@ -53,6 +54,7 @@ class Migration(migrations.Migration):
|
|||
'verbose_name': 'VOD Category',
|
||||
'verbose_name_plural': 'VOD Categories',
|
||||
'ordering': ['name'],
|
||||
'unique_together': {('name', 'm3u_account', 'category_type')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,19 @@ import uuid
|
|||
|
||||
class VODCategory(models.Model):
|
||||
"""Categories for organizing VODs (e.g., Action, Comedy, Drama)"""
|
||||
|
||||
CATEGORY_TYPE_CHOICES = [
|
||||
('movie', 'Movie'),
|
||||
('series', 'Series'),
|
||||
]
|
||||
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
category_type = models.CharField(
|
||||
max_length=10,
|
||||
choices=CATEGORY_TYPE_CHOICES,
|
||||
default='movie',
|
||||
help_text="Type of content this category contains"
|
||||
)
|
||||
m3u_account = models.ForeignKey(
|
||||
M3UAccount,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -22,9 +34,10 @@ class VODCategory(models.Model):
|
|||
verbose_name = "VOD Category"
|
||||
verbose_name_plural = "VOD Categories"
|
||||
ordering = ['name']
|
||||
unique_together = ['name', 'm3u_account', 'category_type']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return f"{self.name} ({self.get_category_type_display()})"
|
||||
|
||||
|
||||
class Series(models.Model):
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ from apps.m3u.serializers import M3UAccountSerializer
|
|||
|
||||
|
||||
class VODCategorySerializer(serializers.ModelSerializer):
|
||||
category_type_display = serializers.CharField(source='get_category_type_display', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = VODCategory
|
||||
fields = '__all__'
|
||||
|
|
|
|||
|
|
@ -52,7 +52,11 @@ def refresh_movies(account):
|
|||
VODCategory.objects.get_or_create(
|
||||
name=cat_data['category_name'],
|
||||
m3u_account=account,
|
||||
defaults={'name': cat_data['category_name']}
|
||||
category_type='movie',
|
||||
defaults={
|
||||
'name': cat_data['category_name'],
|
||||
'category_type': 'movie'
|
||||
}
|
||||
)
|
||||
|
||||
# Get movies
|
||||
|
|
@ -69,12 +73,24 @@ def refresh_movies(account):
|
|||
category = None
|
||||
if movie_data.get('category_id'):
|
||||
try:
|
||||
category = VODCategory.objects.get(
|
||||
name__icontains=movie_data.get('category_name', ''),
|
||||
m3u_account=account
|
||||
)
|
||||
except VODCategory.DoesNotExist:
|
||||
pass
|
||||
# First try exact match by category_id if available
|
||||
category = VODCategory.objects.filter(
|
||||
m3u_account=account,
|
||||
category_type='movie'
|
||||
).filter(
|
||||
name__iexact=movie_data.get('category_name', '')
|
||||
).first()
|
||||
|
||||
# If no exact match, try contains but limit to first result
|
||||
if not category and movie_data.get('category_name'):
|
||||
category = VODCategory.objects.filter(
|
||||
name__icontains=movie_data.get('category_name', ''),
|
||||
m3u_account=account,
|
||||
category_type='movie'
|
||||
).first()
|
||||
except Exception as e:
|
||||
logger.warning(f"Error finding category for movie {movie_data.get('name', 'Unknown')}: {e}")
|
||||
category = None
|
||||
|
||||
# Create/update movie
|
||||
stream_url = f"{account.server_url}/movie/{account.username}/{account.password}/{movie_data['stream_id']}.{movie_data.get('container_extension', 'mp4')}"
|
||||
|
|
@ -137,7 +153,11 @@ def refresh_series(account):
|
|||
VODCategory.objects.get_or_create(
|
||||
name=cat_data['category_name'],
|
||||
m3u_account=account,
|
||||
defaults={'name': cat_data['category_name']}
|
||||
category_type='series',
|
||||
defaults={
|
||||
'name': cat_data['category_name'],
|
||||
'category_type': 'series'
|
||||
}
|
||||
)
|
||||
|
||||
# Get series list
|
||||
|
|
@ -154,12 +174,24 @@ def refresh_series(account):
|
|||
category = None
|
||||
if series_item.get('category_id'):
|
||||
try:
|
||||
category = VODCategory.objects.get(
|
||||
name__icontains=series_item.get('category_name', ''),
|
||||
m3u_account=account
|
||||
)
|
||||
except VODCategory.DoesNotExist:
|
||||
pass
|
||||
# First try exact match
|
||||
category = VODCategory.objects.filter(
|
||||
m3u_account=account,
|
||||
category_type='series'
|
||||
).filter(
|
||||
name__iexact=series_item.get('category_name', '')
|
||||
).first()
|
||||
|
||||
# If no exact match, try contains but limit to first result
|
||||
if not category and series_item.get('category_name'):
|
||||
category = VODCategory.objects.filter(
|
||||
name__icontains=series_item.get('category_name', ''),
|
||||
m3u_account=account,
|
||||
category_type='series'
|
||||
).first()
|
||||
except Exception as e:
|
||||
logger.warning(f"Error finding category for series {series_item.get('name', 'Unknown')}: {e}")
|
||||
category = None
|
||||
|
||||
# Create/update series
|
||||
series_data_dict = {
|
||||
|
|
|
|||
|
|
@ -789,7 +789,6 @@ export default class API {
|
|||
errorNotification('Failed to refresh M3U account', e);
|
||||
}
|
||||
}
|
||||
|
||||
static async refreshAllPlaylist() {
|
||||
try {
|
||||
const response = await request(`${host}/api/m3u/refresh/`, {
|
||||
|
|
@ -801,6 +800,16 @@ export default class API {
|
|||
errorNotification('Failed to refresh all M3U accounts', e);
|
||||
}
|
||||
}
|
||||
static async refreshVODContent(accountId) {
|
||||
try {
|
||||
const response = await request(`${host}/api/m3u/accounts/${accountId}/refresh-vod/`, {
|
||||
method: 'POST'
|
||||
});
|
||||
return response;
|
||||
} catch (e) {
|
||||
errorNotification('Failed to refresh VOD content', e);
|
||||
}
|
||||
}
|
||||
|
||||
static async deletePlaylist(id) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ export default function M3URefreshNotification() {
|
|||
case 'processing_groups':
|
||||
message = 'Group parsing';
|
||||
break;
|
||||
|
||||
case 'vod_refresh':
|
||||
message = 'VOD content refresh';
|
||||
break;
|
||||
}
|
||||
|
||||
if (taskProgress == 0) {
|
||||
|
|
@ -143,6 +147,9 @@ export default function M3URefreshNotification() {
|
|||
fetchChannelGroups();
|
||||
fetchEPGData();
|
||||
fetchPlaylists();
|
||||
} else if (data.action == 'vod_refresh') {
|
||||
// VOD refresh completed, could trigger additional UI updates if needed
|
||||
fetchPlaylists(); // Refresh playlist data to show updated VOD info
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ const M3U = ({
|
|||
username: '',
|
||||
password: '',
|
||||
stale_stream_days: 7,
|
||||
enable_vod: false,
|
||||
},
|
||||
|
||||
validate: {
|
||||
|
|
@ -86,6 +87,7 @@ const M3U = ({
|
|||
username: m3uAccount.username ?? '',
|
||||
password: '',
|
||||
stale_stream_days: m3uAccount.stale_stream_days !== undefined && m3uAccount.stale_stream_days !== null ? m3uAccount.stale_stream_days : 7,
|
||||
enable_vod: m3uAccount.enable_vod || false,
|
||||
});
|
||||
|
||||
if (m3uAccount.account_type == 'XC') {
|
||||
|
|
@ -256,6 +258,19 @@ const M3U = ({
|
|||
</Group>
|
||||
)}
|
||||
|
||||
<Group justify="space-between">
|
||||
<Box>Enable VOD Scanning</Box>
|
||||
<Switch
|
||||
id="enable_vod"
|
||||
name="enable_vod"
|
||||
description="Scan and import VOD content (movies/series) from this Xtream account"
|
||||
key={form.key('enable_vod')}
|
||||
{...form.getInputProps('enable_vod', {
|
||||
type: 'checkbox',
|
||||
})}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
<TextInput
|
||||
id="username"
|
||||
name="username"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue