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

Code before:
            '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
            while page_num < total_pages:
                season_json = self._download_json(
                    season_url.format(season_id, show_id, str(page_num + 1)), show_name, headers=headers,
                    note='Downloading season {} JSON metadata{}'.format(season_id, f' page {page_num}' if page_num else ''))
                if page_num == 0:
                    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_path = episode['attributes']['path']
                    yield self.url_result(
                        f'{self._DOMAIN}videos/{video_path}',
                        ie=self._VIDEO_IE.ie_key(), video_id=episode.get('id') or video_path)
                page_num += 1

    def _real_extract(self, url):
        show_name = self._match_valid_url(url).group('show_name')
        return self.playlist_result(self._entries(show_name), playlist_id=show_name)


class DiscoveryPlusItalyIE(DiscoveryPlusBaseIE):
    _VALID_URL = r'https?://(?:www\.)?discoveryplus\.com/it/video(?:/sport|/olympics)?' + DPlayBaseIE._PATH_REGEX
    _TESTS = [{
        'url': 'https://www.discoveryplus.com/it/video/i-signori-della-neve/stagione-2-episodio-1-i-preparativi',
        'only_matching': True,
    }, {
        'url': 'https://www.discoveryplus.com/it/video/super-benny/trailer',
        'only_matching': True,
    }, {
        'url': 'https://www.discoveryplus.com/it/video/olympics/dplus-sport-dplus-sport-sport/water-polo-greece-italy',
        'only_matching': True,
    }, {
        'url': 'https://www.discoveryplus.com/it/video/sport/dplus-sport-dplus-sport-sport/lisa-vittozzi-allinferno-e-ritorno',
        'only_matching': True,
    }]

    _PRODUCT = 'dplus_it'
    _DISCO_API_PARAMS = {
        'disco_host': 'eu1-prod-direct.discoveryplus.com',

Review comment (refactor):
`meta['taxonomies']` has category/tag data that isn't extracted now for the new shows in `_get_disco_api_info()` despite being requested in the API call there.

The data can be extracted with `traverse_obj(meta, ('taxonomies', lambda _, v: v.get('category') == 'genre', 'title', {strip_or_none}))` and merged into the dict returned by `_get_disco_api_info()`. If the result is set into `categories`, the test values have to be updated, for test 0
```py
            'categories': ['Gold', 'Schatzsucher'],
```
and for new test 1:
```py
            'categories': ['DMAX Originals', 'Jobs', 'Blaulicht'],
```
In case it's disturbing to have the same value in both `categories` and `tags` (eg, `Schatzsucher`/`schatzsucher`), one could decide to merge these into `tags` (eg, `tags.extend(c for c in categories if c.lower() not in tags)`), or to remove any tag value from the `categories`.


Code after:
            'episode_number': 1,
            'season': 'Season 1',
            'season_number': 1,
            'series': 'Evil - Gesichter des Bösen',
            'duration': 2626.0,
            'upload_date': '20240926',
            'timestamp': 1727388000,
            'creators': ['TLC'],
            '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),
        }