From bd49b9c70ed7e1e9a1be116e524e5b1250cfd826 Mon Sep 17 00:00:00 2001 From: Mike0001-droid Date: Fri, 28 Jun 2024 16:20:43 +0500 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D0=B1?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D1=88=D0=BE=D0=B9=20=D1=80=D0=B5=D1=84=D0=B0?= =?UTF-8?q?=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/proj/audio/admin.py | 1 + server/proj/audio/models.py | 7 ++ server/proj/audio/schemas.py | 6 -- server/proj/audio/service.py | 46 ++++++++- server/proj/audio/views.py | 184 +++++++++++------------------------ 5 files changed, 107 insertions(+), 137 deletions(-) diff --git a/server/proj/audio/admin.py b/server/proj/audio/admin.py index 1de4243..1130bbd 100644 --- a/server/proj/audio/admin.py +++ b/server/proj/audio/admin.py @@ -7,6 +7,7 @@ class SongAdmin(admin.ModelAdmin): exclude = ('azura_id',) readonly_fields = ['slug'] + @admin.register(FavoriteSong) class FavoriteSongAdmin(admin.ModelAdmin): list_display = ('id', 'song', 'user') diff --git a/server/proj/audio/models.py b/server/proj/audio/models.py index c2d28d7..68e2c11 100644 --- a/server/proj/audio/models.py +++ b/server/proj/audio/models.py @@ -1,6 +1,7 @@ from django.db import models from account.models import MyUser from django.template.defaultfilters import slugify +from audio.service import AzuraCast class Song(models.Model): unique_id = models.CharField('ID трека для плеера', max_length=255, blank=True, null=True) @@ -25,6 +26,11 @@ class Song(models.Model): unique_together = ('azura_id', ) verbose_name_plural = 'Треки' + def delete(self): + azura = AzuraCast() + azura.delete_song(self.azura_id) + super(Song, self).delete() + class FavoriteSong(models.Model): song = models.ForeignKey(Song, verbose_name='Трек', on_delete=models.CASCADE, null=True, blank=True) @@ -48,6 +54,7 @@ class PlayList(models.Model): class Meta: verbose_name = 'Плейлисты' + unique_together = ('name', 'user') verbose_name_plural = 'Плейлисты' class Podkast(models.Model): diff --git a/server/proj/audio/schemas.py b/server/proj/audio/schemas.py index e47a7d5..7c723a2 100644 --- a/server/proj/audio/schemas.py +++ b/server/proj/audio/schemas.py @@ -63,12 +63,6 @@ class PlayListSchema(AutoSchema): required=False, schema=coreschema.String(description='Название плейлиста') ), - coreapi.Field( - name='playlist_id', - location='form', - required=False, - schema=coreschema.Integer(description='ID плейлиста') - ), coreapi.Field( name='playlist_art', location='form', diff --git a/server/proj/audio/service.py b/server/proj/audio/service.py index b9caaa6..9ab297c 100644 --- a/server/proj/audio/service.py +++ b/server/proj/audio/service.py @@ -1,25 +1,61 @@ from conf.settings import AZURACAST_URL, AZURACAST_API_KEY import requests +from django.http import HttpResponse - -def authorize_url(url): +def authorize_url(method, url): file_url = url API_KEY = AZURACAST_API_KEY headers = { "Authorization": f"Bearer {API_KEY}" } - return requests.get(file_url, headers=headers) + return requests.request(method, file_url, headers=headers) class AzuraCast: api_key = AZURACAST_API_KEY url = AZURACAST_URL + @staticmethod + def get_nowplaying(): + file_url = F"{AZURACAST_URL}api/nowplaying/it-radio" + response = authorize_url("get", file_url) + return response.json() + + @staticmethod + def get_all_songs(): + file_url = F"{AZURACAST_URL}api/station/1/files" + response = authorize_url("get", file_url) + data = [] + for i in response.json(): + i['azura_id'] = i.pop('song_id') + data.append(i) + return data + @staticmethod def add_to_playlist(azura_id, data): file_url = f"{AZURACAST_URL}api/station/it-radio/file/{azura_id}" - response = authorize_url(file_url) + response = authorize_url("get", file_url) file_play = f"{AZURACAST_URL}api/station/it-radio/file/{response.json()['unique_id']}/play" data.update(unique_id=file_play) return data - \ No newline at end of file + @staticmethod + def delete_song(azura_id): + file_url = f"{AZURACAST_URL}api/station/it-radio/file/{azura_id}" + response = authorize_url("delete", file_url) + return response + + @staticmethod + def get_audio(song_obj, unique_id): + file_url = f"{AZURACAST_URL}/api/station/it-radio/file/{unique_id}/play" + response = authorize_url("get", file_url) + file_response = HttpResponse(response.content, content_type='audio/mpeg') + file = f'{song_obj.title}-{song_obj.artist}.mp3' + file_response['Content-Disposition'] = f'attachment; filename={file}' + return file_response + + @staticmethod + def get_unique_id(azura_id): + file_url = f"{AZURACAST_URL}api/station/it-radio/file/{azura_id}" + response = authorize_url("get", file_url) + return response.json()['unique_id'] + diff --git a/server/proj/audio/views.py b/server/proj/audio/views.py index 8f53713..371e8cf 100644 --- a/server/proj/audio/views.py +++ b/server/proj/audio/views.py @@ -1,39 +1,28 @@ -from django.shortcuts import render -from rest_framework.viewsets import ViewSet, GenericViewSet +from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework.decorators import action from rest_framework import status -from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned -from django.shortcuts import get_object_or_404, get_list_or_404 +from django.core.exceptions import ObjectDoesNotExist from rest_framework.permissions import IsAuthenticated, AllowAny from audio.service import AzuraCast -from django.http import HttpResponse -import requests from audio.schemas import SongSchema, DeleteSongSchema, PlayListSchema from audio.models import Song, FavoriteSong, PlayList, Podkast from audio.serializers import SongSerializer, FavoriteSongSerializer, PlayListSerializer, PodkastSerializer -from conf.settings.base import AZURACAST_URL, AZURACAST_API_KEY -def authorize_url(url): - file_url = url - API_KEY = AZURACAST_API_KEY - headers = { - "Authorization": f"Bearer {API_KEY}" - } - return requests.get(file_url, headers=headers) + class PodkastViewSet(GenericViewSet): - queryset = Podkast + queryset = Podkast.objects.all() serializer_class = PodkastSerializer permission_classes = (IsAuthenticated, ) def list(self, request): - queryset = self.get_queryset().objects.all() + queryset = self.get_queryset() serializer = self.get_serializer(queryset, many=True) return Response(serializer.data, status=status.HTTP_200_OK) def retrieve(self, request, pk): try: - queryset = self.get_queryset().objects.get(pk=pk) + queryset = self.get_queryset().get(pk=pk) serializer = self.get_serializer(queryset) return Response(serializer.data, status=status.HTTP_200_OK) except ObjectDoesNotExist: @@ -41,20 +30,20 @@ class PodkastViewSet(GenericViewSet): {'detail': 'Объекта не существует', 'error': {'PlayList': 'Объекта не существует'}}, status=status.HTTP_404_NOT_FOUND) - class PlayListViewSet(GenericViewSet): azura = AzuraCast() queryset = PlayList.objects.all() serializer_class = PlayListSerializer permission_classes = (IsAuthenticated,) + def list(self, request): - queryset = self.get_queryset().objects.filter(user=request.user) + queryset = self.get_queryset().filter(user=request.user) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data, status=status.HTTP_200_OK) def retrieve(self, request, pk): try: - queryset = self.get_queryset().objects.get(pk=pk, user=request.user) + queryset = self.get_queryset().get(pk=pk, user=request.user) serializer = self.get_serializer(queryset) return Response(serializer.data, status=status.HTTP_200_OK) except ObjectDoesNotExist: @@ -65,18 +54,12 @@ class PlayListViewSet(GenericViewSet): @action(detail=False, methods=['post'], schema=PlayListSchema()) def create_playlist(self, request): if request.data.get('name', False): - try: - instance = self.get_queryset().objects.get(pk=request.data['playlist_id'], user=request.user.pk) - data = request.data - data.update(user=request.user.pk) - serializer = self.get_serializer(data=request.data, instance=instance) - serializer.is_valid(raise_exception=True) - serializer.save() - return Response(serializer.data) - except ObjectDoesNotExist: - return Response( - {'detail': 'Объекта не существует', 'error': {'PlayList': 'Объекта не существует'}}, - status=status.HTTP_404_NOT_FOUND) + data = request.data + data.update(user=request.user.pk) + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response(serializer.data) else: playlist_pk = self.get_queryset().objects.filter(user=request.user.pk) name = f"Плейлист № {len(playlist_pk)+1}" @@ -87,35 +70,25 @@ class PlayListViewSet(GenericViewSet): serializer.save() return Response(serializer.data) - @action(detail=False, methods=['post'], schema=PlayListSchema()) - def update_playlist(self, request): - try: - instance = self.get_queryset().objects.get(pk=request.data['playlist_id'], user=request.user.pk) - serializer = self.get_serializer(data=request.data, partial=True, instance=instance) - serializer.is_valid(raise_exception=True) - serializer.save() - return Response(serializer.data) - except ObjectDoesNotExist: - return Response( - {'detail': 'Объекта не существует', 'error': {'PlayList': 'Объекта не существует'}}, - status=status.HTTP_404_NOT_FOUND) + @action(detail=True, methods=['post'], schema=PlayListSchema()) + def update_playlist(self, request, *args, **kwargs): + instance = self.get_object() + serializer = self.get_serializer(data=request.data, partial=True, instance=instance) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response(serializer.data) - @action(detail=False, methods=['post'], schema=PlayListSchema()) - def delete_playlist(self, request): - try: - item = self.get_queryset().objects.get(user=request.user, pk=request.data.get('playlist_id')) - item.delete() - return Response(status=status.HTTP_202_ACCEPTED) - except ObjectDoesNotExist: - return Response( - {'detail': 'Объекта не существует', 'error': {'PlayList': 'Объекта не существует'}}, - status=status.HTTP_404_NOT_FOUND) + @action(detail=True, methods=['post']) + def delete_playlist(self, request, *args, **kwargs): + item = self.get_object() + item.delete() + return Response({'detail': 'Объект удалён'}, status=status.HTTP_200_OK) - @action(detail=False, methods=['post'], schema=PlayListSchema()) - def delete_song_with_playlist(self, request): + @action(detail=True, methods=['post'], schema=PlayListSchema()) + def delete_song_with_playlist(self, request, *args, **kwargs): try: song = Song.objects.get(azura_id=request.data.get('azura_id')) - item = self.get_queryset().objects.get(user=request.user, pk=request.data.get('playlist_id')) + item = self.get_object() item.song.remove(song) return Response({'detail': 'Объект удалён'}, status=status.HTTP_200_OK) except ObjectDoesNotExist: @@ -123,7 +96,6 @@ class PlayListViewSet(GenericViewSet): {'detail': 'Объекта не существует', 'error': {'PlayList': 'Объекта не существует'}}, status=status.HTTP_404_NOT_FOUND) - @action(detail=True, methods=['post'], schema=PlayListSchema()) def add_to_playlist(self, request, *args, **kwargs): song = None @@ -134,77 +106,54 @@ class PlayListViewSet(GenericViewSet): song_serializer = SongSerializer(data=data) if song_serializer.is_valid(): song_serializer.save() - song = song_serializer.data + song = song_serializer.data['id'] instance = self.get_object() instance.song.add(song) serializer = self.get_serializer(instance) return Response(serializer.data) - - + class SongViewSet(GenericViewSet): - queryset = Song + azura = AzuraCast() + queryset = Song.objects.all() serializer_class = SongSerializer permission_classes = (IsAuthenticated,) + lookup_field = 'azura_id' - def list(self, request): songs_pk = FavoriteSong.objects.filter(user=request.user, song__isnull=False).values_list('song_id', flat=True) - songs = self.get_queryset().objects.filter(id__in=songs_pk) + songs = self.get_queryset().filter(id__in=songs_pk) serializer = self.get_serializer(songs, many=True) return Response(serializer.data) - @action( - detail=False, - methods=['get'], - url_path='check_is_favorite/(?P[a-zA-Z0-9_]+)', - url_name='check_is_favorite', - ) - def check_is_favorite(self, request, azura_id): + @action(detail=True, methods=['get']) + def check_is_favorite(self, request, *args, **kwargs): try: - song_obj = self.get_queryset().objects.get(azura_id=azura_id) + song_obj = self.get_object() favorite_songs = FavoriteSong.objects.get(user=request.user, song=song_obj) return Response({"is_favorite": True}, status=status.HTTP_200_OK) except ObjectDoesNotExist: return Response({"is_favorite": False}, status=status.HTTP_200_OK) - @action( - detail=False, - methods=['get'], - url_path='get_audio/(?P[a-zA-Z0-9_]+)', - url_name='get_audio', - ) - def get_audio(self, request, azura_id): - try: - song_obj = self.get_queryset().objects.get(azura_id=azura_id) - file_url = song_obj.unique_id - response = authorize_url(file_url) - response.raise_for_status() - - file_response = HttpResponse(response.content, content_type='audio/mpeg') - file = f'{song_obj.title}-{song_obj.artist}.mp3' - file_response['Content-Disposition'] = f'attachment; filename={file}' - return file_response - - except ObjectDoesNotExist: - return Response({"error": 'Объекта не существует'}, status=status.HTTP_404_NOT_FOUND) - - - - @action(detail=False, methods=['post'], schema=SongSchema()) - def add_favorite(self, request): + @action(detail=True, methods=['get']) + def get_audio(self, request, *args, **kwargs): + song_obj = self.get_object() + unique_id = song_obj.unique_id + response = self.azura.get_audio(song_obj, unique_id) + return response + + @action(detail=True, methods=['post'], schema=SongSchema()) + def add_favorite(self, request, *args, **kwargs): data = None try: - song = self.get_queryset().objects.get(azura_id=request.data.get('azura_id')) + song = self.get_queryset().get(kwargs.get('azura_id')) data = { "song": song.pk, "user": request.user.pk } except ObjectDoesNotExist: - file_url = f"{AZURACAST_URL}api/station/it-radio/file/{request.data['azura_id']}" - response = authorize_url(file_url) + unique_id = self.azura.get_unique_id(kwargs.get('azura_id')) data = request.data - file_play = f"{AZURACAST_URL}/api/station/it-radio/file/{response.json()['unique_id']}/play" - data.update(unique_id=file_play) + data.update(unique_id=unique_id) serializer = self.get_serializer(data=data) if serializer.is_valid(): serializer.save() @@ -219,34 +168,17 @@ class SongViewSet(GenericViewSet): else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - @action(detail=False, methods=['post'], schema=DeleteSongSchema()) + @action(detail=False, methods=['post']) def delete_song(self, request): - try: - song = self.get_queryset().objects.get(azura_id=request.data.get('azura_id')) - item = FavoriteSong.objects.get(user=request.user, song=song.pk) - item.delete() - return Response(status=status.HTTP_202_ACCEPTED) - except ObjectDoesNotExist: - return Response({"error": 'Объекта не существует'}, status=status.HTTP_404_NOT_FOUND) + song = self.get_object() + item = FavoriteSong.objects.get(user=request.user, song=song.pk) + item.delete() + return Response(status=status.HTTP_202_ACCEPTED) @action(detail=False, methods=['get']) def get_all_song(self, request): - file_url = F"{AZURACAST_URL}api/station/1/files" - response = authorize_url(file_url) - data = [] - for i in response.json(): - i['azura_id'] = i.pop('song_id') - data.append(i) - return Response(data, status=status.HTTP_200_OK) + return Response(self.azura.get_all_songs(), status=status.HTTP_200_OK) @action(detail=False, methods=['get'], permission_classes=(AllowAny,)) def get_nowplaying(self, request): - file_url = F"{AZURACAST_URL}api/nowplaying/it-radio" - response = authorize_url(file_url) - return Response(response.json(), status=status.HTTP_200_OK) - - - - - - \ No newline at end of file + return Response(self.azura.get_nowplaying(), status=status.HTTP_200_OK)