Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Youtube] youtube-dl fails to retrieve the hls manifest for livestreams #15202

Closed
FDMX2 opened this issue Jan 9, 2018 · 21 comments
Closed

[Youtube] youtube-dl fails to retrieve the hls manifest for livestreams #15202

FDMX2 opened this issue Jan 9, 2018 · 21 comments
Labels
bug

Comments

@FDMX2
Copy link

@FDMX2 FDMX2 commented Jan 9, 2018

The way to retrieve the hls manifest for youtube livestreams changed.
See @yan12125 s comment below for fix.

Original:

Please follow the guide below

  • You will be asked some questions and requested to provide some information, please read them carefully and answer honestly
  • Put an x into all the boxes [ ] relevant to your issue (like this: [x])
  • Use the Preview tab to see what your issue will actually look like

Make sure you are using the latest version: run youtube-dl --version and ensure your version is 2018.01.07. If it's not, read this FAQ entry and update. Issues with outdated version will be rejected.

  • [ x ] I've verified and I assure that I'm running youtube-dl 2018.01.07

Before submitting an issue make sure you have:

  • [ x ] At least skimmed through the README, most notably the FAQ and BUGS sections
  • [ x ] Searched the bugtracker for similar issues including closed ones

What is the purpose of your issue?

  • [ x ] Bug report (encountered problems with youtube-dl)
  • Site support request (request for adding support for a new site)
  • Feature request (request for a new functionality)
  • Question
  • Other

Youtube seemed to change how they deliver the hls files for livestreams, if the livestreams allows you to jump back several hours. Instead of providing an hls stream url, youtube-dl (2018.01.07) only provides the latest segment of the stream.

For example:
This livestream works flawless like before:
NASA Livestream
https://www.youtube.com/watch?v=RtU_mdL2vBM

this one (with the ability to go back) doesn't:
Live Train 24
https://www.youtube.com/watch?v=qghQ5eKGcyE

Streamlink also suffered from this issue, so i think it's a change on youtubes side:
streamlink/streamlink#1421

@lukashruby
Copy link

@lukashruby lukashruby commented Jan 9, 2018

I am experiencing the same problem.

@hmedia1
Copy link

@hmedia1 hmedia1 commented Jan 9, 2018

This stream (https://youtu.be/9h6Vz6ylIdE) and the NASA one mentioned above have been active since before this change by YouTube.

If you youtube-dl -F any new streams, you'll see (at least this is what I'm seeing anyway) that they don't have hls streams anymore.

Further - it appears that on the browser, when clicking the nerd stats, there is no longer the line that indicates if it's a DASH stream or not, seemingly confirming that it's just all DASH now. It's not overly surprising given that HLS streams were 30fps irrespective of what went in - every stream had to be converted for archive and this had long been just a compatibility feature.

Perhaps what is needed is to change this to a feature request; simply for youtube-dl to support dynamic MPD manifests (it already fully supports static ones)

I know from manual debugging, and lots of grep and jq (and more recently using youtube-dl with the --youtube-include-dash-manifest option), that the MPD playlist is available from the earliest segment available on the stream (about 4 hours worth if the stream is 24/7 from memory), so it could be cleanly implemented.

