mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 06:35:12 +00:00 
			
		
		
		
	Merge branch 'youtube-dash-manifest'
Conflicts: youtube_dl/extractor/youtube.py
This commit is contained in:
		| @@ -1106,6 +1106,8 @@ class YoutubeDL(object): | ||||
|                 res += 'audio' | ||||
|             if fdict.get('abr') is not None: | ||||
|                 res += '@%3dk' % fdict['abr'] | ||||
|             if fdict.get('asr') is not None: | ||||
|                 res += ' (%5dHz)' % fdict['asr'] | ||||
|             if fdict.get('filesize') is not None: | ||||
|                 if res: | ||||
|                     res += ', ' | ||||
|   | ||||
| @@ -63,6 +63,7 @@ class InfoExtractor(object): | ||||
|                     * tbr        Average bitrate of audio and video in KBit/s | ||||
|                     * abr        Average audio bitrate in KBit/s | ||||
|                     * acodec     Name of the audio codec in use | ||||
|                     * asr        Audio sampling rate in Hertz | ||||
|                     * vbr        Average video bitrate in KBit/s | ||||
|                     * vcodec     Name of the video codec in use | ||||
|                     * filesize   The number of bytes, if known in advance | ||||
|   | ||||
| @@ -27,6 +27,7 @@ from ..utils import ( | ||||
|     get_element_by_id, | ||||
|     get_element_by_attribute, | ||||
|     ExtractorError, | ||||
|     int_or_none, | ||||
|     RegexNotFoundError, | ||||
|     unescapeHTML, | ||||
|     unified_strdate, | ||||
| @@ -270,6 +271,21 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|                 u"uploader_id": u"setindia" | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             u"url": u"http://www.youtube.com/watch?v=a9LDPn-MO4I", | ||||
|             u"file": u"a9LDPn-MO4I.m4a", | ||||
|             u"note": u"256k DASH audio (format 141) via DASH manifest", | ||||
|             u"params": { | ||||
|                 u"format": "141" | ||||
|             }, | ||||
|             u"info_dict": { | ||||
|                 u"upload_date": "20121002", | ||||
|                 u"uploader_id": "8KVIDEO", | ||||
|                 u"description": "No description available.", | ||||
|                 u"uploader": "8KVIDEO", | ||||
|                 u"title": "UHDTV TEST 8K VIDEO.mp4" | ||||
|             } | ||||
|         }, | ||||
|     ] | ||||
|  | ||||
|  | ||||
| @@ -1067,18 +1083,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|         video_id = mobj.group(2) | ||||
|         return video_id | ||||
|  | ||||
|     def _get_video_url_list(self, url_map): | ||||
|         """ | ||||
|         Transform a dictionary in the format {itag:url} to a list of (itag, url) | ||||
|         with the requested formats. | ||||
|         """ | ||||
|         existing_formats = [x for x in self._formats if x in url_map] | ||||
|         if len(existing_formats) == 0: | ||||
|             raise ExtractorError(u'no known formats available for video') | ||||
|         video_url_list = [(f, url_map[f]) for f in existing_formats] # All formats | ||||
|         video_url_list.reverse() # order worst to best | ||||
|         return video_url_list | ||||
|  | ||||
|     def _extract_from_m3u8(self, manifest_url, video_id): | ||||
|         url_map = {} | ||||
|         def _get_urls(_manifest): | ||||
| @@ -1252,7 +1256,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|                 video_annotations = self._extract_annotations(video_id) | ||||
|  | ||||
|         # Decide which formats to download | ||||
|  | ||||
|         try: | ||||
|             mobj = re.search(r';ytplayer.config = ({.*?});', video_webpage) | ||||
|             if not mobj: | ||||
| @@ -1277,9 +1280,26 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|         except ValueError: | ||||
|             pass | ||||
|  | ||||
|         def _map_to_format_list(urlmap): | ||||
|             formats = [] | ||||
|             for itag, video_real_url in urlmap.items(): | ||||
|                 dct = { | ||||
|                     'format_id': itag, | ||||
|                     'url': video_real_url, | ||||
|                     'player_url': player_url, | ||||
|                 } | ||||
|                 dct.update(self._formats[itag]) | ||||
|                 formats.append(dct) | ||||
|             return formats | ||||
|  | ||||
|         if 'conn' in video_info and video_info['conn'][0].startswith('rtmp'): | ||||
|             self.report_rtmp_download() | ||||
|             video_url_list = [('_rtmp', video_info['conn'][0])] | ||||
|             formats = [{ | ||||
|                 'format_id': '_rtmp', | ||||
|                 'protocol': 'rtmp', | ||||
|                 'url': video_info['conn'][0], | ||||
|                 'player_url': player_url, | ||||
|             }] | ||||
|         elif len(video_info.get('url_encoded_fmt_stream_map', [])) >= 1 or len(video_info.get('adaptive_fmts', [])) >= 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: | ||||
| @@ -1324,23 +1344,49 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|                     if 'ratebypass' not in url: | ||||
|                         url += '&ratebypass=yes' | ||||
|                     url_map[url_data['itag'][0]] = url | ||||
|             video_url_list = self._get_video_url_list(url_map) | ||||
|             formats = _map_to_format_list(url_map) | ||||
|         elif video_info.get('hlsvp'): | ||||
|             manifest_url = video_info['hlsvp'][0] | ||||
|             url_map = self._extract_from_m3u8(manifest_url, video_id) | ||||
|             video_url_list = self._get_video_url_list(url_map) | ||||
|             formats = _map_to_format_list(url_map) | ||||
|         else: | ||||
|             raise ExtractorError(u'no conn, hlsvp or url_encoded_fmt_stream_map information found in video info') | ||||
|  | ||||
|         formats = [] | ||||
|         for itag, video_real_url in video_url_list: | ||||
|             dct = { | ||||
|                 'format_id': itag, | ||||
|                 'url': video_real_url, | ||||
|                 'player_url': player_url, | ||||
|             } | ||||
|             dct.update(self._formats[itag]) | ||||
|             formats.append(dct) | ||||
|         # Look for the DASH manifest | ||||
|         dash_manifest_url_lst = video_info.get('dashmpd') | ||||
|         if dash_manifest_url_lst and dash_manifest_url_lst[0]: | ||||
|             try: | ||||
|                 dash_doc = self._download_xml( | ||||
|                     dash_manifest_url_lst[0], video_id, | ||||
|                     note=u'Downloading DASH manifest', | ||||
|                     errnote=u'Could not download DASH manifest') | ||||
|                 for r in dash_doc.findall(u'.//{urn:mpeg:DASH:schema:MPD:2011}Representation'): | ||||
|                     url_el = r.find('{urn:mpeg:DASH:schema:MPD:2011}BaseURL') | ||||
|                     if url_el is None: | ||||
|                         continue | ||||
|                     format_id = r.attrib['id'] | ||||
|                     video_url = url_el.text | ||||
|                     filesize = int_or_none(url_el.attrib.get('{http://youtube.com/yt/2012/10/10}contentLength')) | ||||
|                     f = { | ||||
|                         'format_id': format_id, | ||||
|                         'url': video_url, | ||||
|                         'width': int_or_none(r.attrib.get('width')), | ||||
|                         'tbr': int_or_none(r.attrib.get('bandwidth'), 1000), | ||||
|                         'asr': int_or_none(r.attrib.get('audioSamplingRate')), | ||||
|                         'filesize': filesize, | ||||
|                     } | ||||
|                     try: | ||||
|                         existing_format = next( | ||||
|                             fo for fo in formats | ||||
|                             if fo['format_id'] == format_id) | ||||
|                     except StopIteration: | ||||
|                         f.update(self._formats.get(format_id, {})) | ||||
|                         formats.append(f) | ||||
|                     else: | ||||
|                         existing_format.update(f) | ||||
|  | ||||
|             except (ExtractorError, KeyError) as e: | ||||
|                 self.report_warning(u'Skipping DASH manifest: %s' % e, video_id) | ||||
|  | ||||
|         self._sort_formats(formats) | ||||
|  | ||||
|   | ||||
| @@ -1131,8 +1131,8 @@ class HEADRequest(compat_urllib_request.Request): | ||||
|         return "HEAD" | ||||
|  | ||||
|  | ||||
| def int_or_none(v): | ||||
|     return v if v is None else int(v) | ||||
| def int_or_none(v, scale=1): | ||||
|     return v if v is None else (int(v) // scale) | ||||
|  | ||||
|  | ||||
| def parse_duration(s): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Philipp Hagemeister
					Philipp Hagemeister