[extractor/cbc] Fix live extractor, playlist _VALID_URL
(#6625)
Authored by: makew0rld
This commit is contained in:
parent
b5f61b69d4
commit
7a7b1376fb
1 changed files with 83 additions and 37 deletions
|
@ -8,14 +8,16 @@ from ..compat import (
|
||||||
compat_str,
|
compat_str,
|
||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
|
ExtractorError,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
join_nonempty,
|
join_nonempty,
|
||||||
js_to_json,
|
js_to_json,
|
||||||
orderedSet,
|
orderedSet,
|
||||||
|
parse_iso8601,
|
||||||
smuggle_url,
|
smuggle_url,
|
||||||
strip_or_none,
|
strip_or_none,
|
||||||
|
traverse_obj,
|
||||||
try_get,
|
try_get,
|
||||||
ExtractorError,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -404,7 +406,7 @@ class CBCGemIE(InfoExtractor):
|
||||||
|
|
||||||
class CBCGemPlaylistIE(InfoExtractor):
|
class CBCGemPlaylistIE(InfoExtractor):
|
||||||
IE_NAME = 'gem.cbc.ca:playlist'
|
IE_NAME = 'gem.cbc.ca:playlist'
|
||||||
_VALID_URL = r'https?://gem\.cbc\.ca/media/(?P<id>(?P<show>[0-9a-z-]+)/s(?P<season>[0-9]+))/?(?:[?#]|$)'
|
_VALID_URL = r'https?://gem\.cbc\.ca/(?:media/)?(?P<id>(?P<show>[0-9a-z-]+)/s(?P<season>[0-9]+))/?(?:[?#]|$)'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
# TV show playlist, all public videos
|
# TV show playlist, all public videos
|
||||||
'url': 'https://gem.cbc.ca/media/schitts-creek/s06',
|
'url': 'https://gem.cbc.ca/media/schitts-creek/s06',
|
||||||
|
@ -414,6 +416,9 @@ class CBCGemPlaylistIE(InfoExtractor):
|
||||||
'title': 'Season 6',
|
'title': 'Season 6',
|
||||||
'description': 'md5:6a92104a56cbeb5818cc47884d4326a2',
|
'description': 'md5:6a92104a56cbeb5818cc47884d4326a2',
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
'url': 'https://gem.cbc.ca/schitts-creek/s06',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
_API_BASE = 'https://services.radio-canada.ca/ott/cbc-api/v2/shows/'
|
_API_BASE = 'https://services.radio-canada.ca/ott/cbc-api/v2/shows/'
|
||||||
|
|
||||||
|
@ -473,8 +478,9 @@ class CBCGemPlaylistIE(InfoExtractor):
|
||||||
|
|
||||||
class CBCGemLiveIE(InfoExtractor):
|
class CBCGemLiveIE(InfoExtractor):
|
||||||
IE_NAME = 'gem.cbc.ca:live'
|
IE_NAME = 'gem.cbc.ca:live'
|
||||||
_VALID_URL = r'https?://gem\.cbc\.ca/live/(?P<id>\d+)'
|
_VALID_URL = r'https?://gem\.cbc\.ca/live(?:-event)?/(?P<id>\d+)'
|
||||||
_TEST = {
|
_TESTS = [
|
||||||
|
{
|
||||||
'url': 'https://gem.cbc.ca/live/920604739687',
|
'url': 'https://gem.cbc.ca/live/920604739687',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'title': 'Ottawa',
|
'title': 'Ottawa',
|
||||||
|
@ -488,34 +494,74 @@ class CBCGemLiveIE(InfoExtractor):
|
||||||
'uploader': 'CBCC-NEW',
|
'uploader': 'CBCC-NEW',
|
||||||
},
|
},
|
||||||
'skip': 'Live might have ended',
|
'skip': 'Live might have ended',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': 'https://gem.cbc.ca/live/44',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '44',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'is_live': True,
|
||||||
|
'title': r're:^Ottawa [0-9\-: ]+',
|
||||||
|
'description': 'The live TV channel and local programming from Ottawa',
|
||||||
|
'live_status': 'is_live',
|
||||||
|
'thumbnail': r're:https://images.gem.cbc.ca/v1/cbc-gem/live/.*'
|
||||||
|
},
|
||||||
|
'params': {'skip_download': True},
|
||||||
|
'skip': 'Live might have ended',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': 'https://gem.cbc.ca/live-event/10835',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '10835',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'is_live': True,
|
||||||
|
'title': r're:^The National \| Biden’s trip wraps up, Paltrow testifies, Bird flu [0-9\-: ]+',
|
||||||
|
'description': 'March 24, 2023 | President Biden’s Ottawa visit ends with big pledges from both countries. Plus, Gwyneth Paltrow testifies in her ski collision trial.',
|
||||||
|
'live_status': 'is_live',
|
||||||
|
'thumbnail': r're:https://images.gem.cbc.ca/v1/cbc-gem/live/.*',
|
||||||
|
'timestamp': 1679706000,
|
||||||
|
'upload_date': '20230325',
|
||||||
|
},
|
||||||
|
'params': {'skip_download': True},
|
||||||
|
'skip': 'Live might have ended',
|
||||||
}
|
}
|
||||||
|
]
|
||||||
# It's unclear where the chars at the end come from, but they appear to be
|
|
||||||
# constant. Might need updating in the future.
|
|
||||||
# There are two URLs, some livestreams are in one, and some
|
|
||||||
# in the other. The JSON schema is the same for both.
|
|
||||||
_API_URLS = ['https://tpfeed.cbc.ca/f/ExhSPC/t_t3UKJR6MAT', 'https://tpfeed.cbc.ca/f/ExhSPC/FNiv9xQx_BnT']
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
video_info = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['data']
|
||||||
|
|
||||||
for api_url in self._API_URLS:
|
# Two types of metadata JSON
|
||||||
video_info = next((
|
if not video_info.get('formattedIdMedia'):
|
||||||
stream for stream in self._download_json(api_url, video_id)['entries']
|
video_info = traverse_obj(
|
||||||
if stream.get('guid') == video_id), None)
|
video_info, (('freeTv', ('streams', ...)), 'items', lambda _, v: v['key'] == video_id, {dict}),
|
||||||
if video_info:
|
get_all=False, default={})
|
||||||
break
|
|
||||||
else:
|
video_stream_id = video_info.get('formattedIdMedia')
|
||||||
|
if not video_stream_id:
|
||||||
raise ExtractorError('Couldn\'t find video metadata, maybe this livestream is now offline', expected=True)
|
raise ExtractorError('Couldn\'t find video metadata, maybe this livestream is now offline', expected=True)
|
||||||
|
|
||||||
|
stream_data = self._download_json(
|
||||||
|
'https://services.radio-canada.ca/media/validation/v2/', video_id, query={
|
||||||
|
'appCode': 'mpx',
|
||||||
|
'connectionType': 'hd',
|
||||||
|
'deviceType': 'ipad',
|
||||||
|
'idMedia': video_stream_id,
|
||||||
|
'multibitrate': 'true',
|
||||||
|
'output': 'json',
|
||||||
|
'tech': 'hls',
|
||||||
|
'manifestType': 'desktop',
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'_type': 'url_transparent',
|
|
||||||
'ie_key': 'ThePlatform',
|
|
||||||
'url': video_info['content'][0]['url'],
|
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'title': video_info.get('title'),
|
'formats': self._extract_m3u8_formats(stream_data['url'], video_id, 'mp4', live=True),
|
||||||
'description': video_info.get('description'),
|
|
||||||
'tags': try_get(video_info, lambda x: x['keywords'].split(', ')),
|
|
||||||
'thumbnail': video_info.get('cbc$staticImage'),
|
|
||||||
'is_live': True,
|
'is_live': True,
|
||||||
|
**traverse_obj(video_info, {
|
||||||
|
'title': 'title',
|
||||||
|
'description': 'description',
|
||||||
|
'thumbnail': ('images', 'card', 'url'),
|
||||||
|
'timestamp': ('airDate', {parse_iso8601}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue