From 57432748a4d50c4fcd56d018dd38a64786ea102f Mon Sep 17 00:00:00 2001 From: kappa118 Date: Fri, 28 Feb 2025 14:08:05 -0500 Subject: [PATCH] added m3u profile support --- apps/m3u/api_urls.py | 12 +----------- apps/m3u/api_views.py | 17 +++++++++++------ apps/m3u/models.py | 33 +++++++++++++++++++++++++++++++++ apps/m3u/serializers.py | 11 +++++++---- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/apps/m3u/api_urls.py b/apps/m3u/api_urls.py index 5c216680..41fc2fbc 100644 --- a/apps/m3u/api_urls.py +++ b/apps/m3u/api_urls.py @@ -6,23 +6,13 @@ app_name = 'm3u' router = DefaultRouter() router.register(r'accounts', M3UAccountViewSet, basename='m3u-account') +router.register(r'accounts\/(?P\d+)\/profiles', M3UAccountProfileViewSet, basename='m3u-account-profiles') router.register(r'filters', M3UFilterViewSet, basename='m3u-filter') router.register(r'server-groups', ServerGroupViewSet, basename='server-group') -router.register(r'profiles', M3UAccountViewSet, basename='m3u-account-profiles') urlpatterns = [ path('refresh/', RefreshM3UAPIView.as_view(), name='m3u_refresh'), path('refresh//', RefreshSingleM3UAPIView.as_view(), name='m3u_refresh_single'), - path('m3u/accounts//profiles/', M3UAccountProfileViewSet.as_view({ - 'get': 'list', - 'post': 'create' - }), name='m3uaccountprofile-list'), - path('m3u/accounts//profiles//', M3UAccountProfileViewSet.as_view({ - 'get': 'retrieve', - 'put': 'update', - 'patch': 'partial_update', - 'delete': 'destroy' - }), name='m3uaccountprofile-detail'), ] urlpatterns += router.urls diff --git a/apps/m3u/api_views.py b/apps/m3u/api_views.py index 53ec9f9f..df9c13fc 100644 --- a/apps/m3u/api_views.py +++ b/apps/m3u/api_views.py @@ -70,6 +70,7 @@ class UserAgentViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] class M3UAccountProfileViewSet(viewsets.ModelViewSet): + queryset = M3UAccountProfile.objects.all() serializer_class = M3UAccountProfileSerializer permission_classes = [IsAuthenticated] @@ -78,10 +79,14 @@ class M3UAccountProfileViewSet(viewsets.ModelViewSet): return M3UAccountProfile.objects.filter(m3u_account_id=m3u_account_id) def perform_create(self, serializer): - m3u_account_id = self.kwargs['account_id'] - try: - m3u_account = M3UAccount.objects.get(id=m3u_account_id) - except M3UAccount.DoesNotExist: - raise NotFound(f'M3UAccount with id {m3u_account_id} not found.') + # Get the account ID from the URL + account_id = self.kwargs['account_id'] - serializer.save(m3u_account=m3u_account) + # Get the M3UAccount instance for the account_id + m3u_account = M3UAccount.objects.get(id=account_id) + + # Save the 'm3u_account' in the serializer context + serializer.context['m3u_account'] = m3u_account + + # Perform the actual save + serializer.save(m3u_account_id=m3u_account) diff --git a/apps/m3u/models.py b/apps/m3u/models.py index c878729e..3e1fd228 100644 --- a/apps/m3u/models.py +++ b/apps/m3u/models.py @@ -2,6 +2,7 @@ from django.db import models from django.core.exceptions import ValidationError from core.models import UserAgent import re +from django.dispatch import receiver class M3UAccount(models.Model): """Represents an M3U Account for IPTV streams.""" @@ -163,16 +164,25 @@ class M3UAccountProfile(models.Model): max_length=255, help_text="Name for the M3U account profile" ) + is_default = models.BooleanField( + default=False, + help_text="Set to false to deactivate this profile" + ) max_streams = models.PositiveIntegerField( default=0, help_text="Maximum number of concurrent streams (0 for unlimited)" ) + is_active = models.BooleanField( + default=True, + help_text="Set to false to deactivate this profile" + ) search_pattern = models.CharField( max_length=255, ) replace_pattern = models.CharField( max_length=255, ) + current_viewers = models.PositiveIntegerField(default=0) class Meta: constraints = [ @@ -181,3 +191,26 @@ class M3UAccountProfile(models.Model): def __str__(self): return f"{self.name} ({self.m3u_account.name})" + +@receiver(models.signals.post_save, sender=M3UAccount) +def create_profile_for_m3u_account(sender, instance, created, **kwargs): + """Automatically create an M3UAccountProfile when M3UAccount is created.""" + if created: + M3UAccountProfile.objects.create( + m3u_account=instance, + name=f'{instance.name} Default', + max_streams=instance.max_streams, + is_default=True, + is_active=True, + search_pattern="^(.*)$", + replace_pattern="$1", + ) + else: + profile = M3UAccountProfile.objects.get( + m3u_account=instance, + is_default=True, + ) + console.log(profile) + + profile.max_streams = instance.max_streams + profile.save() diff --git a/apps/m3u/serializers.py b/apps/m3u/serializers.py index 83afe225..fe2f598e 100644 --- a/apps/m3u/serializers.py +++ b/apps/m3u/serializers.py @@ -15,13 +15,16 @@ from .models import M3UAccountProfile class M3UAccountProfileSerializer(serializers.ModelSerializer): class Meta: model = M3UAccountProfile - fields = ['id', 'name', 'max_streams', 'search_pattern', 'replace_pattern'] + fields = ['id', 'name', 'max_streams', 'is_active', 'is_default', 'current_viewers', 'search_pattern', 'replace_pattern'] read_only_fields = ['id'] def create(self, validated_data): - # Get the account from the context and assign it directly - m3u_account = self.context['m3u_account'] - return M3UAccountProfile.objects.create(m3u_account=m3u_account, **validated_data) + m3u_account = self.context.get('m3u_account') + + # Use the m3u_account when creating the profile + validated_data['m3u_account_id'] = m3u_account.id + + return super().create(validated_data) class M3UAccountSerializer(serializers.ModelSerializer):