diff --git a/api/funkwhale_api/music/forms.py b/api/funkwhale_api/music/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..04e4bfe057c0723b161265c63000a2494c687a9d --- /dev/null +++ b/api/funkwhale_api/music/forms.py @@ -0,0 +1,23 @@ +from django import forms + +from . import models + + +class TranscodeForm(forms.Form): + FORMAT_CHOICES = [ + ('ogg', 'ogg'), + ('mp3', 'mp3'), + ] + + to = forms.ChoiceField(choices=FORMAT_CHOICES) + BITRATE_CHOICES = [ + (64, '64'), + (128, '128'), + (256, '256'), + ] + bitrate = forms.ChoiceField( + choices=BITRATE_CHOICES, required=False) + + track_file = forms.ModelChoiceField( + queryset=models.TrackFile.objects.all() + ) diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index 2395454c46429a5b48ccee7fe22e25bf39808318..8e46cbd71612f6b6d65563d136408efd4e0401ac 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -1,11 +1,16 @@ +import ffmpeg import os import json +import subprocess import unicodedata import urllib + from django.urls import reverse from django.db import models, transaction from django.db.models.functions import Length from django.conf import settings +from django.http import StreamingHttpResponse + from rest_framework import viewsets, views, mixins from rest_framework.decorators import detail_route, list_route from rest_framework.response import Response @@ -19,6 +24,7 @@ from funkwhale_api.common.permissions import ( ConditionalAuthentication, HasModelPermission) from taggit.models import Tag +from . import forms from . import models from . import serializers from . import importers @@ -183,6 +189,40 @@ class TrackFileViewSet(viewsets.ReadOnlyModelViewSet): f.audio_file.url) return response + @list_route(methods=['get']) + def viewable(self, request, *args, **kwargs): + return Response({}, status=200) + + @list_route(methods=['get']) + def transcode(self, request, *args, **kwargs): + form = forms.TranscodeForm(request.GET) + if not form.is_valid(): + return Response(form.errors, status=400) + + f = form.cleaned_data['track_file'] + output_kwargs = { + 'format': form.cleaned_data['to'] + } + args = (ffmpeg + .input(f.audio_file.path) + .output('pipe:', **output_kwargs) + .get_args() + ) + # we use a generator here so the view return immediatly and send + # file chunk to the browser, instead of blocking a few seconds + def _transcode(): + p = subprocess.Popen( + ['ffmpeg'] + args, + stdout=subprocess.PIPE) + for line in p.stdout: + yield line + + response = StreamingHttpResponse( + _transcode(), status=200, + content_type=form.cleaned_data['to']) + + return response + class TagViewSet(viewsets.ReadOnlyModelViewSet): queryset = Tag.objects.all().order_by('name')