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

Code before:

        if '>Programmet er ikke længere tilgængeligt' in webpage:
            raise ExtractorError(
                'Video %s is not available' % raw_video_id, expected=True)

        video_id = self._search_regex(
            (r'data-(?:material-identifier|episode-slug)="([^"]+)"',
             r'data-resource="[^>"]+mu/programcard/expanded/([^"]+)"'),
            webpage, 'video id', default=None)

        if not video_id:
            video_id = self._search_regex(
                r'(urn(?:%3A|:)dr(?:%3A|:)mu(?:%3A|:)programcard(?:%3A|:)[\da-f]+)',
                webpage, 'urn', default=None)
            if video_id:
                video_id = compat_urllib_parse_unquote(video_id)

        _PROGRAMCARD_BASE = 'https://www.dr.dk/mu-online/api/1.4/programcard'
        query = {'expanded': 'true'}

        if video_id:
            programcard_url = '%s/%s' % (_PROGRAMCARD_BASE, video_id)
        else:
            programcard_url = _PROGRAMCARD_BASE
            is_radio_url = 'dr.dk/lyd' in url
            if is_radio_url:
                json_string = self._search_regex(
                    r'__NEXT_DATA__[^>]*>(.*)<\/script>',
                    webpage,
                    'next_data'
                )
                json_blob = self._parse_json(json_string, '1')
                video_id = json_blob['props']['pageProps']['episode']['productionNumber']
            else:
                page = self._parse_json(
                    self._search_regex(
                        r'data\s*=\s*({.+?})\s*(?:;|</script)', webpage,
                        'data'), '1')['cache']['page']
                page = page[list(page.keys())[0]]
                item = try_get(
                    page, (lambda x: x['item'], lambda x: x['entries'][0]['item']),
                    dict)
                video_id = item['customId'].split(':')[-1]
            query['productionnumber'] = video_id

        data = self._download_json(
            programcard_url, video_id, 'Downloading video JSON', query=query)

        supplementary_data = {}
        if re.search(r'_\d+$', raw_video_id):
            supplementary_data = self._download_json(

Review comment (refactor):
can radio pages also have a `dr.dk/radio` url?

maybe we should do it like this:

```diff
     _VALID_URL = r'''(?x)
                     https?://
                         (?:
-                            (?:www\.)?dr\.dk/(?:tv/se|nyheder|(?:radio|lyd)(?:/ondemand)?)/(?:[^/]+/)*|
+                            (?:www\.)?dr\.dk/(?:tv/se|nyheder|(?P<radio>radio|lyd)(?:/ondemand)?)/(?:[^/]+/)*|
                             (?:www\.)?(?:dr\.dk|dr-massive\.com)/drtv/(?:se|episode|program)/
                         )
                         (?P<id>[\da-z_-]+)
                     '''
```
```diff
     def _real_extract(self, url):
-        raw_video_id = self._match_id(url)
+        raw_video_id, is_radio_url = self._match_valid_url(url).group('id', 'radio')
```
```suggestion
            if is_radio_url:
```

Code after:
            'timestamp': 1678786200,
            'duration': 120.043,
            'season_id': 'urn:dr:mu:bundle:63a4f7c87140143504b6710f',
            'series': 'P4 København regionale nyheder',
            'upload_date': '20230314',
            'release_year': 0,
            'description': 'Hør seneste regionale nyheder fra P4 København.',
            'season': 'Regionale nyheder',
            'title': 'Regionale nyheder',
        },
    }]

    def _real_extract(self, url):
        raw_video_id, is_radio_url = self._match_valid_url(url).group('id', 'radio')

        webpage = self._download_webpage(url, raw_video_id)

        if '>Programmet er ikke længere tilgængeligt' in webpage:
            raise ExtractorError(
                'Video %s is not available' % raw_video_id, expected=True)

        video_id = self._search_regex(
            (r'data-(?:material-identifier|episode-slug)="([^"]+)"',
             r'data-resource="[^>"]+mu/programcard/expanded/([^"]+)"'),
            webpage, 'video id', default=None)

        if not video_id:
            video_id = self._search_regex(
                r'(urn(?:%3A|:)dr(?:%3A|:)mu(?:%3A|:)programcard(?:%3A|:)[\da-f]+)',
                webpage, 'urn', default=None)
            if video_id:
                video_id = compat_urllib_parse_unquote(video_id)

        _PROGRAMCARD_BASE = 'https://www.dr.dk/mu-online/api/1.4/programcard'
        query = {'expanded': 'true'}

        if video_id:
            programcard_url = '%s/%s' % (_PROGRAMCARD_BASE, video_id)
        else:
            programcard_url = _PROGRAMCARD_BASE
            if is_radio_url:
                video_id = self._search_nextjs_data(
                    webpage, raw_video_id)['props']['pageProps']['episode']['productionNumber']
            else:
                json_data = self._search_json(
                    r'window\.__data\s*=', webpage, 'data', raw_video_id)
                video_id = traverse_obj(json_data, (
                    'cache', 'page', ..., (None, ('entries', 0)), 'item', 'customId',
                    {lambda x: x.split(':')[-1]}), get_all=False)
                if not video_id:
                    raise ExtractorError('Unable to extract video id')