twitch_logo

How to Find the Video URL of Twitch.tv Streams

extract video URLs to watch live streams through VLC for reduced lagging or to download entire past broadcasts

Twitch.tv 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 https://gist.github.com/8593472.git .
user@users-desktop:~$ pip install m3u8
user@users-desktop:~$ python twitch_live_url.py gamesdonequick
Video URLs (sorted by quality):

3362 kbit/s (Source), resolution=(1280, 720)
---------------------------------------------
http://video15.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/chunked/py-index-live.m3u8?token=id=1418093999473934365,bid=12509293952,exp=1420554598,node=video15-1.ams01.hls.justin.tv,nname=video15.ams01,fmt=chunked&sig=395f5905fb1a1d67f0c43ff16c87a992ff0d5a56

1718 kbit/s (High), resolution=?
---------------------------------
http://video15.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/high/py-index-live.m3u8?token=id=1418093999473934365,bid=12509293952,exp=1420554598,node=video15-1.ams01.hls.justin.tv,nname=video15.ams01,fmt=high&sig=43fb62091c5177ed25fa1ee58c3880adc828a30c

906 kbit/s (Medium), resolution=?
----------------------------------
http://video15.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/medium/py-index-live.m3u8?token=id=1418093999473934365,bid=12509293952,exp=1420554598,node=video15-1.ams01.hls.justin.tv,nname=video15.ams01,fmt=medium&sig=a771f42f0bc2a1743558a83f4a9c9679a0bfe29a

582 kbit/s (Low), resolution=?
-------------------------------
http://video15.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/low/py-index-live.m3u8?token=id=1418093999473934365,bid=12509293952,exp=1420554598,node=video15-1.ams01.hls.justin.tv,nname=video15.ams01,fmt=low&sig=cc2e22fbd1a0a0d34a8f9b56162482fe974d3bcd

160 kbit/s (Mobile), resolution=?
----------------------------------
http://video15.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/mobile/py-index-li
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:

http://api.twitch.tv/api/channels/{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: http://api.twitch.tv/api/channels/gamesdonequick/access_token

The response should look similar to this:

{
    "token": 
        "{\"user_id\":null,
            \"channel\":\"gamesdonequick\",
            \"expires\":1420470744,
            \"chansub\": {
                \"view_until\":1924905600,
                \"restricted_bitrates\":[]
            },
            \"private\": {
                \"allowed_to_view\":true
            },
            \"privileged\":false,
            \"source_restricted\":false
        }",
    "sig":"c176d91c9216b84fd3717c3fb4efcc755c46f3c6",
    "mobile_restricted":false
}

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:

http://usher.twitch.tv/api/channel/hls/{channel}.m3u8? →
player=twitchweb&&token={token}&sig={sig}& →
allow_audio_only=true&allow_source=true&type=any&p={random}'

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,

http://usher.twitch.tv/api/channel/hls/gamesdonequick.m3u8? →
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}& →
sig=19b3425a3cf937e6c15e35717c7e25baab083a70&allow_audio_only=true&allow_source=true&type=any&p=9333029

This API call should return a m3u file like this:

