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

Code before:
            'release_date': '20230619',
            'thumbnail': r're:https://images.vkplay.live/public_video_stream/12279401/preview\?change_time=\d+',
            'view_count': int,
            'concurrent_view_count': int,
            'like_count': int,
            'categories': ['EVE Online'],
            'live_status': 'is_live',
        },
        'skip': 'livestream',
        'params': {'skip_download': True},
    }]

    def _real_extract(self, url):
        username = self._match_id(url)

        initial_state = self._extract_initial_state(url, username)
        stream_info = traverse_obj(initial_state, ('stream', 'stream', 'data', 'stream'))
        if not stream_info:
            stream_info = self._download_json(f'https://api.vkplay.live/v1/blog/{username}/public_video_stream', username)
        playurls = traverse_obj(stream_info, ('data', 0, 'playerUrls', ..., {
            'url': ('url', {url_or_none}),
            'format_id': ('type', {str_or_none}),
        }))
        if not playurls:
            if not traverse_obj(stream_info, ('isOnline', {bool})):
                raise ExtractorError('Stream is offline', expected=True)

        return {
            'formats': self._parse_playurls(playurls, username),
            **traverse_obj(stream_info, {
                'id': ('id', {str}),
                'title': ('title', {str}),
                'release_timestamp': ('startTime', {int_or_none}),
                'uploader': ('user', 'nick', {str_or_none}),
                'uploader_id': ('user', 'id', {int_or_none}),
                'thumbnail': ('previewUrl', {url_or_none}),
                'view_count': ('count', 'views', {int_or_none}),
                'concurrent_view_count': ('count', 'viewers', {int_or_none}),
                'like_count': ('count', 'likes', {int_or_none}),
                'categories': ('category', 'title', {lambda i: [str_or_none(i)]}),
                'is_live': ('isOnline', {bool}),
            })
        }


Review comment (refactor):
`UserNotLive` is more appropriate here, and will allow users to `--wait-for-video`
```suggestion
        formats = self._extract_formats(stream_info, username)
        if not formats and not traverse_obj(stream_info, ('isOnline', {bool})):
                raise UserNotLive(video_id=username)
```

Code after:

        record_info = traverse_obj(self._download_json(
            f'https://api.vkplay.live/v1/blog/{username}/public_video_stream/record/{video_id}', video_id, fatal=False),
            ('data', 'record', {dict}))
        if not record_info:
            record_info = self._extract_from_initial_state(url, video_id, ('record', 'currentRecord', 'data'))

        return {
            **self._extract_common_meta(record_info),
            'id': video_id,
            'formats': self._extract_formats(record_info, video_id),
        }


class VKPlayLiveIE(VKPlayBaseIE):
    _VALID_URL = r'https?://vkplay\.live/(?P<id>[^/]+)/?(?:[#?]|$)'
    _TESTS = [{
        'url': 'https://vkplay.live/bayda',
        'info_dict': {
            'id': 'f02c321e-427b-408d-b12f-ae34e53e0ea2',
            'ext': 'mp4',
            'title': r're:эскапизм крута .*',
            'uploader': 'Bayda',
            'uploader_id': 12279401,
            'release_timestamp': 1687209962,
            'release_date': '20230619',
            'thumbnail': r're:https://images.vkplay.live/public_video_stream/12279401/preview\?change_time=\d+',
            'view_count': int,
            'concurrent_view_count': int,
            'like_count': int,
            'categories': ['EVE Online'],
            'live_status': 'is_live',
        },
        'skip': 'livestream',
        'params': {'skip_download': True},
    }]

    def _real_extract(self, url):
        username = self._match_id(url)

        stream_info = self._download_json(
            f'https://api.vkplay.live/v1/blog/{username}/public_video_stream', username, fatal=False)
        if not stream_info:
            stream_info = self._extract_from_initial_state(url, username, ('stream', 'stream', 'data', 'stream'))

        formats = self._extract_formats(stream_info, username)
        if not formats and not traverse_obj(stream_info, ('isOnline', {bool})):
            raise UserNotLive(video_id=username)

        return {
            **self._extract_common_meta(stream_info),