Search code examples
javascriptpythonhtmldjangohtml5-audio

How to provide seekable/scrubbable audio to frontend using Django


I'm trying to provide audio to the HTML Django template, originally I tried like this:

<audio id="audio" src="{{audio_path}}" controls></audio>

This was sufficient to get audio playing on the website with pause/play, speed up/down, volume up/down but the user was not able to move the progress bar at all, it either froze, or returned to the starting position.

I did lots of searching and found many things that claimed to enable seeking/scrubbing, but none of them have worked. Currently my code is as follows, first the audio API view:

class AudioFetchView(View):
    def get(self, request, audio_id, *args, **kwargs):
        audio_file = UploadAudio.objects.get(pk=audio_id)

        response = StreamingHttpResponse(content_type='audio/mpeg')
        response['Content-Disposition'] = 'attachment; filename=%s' % audio_file.path
        response['Accept-Ranges'] = 'bytes'
        response['X-Sendfile'] = audio_file.path
        return response

audio_fetch = AudioFetchView.as_view()

Then the HTML:

<audio id="audio" crossOrigin="anonymous" preload="auto" src="{{audio_fetch_url}}"></audio>

Now the audio is not able to be played at all, the error message is: "Uncaught (in promise) DOMException: The element has no supported sources."

Does anyone know how to correctly provide an .mp3 file to the frontend in a way that allows scrubbing/seeking?


Solution

  • I have no idea why this worked, but my code is now working like this:

    class AudioFetchView(View):
    def get(self, request, audio_id, *args, **kwargs):
        audio_file = UploadAudio.objects.get(pk=audio_id)
    
        with open(audio_file.absolute_path, 'rb') as fh:
            response = HttpResponse(fh.read(), content_type='audio/mpeg')
            response['Content-Disposition'] = 'attachment; filename=%s' % audio_file.path
            response['Accept-Ranges'] = 'bytes'
            response['X-Sendfile'] = audio_file.path
            response['Content-Length'] = os.path.getsize(audio_file.absolute_path)
        return response
    
    audio_fetch = AudioFetchView.as_view()
    

    HTML:

    <audio id="audio" src={{audio_fetch_url}} type="audio/mpeg"> </audio>
    

    Figured I'd post in case anyone finds this in the future.