diff --git a/apps/video/serializers.py b/apps/video/serializers.py index daffbbd..cf1ac97 100644 --- a/apps/video/serializers.py +++ b/apps/video/serializers.py @@ -21,15 +21,19 @@ class VideoListSerializer(serializers.ModelSerializer): video_file = serializers.SerializerMethodField() share_link = serializers.CharField(read_only=True) video_time = serializers.SerializerMethodField() + total_time_formatted = serializers.SerializerMethodField() class Meta: model = Video fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'video_type', - 'video_file', 'video_url', 'video_time', 'view_count', 'created_at', 'share_link'] + 'video_file', 'video_url', 'video_time', 'view_count', 'created_at', 'share_link', 'total_time_formatted'] def get_thumbnail(self, obj): return get_thumbs(obj.thumbnail, self.context.get('request')) + def get_total_time_formatted(self, obj): + return format_media_time(obj.video_time) + def get_video_file(self, obj): """Get full URL for video file if it exists""" if obj.video_file: @@ -45,15 +49,19 @@ class VideoListSerializer(serializers.ModelSerializer): class VideoPlaylistListSerializer(serializers.ModelSerializer): thumbnail = serializers.SerializerMethodField() + video_time = serializers.SerializerMethodField() total_time_formatted = serializers.SerializerMethodField() class Meta: model = VideoPlaylist - fields = ['id', 'title', 'slug', 'thumbnail', 'slogan', 'view_count', 'total_time_formatted', 'order', 'created_at'] + fields = ['id', 'title', 'slug', 'thumbnail', 'slogan', 'view_count', 'video_time', 'total_time_formatted', 'order', 'created_at'] def get_thumbnail(self, obj): return get_thumbs(obj.thumbnail, self.context.get('request')) + def get_video_time(self, obj): + return format_duration(obj.total_time) + def get_total_time_formatted(self, obj): return format_duration(obj.total_time) @@ -68,17 +76,21 @@ class VideoPlaylistDetailSerializer(serializers.ModelSerializer): user_rate = serializers.SerializerMethodField() average_rate = serializers.SerializerMethodField() videos = serializers.SerializerMethodField() + video_time = serializers.SerializerMethodField() total_time_formatted = serializers.SerializerMethodField() class Meta: model = VideoPlaylist fields = ['id', 'title', 'slug', 'thumbnail', 'slogan', 'description', - 'view_count', 'total_time_formatted', 'order', 'status', + 'view_count', 'video_time', 'total_time_formatted', 'order', 'status', 'categories', 'created_at', 'user_rate', 'average_rate', 'bookmark', 'videos'] def get_thumbnail(self, obj): return get_thumbs(obj.thumbnail, self.context.get('request')) + def get_video_time(self, obj): + return format_duration(obj.total_time) + def get_total_time_formatted(self, obj): return format_duration(obj.total_time) @@ -147,16 +159,20 @@ class VideoDetailSerializer(serializers.ModelSerializer): playlist_videos = serializers.SerializerMethodField() share_link = serializers.CharField(read_only=True) video_time = serializers.SerializerMethodField() + total_time_formatted = serializers.SerializerMethodField() class Meta: model = Video fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'video_type', 'video_file', 'video_url', 'video_time', 'view_count', 'categories', 'created_at', 'user_rate', 'average_rate', 'bookmark', - 'is_in_playlist', 'playlist_videos', 'share_link', 'video_time'] + 'is_in_playlist', 'playlist_videos', 'share_link', 'video_time', 'total_time_formatted'] def get_video_time(self, obj): - return format_media_time(obj.video_time) + return format_media_time(obj.video_time) + + def get_total_time_formatted(self, obj): + return format_media_time(obj.video_time) def get_thumbnail(self, obj): return get_thumbs(obj.thumbnail, self.context.get('request')) diff --git a/apps/video/views.py b/apps/video/views.py index 1fbea2e..94b92ae 100644 --- a/apps/video/views.py +++ b/apps/video/views.py @@ -286,13 +286,13 @@ class VideoListAPIView(generics.ListAPIView): """ API view to list all video playlists, with optional filtering by category or collection """ - serializer_class = VideoListSerializer + serializer_class = VideoPlaylistListSerializer permission_classes = (IsAuthenticated,) authentication_classes = [TokenAuthentication] pagination_class = StandardResultsSetPagination @swagger_auto_schema( - operation_description="Get a list of videos with optional filtering", + operation_description="Get a list of video playlists with optional filtering", tags=["Dobodbi - Video"], manual_parameters=[ openapi.Parameter( @@ -322,6 +322,13 @@ class VideoListAPIView(generics.ListAPIView): description='Search playlists by title', type=openapi.TYPE_STRING, required=False + ), + openapi.Parameter( + name='sort', + in_=openapi.IN_QUERY, + description='Sort playlists by field. Options: created_at, -created_at, view_count, -view_count, title, -title, order, -order', + type=openapi.TYPE_STRING, + required=False ) ], responses={ @@ -335,7 +342,7 @@ class VideoListAPIView(generics.ListAPIView): return super().get(request, *args, **kwargs) def get_queryset(self): - queryset = Video.objects.filter(status=True).order_by('-created_at') + queryset = VideoPlaylist.objects.filter(status=True).order_by('order', '-created_at') # Search by title if search parameter is provided search_query = self.request.query_params.get('search', None) @@ -345,36 +352,35 @@ class VideoListAPIView(generics.ListAPIView): # Filter by category if provided category_slug = self.request.query_params.get('category', None) if category_slug: - queryset = queryset.filter(playlist_appearances__playlist__categories__slug=category_slug) + queryset = queryset.filter(categories__slug=category_slug) # Filter by collection if provided collection_slug = self.request.query_params.get('collection', None) if collection_slug: - queryset = queryset.filter(playlist_appearances__playlist__collections__slug=collection_slug) + queryset = queryset.filter(collections__slug=collection_slug) is_bookmark = self.request.query_params.get('is_bookmark', '').lower() if is_bookmark == 'true': # Import Bookmark model here to avoid circular imports from apps.bookmark.models import Bookmark - # Get all bookmarked video IDs for the current user + # Get all bookmarked playlist IDs for the current user bookmarked_ids = Bookmark.objects.filter( user=self.request.user, - service=Bookmark.ServiceChoices.VIDEO, + service=Bookmark.ServiceChoices.VIDEO_PLAYLIST, status=True ).values_list('content_id', flat=True) - # Filter videos by these IDs + # Filter playlists by these IDs queryset = queryset.filter(id__in=bookmarked_ids) sort = self.request.query_params.get('sort', '-created_at') allowed_sorts = [ 'created_at', '-created_at', 'view_count', '-view_count', - 'title', '-title', - 'total_time', '-total_time','-created_at','created_at' + 'title', '-title', 'order', '-order', + 'total_time', '-total_time' ] if sort in allowed_sorts: - # Handle multiple sort fields (e.g., '-pin,-created_at') if ',' in sort: queryset = queryset.order_by(*sort.split(',')) else: @@ -382,7 +388,7 @@ class VideoListAPIView(generics.ListAPIView): else: queryset = queryset.order_by('-created_at') - return queryset.distinct() + return queryset class VideoPlaylistDetailAPIView(generics.RetrieveAPIView): @@ -415,7 +421,7 @@ class VideoPlaylistDetailAPIView(generics.RetrieveAPIView): class VideoDetailAPIView(Gone410ViewMixin, CanonicalSlugViewSetMixin, generics.RetrieveAPIView): - serializer_class = VideoDetailSerializer + serializer_class = VideoPlaylistDetailSerializer permission_classes = (IsAuthenticated,) authentication_classes = [TokenAuthentication] lookup_field = 'slug' @@ -424,12 +430,12 @@ class VideoDetailAPIView(Gone410ViewMixin, CanonicalSlugViewSetMixin, generics.R active_expected_value = True @swagger_auto_schema( - operation_description="Get video details by slug", + operation_description="Get video playlist details by slug", tags=["Dobodbi - Video"], responses={ 200: openapi.Response( - description="Video details", - schema=VideoDetailSerializer() + description="Video playlist details", + schema=VideoPlaylistDetailSerializer() ) } ) @@ -437,13 +443,13 @@ class VideoDetailAPIView(Gone410ViewMixin, CanonicalSlugViewSetMixin, generics.R return super().get(request, *args, **kwargs) def get_queryset(self): - return Video.objects.all() + return VideoPlaylist.objects.all() - # def retrieve(self, request, *args, **kwargs): - # instance = self.get_object() - # instance.increment_view_count() - # serializer = self.get_serializer(instance) - # return Response(serializer.data) + def retrieve(self, request, *args, **kwargs): + instance = self.get_object() + instance.increment_view_count() + serializer = self.get_serializer(instance) + return Response(serializer.data) class DovodiVideoCategoryViewSet(ModelViewSet):