PavelDuk
@PavelDuk
Python Dev

Как лучше всего раздавать mp3 в Django через вьюху?

Парни, помогите!)
На сайте нужно проигрывать музыку.
Нашел вот этот превосходный плеер.

Имеется простая view:
def results(request):
    
     music = Music.objects.get(id=1)
     context = {
            'music': music
        }
        return render(request, "main_app/main_page.html", context)


В шаблоне следующее:
{% for mp3 in music %}

<!-- аудио_плеер -->
            <div>
                <audio preload="auto" controls>
                    <source src="{{ mp3.file.url }}">
                </audio>
                {#  Логика плеера  #}
                {% compress js %}
                    <script type="text/javascript" src="{% static "main_app/js/audio_player.js" %}"></script>
                {% endcompress %}

                <script>
                        $(function () {
                            $('audio').audioPlayer();
                        });

                </script>
            </div>

{% endfor %}


В результате плеер выдает:
Uncaught DOMException: Failed to execute 'end' on 'TimeRanges': The index provided (0) is greater than or equal to the maximum bound (0).

Так в косноли данная ошибка вылезает около 40 раз потом аудио с лагами в плеере(непрафильно отображается полоса буфера) начинает проигрываться.

Если заменить тег шаблона пути к файлу с {{ mp3.file.url }}
на какую-нибудь ссылку на аудио файл из интернетов:
<audio preload="auto" controls>
                    <source src="https://data.ipleer.fm/file/149907929/WHd2U3VmNzM4alhUd1hVbE8xTm93SG5GbnRsQ2cwSnBoRTRaZnhDMVdaWk9BMjRNUG5OVUlicTlmODJDZ2M0cmdQM3pWbE1wK2RPbyt4OE40Y1BRUVVzQnJJcnJNMkhIK01HRzFtL3dvajJjdHdVK1cydUV3YUw3S2ZRSEVhUDk/Tima_Belorusskih_-_Nezabudka_(iPleer.fm).mp3">
                </audio>


То плеер работает так как и должен: медленно подгружает по необходимости файл и при этом не выдает никакой ошибки.

Покопался с этой ошибкой - сделал вывод что mp3 в моем случае нужно стримить а не просто отдавать ссылку на файл.

Нашел вот это на стеке:
import os
import mimetypes
from django.http import StreamingHttpResponse
from django.core.servers.basehttp import FileWrapper

def download_file(request):
   the_file = '/some/file/name.png'
   filename = os.path.basename(the_file)
   chunk_size = 8192
   response = StreamingHttpResponse(FileWrapper(open(the_file, 'rb'), chunk_size),
                           content_type=mimetypes.guess_type(the_file)[0])
   response['Content-Length'] = os.path.getsize(the_file)    
   response['Content-Disposition'] = "attachment; filename=%s" % filename
   return response


Если это то что нужно я не понимаю как приспособить данное решение к выборке файлов из БД.
Например если вместе с путем к MP3 у меня в контексте идет еще описание, рэйтинг и т.д

Помогите разобраться как правильно стримить выборку из MP3 файлов?
Возможно у вас найдется решение получше.
  • Вопрос задан
  • 111 просмотров
Решения вопроса 2
sergey-gornostaev
@sergey-gornostaev
Седой и строгий
Метод get возвращает не QuerySet, а один экземпляр модели. Но вы по нему пытаетесь итерировать. Загляните в исходный код сгенерированной страницы и посмотрите, что подставилось в атрибут src тега source.

Покопался с этой ошибкой - сделал вывод что mp3 в моем случае нужно стримить а не просто отдавать ссылку на файл.

Во-первых, сам вывод ошибочный. Во-вторых, Django не очень подходит для стриминга.
Ответ написан
PavelDuk
@PavelDuk Автор вопроса
Python Dev
В результате всех хитросплетений было принято решение не заниматься садо-мазо а раздовать mp3 по средствам NGINX.
P.S Данное решение не заработает на встроенном сервере: runserver Django, потому что данный сервер не поддерживает частичный ответ 206 . Придется запускать джанго приложение на NGINX'е

Вот тут обсуждение.

Вот рабочий код:
def stream_mp3(request, song):
    if song:
        song_name = song
        mp3_path = os.getcwd() + '/media/charge/music/' + song_name
        # mp3_data = open(mp3_path, "rb").read()
        # response = HttpResponse(mp3_data, content_type="audio/mpeg", status=206)
        response = HttpResponse('', content_type="audio/mpeg", status=206)
        response['X-Accel-Redirect'] = '/media/charge/music/' + song_name
        response['X-Accel-Buffering'] = 'no'
        response['Content-Length'] = os.path.getsize(mp3_path)
        response['Content-Dispostion'] = "attachment; filename=" + mp3_path
        response['Accept-Ranges'] = 'bytes'

        return response


    else:
        raise Http404("Музыка удалена. Запускай поиск по новой.")
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы