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

Code before:
        'info_dict': {
            'id': 'video?q=rumble&sort=views',
            'title': 'Search results for: rumble',
            'age_limit': 0,
        },
    }]

    def _real_extract(self, url):
        page_id = self._match_id(url)
        webpage = self._download_webpage(url, page_id)
        url_info = next(RumbleEmbedIE.extract_from_webpage(self._downloader, url, webpage), None)
        if not url_info:
            raise UnsupportedError(url)

        release_ts_str = self._search_regex(
            r'(?:Livestream begins|Streamed on):\s+<time datetime="([^"]+)',
            webpage, 'release date', fatal=False, default=None)
        like_count_str = self._search_regex(
            r'<span data-js="rumbles_up_votes">([\d,\.KM]+)<',
            webpage, 'like count', fatal=False, default=None)
        dislike_count_str = self._search_regex(
            r'<span data-js="rumbles_down_votes">([\d,\.KM]+)<',
            webpage, 'dislike count', fatal=False, default=None)
        view_count_str = self._search_regex(
            r'"userInteractionCount":([\d,]+)}',
            webpage, 'view count', fatal=False, default=None)

        return self.url_result(
            url_info['url'], ie_key=url_info['ie_key'], url_transparent=True,
            view_count=parse_count(view_count_str),
            release_timestamp=parse_iso8601(release_ts_str),
            like_count=parse_count(like_count_str),
            dislike_count=parse_count(dislike_count_str),
            description=clean_html(get_element_by_class('media-description', webpage)),
        )


class RumbleChannelIE(InfoExtractor):
    _VALID_URL = r'(?P<url>https?://(?:www\.)?rumble\.com/(?:c|user)/(?P<id>[^&?#$/]+))'

    _TESTS = [{
        'url': 'https://rumble.com/c/Styxhexenhammer666',
        'playlist_mincount': 1160,
        'info_dict': {
            'id': 'Styxhexenhammer666',
        },
    }, {
        'url': 'https://rumble.com/user/goldenpoodleharleyeuna',
        'playlist_mincount': 4,
        'info_dict': {
            'id': 'goldenpoodleharleyeuna',

Review comment (security):
- `fatal=False` is redundant if there is a `default`
- `.` does not need to be escaped inside a regex character class
- For `view_count`, would it be better to parse the JSON LD instead? Would save a step maybe. Or else the regex pattern should allow whitespace, e.g. `r'"userInteractionCount"\s*:\s*(\d+)'` . And it's a JSON int value, so the `,` and `parse_count` are unnecessary
- all of this might make more sense inlined in the return, and then for readability it should return an info_dict instead of `self.url_result()`, e.g.:
```py
        return {
            '_type': 'url_transparent'
            'ie_key': url_info['ie_key'],
            'url': url_info['url'],
            'like_count': parse_count(self._search_regex(
                r'<span data-js="rumbles_up_votes">\s*([\d,.KM]+)', webpage, 'like count', default=None)),
            # etc...
        }
```


Code after:
        'info_dict': {
            'id': 'video?q=rumble&sort=views',
            'title': 'Search results for: rumble',
            'age_limit': 0,
        },
    }]

    def _real_extract(self, url):
        page_id = self._match_id(url)
        webpage = self._download_webpage(url, page_id)
        url_info = next(RumbleEmbedIE.extract_from_webpage(self._downloader, url, webpage), None)
        if not url_info:
            raise UnsupportedError(url)

        return {
            '_type': 'url_transparent',
            'ie_key': url_info['ie_key'],
            'url': url_info['url'],
            'release_timestamp': parse_iso8601(self._search_regex(
                r'(?:Livestream begins|Streamed on):\s+<time datetime="([^"]+)', webpage, 'release date', default=None)),
            'view_count': int_or_none(self._search_regex(
                r'"userInteractionCount"\s*:\s*(\d+)', webpage, 'view count', default=None)),
            'like_count': parse_count(self._search_regex(
                r'<span data-js="rumbles_up_votes">\s*([\d,.KM]+)', webpage, 'like count', default=None)),
            'dislike_count': parse_count(self._search_regex(
                r'<span data-js="rumbles_down_votes">\s*([\d,.KM]+)', webpage, 'dislike count', default=None)),
            'description': clean_html(get_element_by_class('media-description', webpage))
        }


class RumbleChannelIE(InfoExtractor):
    _VALID_URL = r'(?P<url>https?://(?:www\.)?rumble\.com/(?:c|user)/(?P<id>[^&?#$/]+))'

    _TESTS = [{
        'url': 'https://rumble.com/c/Styxhexenhammer666',
        'playlist_mincount': 1160,
        'info_dict': {
            'id': 'Styxhexenhammer666',
        },
    }, {
        'url': 'https://rumble.com/user/goldenpoodleharleyeuna',
        'playlist_mincount': 4,
        'info_dict': {
            'id': 'goldenpoodleharleyeuna',
        },
    }]

    def entries(self, url, playlist_id):
        for page in itertools.count(1):
            try:
                webpage = self._download_webpage(f'{url}?page={page}', playlist_id, note='Downloading page %d' % page)