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

Code before:
    _TESTS = [{
        'url': 'https://nuum.ru/channel/mts_live',
        'only_matching': True,
    }]

    def _get_container(self, url):
        channel_name = self._match_id(url)
        broadcast = self._fetch(
            'broadcasts/public', video_id=channel_name, description='channel',
            query={
                'with_extra': 'true',
                'channel_name': channel_name,
                'with_deleted': 'true',
            }
        )
        if not traverse_obj(broadcast, ('channel', 'channel_is_live')):
            raise ExtractorError('The channel is not currently live', expected=True)
        return broadcast.get('media_container')

    def _get_media_url(self, media_meta):
        return media_meta['media_url'], True


class NuumStreamIE(NuumBaseIE):
    IE_NAME = 'nuum:stream'
    _VALID_URL = r'https?://nuum\.ru/streams/(?P<id>[\d]+)'
    _TESTS = [{
        'url': 'https://nuum.ru/streams/1592713-7-days-to-die',
        'only_matching': True,
    }]


class NuumVideoIE(NuumBaseIE):
    IE_NAME = 'nuum:video'
    _VALID_URL = r'https?://nuum\.ru/videos/(?P<id>[\d]+)'
    _TESTS = [{
        'url': 'https://nuum.ru/videos/1567547-toxi-hurtz',
        'md5': 'f1d9118a30403e32b702a204eb03aca3',
        'info_dict': {
            'id': '1546357',
            'ext': 'mp4',
            'title': 'Toxi$ - Hurtz',
            'description': '',
            'timestamp': 1702631651,
            'upload_date': '20231215',
            'thumbnail': r're:^https?://.+\.jpg',
            'view_count': int,
        },
    }]



Review comment (refactor):
As streams, videos, and clips have the same ID space and no code differences, I think they should be a single extractor.
If the channel extractor is changed to be for playlists, then some stuff should also be moved out of the base class/can be simplified.

Code after:
                'duration': ('media_duration', {int_or_none}),
                'thumbnail': ('media_meta', ('media_preview_archive_url', 'media_preview_url'), {url_or_none}),
            }, get_all=False),
        })


class NuumMediaIE(NuumBaseIE):
    IE_NAME = 'nuum:media'
    _VALID_URL = r'https?://nuum\.ru/(?:streams|videos|clips)/(?P<id>[\d]+)'
    _TESTS = [{
        'url': 'https://nuum.ru/streams/1592713-7-days-to-die',
        'only_matching': True,
    }, {
        'url': 'https://nuum.ru/videos/1567547-toxi-hurtz',
        'md5': 'f1d9118a30403e32b702a204eb03aca3',
        'info_dict': {
            'id': '1567547',
            'ext': 'mp4',
            'title': 'Toxi$ - Hurtz',
            'description': '',
            'timestamp': 1702631651,
            'upload_date': '20231215',
            'thumbnail': r're:^https?://.+\.jpg',
            'view_count': int,
            'concurrent_view_count': int,
            'channel_id': '6911',
            'channel': 'toxis',
            'duration': 116,
        },
    }, {
        'url': 'https://nuum.ru/clips/1552564-pro-misu',
        'md5': 'b248ae1565b1e55433188f11beeb0ca1',
        'info_dict': {
            'id': '1552564',
            'ext': 'mp4',
            'title': 'Про Мису 🙃',
            'timestamp': 1701971828,
            'upload_date': '20231207',
            'thumbnail': r're:^https?://.+\.jpg',
            'view_count': int,
            'concurrent_view_count': int,
            'channel_id': '3320',
            'channel': 'Misalelik',
            'duration': 41,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        video_data = self._call_api(f'media-containers/{video_id}', video_id, 'media')