diff --git a/yt_dlp/extractor/tver.py b/yt_dlp/extractor/tver.py index ffcc6a76b7..7db81c114c 100644 --- a/yt_dlp/extractor/tver.py +++ b/yt_dlp/extractor/tver.py @@ -17,7 +17,7 @@ from ..utils.traversal import require, traverse_obj class TVerIE(StreaksBaseIE): - _VALID_URL = r'https?://(?:www\.)?tver\.jp/(?:(?Plp|corner|series|episodes?|feature)/)+(?P[a-zA-Z0-9]+)' + _VALID_URL = r'https?://(?:www\.)?tver\.jp/(?:(?Plp|corner|series|episodes?|feature|talents)/)+(?P[a-zA-Z0-9]+)' _GEO_COUNTRIES = ['JP'] _GEO_BYPASS = False _TESTS = [{ @@ -96,6 +96,13 @@ class TVerIE(StreaksBaseIE): }, { 'url': 'https://tver.jp/series/srkq2shp9d', 'only_matching': True, + }, { + 'url': 'https://tver.jp/talents/t0134c7', + 'info_dict': { + 'id': 't0134c7', + 'title': '千鳥', + }, + 'playlist_mincount': 1, }] BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/%s/default_default/index.html?videoId=%s' _HEADERS = { @@ -137,6 +144,17 @@ class TVerIE(StreaksBaseIE): yield from traverse_obj(episodes_info, ( 'result', 'contents', lambda _, v: v['type'] == 'episode', 'content', 'id', {str})) + def _yield_episode_ids_for_talent(self, talent_id): + episodes_info = self._call_platform_api( + f'v1/callTalentEpisode/{talent_id}', talent_id, + 'Downloading talent episodes info', fatal=False, query={'require_data': 'later'}) + episode_ids = list(traverse_obj(episodes_info, ( + 'result', 'contents', lambda _, v: v.get('type') == 'episode', 'content', 'id', {str}))) + if episode_ids: + yield from episode_ids + else: + self.report_warning('No episodes found for talent', video_id=talent_id) + def _real_extract(self, url): video_id, video_type = self._match_valid_url(url).group('id', 'type') backend = self._configuration_arg('backend', ['streaks'])[0] @@ -151,6 +169,18 @@ class TVerIE(StreaksBaseIE): traverse_obj(series_info, ('result', 'content', 'content', 'title', {str})), ie=TVerIE, getter=lambda x: f'https://tver.jp/episodes/{x}') + if video_type == 'talents': + # Talent metadata (non-fatal). Prefer v1; adjust traversal flexibly. + talent_info = self._call_platform_api( + f'v1/callTalent/{video_id}', video_id, 'Downloading talent info', fatal=False) + talent_title = traverse_obj(talent_info, ( + 'result', ('content', 'talent'), 'content', ('title', 'name'), {str})) or traverse_obj( + talent_info, ('result', ('content', 'talent'), ('title', 'name'), {str})) + entries_iter = list(self._yield_episode_ids_for_talent(video_id)) + return self.playlist_from_matches( + entries_iter, video_id, talent_title, + ie=TVerIE, getter=lambda x: f'https://tver.jp/episodes/{x}') + if video_type != 'episodes': webpage = self._download_webpage(url, video_id, note='Resolving to new URL') video_id = self._match_id(self._search_regex(