#EXTM3U
#EXT-X-TWITCH-INFO:NODE="video62.ams01",MANIFEST-NODE="video62.ams01",SERVER-TIME="1420471407.91",USER-IP="83.228.241.174",CLUSTER="ams01",MANIFEST-CLUSTER="ams01"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="Source",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3287062,RESOLUTION=1280x720,CODECS="avc1.4D4029,mp4a.40.2",VIDEO="chunked"
http://video62.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/chunked/py-index-live.m3u8?token=id=6986430544396636668,bid=12509293952,exp=1420557807,node=video62-1.ams01.hls.justin.tv,nname=video62.ams01,fmt=chunked&sig=51f7f401342979dd9af3a1f366a339ab7dceb4f9
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="high",NAME="High",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1760000,CODECS="avc1.66.31,mp4a.40.2",VIDEO="high"
http://video62.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/high/py-index-live.m3u8?token=id=6986430544396636668,bid=12509293952,exp=1420557807,node=video62-1.ams01.hls.justin.tv,nname=video62.ams01,fmt=high&sig=017bf5f8c9aace7e6a4f169e06188a086a5fd298
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="medium",NAME="Medium",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=928000,CODECS="avc1.66.31,mp4a.40.2",VIDEO="medium"
http://video62.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/medium/py-index-live.m3u8?token=id=6986430544396636668,bid=12509293952,exp=1420557807,node=video62-1.ams01.hls.justin.tv,nname=video62.ams01,fmt=medium&sig=00f249f9c89938b747115f0f1f383900d06c58a7
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Low",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=596000,CODECS="avc1.66.31,mp4a.40.2",VIDEO="low"
http://video62.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/low/py-index-live.m3u8?token=id=6986430544396636668,bid=12509293952,exp=1420557807,node=video62-1.ams01.hls.justin.tv,nname=video62.ams01,fmt=low&sig=f61c7b7821aa281974bbb5a1e5bb8bac4d7e3ab2
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mobile",NAME="Mobile",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=164000,CODECS="avc1.66.31,mp4a.40.2",VIDEO="mobile"
http://video62.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/mobile/py-index-live.m3u8?token=id=6986430544396636668,bid=12509293952,exp=1420557807,node=video62-1.ams01.hls.justin.tv,nname=video62.ams01,fmt=mobile&sig=78597f44e32af0900f4526d4c31d9befffcbb798
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="audio_only",NAME="Audio Only",AUTOSELECT=NO,DEFAULT=NO
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000,CODECS="mp4a.40.2",VIDEO="audio_only"
http://video62.ams01.hls.twitch.tv/hls25/gamesdonequick_12509293952_185809391/audio_only/py-index-live.m3u8?token=id=6986430544396636668,bid=12509293952,exp=1420557807,node=video62-1.ams01.hls.justin.tv,nname=video62.ams01,fmt=audio_only&sig=53fac453e3a02c47bcd9132ff6991b8f78c229b4

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 http://www.twitch.tv/riotgames/b/577357806

user@users-desktop:~$ mkdir past &#038;&#038; cd $_
user@users-desktop:~$ git clone https://gist.github.com/8340312.git .
user@users-desktop:~$ python twitch_past_broadcast_downloader.py 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 http://www.twitch.tv/riotgames/b/577357806, for example, has the video id 577357806. You can plug this video id in the following API call

https://api.twitch.tv/api/videos/{videoid}

In our example this would be:

https://api.twitch.tv/api/videos/a577357806

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": "http://media-cdn.twitch.tv/store89.media66/archives/2014-10-12/format_240p_577357806.flv",
            "vod_count_url": "http://countess.twitch.tv/ping.gif?u=%7B%22type%22:%22vod%22,%22id%22:5773578060%7D"
        },
        {
            "length": 1802,
            "upkeep": "pass",
            "url": "http://media-cdn.twitch.tv/store63.media54/archives/2014-10-12/format_240p_577363096.flv",
            "vod_count_url": "http://countess.twitch.tv/ping.gif?u=%7B%22type%22:%22vod%22,%22id%22:5773630960%7D"
        }
