Streaming audio on AnyAudio was now a better experience than before. But there is a problem here. For every media request made to the server, the first thing done is fetching the media from YouTube servers (see line 1 in the code above). And after this, a fixed part of the media is sent as a response to the client.

The lengthy songs present on YouTube, such as jukeboxes and music compilations, have a large file size just for the audio. And considering the fact that there is a backend request made by the media player for every seek, listening to long audio would take forever.

The solution to this is quite simple — ask just for what you need.

Ask just for what you need

Earlier, every request of media made to the server resulted in downloading the whole audio from YouTube before serving any. This problem was solved by —

Limiting the size of media served by the server with each stream request. Requesting partial content from YouTube.

The limit of file size helps to restrict the amount of data that will be requested from YouTube and as a result, we will have much more deterministic stream time than before. Here is a piece of code that explains the process —

By putting the Range header with the request made to YouTube, the amount of data that the server needs to download before serving it to the client becomes less.

One more step forward — Connecting Streams

With this change, streaming was a lot better than before. But this was still not the optimal performance that one expects from a media streaming service.

The client doesn’t get a response from the server unless the server has downloaded the partial data from YouTube and the response has been prepared and sent. This can be improved by streaming the content from YouTube directly to the user. In simple words, by connecting the data stream from YouTube to the connection where the client is expecting a reply.

To enable streaming in requests , we can simply add the stream=True parameter while making the request. Combining this with Flask’s streaming abilities, we can instantly start serving data to the client without waiting for some requests to complete. Here is a rough sample of how this would work —

This resulted in a Time to First Byte ( TTFB ) value of around 400ms on a dual core server with average client speed. Though this is nowhere compared to the requests made to YouTube from the same client (around 15ms), it is an achievement for a hobby project with a cheap server.

What are we planning next?

As of now, it is very difficult to invest time in AnyAudio. But we are really looking forward to introducing API v3 to the server which allows more straightforward requests and playlist support. This would mean that users would be able to listen to complete YouTube playlists on the web app.

We are also planning to improve the suggestions made on the web app. As of now, it is just related to the current song that is being played. But instead, it can be a lot better by taking into account the reader’s listening habits, search queries, how often the songs bump into the suggestion for the user and so on.

Integrating this would require the users to create an account on the platform, which we do not wish to include as we just want the platform to be as hassle-free as possible. So for this, we are planning just to use the browser’s local storage. Additional features would include saving songs and listening to them whenever the user wants. Offline listening is also something that we are looking to integrate once it turns out to be a good PWA.

Parting words

I have learned a lot with this project and hope to learn a lot more. We would love if you drop by and star our GitHub repositories. And if you are a developer and love to fix some dirty code and introduce awesome test cases, feel free to get in touch with us at our Gitter channel.

So, visit AnyAudio now to listen to your favourite songs.

Please let us know your views and stay tuned for more.