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

Code before:
            'thumbnail': 'https://eu1-prod-images.disco-api.com/2024/11/29/e9f3e3ae-74ec-3631-81b7-fc7bbe844741.jpeg',
            'tags': ['kriminalfall', 'böse', 'verbrecher', 'zusammenleben', 'mord', 'familie', 'ermittler', 'leben', 'fälle', 'opfer', 'tod', 'mörder', 'crime'],
            'categories': ['True Crime', 'Mord'],
        },
        'params': {'skip_download': 'm3u8'},
    }]

    def _real_extract(self, url):
        domain, programme, alternate_id = self._match_valid_url(url).groups()
        country = 'DE'
        realm = domain.replace('.', '')
        environment = domain.split('.')[0]
        meta = self._download_json(
            f'https://de-api.loma-cms.com/feloma/videos/{alternate_id}/',
            alternate_id, query={
                'environment': environment,
                'v': '2',
                'filter[show.slug]': programme,
            }, fatal=False)
        video_id = traverse_obj(meta, ('uid', {str}, {lambda s: s[-7:]}))
        categories = traverse_obj(meta, ('taxonomies', lambda _, v: v.get('category') == 'genre', 'title', {strip_or_none}))

        disco_api_info = self._get_disco_api_info(
            url, video_id, 'eu1-prod.disco-api.com', realm, country)
        disco_api_info['categories'] = categories
        return disco_api_info

    def _update_disco_api_headers(self, headers, disco_base, display_id, realm):
        headers.update({
            'x-disco-params': f'realm={realm}',
            'x-disco-client': 'Alps:HyogaPlayer:0.0.0',
            'Authorization': self._get_auth(disco_base, display_id, realm),
        })


class DiscoveryPlusShowBaseIE(DPlayBaseIE):

    def _entries(self, show_name):
        headers = {
            'x-disco-client': self._X_CLIENT,
            'x-disco-params': f'realm={self._REALM}',
            'referer': self._DOMAIN,
            'Authentication': self._get_auth(self._BASE_API, None, self._REALM),
        }
        show_json = self._download_json(
            f'{self._BASE_API}cms/routes/{self._SHOW_STR}/{show_name}?include=default',
            video_id=show_name, headers=headers)['included'][self._INDEX]['attributes']['component']
        show_id = show_json['mandatoryParams'].split('=')[-1]
        season_url = self._BASE_API + 'content/videos?sort=episodeNumber&filter[seasonNumber]={}&filter[show.id]={}&page[size]=100&page[number]={}'
        for season in show_json['filters'][0]['options']:
            season_id = season['id']

Review comment (suggestion):
- If the `meta` API call is non-fatal, then we need a fallback value for `video_id`
- Inline when it's reasonable to do so
- If we're going to modify the `disco_api_info` result for `categories`, then we may as well preserve the `display_id` too

```suggestion
        meta = self._download_json(
            f'https://de-api.loma-cms.com/feloma/videos/{alternate_id}/',
            alternate_id, query={
                'environment': domain.split('.')[0],
                'v': '2',
                'filter[show.slug]': programme,
            }, fatal=False)
        video_id = traverse_obj(meta, ('uid', {str}, {lambda s: s[-7:]})) or alternate_id

        disco_api_info = self._get_disco_api_info(
            url, video_id, 'eu1-prod.disco-api.com', domain.replace('.', ''), 'DE')
        disco_api_info['display_id'] = alternate_id
        disco_api_info['categories'] = traverse_obj(meta, (
            'taxonomies', lambda _, v: v['category'] == 'genre', 'title', {str.strip}, filter, all, filter))
        return disco_api_info
```

Code after:
            'thumbnail': 'https://eu1-prod-images.disco-api.com/2024/11/29/e9f3e3ae-74ec-3631-81b7-fc7bbe844741.jpeg',
            'tags': 'count:13',
            'categories': ['True Crime', 'Mord'],
        },
        'params': {'skip_download': 'm3u8'},
    }]

    def _real_extract(self, url):
        domain, programme, alternate_id = self._match_valid_url(url).groups()
        meta = self._download_json(
            f'https://de-api.loma-cms.com/feloma/videos/{alternate_id}/',
            alternate_id, query={
                'environment': domain.split('.')[0],
                'v': '2',
                'filter[show.slug]': programme,
            }, fatal=False)
        video_id = traverse_obj(meta, ('uid', {str}, {lambda s: s[-7:]})) or alternate_id

        disco_api_info = self._get_disco_api_info(
            url, video_id, 'eu1-prod.disco-api.com', domain.replace('.', ''), 'DE')
        disco_api_info['display_id'] = alternate_id
        disco_api_info['categories'] = traverse_obj(meta, (
            'taxonomies', lambda _, v: v['category'] == 'genre', 'title', {str.strip}, filter, all, filter))

        return disco_api_info

    def _update_disco_api_headers(self, headers, disco_base, display_id, realm):
        headers.update({
            'x-disco-params': f'realm={realm}',
            'x-disco-client': 'Alps:HyogaPlayer:0.0.0',
            'Authorization': self._get_auth(disco_base, display_id, realm),
        })


class DiscoveryPlusShowBaseIE(DPlayBaseIE):

    def _entries(self, show_name):
        headers = {
            'x-disco-client': self._X_CLIENT,
            'x-disco-params': f'realm={self._REALM}',
            'referer': self._DOMAIN,
            'Authentication': self._get_auth(self._BASE_API, None, self._REALM),
        }
        show_json = self._download_json(
            f'{self._BASE_API}cms/routes/{self._SHOW_STR}/{show_name}?include=default',
            video_id=show_name, headers=headers)['included'][self._INDEX]['attributes']['component']
        show_id = show_json['mandatoryParams'].split('=')[-1]
        season_url = self._BASE_API + 'content/videos?sort=episodeNumber&filter[seasonNumber]={}&filter[show.id]={}&page[size]=100&page[number]={}'
        for season in show_json['filters'][0]['options']:
            season_id = season['id']
            total_pages, page_num = 1, 0