111 lines
4.4 KiB
Python
111 lines
4.4 KiB
Python
|
|
"""Playlist API views"""
|
||
|
|
|
||
|
|
from django.shortcuts import get_object_or_404
|
||
|
|
from rest_framework import status
|
||
|
|
from rest_framework.response import Response
|
||
|
|
from playlist.models import Playlist, PlaylistItem
|
||
|
|
from playlist.serializers import PlaylistSerializer, PlaylistItemSerializer
|
||
|
|
from common.views import ApiBaseView, AdminWriteOnly
|
||
|
|
|
||
|
|
|
||
|
|
class PlaylistListView(ApiBaseView):
|
||
|
|
"""Playlist list endpoint"""
|
||
|
|
permission_classes = [AdminWriteOnly]
|
||
|
|
|
||
|
|
def get(self, request):
|
||
|
|
"""Get playlist list"""
|
||
|
|
playlists = Playlist.objects.filter(owner=request.user)
|
||
|
|
serializer = PlaylistSerializer(playlists, many=True)
|
||
|
|
return Response({'data': serializer.data})
|
||
|
|
|
||
|
|
def post(self, request):
|
||
|
|
"""Subscribe to playlist - TubeArchivist pattern with Celery task"""
|
||
|
|
from playlist.serializers import PlaylistSubscribeSerializer
|
||
|
|
import uuid
|
||
|
|
|
||
|
|
# Check playlist quota
|
||
|
|
if not request.user.can_add_playlist:
|
||
|
|
return Response(
|
||
|
|
{'error': f'Playlist limit reached. Maximum {request.user.max_playlists} playlists allowed.'},
|
||
|
|
status=status.HTTP_403_FORBIDDEN
|
||
|
|
)
|
||
|
|
|
||
|
|
# Check if it's a URL subscription
|
||
|
|
if 'url' in request.data:
|
||
|
|
url_serializer = PlaylistSubscribeSerializer(data=request.data)
|
||
|
|
url_serializer.is_valid(raise_exception=True)
|
||
|
|
playlist_url = request.data['url']
|
||
|
|
|
||
|
|
# Trigger async Celery task (TubeArchivist pattern)
|
||
|
|
from task.tasks import subscribe_to_playlist
|
||
|
|
task = subscribe_to_playlist.delay(request.user.id, playlist_url)
|
||
|
|
|
||
|
|
return Response(
|
||
|
|
{
|
||
|
|
'message': 'Playlist subscription task started',
|
||
|
|
'task_id': str(task.id)
|
||
|
|
},
|
||
|
|
status=status.HTTP_202_ACCEPTED
|
||
|
|
)
|
||
|
|
|
||
|
|
# Otherwise create custom playlist
|
||
|
|
# Auto-generate required fields for custom playlists
|
||
|
|
data = request.data.copy()
|
||
|
|
if 'playlist_id' not in data:
|
||
|
|
data['playlist_id'] = f'custom-{uuid.uuid4().hex[:12]}'
|
||
|
|
if 'title' not in data and 'name' in data:
|
||
|
|
data['title'] = data['name']
|
||
|
|
if 'playlist_type' not in data:
|
||
|
|
data['playlist_type'] = 'custom'
|
||
|
|
|
||
|
|
serializer = PlaylistSerializer(data=data)
|
||
|
|
serializer.is_valid(raise_exception=True)
|
||
|
|
serializer.save(owner=request.user)
|
||
|
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||
|
|
|
||
|
|
|
||
|
|
class PlaylistDetailView(ApiBaseView):
|
||
|
|
"""Playlist detail endpoint"""
|
||
|
|
permission_classes = [AdminWriteOnly]
|
||
|
|
|
||
|
|
def get(self, request, playlist_id):
|
||
|
|
"""Get playlist details with items"""
|
||
|
|
playlist = get_object_or_404(Playlist, playlist_id=playlist_id, owner=request.user)
|
||
|
|
|
||
|
|
# Check if items are requested
|
||
|
|
include_items = request.query_params.get('include_items', 'false').lower() == 'true'
|
||
|
|
|
||
|
|
serializer = PlaylistSerializer(playlist)
|
||
|
|
response_data = serializer.data
|
||
|
|
|
||
|
|
if include_items:
|
||
|
|
# Get all playlist items with audio details
|
||
|
|
items = PlaylistItem.objects.filter(playlist=playlist).select_related('audio').order_by('position')
|
||
|
|
from audio.serializers import AudioSerializer
|
||
|
|
response_data['items'] = [{
|
||
|
|
'id': item.id,
|
||
|
|
'position': item.position,
|
||
|
|
'added_date': item.added_date,
|
||
|
|
'audio': AudioSerializer(item.audio).data
|
||
|
|
} for item in items]
|
||
|
|
|
||
|
|
return Response(response_data)
|
||
|
|
|
||
|
|
def post(self, request, playlist_id):
|
||
|
|
"""Trigger actions on playlist (e.g., download)"""
|
||
|
|
playlist = get_object_or_404(Playlist, playlist_id=playlist_id, owner=request.user)
|
||
|
|
action = request.data.get('action')
|
||
|
|
|
||
|
|
if action == 'download':
|
||
|
|
from task.tasks import download_playlist_task
|
||
|
|
download_playlist_task.delay(playlist.id)
|
||
|
|
return Response({'detail': 'Download task started'}, status=status.HTTP_202_ACCEPTED)
|
||
|
|
|
||
|
|
return Response({'detail': 'Invalid action'}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
|
|
||
|
|
def delete(self, request, playlist_id):
|
||
|
|
"""Delete playlist"""
|
||
|
|
playlist = get_object_or_404(Playlist, playlist_id=playlist_id, owner=request.user)
|
||
|
|
playlist.delete()
|
||
|
|
return Response(status=status.HTTP_204_NO_CONTENT)
|