As a sidenote - same deal for streamlink - this never supported DASH at all for live streams with youtube, but it seems now that a combination of youtubes new defaults and some minor changes mentioned on this thread (and fixed [here])(streamlink/streamlink#1423), that there is some playability.

@Bangaio65
Copy link

@Bangaio65 Bangaio65 commented Jan 9, 2018

Yeah I started seeing this error yesterday. I have a script that grabs the link through youtube-dl and feeds it to ffmpeg (using the -live_start_index option to be able to start at the designated time, not sure if this is possible to do with just youtube-dl) and using -f best give me ERROR: requested format not available. Using -f 137 I get an error in ffmpeg: Found duplicated MOOV Atom. Skipped it. Using youtube-dl alone, it only downloads a couple seconds before stopping... but I need the rewind feature anyway.

@hmedia1
Copy link

@hmedia1 hmedia1 commented Jan 10, 2018

-live_start_index is only going to work for a hls playlist.

One way to deal with the MOOV Atom thing for hacking and integration testing, is use ffmpeg with -f concat. I know there's other ways, but short of something that accounts for every potential timestamp issue across all different files, I've found concat to be dead simple;

youtube-dl can get the manifest with --youtube-include-dash-manifest
From there, you could download your initialization segment to a file (say: "base"), and then parse the individual segments into manageable files, say;

cat list-of-segment-urls | while read url
do 
   curl -s "$url" > ${i}_tmp.ts ; (( i++ ))
done

ffmpeg/ffplay can then either transcode or just copy out / stitch the files together;

for file in $(echo base *_tmp.ts | sort -g)
do 
    echo "file '"$file"'" >> list.txt 
done

list.txt will look like this;

file 'base'
file '0_tmp.ts'
file '1_tmp.ts'
file '2_tmp.ts'
file '3_tmp.ts'
etc...

Then you can play it;

ffmpeg -f concat -i list.txt -c copy -f mpegts -bsf:v h264_mp4toannexb -y my_live_stream.ts

Now instead of -live_start_index the beginning will simply be the top line of the list-of-segment-urls file.

@FDMX2
Copy link
Author

@FDMX2 FDMX2 commented Jan 10, 2018

I'm only inetersted in the link pointing at the dash manifest, but the --youtube-include-dash-manifest argument (together with -J) did not include the dash manifest url.

If nobody else is on it i can find out how to retrieve this url.

@hmedia1
Copy link

@hmedia1 hmedia1 commented Jan 11, 2018

The live dash manifest URL is in the player config JSON.

youtube-dl --print-traffic https://youtu.be/<id> \
| grep -oP "/api/manifest/dash/.*? " \
| echo "https://manifest.googlevideo.com/$(cat -)"

https://manifest.googlevideo.com//api/manifest/dash/etc....

Or extract it yourself:

curl -sL "https://youtu.be/<id>" \
| grep -oP "ytplayer.config =\K.*?}(?=;)" \
| jq -r .args.dashmpd

https://manifest.googlevideo.com/api/manifest/dash/etc....
@vkot
Copy link

@vkot vkot commented Jan 11, 2018

Apparently Youtube still has HLS for live streams:
For Euronews Live:

youtube-dl -j https://www.youtube.com/watch?v=xAE4xX8Izvo
Only produces MPD formats

youtube-dl --print-traffic https://www.youtube.com/watch?v=xAE4xX8Izvo
Has no HLS entries

BUT
curl -sL -k "https://www.youtube.com/watch?v=xAE4xX8Izvo"
has a very valid HLS link:

"hlsvp":"https://manifest.googlevideo.com/api/manifest/hls_variant/gcr....m3u8

@hmedia1
Copy link

@hmedia1 hmedia1 commented Jan 12, 2018

The HLS playlist was previously accessible in more extraction points and query strings which were favored by youtube-dl as it really seems to only return the list of dash segments on live streams as a last ditch effort.

In my opinion all live feeds should be returned; it's actually nice to see 50p or 60p videos stream at their ingested frame rate.

@yan12125 yan12125 added the bug label Jan 12, 2018
@yan12125
Copy link
Collaborator

@yan12125 yan12125 commented Jan 12, 2018

A quick and dirty patch for HLS:

diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
index 0919bef0e..9ad662777 100644
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -1537,7 +1537,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
             ytplayer_config = self._get_ytplayer_config(video_id, video_webpage)
             if ytplayer_config:
                 args = ytplayer_config['args']
-                if args.get('url_encoded_fmt_stream_map'):
+                if args.get('url_encoded_fmt_stream_map') or args.get('hlsvp'):
                     # Convert to the same format returned by compat_parse_qs
                     video_info = dict((k, [v]) for k, v in args.items())
                     add_dash_mpd(video_info)
@@ -1802,15 +1802,16 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
 
         chapters = self._extract_chapters(description_original, video_duration)
 
+        formats = []
         if 'conn' in video_info and video_info['conn'][0].startswith('rtmp'):
             self.report_rtmp_download()
-            formats = [{
+            formats.append({
                 'format_id': '_rtmp',
                 'protocol': 'rtmp',
                 'url': video_info['conn'][0],
                 'player_url': player_url,
-            }]
-        elif len(video_info.get('url_encoded_fmt_stream_map', [''])[0]) >= 1 or len(video_info.get('adaptive_fmts', [''])[0]) >= 1:
+            })
+        if len(video_info.get('url_encoded_fmt_stream_map', [''])[0]) >= 1 or len(video_info.get('adaptive_fmts', [''])[0]) >= 1:
             encoded_url_map = video_info.get('url_encoded_fmt_stream_map', [''])[0] + ',' + video_info.get('adaptive_fmts', [''])[0]
             if 'rtmpe%3Dyes' in encoded_url_map:
                 raise ExtractorError('rtmpe downloads are not supported, see https://github.com/rg3/youtube-dl/issues/343 for more information.', expected=True)
@@ -1827,7 +1828,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                                 'width': int_or_none(width_height[0]),
                                 'height': int_or_none(width_height[1]),
                             }
