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

Code before:
                    ''' % (
        OpencastBaseIE._INSTANCES_RE,
        OpencastBaseIE._UUID_RE,
    )

    _API_BASE = 'https://%s/search/episode.json?id=%s'

    _TESTS = [
        {
            'url': 'https://oc-video1.ruhr-uni-bochum.de/paella/ui/watch.html?id=ed063cd5-72c8-46b5-a60a-569243edcea8',
            'md5': '554c8e99a90f7be7e874619fcf2a3bc9',
            'info_dict': {
                'id': 'ed063cd5-72c8-46b5-a60a-569243edcea8',
                'ext': 'mp4',
                'title': '11 - Kryptographie - 24.11.2015',
                'thumbnail': r're:^https?://.*\.jpg$',
                'timestamp': 1606208400,
                'upload_date': '20201124',
            },
        }
    ]

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        host = mobj.group('host')
        video_id = mobj.group('id')

        video = self._call_api(host, video_id, note='Downloading video JSON')['search-results']['result']['mediapackage']

        return self._parse_mediapackage(video)


class OpencastPlaylistIE(OpencastBaseIE):
    _VALID_URL = r'''(?x)
                            https?://(?P<host>%s)/engage/ui/index.html\?.*?
                            epFrom=(?P<id>%s)
                    ''' % (
        OpencastBaseIE._INSTANCES_RE,
        OpencastBaseIE._UUID_RE,
    )

    _API_BASE = 'https://%s/search/episode.json?sid=%s'

    _TESTS = [
        {
            'url': 'https://oc-video1.ruhr-uni-bochum.de/engage/ui/index.html?epFrom=cf68a4a1-36b1-4a53-a6ba-61af5705a0d0',
            'info_dict': {
                'id': 'cf68a4a1-36b1-4a53-a6ba-61af5705a0d0',
                'title': 'Kryptographie - WiSe 15/16',
            },
            'playlist_mincount': 28,

Review comment (suggestion):

```suggestion
        host, video_id = self._match_valid_url(url).groups()
```


Code after:
            'info_dict': {
                'id': 'ed063cd5-72c8-46b5-a60a-569243edcea8',
                'ext': 'mp4',
                'title': '11 - Kryptographie - 24.11.2015',
                'thumbnail': r're:^https?://.*\.jpg$',
                'timestamp': 1606208400,
                'upload_date': '20201124',
            },
        }
    ]

    def _real_extract(self, url):
        host, video_id = self._match_valid_url(url).group('host', 'id')
        return self._parse_mediapackage(
            self._call_api(host, video_id)['search-results']['result']['mediapackage'])


class OpencastPlaylistIE(OpencastBaseIE):
    _VALID_URL = r'''(?x)
                            https?://(?P<host>%s)/engage/ui/index.html\?.*?
                            epFrom=(?P<id>%s)
                    ''' % (OpencastBaseIE._INSTANCES_RE, OpencastBaseIE._UUID_RE)

    _API_BASE = 'https://%s/search/episode.json?sid=%s'

    _TESTS = [
        {
            'url': 'https://oc-video1.ruhr-uni-bochum.de/engage/ui/index.html?epFrom=cf68a4a1-36b1-4a53-a6ba-61af5705a0d0',
            'info_dict': {
                'id': 'cf68a4a1-36b1-4a53-a6ba-61af5705a0d0',
                'title': 'Kryptographie - WiSe 15/16',
            },
            'playlist_mincount': 28,
        },
        {
            'url': 'https://oc-video.ruhr-uni-bochum.de/engage/ui/index.html?e=1&p=1&epFrom=b1a54262-3684-403f-9731-8e77c3766f9a',
            'info_dict': {
                'id': 'b1a54262-3684-403f-9731-8e77c3766f9a',
                'title': 'inSTUDIES-Social movements and prefigurative politics in a global perspective',
            },
            'playlist_mincount': 6,
        },
    ]

    def _real_extract(self, url):
        host, video_id = self._match_valid_url(url).group('host', 'id')

        entries = [
            self._parse_mediapackage(episode['mediapackage'])
            for episode in variadic(self._call_api(host, video_id)['search-results']['result'])
            if episode.get('mediapackage')