From 74dc1bf1989ee5d1187ba0164bea28e75ce23219 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Mon, 5 Feb 2024 13:29:21 +0900 Subject: [PATCH 01/14] [ie/viu] Fix `_VALID_URL` in `ViuOTTIE` --- yt_dlp/extractor/viu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 6f9af9f643..279d797210 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -151,7 +151,7 @@ def _real_extract(self, url): class ViuOTTIE(InfoExtractor): IE_NAME = 'viu:ott' _NETRC_MACHINE = 'viu' - _VALID_URL = r'https?://(?:www\.)?viu\.com/ott/(?P[a-z]{2})/(?P[a-z]{2}-[a-z]{2})/vod/(?P\d+)' + _VALID_URL = r'https?://(?:www\.)?viu\.com/ott/(?P[a-z]{2})/(?P[a-z]{2}(?:-[a-z]{2})?)/vod/(?P\d+)' _TESTS = [{ 'url': 'http://www.viu.com/ott/sg/en-us/vod/3421/The%20Prime%20Minister%20and%20I', 'info_dict': { From 1ba1fb1327f4375307190fa516b07f4f65905fce Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Tue, 13 Feb 2024 20:37:26 +0800 Subject: [PATCH 02/14] [viu:ott] Fix indonesian (and probably malaysian) viu extraction --- yt_dlp/extractor/viu.py | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 279d797210..eea44d3c2d 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -8,7 +8,9 @@ from ..compat import compat_str from ..utils import ( ExtractorError, + float_or_none, int_or_none, + merge_dicts, remove_end, strip_or_none, traverse_obj, @@ -196,6 +198,21 @@ class ViuOTTIE(InfoExtractor): 'noplaylist': False, }, 'skip': 'Geo-restricted to Hong Kong', + }, { + 'url': 'https://www.viu.com/ott/id/id/vod/1130404/Dr-Stone-Stone-Wars', + 'info_dict': { + 'id': '1130404', + 'ext': 'mp4', + 'duration': 1440.0, + 'title': 'Dr. Stone: Stone Wars - Dr. Stone: Stone Wars - Episode 11', + 'episode_number': 11, + 'episode': 'Dr. Stone: Stone Wars - Dr. Stone: Stone Wars - Episode 11', + 'description': 'md5:65aa14cb80e0d18acf829513b6d64297', + 'series': 'Dr. Stone: Stone Wars', + 'series_id': '35837', + 'thumbnail': 'https://prod-images.viu.com/clip_asset_v6/1165917542/1165917580/e31e9fb2dc0d38db7f6c9b4de1f62d55d5fdfb80', + + } }] _AREA_ID = { @@ -271,6 +288,68 @@ def _real_extract(self, url): url, idata = unsmuggle_url(url, {}) country_code, lang_code, video_id = self._match_valid_url(url).groups() + if country_code in ('id'): + webpage = self._download_webpage(url, video_id) + json_ld = self._search_json_ld(webpage, video_id) + next_js_data = self._search_nextjs_data(webpage, video_id)['props'] + runtime_info = next_js_data['initialState']['app']['runtimeInfo'] + + product_detail_json = traverse_obj(next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), get_all=False) + current_product_info = traverse_obj(product_detail_json, ('data', 'current_product')) + current_product_subtitle_info = current_product_info.get('subtitle') + + formats, subtitles = [], {} + + for subtitle_info in current_product_subtitle_info: + subtitles.setdefault(subtitle_info.get('code'), []).append({ + 'url': subtitle_info.get('url'), + 'name': subtitle_info.get('name') + }) + + stream_info_json = self._download_json('https://api-gateway-global.viu.com/api/playback/distribute', video_id, query={ + 'platform_flag_label': 'web', + 'area_id': runtime_info.get('areaId') or 1000, + 'language_flag_id': int_or_none(runtime_info.get('languageFlagId'), default=3), + 'countryCode': country_code.upper(), + 'ccs_product_id': current_product_info.get('ccs_product_id') + }, headers={ + 'Authorization': f'Bearer {self._get_token(country_code, video_id)}' + }) + + stream_urls = traverse_obj(stream_info_json, ('data', 'stream', ('url', 'airplayurl'), lambda _, v: v)) + + for stream_url in stream_urls: + fmts, subs = self._extract_m3u8_formats_and_subtitles(stream_url, video_id, fatal=False) + formats.extend(fmts) + self._merge_subtitles(subs, target=subtitles) + + return merge_dicts({ + 'id': video_id, + 'formats': formats, + 'subtitles': subtitles, + 'thumbnails': json_ld.get('thumbnails'), + }, + traverse_obj(json_ld, { + 'thumbnails': 'thumbnails', + 'title': 'title', + 'episode': 'episode', + 'episode_number': 'episode_number' + }), + traverse_obj(current_product_info, { + 'description': 'description', + 'thumbnail': ('cover_image_url', {url_or_none}), + 'duration': ('time_duration', {float_or_none}), + 'episode_number': ('number', {float_or_none}), + + }), + traverse_obj(product_detail_json, ('data', 'series', { + 'series_id': 'series_id', + 'series': 'name' + })), + { + 'title': self._html_search_meta(['og:title'], webpage), + 'thumbnail': self._html_search_meta(['og:image'], webpage)} + ) query = { 'r': 'vod/ajax-detail', 'platform_flag_label': 'web', From c588ffdedeecb8d2b97c2fa9b2c4e09a07c1b990 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Wed, 14 Feb 2024 21:25:01 +0800 Subject: [PATCH 03/14] inline remove unneccessary variable `stream_urls` --- yt_dlp/extractor/viu.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index eea44d3c2d..95fd14359e 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -315,10 +315,8 @@ def _real_extract(self, url): }, headers={ 'Authorization': f'Bearer {self._get_token(country_code, video_id)}' }) - - stream_urls = traverse_obj(stream_info_json, ('data', 'stream', ('url', 'airplayurl'), lambda _, v: v)) - for stream_url in stream_urls: + for stream_url in traverse_obj(stream_info_json, ('data', 'stream', ('url', 'airplayurl'), lambda _, v: v)): fmts, subs = self._extract_m3u8_formats_and_subtitles(stream_url, video_id, fatal=False) formats.extend(fmts) self._merge_subtitles(subs, target=subtitles) From 7b9f56ade5aefbed689a503112eda9e5fa2b0566 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Wed, 21 Feb 2024 18:39:21 +0800 Subject: [PATCH 04/14] reformat `product_detail_json` --- yt_dlp/extractor/viu.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 95fd14359e..ea75a93623 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -294,7 +294,9 @@ def _real_extract(self, url): next_js_data = self._search_nextjs_data(webpage, video_id)['props'] runtime_info = next_js_data['initialState']['app']['runtimeInfo'] - product_detail_json = traverse_obj(next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), get_all=False) + product_detail_json = traverse_obj( + next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), + get_all=False) current_product_info = traverse_obj(product_detail_json, ('data', 'current_product')) current_product_subtitle_info = current_product_info.get('subtitle') From c7a528c198a46b19fadef3641dd3b9f0dc11f396 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Wed, 21 Feb 2024 18:41:12 +0800 Subject: [PATCH 05/14] remove trailing spaces --- yt_dlp/extractor/viu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index ea75a93623..a65843cf63 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -295,7 +295,7 @@ def _real_extract(self, url): runtime_info = next_js_data['initialState']['app']['runtimeInfo'] product_detail_json = traverse_obj( - next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), + next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), get_all=False) current_product_info = traverse_obj(product_detail_json, ('data', 'current_product')) current_product_subtitle_info = current_product_info.get('subtitle') From 13879e2cef3c9847c00282ab52521dedc1ecf5ab Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Sat, 24 Feb 2024 15:49:02 +0800 Subject: [PATCH 06/14] remove duplicated same extraction process to `thumbnails` --- yt_dlp/extractor/viu.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index a65843cf63..3df12d7ed4 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -327,7 +327,6 @@ def _real_extract(self, url): 'id': video_id, 'formats': formats, 'subtitles': subtitles, - 'thumbnails': json_ld.get('thumbnails'), }, traverse_obj(json_ld, { 'thumbnails': 'thumbnails', From 1ec2c788bb22b2804f5d795ea5408c8b57212271 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Sat, 24 Feb 2024 15:56:55 +0800 Subject: [PATCH 07/14] add note to skip as geo-restricted to Indonesia --- yt_dlp/extractor/viu.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 3df12d7ed4..cfddfed5f6 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -212,7 +212,8 @@ class ViuOTTIE(InfoExtractor): 'series_id': '35837', 'thumbnail': 'https://prod-images.viu.com/clip_asset_v6/1165917542/1165917580/e31e9fb2dc0d38db7f6c9b4de1f62d55d5fdfb80', - } + }, + 'skip': 'Geo-restricted to Indonesia' }] _AREA_ID = { From dbb084c0015d80901b2f7e4e0848ef36bee19ff7 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Mon, 26 Feb 2024 19:36:26 +0800 Subject: [PATCH 08/14] add comment about possible to bypass geo-blocking --- yt_dlp/extractor/viu.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index cfddfed5f6..9962e9f956 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -295,6 +295,9 @@ def _real_extract(self, url): next_js_data = self._search_nextjs_data(webpage, video_id)['props'] runtime_info = next_js_data['initialState']['app']['runtimeInfo'] + # Weird thing happen if i insert technilacally geo-blocked content like + # like https://www.viu.com/ott/sg/en/vod/108599/The-Beauty-Inside in ID region, + # it still download. Maybe API not affected by geo-block? product_detail_json = traverse_obj( next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), get_all=False) From 9dcf080549cedb20cc479e9c5f862f2e894f2598 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Mon, 26 Feb 2024 20:19:46 +0800 Subject: [PATCH 09/14] update comment --- yt_dlp/extractor/viu.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 9962e9f956..d7b0107625 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -295,9 +295,8 @@ def _real_extract(self, url): next_js_data = self._search_nextjs_data(webpage, video_id)['props'] runtime_info = next_js_data['initialState']['app']['runtimeInfo'] - # Weird thing happen if i insert technilacally geo-blocked content like - # like https://www.viu.com/ott/sg/en/vod/108599/The-Beauty-Inside in ID region, - # it still download. Maybe API not affected by geo-block? + # NOTE: some geo-blocked like https://www.viu.com/ott/sg/en/vod/108599/The-Beauty-Inside actually can bypassed + # on other region (like in ID) product_detail_json = traverse_obj( next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), get_all=False) From e9e2fe84a2c3af1febd7e95ab9f025f16985a734 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Fri, 1 Mar 2024 13:19:20 +0800 Subject: [PATCH 10/14] use regex rather than full string match in `thumbnail` test --- yt_dlp/extractor/viu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index d7b0107625..41fa9b52f9 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -210,7 +210,7 @@ class ViuOTTIE(InfoExtractor): 'description': 'md5:65aa14cb80e0d18acf829513b6d64297', 'series': 'Dr. Stone: Stone Wars', 'series_id': '35837', - 'thumbnail': 'https://prod-images.viu.com/clip_asset_v6/1165917542/1165917580/e31e9fb2dc0d38db7f6c9b4de1f62d55d5fdfb80', + 'thumbnail': r're:https?://prod-images\.viu\.com/clip_asset_v6/\d+/\d+/[a-f0-9]+', }, 'skip': 'Geo-restricted to Indonesia' From 3f7d3d20bd17f84a36ceff2e44d48b2eb32168dd Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Fri, 1 Mar 2024 13:24:37 +0800 Subject: [PATCH 11/14] delete single use variable `current_product_subtitle_info` --- yt_dlp/extractor/viu.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 41fa9b52f9..1ef55bcfb2 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -301,11 +301,10 @@ def _real_extract(self, url): next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), get_all=False) current_product_info = traverse_obj(product_detail_json, ('data', 'current_product')) - current_product_subtitle_info = current_product_info.get('subtitle') formats, subtitles = [], {} - for subtitle_info in current_product_subtitle_info: + for subtitle_info in current_product_info.get('subtitle') or []: subtitles.setdefault(subtitle_info.get('code'), []).append({ 'url': subtitle_info.get('url'), 'name': subtitle_info.get('name') From 1c04f8d345fc40df723297632b2aa4c548250844 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Wed, 10 Apr 2024 07:34:46 +0800 Subject: [PATCH 12/14] merge the `ID` extraction and the old way extraction This commit is untested outside `ID` region --- yt_dlp/extractor/viu.py | 122 +++++++++++++--------------------------- 1 file changed, 39 insertions(+), 83 deletions(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 1ef55bcfb2..794550c3ed 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -7,8 +7,8 @@ from .common import InfoExtractor from ..compat import compat_str from ..utils import ( + DownloadError, ExtractorError, - float_or_none, int_or_none, merge_dicts, remove_end, @@ -199,21 +199,18 @@ class ViuOTTIE(InfoExtractor): }, 'skip': 'Geo-restricted to Hong Kong', }, { - 'url': 'https://www.viu.com/ott/id/id/vod/1130404/Dr-Stone-Stone-Wars', + 'url': 'https://www.viu.com/ott/id/id/vod/2221644/Detective-Conan', 'info_dict': { - 'id': '1130404', + 'id': '2221644', 'ext': 'mp4', - 'duration': 1440.0, - 'title': 'Dr. Stone: Stone Wars - Dr. Stone: Stone Wars - Episode 11', - 'episode_number': 11, - 'episode': 'Dr. Stone: Stone Wars - Dr. Stone: Stone Wars - Episode 11', - 'description': 'md5:65aa14cb80e0d18acf829513b6d64297', - 'series': 'Dr. Stone: Stone Wars', - 'series_id': '35837', + 'description': 'md5:b199bcdb07b1e01a03529f155349ddd5', + 'duration': 1425, + 'series': 'Detective Conan', + 'title': 'Detective Conan - Episode 1150', + 'episode': 'Detective Conan - Episode 1150', + 'episode_number': 1150, 'thumbnail': r're:https?://prod-images\.viu\.com/clip_asset_v6/\d+/\d+/[a-f0-9]+', - - }, - 'skip': 'Geo-restricted to Indonesia' + } }] _AREA_ID = { @@ -289,89 +286,41 @@ def _real_extract(self, url): url, idata = unsmuggle_url(url, {}) country_code, lang_code, video_id = self._match_valid_url(url).groups() - if country_code in ('id'): - webpage = self._download_webpage(url, video_id) - json_ld = self._search_json_ld(webpage, video_id) - next_js_data = self._search_nextjs_data(webpage, video_id)['props'] - runtime_info = next_js_data['initialState']['app']['runtimeInfo'] + webpage = self._download_webpage(url, video_id, fatal=False) + json_ld = self._search_json_ld(webpage, video_id, fatal=False) + next_js_data = (self._search_nextjs_data(webpage, video_id, fatal=False) or {}).get('props') + runtime_info = traverse_obj(next_js_data, ('initialState', 'app', 'runtimeInfo')) - # NOTE: some geo-blocked like https://www.viu.com/ott/sg/en/vod/108599/The-Beauty-Inside actually can bypassed - # on other region (like in ID) - product_detail_json = traverse_obj( - next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), - get_all=False) - current_product_info = traverse_obj(product_detail_json, ('data', 'current_product')) - - formats, subtitles = [], {} - - for subtitle_info in current_product_info.get('subtitle') or []: - subtitles.setdefault(subtitle_info.get('code'), []).append({ - 'url': subtitle_info.get('url'), - 'name': subtitle_info.get('name') - }) - - stream_info_json = self._download_json('https://api-gateway-global.viu.com/api/playback/distribute', video_id, query={ - 'platform_flag_label': 'web', - 'area_id': runtime_info.get('areaId') or 1000, - 'language_flag_id': int_or_none(runtime_info.get('languageFlagId'), default=3), - 'countryCode': country_code.upper(), - 'ccs_product_id': current_product_info.get('ccs_product_id') - }, headers={ - 'Authorization': f'Bearer {self._get_token(country_code, video_id)}' - }) - - for stream_url in traverse_obj(stream_info_json, ('data', 'stream', ('url', 'airplayurl'), lambda _, v: v)): - fmts, subs = self._extract_m3u8_formats_and_subtitles(stream_url, video_id, fatal=False) - formats.extend(fmts) - self._merge_subtitles(subs, target=subtitles) - - return merge_dicts({ - 'id': video_id, - 'formats': formats, - 'subtitles': subtitles, - }, - traverse_obj(json_ld, { - 'thumbnails': 'thumbnails', - 'title': 'title', - 'episode': 'episode', - 'episode_number': 'episode_number' - }), - traverse_obj(current_product_info, { - 'description': 'description', - 'thumbnail': ('cover_image_url', {url_or_none}), - 'duration': ('time_duration', {float_or_none}), - 'episode_number': ('number', {float_or_none}), - - }), - traverse_obj(product_detail_json, ('data', 'series', { - 'series_id': 'series_id', - 'series': 'name' - })), - { - 'title': self._html_search_meta(['og:title'], webpage), - 'thumbnail': self._html_search_meta(['og:image'], webpage)} - ) query = { 'r': 'vod/ajax-detail', 'platform_flag_label': 'web', 'product_id': video_id, } - area_id = self._AREA_ID.get(country_code.upper()) + area_id = self._AREA_ID.get(country_code.upper()) or runtime_info.get('areaId') if area_id: query['area_id'] = area_id - product_data = self._download_json( - f'http://www.viu.com/ott/{country_code}/index.php', video_id, - 'Downloading video info', query=query)['data'] + try: + product_data = self._download_json( + f'http://www.viu.com/ott/{country_code}/index.php', video_id, + 'Downloading video info', query=query, fatal=False)['data'] + # The `fatal` in `_download_json` didn't prevent json error + # FIXME: probably the error still too broad + except (DownloadError, ExtractorError): + # NOTE: some geo-blocked like https://www.viu.com/ott/sg/en/vod/108599/The-Beauty-Inside actually can bypassed + # on other region (like in ID) + product_data = traverse_obj( + next_js_data, ('pageProps', 'fallback', lambda k, v: v if re.match(r'@"PRODUCT_DETAIL"[^:]+', k) else None), + get_all=False)['data'] video_data = product_data.get('current_product') if not video_data: self.raise_geo_restricted() - series_id = video_data.get('series_id') + series_id = video_data.get('series_id') or traverse_obj(product_data, ('series', 'series_id')) if self._yes_playlist(series_id, video_id, idata): - series = product_data.get('series') or {} + series = product_data.get('series') or traverse_obj(product_data, ('series', 'name')) or {} product = series.get('product') if product: entries = [] @@ -389,7 +338,9 @@ def _real_extract(self, url): duration_limit = False query = { 'ccs_product_id': video_data['ccs_product_id'], - 'language_flag_id': self._LANGUAGE_FLAG.get(lang_code.lower()) or '3', + 'language_flag_id': self._LANGUAGE_FLAG.get(lang_code.lower()) or runtime_info.get('languageFlagId') or '3', + 'platform_flag_label': 'web', + 'countryCode': country_code.upper() } def download_playback(): @@ -465,7 +416,7 @@ def download_playback(): }) title = strip_or_none(video_data.get('synopsis')) - return { + return merge_dicts({ 'id': video_id, 'title': title, 'description': video_data.get('description'), @@ -476,7 +427,12 @@ def download_playback(): 'thumbnail': url_or_none(video_data.get('cover_image_url')), 'formats': formats, 'subtitles': subtitles, - } + }, traverse_obj(json_ld, { + 'thumbnails': 'thumbnails', + 'title': 'title', + 'episode': 'episode', + 'episode_number': 'episode_number' + })) class ViuOTTIndonesiaBaseIE(InfoExtractor): From f92dedc92a3356958f986ffc145e61a39d554945 Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Thu, 11 Apr 2024 07:13:34 +0800 Subject: [PATCH 13/14] handle `_download_json` error correctly This commit will fallback to webpage extraction if the API url is not found in particular regiom --- yt_dlp/extractor/viu.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index 794550c3ed..cc757eab8c 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -6,8 +6,8 @@ from .common import InfoExtractor from ..compat import compat_str +from ..networking.exceptions import HTTPError from ..utils import ( - DownloadError, ExtractorError, int_or_none, merge_dicts, @@ -304,10 +304,12 @@ def _real_extract(self, url): try: product_data = self._download_json( f'http://www.viu.com/ott/{country_code}/index.php', video_id, - 'Downloading video info', query=query, fatal=False)['data'] + 'Downloading video info', query=query)['data'] # The `fatal` in `_download_json` didn't prevent json error # FIXME: probably the error still too broad - except (DownloadError, ExtractorError): + except ExtractorError as e: + if not isinstance(e.cause, (json.JSONDecodeError, HTTPError)): + raise # NOTE: some geo-blocked like https://www.viu.com/ott/sg/en/vod/108599/The-Beauty-Inside actually can bypassed # on other region (like in ID) product_data = traverse_obj( From dfc4769853fec95bfd4714385ea7dbeba508b27e Mon Sep 17 00:00:00 2001 From: HobbyistDev Date: Fri, 2 Aug 2024 18:30:11 +0900 Subject: [PATCH 14/14] Fix formatting issue --- yt_dlp/extractor/viu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py index a192e6c376..ec8a306ea3 100644 --- a/yt_dlp/extractor/viu.py +++ b/yt_dlp/extractor/viu.py @@ -209,7 +209,7 @@ class ViuOTTIE(InfoExtractor): 'episode': 'Detective Conan - Episode 1150', 'episode_number': 1150, 'thumbnail': r're:https?://prod-images\.viu\.com/clip_asset_v6/\d+/\d+/[a-f0-9]+', - } + }, }] _AREA_ID = { @@ -341,7 +341,7 @@ def _real_extract(self, url): 'ccs_product_id': video_data['ccs_product_id'], 'language_flag_id': self._LANGUAGE_FLAG.get(lang_code.lower()) or runtime_info.get('languageFlagId') or '3', 'platform_flag_label': 'web', - 'countryCode': country_code.upper() + 'countryCode': country_code.upper(), } def download_playback(): @@ -432,7 +432,7 @@ def download_playback(): 'thumbnails': 'thumbnails', 'title': 'title', 'episode': 'episode', - 'episode_number': 'episode_number' + 'episode_number': 'episode_number', }))