aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--yt_dlp/extractor/brightcove.py27
-rw-r--r--yt_dlp/extractor/dplay.py6
-rw-r--r--yt_dlp/extractor/extractors.py4
-rw-r--r--yt_dlp/extractor/fujitv.py17
-rw-r--r--yt_dlp/extractor/instagram.py5
-rw-r--r--yt_dlp/extractor/rutube.py21
-rw-r--r--yt_dlp/extractor/toggo.py73
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'),
+ }