from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404, CreateAPIView, DestroyAPIView from rest_framework.views import APIView from rest_framework.response import Response from marietje.api.openapi import CustomAutoSchema from marietje.api.permissions import IsAuthenticatedOrTokenHasScopeForMethod from django.http import Http404 from queues.api.v1.serializers import PlaylistSerializer, QueueSerializer, PlaylistSongSerializer from queues.exceptions import RequestException from queues.models import Playlist, PlaylistSong, QueueCommand from queues.services import get_user_or_default_queue from songs.counters import request_counter from songs.models import Song class PlaylistListAPIView(ListAPIView): serializer_class = PlaylistSerializer queryset = Playlist.objects.all() permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = {"GET": ["read"]} class PlaylistRetrieveAPIView(RetrieveAPIView): serializer_class = PlaylistSerializer queryset = Playlist.objects.all() permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = {"GET": ["read"]} class QueueAPIView(APIView): serializer_class = QueueSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = {"GET": ["read"]} schema = CustomAutoSchema( response_schema={ "type": "object", "properties": { "id": {"type": "int", "example": 1}, "name": {"type": "string", "example": "string"}, "playlist": {"type": "int", "example": 1}, "random_playlist": {"type": "int", "example": 1}, "current_song": {"$ref": "#/components/schemas/PlaylistSong"}, "queue": {"type": "array", "items": {"$ref": "#/components/schemas/PlaylistSong"}}, "started_at": {"type": "string", "format": "date-time", "nullable": True}, }, } ) def get(self, request, **kwargs): queue = get_user_or_default_queue(request) if queue is None: raise Http404() return Response(status=200, data=self.serializer_class(queue).data) class QueueSkipAPIView(APIView): serializer_class = QueueSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "POST": ["write"], } schema = CustomAutoSchema( response_schema={ "type": "object", "properties": { "id": {"type": "int", "example": 1}, "name": {"type": "string", "example": "string"}, "playlist": {"type": "int", "example": 1}, "random_playlist": {"type": "int", "example": 1}, "current_song": {"$ref": "#/components/schemas/PlaylistSong"}, "queue": {"type": "array", "items": {"$ref": "#/components/schemas/PlaylistSong"}}, "started_at": {"type": "string", "format": "date-time", "nullable": True}, }, } ) def post(self, request, **kwargs): queue = get_user_or_default_queue(request) if queue is None: return Response(status=404) playlist_song = request.user.queue.current_song() if ( request.user is not None and playlist_song.user != request.user and not request.user.has_perm("queues.can_skip") ): return Response(status=403) playlist_song.state = 2 playlist_song.save() return Response(status=200, data=QueueSerializer(queue).data) class PlaylistSongMoveDownAPIView(APIView): serializer_class = PlaylistSongSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "PATCH": ["write"], } schema = CustomAutoSchema(response_schema={"$ref": "#/components/schemas/PlaylistSong"}) def patch(self, request, **kwargs): playlist_song_id = kwargs.get("id") playlist_song = get_object_or_404(PlaylistSong, id=playlist_song_id) if ( request.user is not None and playlist_song.user != request.user and not request.user.has_perm("queues.can_move") ): return Response(status=403) playlist_song.move_down() return Response(status=200, data=self.serializer_class(playlist_song).data) class PlaylistSongCancelAPIView(DestroyAPIView): serializer_class = PlaylistSongSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "DELETE": ["write"], } def delete(self, request, **kwargs): playlist_song_id = kwargs.get("id") playlist_song = get_object_or_404(PlaylistSong, id=playlist_song_id) if ( request.user is not None and playlist_song.user != request.user and not request.user.has_perm("queues.can_cancel") ): return Response(status=403) playlist_song.delete() return Response(status=200, data=self.serializer_class(playlist_song).data) class QueueRequestAPIView(CreateAPIView): serializer_class = PlaylistSongSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "POST": ["write"], } schema = CustomAutoSchema( request_schema={ "type": "object", "properties": { "song": {"type": "int", "example": 1}, }, } ) def post(self, request, **kwargs): queue = get_user_or_default_queue(request) if queue is None: return Response(status=404) song_id = request.data.get("song", None) if song_id is None: return Response(status=400, data={"success": False, "errorMessage": "Song ID not set."}) song = get_object_or_404(Song, id=song_id, deleted=False) try: playlist_song = queue.request(song, request.user) except RequestException as e: return Response(data={"success": False, "errorMessage": str(e)}) request_counter.labels(queue=queue.name).inc() return Response(status=200, data=self.serializer_class(playlist_song).data) class QueueVolumeDownAPIView(APIView): serializer_class = QueueSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "POST": ["write"], } schema = CustomAutoSchema( response_schema={ "type": "object", "properties": { "id": {"type": "int", "example": 1}, "name": {"type": "string", "example": "string"}, "playlist": {"type": "int", "example": 1}, "random_playlist": {"type": "int", "example": 1}, "current_song": {"$ref": "#/components/schemas/PlaylistSong"}, "queue": {"type": "array", "items": {"$ref": "#/components/schemas/PlaylistSong"}}, "started_at": {"type": "string", "format": "date-time", "nullable": True}, }, } ) def post(self, request, **kwargs): queue = get_user_or_default_queue(request) if queue is None: return Response(status=404) if request.user is not None and not request.user.has_perm("queues.can_control_volume"): return Response(status=403) QueueCommand.objects.create(queue=queue, command="volume_down") return Response(status=200, data=self.serializer_class(queue).data) class QueueVolumeUpAPIView(APIView): serializer_class = QueueSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "POST": ["write"], } schema = CustomAutoSchema( response_schema={ "type": "object", "properties": { "id": {"type": "int", "example": 1}, "name": {"type": "string", "example": "string"}, "playlist": {"type": "int", "example": 1}, "random_playlist": {"type": "int", "example": 1}, "current_song": {"$ref": "#/components/schemas/PlaylistSong"}, "queue": {"type": "array", "items": {"$ref": "#/components/schemas/PlaylistSong"}}, "started_at": {"type": "string", "format": "date-time", "nullable": True}, }, } ) def post(self, request, **kwargs): queue = get_user_or_default_queue(request) if queue is None: return Response(status=404) if request.user is not None and not request.user.has_perm("queues.can_control_volume"): return Response(status=403) QueueCommand.objects.create(queue=queue, command="volume_up") return Response(status=200, data=self.serializer_class(queue).data) class QueueMuteAPIView(APIView): serializer_class = QueueSerializer permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] required_scopes_for_method = { "POST": ["write"], } schema = CustomAutoSchema( response_schema={ "type": "object", "properties": { "id": {"type": "int", "example": 1}, "name": {"type": "string", "example": "string"}, "playlist": {"type": "int", "example": 1}, "random_playlist": {"type": "int", "example": 1}, "current_song": {"$ref": "#/components/schemas/PlaylistSong"}, "queue": {"type": "array", "items": {"$ref": "#/components/schemas/PlaylistSong"}}, "started_at": {"type": "string", "format": "date-time", "nullable": True}, }, } ) def post(self, request, **kwargs): queue = get_user_or_default_queue(request) if queue is None: return Response(status=404) if request.user is not None and not request.user.has_perm("queues.can_control_volume"): return Response(status=403) QueueCommand.objects.create(queue=queue, command="mute") return Response(status=200, data=self.serializer_class(queue).data)