Skip to content
Snippets Groups Projects
Verified Commit 57bf43bb authored by Eliot Berriot's avatar Eliot Berriot
Browse files

API Endpoint to list lirary tracks

parent bdf93479
No related branches found
No related tags found
No related merge requests found
...@@ -7,5 +7,9 @@ router.register( ...@@ -7,5 +7,9 @@ router.register(
r'libraries', r'libraries',
views.LibraryViewSet, views.LibraryViewSet,
'libraries') 'libraries')
router.register(
r'library-tracks',
views.LibraryTrackViewSet,
'library-tracks')
urlpatterns = router.urls urlpatterns = router.urls
...@@ -17,6 +17,20 @@ class LibraryFilter(django_filters.FilterSet): ...@@ -17,6 +17,20 @@ class LibraryFilter(django_filters.FilterSet):
} }
class LibraryTrackFilter(django_filters.FilterSet):
library = django_filters.CharFilter('library__uuid')
class Meta:
model = models.LibraryTrack
fields = {
'library': ['exact'],
'artist_name': ['exact', 'icontains'],
'title': ['exact', 'icontains'],
'album_title': ['exact', 'icontains'],
'audio_mimetype': ['exact', 'icontains'],
}
class FollowFilter(django_filters.FilterSet): class FollowFilter(django_filters.FilterSet):
ordering = django_filters.OrderingFilter( ordering = django_filters.OrderingFilter(
# tuple-mapping retains order # tuple-mapping retains order
......
...@@ -253,6 +253,29 @@ class APILibraryCreateSerializer(serializers.ModelSerializer): ...@@ -253,6 +253,29 @@ class APILibraryCreateSerializer(serializers.ModelSerializer):
return library return library
class APILibraryTrackSerializer(serializers.ModelSerializer):
library = APILibrarySerializer()
class Meta:
model = models.LibraryTrack
fields = [
'id',
'url',
'audio_url',
'audio_mimetype',
'creation_date',
'modification_date',
'fetched_date',
'published_date',
'metadata',
'artist_name',
'album_title',
'title',
'library',
'local_track_file',
]
class FollowSerializer(serializers.Serializer): class FollowSerializer(serializers.Serializer):
id = serializers.URLField() id = serializers.URLField()
object = serializers.URLField() object = serializers.URLField()
......
...@@ -2,6 +2,7 @@ import json ...@@ -2,6 +2,7 @@ import json
import logging import logging
from django.conf import settings from django.conf import settings
from django.utils import timezone
from requests.exceptions import RequestException from requests.exceptions import RequestException
...@@ -58,6 +59,9 @@ def scan_library(library, until=None): ...@@ -58,6 +59,9 @@ def scan_library(library, until=None):
data = lb.get_library_data(library.url) data = lb.get_library_data(library.url)
scan_library_page.delay( scan_library_page.delay(
library_id=library.id, page_url=data['first'], until=until) library_id=library.id, page_url=data['first'], until=until)
library.fetched_date = timezone.now()
library.tracks_count = data['totalItems']
library.save(update_fields=['fetched_date', 'tracks_count'])
@celery.app.task( @celery.app.task(
......
...@@ -14,6 +14,7 @@ from rest_framework.decorators import list_route, detail_route ...@@ -14,6 +14,7 @@ from rest_framework.decorators import list_route, detail_route
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from funkwhale_api.common import utils as funkwhale_utils from funkwhale_api.common import utils as funkwhale_utils
from funkwhale_api.common.permissions import HasModelPermission
from funkwhale_api.music.models import TrackFile from funkwhale_api.music.models import TrackFile
from . import activity from . import activity
...@@ -166,12 +167,16 @@ class MusicFilesViewSet(FederationMixin, viewsets.GenericViewSet): ...@@ -166,12 +167,16 @@ class MusicFilesViewSet(FederationMixin, viewsets.GenericViewSet):
return response.Response(data) return response.Response(data)
class LibraryPermission(HasModelPermission):
model = models.Library
class LibraryViewSet( class LibraryViewSet(
mixins.RetrieveModelMixin, mixins.RetrieveModelMixin,
mixins.UpdateModelMixin, mixins.UpdateModelMixin,
mixins.ListModelMixin, mixins.ListModelMixin,
viewsets.GenericViewSet): viewsets.GenericViewSet):
permission_classes = [rest_permissions.DjangoModelPermissions] permission_classes = [LibraryPermission]
queryset = models.Library.objects.all().select_related( queryset = models.Library.objects.all().select_related(
'actor', 'actor',
'follow', 'follow',
...@@ -184,6 +189,7 @@ class LibraryViewSet( ...@@ -184,6 +189,7 @@ class LibraryViewSet(
'creation_date', 'creation_date',
'fetched_date', 'fetched_date',
'actor__domain', 'actor__domain',
'tracks_count',
) )
@list_route(methods=['get']) @list_route(methods=['get'])
...@@ -203,11 +209,11 @@ class LibraryViewSet( ...@@ -203,11 +209,11 @@ class LibraryViewSet(
data=request.data data=request.data
) )
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
id = tasks.scan_library.delay( result = tasks.scan_library.delay(
library_id=library.pk, library_id=library.pk,
until=serializer.validated_data['until'] until=serializer.validated_data.get('until')
) )
return response.Response({'task': id}) return response.Response({'task': result.id})
@list_route(methods=['get']) @list_route(methods=['get'])
def following(self, request, *args, **kwargs): def following(self, request, *args, **kwargs):
...@@ -249,3 +255,26 @@ class LibraryViewSet( ...@@ -249,3 +255,26 @@ class LibraryViewSet(
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
library = serializer.save() library = serializer.save()
return response.Response(serializer.data, status=201) return response.Response(serializer.data, status=201)
class LibraryTrackViewSet(
mixins.ListModelMixin,
viewsets.GenericViewSet):
permission_classes = [LibraryPermission]
queryset = models.LibraryTrack.objects.all().select_related(
'library__actor',
'library__follow',
'local_track_file',
)
filter_class = filters.LibraryTrackFilter
serializer_class = serializers.APILibraryTrackSerializer
ordering_fields = (
'id',
'artist_name',
'title',
'album_title',
'creation_date',
'modification_date',
'fetched_date',
'published_date',
)
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.utils import timezone
from funkwhale_api.federation import serializers from funkwhale_api.federation import serializers
from funkwhale_api.federation import tasks from funkwhale_api.federation import tasks
...@@ -21,6 +22,7 @@ def test_scan_library_page_does_nothing_if_federation_disabled( ...@@ -21,6 +22,7 @@ def test_scan_library_page_does_nothing_if_federation_disabled(
def test_scan_library_fetches_page_and_calls_scan_page( def test_scan_library_fetches_page_and_calls_scan_page(
mocker, factories, r_mock): mocker, factories, r_mock):
now = timezone.now()
library = factories['federation.Library'](federation_enabled=True) library = factories['federation.Library'](federation_enabled=True)
collection_conf = { collection_conf = {
'actor': library.actor, 'actor': library.actor,
...@@ -39,6 +41,8 @@ def test_scan_library_fetches_page_and_calls_scan_page( ...@@ -39,6 +41,8 @@ def test_scan_library_fetches_page_and_calls_scan_page(
page_url=collection.data['first'], page_url=collection.data['first'],
until=None, until=None,
) )
library.refresh_from_db()
assert library.fetched_date > now
def test_scan_page_fetches_page_and_creates_tracks( def test_scan_page_fetches_page_and_creates_tracks(
......
...@@ -312,7 +312,7 @@ def test_can_patch_library(factories, superuser_api_client): ...@@ -312,7 +312,7 @@ def test_can_patch_library(factories, superuser_api_client):
def test_scan_library(factories, mocker, superuser_api_client): def test_scan_library(factories, mocker, superuser_api_client):
scan = mocker.patch( scan = mocker.patch(
'funkwhale_api.federation.tasks.scan_library.delay', 'funkwhale_api.federation.tasks.scan_library.delay',
return_value='id') return_value=mocker.Mock(id='id'))
library = factories['federation.Library']() library = factories['federation.Library']()
now = timezone.now() now = timezone.now()
data = { data = {
...@@ -329,3 +329,20 @@ def test_scan_library(factories, mocker, superuser_api_client): ...@@ -329,3 +329,20 @@ def test_scan_library(factories, mocker, superuser_api_client):
library_id=library.pk, library_id=library.pk,
until=now until=now
) )
def test_list_library_tracks(factories, superuser_api_client):
library = factories['federation.Library']()
lts = list(reversed(factories['federation.LibraryTrack'].create_batch(
size=5, library=library)))
factories['federation.LibraryTrack'].create_batch(size=5)
url = reverse('api:v1:federation:library-tracks-list')
response = superuser_api_client.get(url, {'library': library.uuid})
assert response.status_code == 200
assert response.data == {
'results': serializers.APILibraryTrackSerializer(lts, many=True).data,
'count': 5,
'previous': None,
'next': None,
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment