From d595de879a5e7528fc5ae027c6b8d0086be8f188 Mon Sep 17 00:00:00 2001 From: Dulus_No <35026145+DulusNo@users.noreply.github.com> Date: Tue, 2 Jan 2018 18:30:30 +0900 Subject: [PATCH] 1080p support --- youtube_dl/extractor/cartoonnetwork.py | 93 ++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 14 deletions(-) diff --git a/youtube_dl/extractor/cartoonnetwork.py b/youtube_dl/extractor/cartoonnetwork.py index 6aeebd7b3..aab9078af 100644 --- a/youtube_dl/extractor/cartoonnetwork.py +++ b/youtube_dl/extractor/cartoonnetwork.py @@ -4,6 +4,14 @@ from __future__ import unicode_literals import re from .turner import TurnerBaseIE +from ..utils import ( + float_or_none, + parse_duration, + xpath_text, + xpath_attr, + int_or_none, + strip_or_none, +) class CartoonNetworkIE(TurnerBaseIE): @@ -26,17 +34,74 @@ class CartoonNetworkIE(TurnerBaseIE): display_id = self._match_id(url) webpage = self._download_webpage(url, display_id) id_type, video_id = re.search(r"_cnglobal\.cvp(Video|Title)Id\s*=\s*'([^']+)';", webpage).groups() - query = ('id' if id_type == 'Video' else 'titleId') + '=' + video_id - return self._extract_cvp_info( - 'http://www.cartoonnetwork.com/video-seo-svc/episodeservices/getCvpPlaylist?networkName=CN2&' + query, video_id, { - 'secure': { - 'media_src': 'http://androidhls-secure.cdn.turner.com/toon/big', - 'tokenizer_src': 'https://token.vgtf.net/token/token_mobile', - }, - }, { - 'url': url, - 'site_name': 'CartoonNetwork', - 'auth_required': self._search_regex( - r'_cnglobal\.cvpFullOrPreviewAuth\s*=\s*(true|false);', - webpage, 'auth required', default='false') == 'true', - }) + + video_data = self._download_xml('http://video-api.cartoonnetwork.com/contentXML/' + video_id, video_id) + + media_id = video_data.attrib['id'] + title = xpath_text(video_data, 'headline', fatal=True) + + streams_data = self._download_json( + 'http://medium.ngtv.io/media/%s/tv' % media_id, + media_id)['media']['tv'] + duration = None + chapters = [] + formats = [] + for supported_type in ('unprotected', 'bulkaes'): + stream_data = streams_data.get(supported_type, {}) + m3u8_url = stream_data.get('url') or stream_data.get('secureUrl') + if not m3u8_url: + continue + if stream_data.get('playlistProtection') == 'spe': + m3u8_url = self._add_akamai_spe_token( + 'http://token.vgtf.net/token/token_spe', + m3u8_url, media_id, { + 'url': url, + 'site_name': 'CartoonNetwork', + 'auth_required': self._search_regex( + r'_cnglobal\.cvpFullOrPreviewAuth\s*=\s*(true|false);', + webpage, 'auth required', default='false') == 'true', + }) + m3u8_formats = self._extract_m3u8_formats( + m3u8_url, media_id, 'mp4', m3u8_id='hls', fatal=False) + if '?hdnea=' in m3u8_url: + for f in m3u8_formats: + f['_seekable'] = False + formats.extend(m3u8_formats) + + duration = float_or_none(stream_data.get('totalRuntime') or + parse_duration(xpath_text(video_data, 'length') or + xpath_text(video_data, 'trt'))) + + if not chapters: + for chapter in stream_data.get('contentSegments', []): + start_time = float_or_none(chapter.get('start')) + duration = float_or_none(chapter.get('duration')) + if start_time is None or duration is None: + continue + chapters.append({ + 'start_time': start_time, + 'end_time': start_time + duration, + }) + self._sort_formats(formats) + + thumbnails = [{ + 'id': image.get('cut'), + 'url': image.text, + 'width': int_or_none(image.get('width')), + 'height': int_or_none(image.get('height')), + } for image in video_data.findall('images/image')] + + return { + 'id': media_id, + 'title': title, + 'description': strip_or_none(xpath_text(video_data, 'description')), + 'duration': duration, + 'timestamp': self._extract_timestamp(video_data), + 'upload_date': xpath_attr(video_data, 'metas', 'version'), + 'series': xpath_text(video_data, 'showTitle'), + 'season_number': int_or_none(xpath_text(video_data, 'seasonNumber')), + 'episode_number': int_or_none(xpath_text(video_data, 'episodeNumber')), + 'chapters': chapters, + 'thumbnails': thumbnails, + 'formats': formats, + }