-            formats = []
             for url_data_str in encoded_url_map.split(','):
                 url_data = compat_parse_qs(url_data_str)
                 if 'itag' not in url_data or 'url' not in url_data:
@@ -1934,9 +1934,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                             if codecs:
                                 dct.update(parse_codecs(codecs))
                 formats.append(dct)
-        elif video_info.get('hlsvp'):
+        if video_info.get('hlsvp'):
             manifest_url = video_info['hlsvp'][0]
-            formats = []
             m3u8_formats = self._extract_m3u8_formats(
                 manifest_url, video_id, 'mp4', fatal=False)
             for a_format in m3u8_formats:
@@ -1952,7 +1951,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 # Accept-Encoding header causes failures in live streams on Youtube and Youtube Gaming
                 a_format.setdefault('http_headers', {})['Youtubedl-no-compression'] = 'True'
                 formats.append(a_format)
-        else:
+        if not formats:
             unavailable_message = self._html_search_regex(
                 r'(?s)<h1[^>]+id="unavailable-message"[^>]*>(.+?)</h1>',
                 video_webpage, 'unavailable message', default=None)
@FDMX2 FDMX2 changed the title [Youtube] Livestreams with "going back"-functionallity not working anymore [Youtube] youtube-dl fails to retrieve the hls manifest for livestreams Jan 12, 2018
@hmedia1
Copy link

@hmedia1 hmedia1 commented Jan 12, 2018

Thanks @yan12125.

In addition to changing the default stream map, it looks like YouTube no longer converts to 30p for HLS.

For the sake of completeness, can I suggest on top of your patch:

--- a/youtube_dl/extractor/youtube.py	2018-01-12 22:41:11.845928145 +0800
+++ b/youtube_dl/extractor/youtube.py	2018-01-12 22:39:32.695954749 +0800
@@ -401,6 +401,8 @@
         '94': {'ext': 'mp4', 'height': 480, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 128, 'vcodec': 'h264', 'preference': -10},
         '95': {'ext': 'mp4', 'height': 720, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 256, 'vcodec': 'h264', 'preference': -10},
         '96': {'ext': 'mp4', 'height': 1080, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 256, 'vcodec': 'h264', 'preference': -10},
+        '300': {'ext': 'mp4', 'height': 720, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 256, 'vcodec': 'h264', 'preference': -10, 'fps': 60},
+        '301': {'ext': 'mp4', 'height': 1080, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 256, 'vcodec': 'h264', 'preference': -10, 'fps': 60},
         '132': {'ext': 'mp4', 'height': 240, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 48, 'vcodec': 'h264', 'preference': -10},
         '151': {'ext': 'mp4', 'height': 72, 'format_note': 'HLS', 'acodec': 'aac', 'abr': 24, 'vcodec': 'h264', 'preference': -10},

To uniformly represent the stream list in the "hlsvp" object:


