How to Find the Video URL of Streamsextract video URLs to watch live streams through VLC for reduced lagging or to download entire past broadcasts is a great source for all things esport. Unfortunately, they suffer from inexplicable video stuttering which can be extremely bothersome. One of the more helpful remedies is playing live streams with VLC. For past broadcasts an obvious solution is to download the video before watching. Both measures require the video url, which can be retrieved by tools like livestreamer and websites like Twitchtools.

Live Video

For the impatient, here’s how to list all Video urls for channel gamesdonequick (only works if the channel is live of course):

user@users-desktop:~$ mkdir live && cd $_
user@users-desktop:~$ git clone .
user@users-desktop:~$ pip install m3u8
user@users-desktop:~$ python gamesdonequick
Video URLs (sorted by quality):

3362 kbit/s (Source), resolution=(1280, 720)

1718 kbit/s (High), resolution=?

906 kbit/s (Medium), resolution=?

582 kbit/s (Low), resolution=?

160 kbit/s (Mobile), resolution=?
Open the live stream of channel <code>riotgames</code> in VLC:

The Python script performs three steps to get to the urls:

Step 1: Request a token

The API call to request a token for channel channel is:{channel}/access_token

The request should return a JSON formatted data with two fields:

  • token: A JSON text with the following fields:
    • user_id: should be null since we are making anonymous API calls
    • channel: should echo the requested channel name
    • expires: a UNIX time stamp giving the expiry date of the token. Tokens seem to be valid 15 minutes. (You only need the token to get the stream url, once you have to url, you don’t have to send the token again for the entire duration of the live broadcast.)
    • chansup: again a JSON text with two fields:
      • view_until: Unix timestamp, usually set to December 31, 2030.
      • restricted_bitrates: The token can probably be restricted to certain bitrates, but should be an empty array in general.
    • private: a JSON text with just one field: allowed_to_view, should be true of course.
    • privileged: usually false, might be related to you subscription status.
    • source_restricted: should be false, if true then the source quality might be unavailable
  • sig: The 20 bytes hex-string representing the signature
  • mobile_restricted: should be false, might restrict the stream to non mobile devices.

Here is an example for the stream gamesdonequick:

The response should look similar to this:

            \"chansub\": {
            \"private\": {

Note that the value of token is text that contains JSON formatted data, therefore all quotes are escaped.

Step 2: Request the Playlist

All video urls for a live streams are packed in a m3u playlist. You can request this file with the following API call:{channel}.m3u8? →
player=twitchweb&&token={token}&sig={sig}& →

where you need to fill in the following values:

  • {channel}: the channel name, e.g., gamesdonequick
  • {token}: the value of token from step 1, e.g., {\"user_id\":null,...}
  • {sig}: the value of sig from step 1, e.g., c176d91c9216b8...
  • {random}: a random integer, up to 6 digits?

For example, →
player=twitchweb&token={"user_id":null,"channel":"gamesdonequick","expires":1420472431, →
"chansub":{"view_until":1924905600,"restricted_bitrates":[]}, →
"private":{"allowed_to_view":true},"privileged":false,"source_restricted":false}& →

This API call should return a m3u file like this:


Step 3: Parse the m3u file

M3U is simple text-based file format and easy to parse. For example, in Python you can use the package ``m3u8``:

m3u8_obj = m3u8.loads(m3u8_text)
for p in m3u8_obj.playlists:
    print(p.stream_info.bandwidth, p.uri)

Past Broadcasts

Download the past broadcast at url

user@users-desktop:~$ mkdir past &#038;&#038; cd $_
user@users-desktop:~$ git clone .
user@users-desktop:~$ python 577357806
downloading 577357806_00.flv
    146.43 MB

Script on GitHub

For past broadcasts we need to know the video id. You see the video id as the digits of the url of the broadcast. The broadcast, for example, has the video id 577357806. You can plug this video id in the following API call{videoid}

In our example this would be:

The API should return actual JSON (no escaped text) this time that represents an array of objects, where each object corresponds to a 30 minute part of the broadcast (the last part obviously can be shorter). So in contrast to live streams the video file is split into 30 minute chunks with different urls. Here’s an example of the response (only the first two objects are shown in full):

"api_id": "a577357806",
"broadcaster_software": "fme",
"channel": "riotgames",
"chunks": {
    "240p": [
            "length": 1800,
            "upkeep": null,
            "url": "",
            "vod_count_url": ",%22id%22:5773578060%7D"
            "length": 1802,
            "upkeep": "pass",
            "url": "",
            "vod_count_url": ",%22id%22:5773630960%7D"
    "360p": [
    "480p": [
"end_offset": 20900,
"increment_view_count_url": ",%22id%22:577357806%7D",
"muted_segments": null,
"path": "/riotgames/b/577357806",
"play_offset": 0,
"preview": "",
"preview_small": "",
"restrictions": {},
"start_offset": 0,
"vod_ad_frequency": "1200",
"vod_ad_length": "30"

The objects should already be sorted, meaning the first 30 minutes of the video come first.

You can find a small script in Python on GitHub that performs the API calls to download a past broadcast. The script accepts video_ids of past broadcasts and downloads the individual parts to numbered files, where the filename is derived from the id of the broadcast:

python 577357806
downloading 577357806_00.flv
195.85 MB done

downloading 577357806_01.flv
137.84 MB

Comments by Disqus

comments powered by Disqus