Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/tbsjp.py (Python)

Code before:
    _GEO_BYPASS = False
    _TESTS = [{
        'url': 'https://cu.tbs.co.jp/episode/14694_2090934_1000117476',
        'skip': 'geo-blocked to japan + 7-day expiry',
        'info_dict': {
            'title': '次世代リアクション王発掘トーナメント',
            'id': '14694_2090934_1000117476',
            'ext': 'mp4',
            'display_id': 'ref:14694_2090934_1000117476',
            'description': 'md5:63a2f445387f9d8c50f4e76396df968f',
            'uploader_id': 'tbs',
            'duration': 2761,
            'thumbnail': 'md5:5e044cd3431b1301de1a25911a6a9a4e',
            'categories': ['エンタメ', '水曜日のダウンタウン', 'ダウンタウン', '浜田雅功', '松本人志', '水ダウ', 'バラエティ', '動画'],
            'series': '水曜日のダウンタウン',
            'episode': '次世代リアクション王発掘トーナメント',
            'episode_number': 335,
            'timestamp': 1749547434,
            'upload_date': '20250610',
            'release_timestamp': 1749646802,
            'release_date': '20250611',
            'modified_timestamp': 1749647146,
            'modified_date': '20250611',
            'live_status': 'not_live',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        meta = self._search_json(r'window\.app\s*=', webpage, 'episode info', video_id, fatal=False)
        episode = traverse_obj(meta, ('falcorCache', 'catalog', 'episode', video_id, 'value'))

        return {
            **self._extract_from_streaks_api('tbs', f'ref:{video_id}', headers={'Referer': 'https://cu.tbs.co.jp/'}),
            'title': traverse_obj(webpage, ({find_element(tag='h3')}, {clean_html})),
            'id': video_id,
            **traverse_obj(episode, {
                'categories': ('keywords', {list}),
                'id': ('content_id', {str}),
                'description': ('description', 0, 'value'),
                'timestamp': ('created_at', {unified_timestamp}),
                'release_timestamp': ('pub_date', {unified_timestamp}),
                'duration': ('tv_episode_info', 'duration', {int_or_none}),
                'episode_number': ('tv_episode_info', 'episode_number', {int_or_none}),
                'episode': ('title', lambda _, v: not v.get('is_phonetic'), 'value'),
                'series': ('custom_data', 'program_name'),
            }, get_all=False),
        }



Review comment (suggestion):
update `_TESTS` to reflect changes below
```diff
@@ -15,26 +15,31 @@ class TBSJPEpisodeIE(StreaksBaseIE):
     _TESTS = [{
         'url': 'https://cu.tbs.co.jp/episode/14694_2090934_1000117476',
-        'skip': 'geo-blocked to japan + 7-day expiry',
         'info_dict': {
-            'title': '次世代リアクション王発掘トーナメント',
             'id': '14694_2090934_1000117476',
             'ext': 'mp4',
+            'title': '次世代リアクション王発掘トーナメント',
+            'cast': 'count:7',
+            'categories': 'count:8',
+            'description': 'md5:0f57448221519627dce7802432729159',
             'display_id': 'ref:14694_2090934_1000117476',
-            'description': 'md5:63a2f445387f9d8c50f4e76396df968f',
-            'uploader_id': 'tbs',
             'duration': 2761,
-            'thumbnail': 'md5:5e044cd3431b1301de1a25911a6a9a4e',
-            'categories': ['エンタメ', '水曜日のダウンタウン', 'ダウンタウン', '浜田雅功', '松本人志', '水ダウ', 'バラエティ', '動画'],
-            'series': '水曜日のダウンタウン',
             'episode': '次世代リアクション王発掘トーナメント',
+            'episode_id': '14694_2090934_1000117476',
             'episode_number': 335,
+            'genres': 'count:1',
+            'live_status': 'not_live',
+            'modified_date': '20250611',
+            'modified_timestamp': 1749647146,
+            'release_date': '20250611',
+            'release_timestamp': 1749646802,
+            'series': '水曜日のダウンタウン',
+            'series_id': '14694',
+            'thumbnail': r're:https?://.+\.jpg',
             'timestamp': 1749547434,
             'upload_date': '20250610',
-            'release_timestamp': 1749646802,
-            'release_date': '20250611',
-            'modified_timestamp': 1749647146,
-            'modified_date': '20250611',
-            'live_status': 'not_live',
+            'uploader': 'TBS',
+            'uploader_id': 'tbs',
         },
+        'skip': 'Geo-restricted to Japan; available for 7 days',
     }]
```

Code after:
        return self._search_json(r'window\.app\s*=', webpage, f'{name} info', item_id, **kwargs)


class TBSJPEpisodeIE(TBSJPBaseIE):
    _VALID_URL = r'https?://cu\.tbs\.co\.jp/episode/(?P<id>[\d_]+)'
    _TESTS = [{
        'url': 'https://cu.tbs.co.jp/episode/14694_2094162_1000123656',
        'skip': 'geo-blocked to japan + 7-day expiry',
        'info_dict': {
            'title': 'クロちゃん、寝て起きたら川のほとりにいてその向こう岸に亡くなった父親がいたら死の淵にいるかと思う説 ほか',
            'id': '14694_2094162_1000123656',
            'ext': 'mp4',
            'display_id': 'ref:14694_2094162_1000123656',
            'description': 'md5:1a82fcdeb5e2e82190544bb72721c46e',
            'uploader': 'TBS',
            'uploader_id': 'tbs',
            'duration': 2752,
            'thumbnail': 'md5:d8855c8c292683c95a84cafdb42300bc',
            'categories': ['エンタメ', '水曜日のダウンタウン', 'ダウンタウン', '浜田雅功', '松本人志', '水ダウ', '動画', 'バラエティ'],
            'cast': ['浜田 雅功', '藤本 敏史', 'ビビる 大木', '千原 ジュニア', '横澤 夏子', 'せいや', 'あの', '服部 潤'],
            'genres': ['variety'],
            'series': '水曜日のダウンタウン',
            'series_id': '14694',
            'episode': 'クロちゃん、寝て起きたら川のほとりにいてその向こう岸に亡くなった父親がいたら死の淵にいるかと思う説 ほか',
            'episode_number': 341,
            'episode_id': '14694_2094162_1000123656',
            'timestamp': 1753778992,
            'upload_date': '20250729',
            'release_timestamp': 1753880402,
            'release_date': '20250730',
            'modified_timestamp': 1753880741,
            'modified_date': '20250730',
            'live_status': 'not_live',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        meta = self._search_window_app_json(webpage, 'episode', video_id, fatal=False)
        episode = traverse_obj(meta, ('falcorCache', 'catalog', 'episode', video_id, 'value'))

        return {
            **self._extract_from_streaks_api(
                'tbs', f'ref:{video_id}', headers={'Origin': 'https://cu.tbs.co.jp'}),
            **traverse_obj(episode, {
                'title': ('title', ..., 'value', {str}, any),
                'cast': (
                    'credit', ..., 'name', ..., 'value', {clean_html}, any,
                    {lambda x: x.split(',')}, ..., {str.strip}, filter, all, filter),
                'categories': ('keywords', ..., {str}, filter, all, filter),