#EXT-X-STREAM-INF:BANDWIDTH=197400,CODECS="mp4a.40.5,avc1.4d400c",RESOLUTION=256x144,FRAME-RATE=30,CLOSED-CAPTIONS=NONE
#EXT-X-STREAM-INF:BANDWIDTH=338100,CODECS="mp4a.40.5,avc1.4d4015",RESOLUTION=426x240,FRAME-RATE=30,CLOSED-CAPTIONS=NONE
#EXT-X-STREAM-INF:BANDWIDTH=829500,CODECS="mp4a.40.2,avc1.4d401e",RESOLUTION=640x360,FRAME-RATE=30,CLOSED-CAPTIONS=NONE
#EXT-X-STREAM-INF:BANDWIDTH=1380750,CODECS="mp4a.40.2,avc1.4d401f",RESOLUTION=854x480,FRAME-RATE=30,CLOSED-CAPTIONS=NONE
#EXT-X-STREAM-INF:BANDWIDTH=3806250,CODECS="mp4a.40.2,avc1.4d4020",RESOLUTION=1280x720,FRAME-RATE=60,CLOSED-CAPTIONS=NONE
#EXT-X-STREAM-INF:BANDWIDTH=6231750,CODECS="mp4a.40.2,avc1.4d402a",RESOLUTION=1920x1080,FRAME-RATE=60,CLOSED-CAPTIONS=NONE

Yielding a clear:


format code  extension  resolution note
91           mp4        256x144    HLS  197k , avc1.42c00b, 30.0fps, mp4a.40.5@ 48k
92           mp4        426x240    HLS  338k , avc1.4d4015, 30.0fps, mp4a.40.5@ 48k
93           mp4        640x360    HLS  829k , avc1.4d401e, 30.0fps, mp4a.40.2@128k
94           mp4        854x480    HLS 1380k , avc1.4d401f, 30.0fps, mp4a.40.2@128k
300          mp4        1280x720   HLS 3806k , avc1.4d4020, 60.0fps, mp4a.40.2@256k
301          mp4        1920x1080  HLS 6231k , avc1.64002a, 60.0fps, mp4a.40.2@256k (best)
@jaydenkieran
Copy link

@jaydenkieran jaydenkieran commented Jan 13, 2018

Any idea on when the patch for this will be pushed to the repo? Thanks, btw

@m0hamedessam
Copy link

@m0hamedessam m0hamedessam commented Jan 13, 2018

hls playlist freezing on vlc and ffmpeg any idea ?

@vkot
Copy link

@vkot vkot commented Jan 13, 2018

Latest FFmpeg builds seem to work ok on those HLS streams; last stable release on Zeranoe indeed freezes

@dstftw dstftw closed this in 391dd6f Jan 13, 2018
@m0hamedessam
Copy link

@m0hamedessam m0hamedessam commented Jan 13, 2018

@vokot both freezing :(

@m0hamedessam
Copy link

@m0hamedessam m0hamedessam commented Jan 13, 2018

@vkot i use this command
youtube-dl -v --hls-prefer-native --hls-use-mpegts --no-resize-buffer --buffer-size 2M -f93 --ignore-config -o - https://m.youtube.com/watch?v=xAE4xX8Izvo |ffplay -

and freeze can you send me yours

@vkot
Copy link

@vkot vkot commented Jan 13, 2018

@m0hamedessam Just copy-pasted your command, runs smooth, no freeze.

Are you sure you have both ffmpeg and ffplay from the latest build? No other ffmpeg binaries in the PATH?

@m0hamedessam
Copy link

@m0hamedessam m0hamedessam commented Jan 13, 2018

@vkot ffplay version N-89788-g1eb7c1d49d Copyright (c) 2003-2018 the FFmpeg developers
built with gcc 7.2.0 (GCC)

same problem here

#15247

@vkot
Copy link

@vkot vkot commented Jan 13, 2018

Strange. Let’s see what other people will report on that other ticket.

@morfeo9950
Copy link

@morfeo9950 morfeo9950 commented Jan 11, 2019

The live dash manifest URL is in the player config JSON.

youtube-dl --print-traffic https://youtu.be/<id> \
| grep -oP "/api/manifest/dash/.*? " \
| echo "https://manifest.googlevideo.com/$(cat -)"

https://manifest.googlevideo.com//api/manifest/dash/etc....

Or extract it yourself:

curl -sL "https://youtu.be/<id>" \
| grep -oP "ytplayer.config =\K.*?}(?=;)" \
| jq -r .args.dashmpd

https://manifest.googlevideo.com/api/manifest/dash/etc....

Where is the player config JSON?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants
You can’t perform that action at this time.