16

I have created a requests object like this:

 obj.mp3 = requests.get('http://foo.com/bar.mp3', stream=True)

I thought that I could just feed this obj.mp3 object into any audio player that expects a file or an URI, obviously this idea is wrong: nothing played. Below are the full code:

#views.py

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'song.html'

    def get_object(self):
        obj = super(ArticleDetailView, self).get_object()

        #code to store mp3 url in obj.mp3 and other stuff

        if obj.mp3:
            obj.mp3 = requests.get(obj.mp3, stream=True).content
        return obj

#song.html
<div class="audio">
  <audio src={{ article.mp3 }} type="audio/mpeg"> 
</div>

What is the correct way of treating return from requests as something that I can stream with a player? I know at least I can write the obj.mp3 to a file, then just point the player to the file location, but I am trying to avoid write the file to disk.

Thanks,

3 Answers 3

29

There's an attribute Response.raw, which is already a file-like object.

resp = requests.get(url, stream=True)
resp.raw # is what you need

Using io.BytesIO(resp.content) is not preferable since behind the scenes you're reading the same amount of data twice (also memory-wise): accessing resp.content reads everything from the network stream, then io.BytesIO(resp.content) is allocating again the same amount of memory, and then you read it from BytesIO object.

Sign up to request clarification or add additional context in comments.

4 Comments

Note that Response.raw will not respect transfer encodings as documented here. Therefore, using raw might be wrong depending on the web server.
After reading issue #465, I'm not sure if the problem mentioned in my last comment still exists.
Looks like you can add resp.raw.decode_content = True to fix it.
Setting raw.decode_content had not worked for me. Wrapping with io.TextIOWrapper(resp.raw, 'utf-8') worked.
10

Look into the io module for using file-like objects.

Probably you could use io.BytesIO which you can initialize with the Response.content. Then instead of list of bytes you get a file-like object.

import io
resp = requests.get(url, stream=True)
obj.mp3 = io.BytesIO(resp.content)

1 Comment

after hours of trying to figure out, i tend to conclude that this is not at all possible: django template expect a string, in particular for any audio player, the string needs to either represent an URL, or a path pointing to the media. however both yours and mine code return an object. thanks anyway.
1

Django's responsibility is to generate the HTML code that is then interpreted by the browser. The browser is what needs to be streaming the audio. You need to pass the mp3 url through Django templates that a player like http://www.jwplayer.com/ can then stream on the client side.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.