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

Code before:
    _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',
                'season_id': 'cf68a4a1-36b1-4a53-a6ba-61af5705a0d0',
                'series': 'Kryptographie - WiSe 15/16',
                'creator': 'Alexander May',
            },
        },
    ]

    def _real_extract(self, url):
        host, video_id = self._match_valid_url(url).group('host', 'id')
        response = self._call_api(host, video_id)
        package = traverse_obj(response, (
            ('search-results', 'result'),
            ('result', ...), # Path needed for oc-p.uni-jena.de
            'mediapackage', {dict}, any)) or {}
        return self._parse_mediapackage(package)


class OpencastPlaylistIE(OpencastBaseIE):
    _VALID_URL = rf'''(?x)
        https?://(?P<host>{OpencastBaseIE._INSTANCES_RE})(?:
            /engage/ui/index\.html\?(?:[^#]+&)?epFrom=|
            /ltitools/index\.html\?(?:[^#]+&)?series=
        )(?P<id>{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': 29,
        },
        {
            'url': 'https://oc-video1.ruhr-uni-bochum.de/ltitools/index.html?subtool=series&series=cf68a4a1-36b1-4a53-a6ba-61af5705a0d0&lng=de',
            'info_dict': {

Review comment (suggestion):
```suggestion
            ('result', ...),  # Path needed for oc-p.uni-jena.de
```

Code after:
    _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',
                'season_id': 'cf68a4a1-36b1-4a53-a6ba-61af5705a0d0',
                'series': 'Kryptographie - WiSe 15/16',
                'creator': 'Alexander May',
            },
        },
    ]

    def _real_extract(self, url):
        host, video_id = self._match_valid_url(url).group('host', 'id')
        response = self._call_api(host, video_id)
        package = traverse_obj(response, (
            ('search-results', 'result'),
            ('result', ...),  # Path needed for oc-p.uni-jena.de
            'mediapackage', {dict}, any)) or {}
        return self._parse_mediapackage(package)


class OpencastPlaylistIE(OpencastBaseIE):
    _VALID_URL = rf'''(?x)
        https?://(?P<host>{OpencastBaseIE._INSTANCES_RE})(?:
            /engage/ui/index\.html\?(?:[^#]+&)?epFrom=|
            /ltitools/index\.html\?(?:[^#]+&)?series=
        )(?P<id>{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': 29,
        },
        {
            'url': 'https://oc-video1.ruhr-uni-bochum.de/ltitools/index.html?subtool=series&series=cf68a4a1-36b1-4a53-a6ba-61af5705a0d0&lng=de',
            'info_dict': {