...
    "360p": [
...
    "480p": [
...
"end_offset": 20900,
"increment_view_count_url": "http://countess.twitch.tv/ping.gif?u=%7B%22type%22:%22archive%22,%22id%22:577357806%7D",
"muted_segments": null,
"path": "/riotgames/b/577357806",
"play_offset": 0,
"preview": "http://static-cdn.jtvnw.net/jtv.thumbs/archive-577357806-320x240.jpg",
"preview_small": "http://static-cdn.jtvnw.net/jtv.thumbs/archive-577357806-150x113.jpg",
"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 twitch_past_broadcast_downloader.py 577357806
downloading 577357806_00.flv
195.85 MB done

downloading 577357806_01.flv
137.84 MB

Archived Comments

Note: I removed the Disqus integration in an effort to cut down on bloat. The following comments were retrieved with the export functionality of Disqus. If you have comments, please reach out to me by Twitter or email.

kolyall Jan 23, 2014 13:17:09 UTC

Now it doesn't work

Johannes Jan 23, 2014 22:18:35 UTC

Both API calls still work for me
- http://api.justin.tv/api/br...
- http://usher.twitch.tv/sele...

The first call always returns JSON formatted data with a couple of video urls; the second call returns "[]" if the stream is offline. But it's Twitch after all and they are constantly trying to resolve their many issues by tinkering with their servers, so maybe the API was down for a while.

Edit: I updated the post with notes on how to get the token and signature for the live stream url. They might be required if your not visiting the channel page first.

Ken Jan 24, 2014 19:52:40 UTC

- http://usher.twitch.tv/sele...
[
{
url: "/select/sirhcez.json?nauthsig=&nauth=&allow_source=true",
type: "error",
error: "missing token"
}
]
it missing token..

Johannes Jan 27, 2014 14:58:08 UTC

For me too, it seems like they are checking the token now. I updated the post on how to get the token. This Python snippet currently works for me (with European and US IP): https://gist.github.com/bad...

Sandra Feb 02, 2014 20:44:53 UTC

It's "Exception", not "Exeption". I know this because I got the exception triggered: "API returned 404".

Johannes Feb 05, 2014 21:37:37 UTC

Fixed it, thanks.

Samme Feb 06, 2014 14:45:39 UTC

The call to get the available streams is currently just returning an emtpy json array.
I sniffed the calls livestreamer do and it sends an additional parameter; "p" (p as in password?) wich seems to be generated for each call. You think that parameter is required now or am I just doing something wrong?

Samme Feb 06, 2014 20:06:17 UTC

Nevermind, it works. I indeed did something wrong...

Spit Feb 16, 2014 11:04:08 UTC

Can you tell me what you did wrong because i am too are getting just an empty json array

Sandra Feb 08, 2014 22:35:00 UTC

Johannes, thank you so much for finding this api. I got the 404 on the first few videos I tried, but it works on some. Just making a guess, I'd say that it doesn't work on older videos? But that's just guessing. The videos I tried to watch were these: http://www.twitch.tv/teamco... I tried to see the Plugged-In Tour - Final Round - Top Table but it just gave me a 404. I tried the LCG Night and it did download the file. It crashed when trying to call json() on the request object, so there's something else weird going on.

For now, I just did a sed 's/"/\n/g' 501571848.json\?onsite=true|grep flv$|xargs totem

Rik Jun 09, 2014 23:58:52 UTC

I would like to know how to find these API links. i tried to find them with the chrome developer toolkit, but i didn't see it passing by.
I know I can use these now, but if they change it in the future i would like to know how to find it.

Thanks in advance!

Johannes Jun 11, 2014 14:36:45 UTC

I prefer to use Wireshark.
- Start capturing; open the URL of the live stream in your browser; stop capturing when the video starts playing.
- Filter for <tt>http.response.phrase == "OK"</tt>. This should provide you with a list of delivered HTTP content.
- Look for interesting content types in the info column, like application/json or application/vnd.apple.mgegurl.

When I tested it today, the first "application/vnd.apple.mpegurl" was a list of urls to different qualities of the stream. To see what triggered this response, simply click the "[Request in frame: ...]" link in the HTTP header display in Wireshark or use "follow tcp stream". In my case there was a call to "usher.twitch.tv/select/gsl.......". This gives you the API call to get the video urls.

Rik Jun 12, 2014 00:57:06 UTC

Thanks a lot for the info!!
I did try Wireshark, but I'm not too familiar with it.
I'll try this coming weekend and see if i can find anything of interest.

DatOneDude Aug 16, 2014 07:26:16 UTC

This is fantastic! thank you sir - you made my day

Austin T. Aug 28, 2014 13:02:12 UTC

Hi! I'm attempting to pull this data out manually (and then transition it into java code).
I'm getting something like this:

[{"url": "/select/lmqtcvasilii.json?nauthsig=625793f94f2354bbadd0faf1acb721fe9b59c0b2;nauth=%22{\\%22user_id\\%22:46105340,\\%22channel\\%22:\\%22lmqtcvasilii\\%22,\\%22expires\\%22:1409217507,\\%22chansub\\%22:{\\%22view_until\\%22:1924905600,\\%22restricted_bitrates\\%22:[]},\\%22private\\%22:{\\%22allowed_to_view\\%22:true},\\%22privileged\\%22:false}%22;allow_source=true", "type": "error", "error": "missing token"}]

"Missing Token", and I have no idea why. Could you take a moment to explain?

Johannes Aug 29, 2014 12:45:55 UTC

It seems like you used the semicolon to separate the nauthsig and nauth pairs, try to use &:
.... 59c0b2;nauth=%22{\\%22use ... ----> .... 59c0b2&nauth=%22{\\%22use ...

Austin T. Aug 29, 2014 15:38:51 UTC

Hi, thanks for the quick reply.
I put everything into a program to automatically generate new urls.

http://usher.twitch.tv/sele..."{\"user_id\":null,\"channel\":\"ongamenet\",\"expires\":1409313212,\"chansub\":{\"view_until\":1924905600,\"restricted_bitrates\":[\"archives\",\"live\",\"high\",\"source\",\"chunked\"]},\"private\":{\"allowed_to_view\":true},\"privileged\":false}"&allow_source=true

But for whatever reason all I get is an empty json array.

[]

I think that's why I substituted the ampersand for a semicolon, partially because one of your examples used semicolons. I get only empty arrays with an ampersand. When I tried semicolons I at least got an error.

Johannes Aug 29, 2014 16:40:09 UTC

Try the following changes:
- no quote after nauth=, and no quote before &allow_source
- don't escape any quote (\" -> ")

For example:
http://usher.twitch.tv/sele...{"user_id":null,"channel":"starladder1","expires":1409316907,"chansub":{"view_until":1924905600,"restricted_bitrates":["archives"]},"private":{"allowed_to_view":true},"privileged":false}&allow_source=true

Austin T. Aug 30, 2014 01:30:10 UTC

Great, thank you very much.
It works

vriska Oct 14, 2014 17:59:36 UTC

hey the api call for past broadcasts doesn't work now. it always returns a 404 page

Johannes Oct 14, 2014 18:59:33 UTC

Thank you for pointing that out. It seems like the api.justin.tv has been shut down. The following works for me: If you want to download the past broadcast http://www.twitch.tv/riotga..., make the following API call: https://api.twitch.tv/api/v...

So for http://www.twitch.tv/riotga...

$ curl -H 'Accept: application/json' -X GET https://api.twitch.tv/api/v... | python -m json.tool

which should give you a JSON formatted list of video urls:

{
"api_id": "a577357806",
"broadcaster_software": "fme",
"channel": "riotgames",
"chunks": {
"240p": [
{
"length": 1800,
"upkeep": null,
"url": "http://media-cdn.twitch.tv/...",
"vod_count_url": "http://countess.twitch.tv/p..."
},
{
"length": 1802,
"upkeep": "pass",
"url": "http://media-cdn.twitch.tv/...",
"vod_count_url": "http://countess.twitch.tv/p..."
},

Edit: I updated the blog post and Gist.

Rik Oct 16, 2014 02:37:25 UTC

If it is a subscriber only channel, with the new API you have to be a subscriber to check the url. so it's now impossible to watch VOD's of subscribers without being a subscriber.
So you have to also specify the OAuth code of an account that you want to download. that must also be specified in the url, so the curl command will be as follows:
curl -H "Accept: application/json" -H "Authorization: OAuth " -X GET https://api.twitch.tv/api/v...

Travis Nov 20, 2014 08:15:15 UTC

Is this still working? I'm trying to get a list of m3u8 video links, which worked fine about two weeks ago, but no for some reason is returning [] (empty json response array).

This is the request:
http://usher.twitch.tv/sele...{%22user_id%22:null%2C%22channel%22:%22nightblue3%22%2C%22expires%22:1416452994%2C%22chansub%22:{%22view_until%22:1924905600%2C%22restricted_bitrates%22:[]}%2C%22private%22:{%22allowed_to_view%22:true}%2C%22privileged%22:false}&allow_source=true

Note: I have tried both URL encoding the request (hence , become %2C, and " become %22) and not (and a combination of encoding , or " only) to no avail.

Thanks.

someguy123 Nov 22, 2014 19:39:02 UTC

I used the same url for about 2-3 months, now it doesn't work. I used Wireshark to get the requests the browser sends when viewing streams and for the last 2 days the requests look different every single time. Here are some examples:
The one I "fixed to work" 2 days ago:
usher.twitch.tv/api/channel..."+id123+".m3u8?token=%7B%22user_id%22%3Anull%2C%22channel%22%3A%22"+id+"%22%2C%22expires%22%3A"+expires+"%2C%22chansub%22%3A%7B%22view_until%22%3A"+view_until+"%2C%22restricted_bitrates%22%3A%5B%5D%7D%2C%22private%22%3A%7B%22allowed_to_view%22%3Atrue%7D%2C%22privileged%22%3Afalse%2C%22source_restricted%22%3Afalse%7D&segment_preference=2&sig="+sig;
Yesterday:
usher.twitch.tv/api/channel... HTTP/1.1

Today:

usher.twitch.tv/api/channel... HTTP/1.1

I don't know what they are doing. Is it possible they want to stop exactly what we are doing ?

kolyall Dec 12, 2014 15:49:55 UTC

Today API call to doesn't work for me
http://usher.twitch.tv/sele...

kolyall Dec 12, 2014 15:50:50 UTC

code responce is always 404

Rik Dec 14, 2014 21:55:22 UTC

That is right, twitch has updated their API (again)
you have to request a token here: http://api.twitch.tv/api/ch...{channel}/access_token
and then you have to use the new URL:

python code: "http://usher.twitch.tv/api/...{CHANNEL}.m3u8?player=twitchweb&token={ENCODED_TOKEN}&sig={SIG}&allow_audio_only=true&allow_source=true&type=any&p={RANDOM}".format(CHANNEL=channel,SIG=access_token_sig,ENCODED_TOKEN=urllib.quote_plus(access_token),RANDOM=int(random() * 999999))

this is an example of a valid request: "http://usher.twitch.tv/api/..."

Rik Dec 14, 2014 21:57:17 UTC

this is an example of a valid request: "http://usher.twitch.tv/api/..."

steve Dec 20, 2014 17:20:35 UTC

I was using something similar to livestreamer but it would embed vlc on the twitch page instead of using VLC by itself.. The person who made this said the new API doesn't provide "source" quality and its the only limitation he could see . His bandaid works fine but the "best" quality is "high" setting and not source. Thanks for your time.

https://github.com/DeniSix/...

steve Dec 20, 2014 17:26:50 UTC

Also i emailed a livestreamer dev about it. He said "make sure you pass "allow_source=true" as a query parameter to the HLS playlist." but I dont think it worked when i tried. maybe i did it wrong

Rik Dec 23, 2014 21:39:00 UTC

It's right that you have to pass "allow_source=true". check my comment (the one above you). That should do the trick =). "allow_audio_only=true" also adds the option to only listen to the stream.

joen Jan 04, 2015 20:36:31 UTC

looks like twitch changed something again

"Transcode does not exist" when I try and grab the live stream stuff

e.g.

"http://usher.twitch.tv/api/..."

I've Tried this with and without allow_source

Rik Jan 05, 2015 18:57:52 UTC

It seems like your request was correct. I've tried a request and it still seems to work.

Make sure that the channel is live ;) , I've only seen that message when i tried to get the m3u for a channel that wasn't live at that moment.

Johannes Jan 05, 2015 19:46:56 UTC

Your API update also works for me. Thanks for posting the changes in the comments, I fixed my Gist file accordingly.

Jendos Jan 27, 2015 01:19:17 UTC

i dont know, ive tried few times and always gettin errors like "invalid token" can someone help me with draskyl's stream?

rikels May 04, 2015 22:43:14 UTC

Twitch just updated their past broadcasts... at least, I now get 3 second parts (just like the live stream) like index-0000000014-pAWB.ts for the channel I watch.

I think you can check here to see if the channel you follow uses the new implementation: https://api.twitch.tv/api/c... (the part: "use_new_rtmp_impl":true)

The m3u is always called index-dvr.m3u8, but the link where it is located is a bit hard for me to find out. I don't have to much time to dig deeper now.

Rikels May 07, 2015 10:19:42 UTC

Okay, I finally had time to dig a little deeper.

what you have to do, is request an access token before you can request the M3U file that is used for the past broadcast stream (yes, this is totally different from how it worked previously, it's now quite close to grabbing the live url)

request a token via the following url:
https://api.twitch.tv/api/v...{ID of the VOD you want to wacht}/access_token?as3=t&oauth_token={the oauth token from your Twitch account}

after that, copy the strings in the following url:
"http://usher.justin.tv/vod/...{sig}&nauth={token}".format(sig=sig,token=token)

than you'll get an M3U file which you can watch via VLC or any other good video player ;)

preview of a valid url, yes if you try, it will say invalid, because I changed the ID's and the token probably ran out of time. It's here just so you have a preview of a correct looking url.

http://usher.justin.tv/vod/...{"user_id":35065643,"vod_id":4746543,"expires":1431063621,"chansub":{"restricted_bitrates":[]},"privileged":true}

rikels May 10, 2015 20:30:38 UTC

The new link for the info of the broadcast can be found here:

https://api.twitch.tv/krake...{ID}

Rikels Jul 22, 2015 15:46:46 UTC

recently they changed the API, you now have to pass "allow_source=true" in the API call to retrieve the raw (Chunked) stream. just like you had to in the old API. The audio only is also gone, for that add "allow_audio_only=true" to the request. Example: http://usher.justin.tv/vod/{ID}?allow_source=true&allow_audio_only=true&nauth={NAUTH}&nauthsig={NAUTHSIG}&player=twitchweb

kondratovich May 17, 2015 10:42:29 UTC

There is a type at '$allow_audio_only=true'

manyanimals Jun 27, 2015 14:54:36 UTC

I just find an easy method to free download twitch videos at http://www.allavsoft.com/ho...

Hope it is what you are looking for.

random23u23u89ee8u89oi May 31, 2016 12:54:34 UTC

Thank you! In the progress of making a chrome extension replacing the flash player with html5. Any idea on how to get commercials links?

Guest Mar 09, 2017 12:53:44 UTC

Thanks for the article!
Unfortunately it didn't works for me, but this did:
https://github.com/systoolz...
I hope it helps.

aKanG cuPez Mar 28, 2017 06:10:28 UTC

I have created a simple PHP library for extracting the video or channel streaming from TwitchTV
https://github.com/akangcup...

any suggestions and forks are welcomed

tari fari May 30, 2017 09:09:01 UTC

Hey, i think twitch modified their api functions. Can you update this version? Want to use this code for my bouquet creator to use twitch streams as a normal channel on enigma2 receivers