diff options
-rw-r--r-- | yt_dlp/extractor/brightcove.py | 27 | ||||
-rw-r--r-- | yt_dlp/extractor/dplay.py | 6 | ||||
-rw-r--r-- | yt_dlp/extractor/extractors.py | 4 | ||||
-rw-r--r-- | yt_dlp/extractor/fujitv.py | 17 | ||||
-rw-r--r-- | yt_dlp/extractor/instagram.py | 5 | ||||
-rw-r--r-- | yt_dlp/extractor/rutube.py | 21 | ||||
-rw-r--r-- | yt_dlp/extractor/toggo.py | 73 |
7 files changed, 127 insertions, 26 deletions
diff --git a/yt_dlp/extractor/brightcove.py b/yt_dlp/extractor/brightcove.py index 171739b46..82bb76f29 100644 --- a/yt_dlp/extractor/brightcove.py +++ b/yt_dlp/extractor/brightcove.py @@ -472,32 +472,22 @@ class BrightcoveNewIE(AdobePassIE): def _parse_brightcove_metadata(self, json_data, video_id, headers={}): title = json_data['name'].strip() - num_drm_sources = 0 formats, subtitles = [], {} sources = json_data.get('sources') or [] for source in sources: container = source.get('container') ext = mimetype2ext(source.get('type')) src = source.get('src') - skip_unplayable = not self.get_param('allow_unplayable_formats') - # https://support.brightcove.com/playback-api-video-fields-reference#key_systems_object - if skip_unplayable and (container == 'WVM' or source.get('key_systems')): - num_drm_sources += 1 - continue - elif ext == 'ism' and skip_unplayable: - continue - elif ext == 'm3u8' or container == 'M2TS': + if ext == 'm3u8' or container == 'M2TS': if not src: continue - f, subs = self._extract_m3u8_formats_and_subtitles( + fmts, subs = self._extract_m3u8_formats_and_subtitles( src, video_id, 'mp4', 'm3u8_native', m3u8_id='hls', fatal=False) - formats.extend(f) subtitles = self._merge_subtitles(subtitles, subs) elif ext == 'mpd': if not src: continue - f, subs = self._extract_mpd_formats_and_subtitles(src, video_id, 'dash', fatal=False) - formats.extend(f) + fmts, subs = self._extract_mpd_formats_and_subtitles(src, video_id, 'dash', fatal=False) subtitles = self._merge_subtitles(subtitles, subs) else: streaming_src = source.get('streaming_src') @@ -544,7 +534,13 @@ class BrightcoveNewIE(AdobePassIE): 'play_path': stream_name, 'format_id': build_format_id('rtmp'), }) - formats.append(f) + fmts = [f] + + # https://support.brightcove.com/playback-api-video-fields-reference#key_systems_object + if container == 'WVM' or source.get('key_systems') or ext == 'ism': + for f in fmts: + f['has_drm'] = True + formats.extend(fmts) if not formats: errors = json_data.get('errors') @@ -552,9 +548,6 @@ class BrightcoveNewIE(AdobePassIE): error = errors[0] self.raise_no_formats( error.get('message') or error.get('error_subcode') or error['error_code'], expected=True) - elif (not self.get_param('allow_unplayable_formats') - and sources and num_drm_sources == len(sources)): - self.report_drm(video_id) self._sort_formats(formats) diff --git a/yt_dlp/extractor/dplay.py b/yt_dlp/extractor/dplay.py index f5d6540c0..51e1f8f3c 100644 --- a/yt_dlp/extractor/dplay.py +++ b/yt_dlp/extractor/dplay.py @@ -564,10 +564,10 @@ class DiscoveryPlusShowBaseIE(DPlayBaseIE): total_pages = try_get(season_json, lambda x: x['meta']['totalPages'], int) or 1 episodes_json = season_json['data'] for episode in episodes_json: - video_id = episode['attributes']['path'] + video_path = episode['attributes']['path'] yield self.url_result( - '%svideos/%s' % (self._DOMAIN, video_id), - ie=self._VIDEO_IE.ie_key(), video_id=video_id) + '%svideos/%s' % (self._DOMAIN, video_path), + ie=self._VIDEO_IE.ie_key(), video_id=episode.get('id') or video_path) page_num += 1 def _real_extract(self, url): diff --git a/yt_dlp/extractor/extractors.py b/yt_dlp/extractor/extractors.py index 8d7c54ec4..73eb374ee 100644 --- a/yt_dlp/extractor/extractors.py +++ b/yt_dlp/extractor/extractors.py @@ -1265,6 +1265,7 @@ from .rutube import ( RutubeMovieIE, RutubePersonIE, RutubePlaylistIE, + RutubeTagsIE, ) from .rutv import RUTVIE from .ruutu import RuutuIE @@ -1513,6 +1514,9 @@ from .toggle import ( ToggleIE, MeWatchIE, ) +from .toggo import ( + ToggoIE, +) from .tokentube import ( TokentubeIE, TokentubeChannelIE diff --git a/yt_dlp/extractor/fujitv.py b/yt_dlp/extractor/fujitv.py index a02a94374..1cea62609 100644 --- a/yt_dlp/extractor/fujitv.py +++ b/yt_dlp/extractor/fujitv.py @@ -5,19 +5,32 @@ from .common import InfoExtractor class FujiTVFODPlus7IE(InfoExtractor): - _VALID_URL = r'https?://i\.fod\.fujitv\.co\.jp/plus7/web/[0-9a-z]{4}/(?P<id>[0-9a-z]+)' + _VALID_URL = r'https?://fod\.fujitv\.co\.jp/title/[0-9a-z]{4}/(?P<id>[0-9a-z]+)' _BASE_URL = 'http://i.fod.fujitv.co.jp/' _BITRATE_MAP = { 300: (320, 180), 800: (640, 360), 1200: (1280, 720), 2000: (1280, 720), + 4000: (1920, 1080), } + _TESTS = [{ + 'url': 'https://fod.fujitv.co.jp/title/5d40/5d40810075', + 'info_dict': { + 'id': '5d40810075', + 'title': '5d40810075', + 'ext': 'mp4', + 'format_id': '4000', + 'thumbnail': 'http://i.fod.fujitv.co.jp/pc/image/wbtn/wbtn_5d40810075.jpg' + }, + 'skip': 'Expires after a week' + }] + def _real_extract(self, url): video_id = self._match_id(url) formats = self._extract_m3u8_formats( - self._BASE_URL + 'abr/pc_html5/%s.m3u8' % video_id, video_id, 'mp4') + self._BASE_URL + 'abr/tv_android/%s.m3u8' % video_id, video_id, 'mp4') for f in formats: wh = self._BITRATE_MAP.get(f.get('tbr')) if wh: diff --git a/yt_dlp/extractor/instagram.py b/yt_dlp/extractor/instagram.py index 2ec24f3e7..84c1daca6 100644 --- a/yt_dlp/extractor/instagram.py +++ b/yt_dlp/extractor/instagram.py @@ -170,7 +170,7 @@ class InstagramIOSIE(InfoExtractor): class InstagramIE(InstagramBaseIE): - _VALID_URL = r'(?P<url>https?://(?:www\.)?instagram\.com/(?:p|tv|reel)/(?P<id>[^/?#&]+))' + _VALID_URL = r'(?P<url>https?://(?:www\.)?instagram\.com(?:/[^/]+)?/(?:p|tv|reel)/(?P<id>[^/?#&]+))' _TESTS = [{ 'url': 'https://instagram.com/p/aye83DjauH/?foo=bar#abc', 'md5': '0d2da106a9d2631273e192b372806516', @@ -266,6 +266,9 @@ class InstagramIE(InstagramBaseIE): }, { 'url': 'https://www.instagram.com/reel/CDUMkliABpa/', 'only_matching': True, + }, { + 'url': 'https://www.instagram.com/marvelskies.fc/reel/CWqAgUZgCku/', + 'only_matching': True, }] @staticmethod diff --git a/yt_dlp/extractor/rutube.py b/yt_dlp/extractor/rutube.py index d027412c4..2f753b41f 100644 --- a/yt_dlp/extractor/rutube.py +++ b/yt_dlp/extractor/rutube.py @@ -230,9 +230,9 @@ class RutubePlaylistBaseIE(RutubeBaseIE): return self._extract_playlist(self._match_id(url)) -class RutubeChannelIE(RutubePlaylistBaseIE): - IE_NAME = 'rutube:channel' - IE_DESC = 'Rutube channels' +class RutubeTagsIE(RutubePlaylistBaseIE): + IE_NAME = 'rutube:tags' + IE_DESC = 'Rutube tags' _VALID_URL = r'https?://rutube\.ru/tags/video/(?P<id>\d+)' _TESTS = [{ 'url': 'http://rutube.ru/tags/video/1800/', @@ -312,3 +312,18 @@ class RutubePlaylistIE(RutubePlaylistBaseIE): playlist_kind = qs['pl_type'][0] playlist_id = qs['pl_id'][0] return self._extract_playlist(playlist_id, item_kind=playlist_kind) + + +class RutubeChannelIE(RutubePlaylistBaseIE): + IE_NAME = 'rutube:channel' + IE_DESC = 'Rutube channel' + _VALID_URL = r'https?://rutube\.ru/channel/(?P<id>\d+)/videos' + _TESTS = [{ + 'url': 'https://rutube.ru/channel/639184/videos/', + 'info_dict': { + 'id': '639184', + }, + 'playlist_mincount': 133, + }] + + _PAGE_TEMPLATE = 'http://rutube.ru/api/video/person/%s/?page=%s&format=json' diff --git a/yt_dlp/extractor/toggo.py b/yt_dlp/extractor/toggo.py new file mode 100644 index 000000000..da5f0c4d1 --- /dev/null +++ b/yt_dlp/extractor/toggo.py @@ -0,0 +1,73 @@ +from .common import InfoExtractor +from ..utils import int_or_none, parse_qs + + +class ToggoIE(InfoExtractor): + IE_NAME = 'toggo' + _VALID_URL = r'https?://(?:www\.)?toggo\.de/[\w-]+/folge/(?P<id>[\w-]+)' + _TESTS = [{ + 'url': 'https://www.toggo.de/weihnachtsmann--co-kg/folge/ein-geschenk-fuer-zwei', + 'info_dict': { + 'id': 'VEP2977', + 'ext': 'mp4', + 'title': 'Ein Geschenk für zwei', + 'display_id': 'ein-geschenk-fuer-zwei', + 'thumbnail': r're:^https?://.*\.(?:jpg|png)', + 'description': 'md5:b7715915bfa47824b4e4ad33fb5962f8', + 'release_timestamp': 1637259179, + 'series': 'Weihnachtsmann & Co. KG', + 'season': 'Weihnachtsmann & Co. KG', + 'season_number': 1, + 'season_id': 'VST118', + 'episode': 'Ein Geschenk für zwei', + 'episode_number': 7, + 'episode_id': 'VEP2977', + 'timestamp': 1581935960, + 'uploader_id': '6057955896001', + 'upload_date': '20200217', + }, + 'params': {'skip_download': True}, + }] + + def _real_extract(self, url): + display_id = self._match_id(url) + data = self._download_json( + f'https://production-n.toggo.de/api/assetstore/vod/asset/{display_id}', display_id)['data'] + + brightcove_id = next( + x['value'] for x in data['custom_fields'] if x.get('key') == 'video-cloud-id') + info = self._downloader.get_info_extractor('BrightcoveNew').extract( + f'http://players.brightcove.net/6057955896001/default_default/index.html?videoId={brightcove_id}') + + for f in info['formats']: + if '/dash/live/cenc/' in f.get('fragment_base_url', ''): + # Get hidden non-DRM format + f['fragment_base_url'] = f['fragment_base_url'].replace('/cenc/', '/clear/') + f['has_drm'] = False + + if '/fairplay/' in f.get('manifest_url', ''): + f['has_drm'] = True + + thumbnails = [{ + 'id': name, + 'url': url, + 'width': int_or_none(next(iter(parse_qs(url).get('width', [])), None)), + } for name, url in (data.get('images') or {}).items()] + + return { + **info, + 'id': data.get('id'), + 'display_id': display_id, + 'title': data.get('title'), + 'language': data.get('language'), + 'thumbnails': thumbnails, + 'description': data.get('description'), + 'release_timestamp': data.get('earliest_start_date'), + 'series': data.get('series_title'), + 'season': data.get('season_title'), + 'season_number': data.get('season_no'), + 'season_id': data.get('season_id'), + 'episode': data.get('title'), + 'episode_number': data.get('episode_no'), + 'episode_id': data.get('id'), + } |