ronantakizawa/codereview-bench huggingface dataset:
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/firsttv.py (Python)

Code before:
class FirstTVLiveIE(InfoExtractor):
    IE_NAME = '1tv-live'
    IE_DESC = 'Первый канал (прямой эфир)'
    _VALID_URL = r'https?://(?:www\.)?1tv\.ru/live'
    _GEO_BYPASS = False
    _GEO_COUNTRIES = ['RU']

    _TESTS = [
        {
            'url': 'https://www.1tv.ru/live',
            'info_dict': {
                'id': 'live',
                'ext': 'mp4',
                'title': 'ПЕРВЫЙ КАНАЛ ПРЯМОЙ ЭФИР СМОТРЕТЬ ОНЛАЙН',
                'is_live': True,
            },
        },
    ]

    def _real_extract(self, url):
        display_id = 'live'
        webpage = self._download_webpage(url, display_id)

        streams_list = self._download_json('https://stream.1tv.ru/api/playlist/1tvch-v1_as_array.json', 'live')
        mpd_url = traverse_obj(streams_list, ('mpd', ..., {url_or_none}, any))
        formats = self._extract_mpd_formats(mpd_url, display_id, mpd_id='dash', fatal=False)
        hls_url = traverse_obj(streams_list, ('hls', ..., {url_or_none}, any))
        formats.extend(self._extract_m3u8_formats(hls_url, display_id, 'mp4', m3u8_id='hls', live=True, fatal=False))
        if not formats:
            raise ExtractorError('Unable to extract any stream')

        return {
            'id': display_id,
            'title': self._html_extract_title(webpage),
            'formats': formats,
            'is_live': True,
        }


Review comment (refactor):
Can't do that since it would raise an ignored subtitle warning. Instead we should write to `_`
```suggestion
        formats, _ = self._extract_mpd_formats_and_subtitles(mpd_url, display_id, mpd_id='dash', fatal=False)
```

Code after:
    IE_NAME = '1tv:live'
    IE_DESC = 'Первый канал (прямой эфир)'
    _VALID_URL = r'https?://(?:www\.)?1tv\.ru/live'

    _TESTS = [{
        'url': 'https://www.1tv.ru/live',
        'info_dict': {
            'id': 'live',
            'ext': 'mp4',
            'title': r're:ПЕРВЫЙ КАНАЛ ПРЯМОЙ ЭФИР СМОТРЕТЬ ОНЛАЙН \d{4}-\d{2}-\d{2} \d{2}:\d{2}$',
            'live_status': 'is_live',
        },
        'params': {'skip_download': 'livestream'},
    }]

    def _real_extract(self, url):
        display_id = 'live'
        webpage = self._download_webpage(url, display_id, fatal=False)

        streams_list = self._download_json('https://stream.1tv.ru/api/playlist/1tvch-v1_as_array.json', display_id)
        mpd_url = traverse_obj(streams_list, ('mpd', ..., {url_or_none}, any, {require('mpd url')}))
        # FFmpeg needs to be passed -re to not seek past live window. This is handled by core
        formats, _ = self._extract_mpd_formats_and_subtitles(mpd_url, display_id, mpd_id='dash')

        return {
            'id': display_id,
            'title': self._html_extract_title(webpage),
            'formats': formats,
            'is_live': True,
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/prankcast.py (Python)

Code before:

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

        webpage = self._download_webpage(url, video_id)
        post = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['ssr_data_posts']
        content = self._parse_json(post['post_contents_json'], video_id)[0]

        return {
            'id': video_id,
            'display_id': display_id,
            'title': self._og_search_title(webpage),
            **traverse_obj(post, {
                'title': ('post_title', {str}),
                'description': ('post_body', {str}),
                'tags': ('post_tags', {lambda x: x.split(',')}, ..., {str.strip}, filter, all, filter),
                'channel_id': ('user_id', {int}, {str_or_none}),
                'uploader': ('user_name', {str}),
            }),
            **traverse_obj(content, {
                'url': (('secure_url', 'url'), {url_or_none}, any),
                'timestamp': (
                    ((('start_date', 'crdate'), {parse_iso8601(delimiter=' ')}),
                     ('created_at', {parse_iso8601})), {int}, any),
                'duration': ('duration', {float_or_none}),
                'categories': ('category', {str}, all),
                'cast': ((
                    {value(post.get('user_name'))},
                    ('guests_json', {json.loads}, ..., 'name'),
                ), {str}, filter, all),
            }),
        }


Review comment (suggestion):
```suggestion
                'categories': ('category', {str}, filter, all, filter),
```

Code after:

        webpage = self._download_webpage(url, video_id)
        post = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['ssr_data_posts']
        content = self._parse_json(post['post_contents_json'], video_id)[0]

        return {
            'id': video_id,
            'display_id': display_id,
            'title': self._og_search_title(webpage),
            **traverse_obj(post, {
                'title': ('post_title', {str}),
                'description': ('post_body', {str}),
                'tags': ('post_tags', {lambda x: x.split(',')}, ..., {str.strip}, filter),
                'channel_id': ('user_id', {int}, {str_or_none}),
                'uploader': ('user_name', {str}),
            }),
            **traverse_obj(content, {
                'url': (('secure_url', 'url'), {url_or_none}, any),
                'timestamp': ((
                    (('start_date', 'crdate'), {parse_iso8601(delimiter=' ')}),
                    ('created_at', {parse_iso8601}),
                ), any),
                'duration': ('duration', {float_or_none}),
                'categories': ('category', {str}, filter, all, filter),
                'cast': ((
                    {value(post.get('user_name'))},
                    ('guests_json', {json.loads}, ..., 'name'),
                ), {str}, filter),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/prankcast.py (Python)

Code before:
        webpage = self._download_webpage(url, video_id)
        post = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['ssr_data_posts']
        content = self._parse_json(post['post_contents_json'], video_id)[0]

        return {
            'id': video_id,
            'display_id': display_id,
            'title': self._og_search_title(webpage),
            **traverse_obj(post, {
                'title': ('post_title', {str}),
                'description': ('post_body', {str}),
                'tags': ('post_tags', {lambda x: x.split(',')}, ..., {str.strip}, filter, all, filter),
                'channel_id': ('user_id', {int}, {str_or_none}),
                'uploader': ('user_name', {str}),
            }),
            **traverse_obj(content, {
                'url': (('secure_url', 'url'), {url_or_none}, any),
                'timestamp': (
                    ((('start_date', 'crdate'), {parse_iso8601(delimiter=' ')}),
                     ('created_at', {parse_iso8601})), {int}, any),
                'duration': ('duration', {float_or_none}),
                'categories': ('category', {str}, all),
                'cast': ((
                    {value(post.get('user_name'))},
                    ('guests_json', {json.loads}, ..., 'name'),
                ), {str}, filter, all),
            }),
        }


Review comment (suggestion):
```suggestion
                ), {str}, filter),
```

Code after:

        return {
            'id': video_id,
            'display_id': display_id,
            'title': self._og_search_title(webpage),
            **traverse_obj(post, {
                'title': ('post_title', {str}),
                'description': ('post_body', {str}),
                'tags': ('post_tags', {lambda x: x.split(',')}, ..., {str.strip}, filter),
                'channel_id': ('user_id', {int}, {str_or_none}),
                'uploader': ('user_name', {str}),
            }),
            **traverse_obj(content, {
                'url': (('secure_url', 'url'), {url_or_none}, any),
                'timestamp': ((
                    (('start_date', 'crdate'), {parse_iso8601(delimiter=' ')}),
                    ('created_at', {parse_iso8601}),
                ), any),
                'duration': ('duration', {float_or_none}),
                'categories': ('category', {str}, filter, all, filter),
                'cast': ((
                    {value(post.get('user_name'))},
                    ('guests_json', {json.loads}, ..., 'name'),
                ), {str}, filter),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/postprocessor/metadataparser.py (Python)

Code before:
import re

from .common import PostProcessor
from ..utils import Namespace, filter_dict, function_with_repr

_NON_ASCII_NUMBERS = '\xB2\xB3\xB9'
_NON_ASCII_LETTERS = '\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\xFF'
_ALLOWABLE_GROUP_NAME_RE = rf'[A-Z_a-z{_NON_ASCII_LETTERS}][0-9A-Z_a-z{_NON_ASCII_NUMBERS}{_NON_ASCII_LETTERS}]*'


class MetadataParserPP(PostProcessor):
    def __init__(self, downloader, actions):
        super().__init__(downloader)
        self._actions = []
        for f in actions:
            action, *args = f
            assert action in self.Actions
            self._actions.append(action(self, *args))

    @classmethod
    def validate_action(cls, action, *data):
        """Each action can be:
                (Actions.INTERPRET, from, to) OR
                (Actions.REPLACE, field, search, replace)
        """
        if action not in cls.Actions:
            raise ValueError(f'{action!r} is not a valid action')
        action(cls, *data)  # So this can raise error to validate

    @staticmethod
    def field_to_template(tmpl):
        if re.match(r'[a-zA-Z_]+$', tmpl):
            return f'%({tmpl})s'

Review comment (suggestion):
```suggestion
_NON_ASCII_LETTERS = '\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\xFF'
_ALLOWABLE_GROUP_NAME_RE = rf'[A-Z_a-z{_NON_ASCII_LETTERS}][0-9A-Z_a-z\xB2\xB3\xB9{_NON_ASCII_LETTERS}]*'
```

Code after:
import re

from .common import PostProcessor
from ..utils import Namespace, filter_dict, function_with_repr


class MetadataParserPP(PostProcessor):
    def __init__(self, downloader, actions):
        super().__init__(downloader)
        self._actions = []
        for f in actions:
            action, *args = f
            assert action in self.Actions
            self._actions.append(action(self, *args))

    @classmethod
    def validate_action(cls, action, *data):
        """Each action can be:
                (Actions.INTERPRET, from, to) OR
                (Actions.REPLACE, field, search, replace)
        """
        if action not in cls.Actions:
            raise ValueError(f'{action!r} is not a valid action')
        action(cls, *data)  # So this can raise error to validate

    @staticmethod
    def field_to_template(tmpl):
        if re.match(r'[a-zA-Z_]+$', tmpl):
            return f'%({tmpl})s'

        from ..YoutubeDL import YoutubeDL
        err = YoutubeDL.validate_outtmpl(tmpl)
        if err:
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nowcanal.py (Python)

Code before:

class NowCanalIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt/[\w\-/]+/detalhe/(?P<id>[\w\-]+)'
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        m = re.search(r'\.addBrightcoveVideoWithJson\(\[\{([^\}]+)\}\]', webpage, re.MULTILINE)
        data = json.loads(f'{{{m.groups(1)[0]}}}')

        bc_id = data['brightcoveVideoId']
        bc_player = 'chhIqzukMq'
        bc_account = '6108484330001'

        return self.url_result(
            f'https://players.brightcove.net/{bc_account}/{bc_player}_default/index.html?videoId={bc_id}',
            BrightcoveNewIE,
        )


Review comment (refactor):
use the IE helper functions
```suggestion
        video_data = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[', webpage, 'video data', video_id)
```
Also can it happen that a page contains multiple videos, and do we need to deal with this?

Code after:
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_URL_TMPL = 'https://players.brightcove.net/6108484330001/chhIqzukMq_default/index.html?videoId={}'

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)

        video_id = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[',
            webpage, 'video data', display_id)['brightcoveVideoId']

        return self.url_result(self._BC_URL_TMPL.format(video_id), BrightcoveNewIE)
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nowcanal.py (Python)

Code before:
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_PLAYER = 'chhIqzukMq'
    _BC_ACCOUNT = '6108484330001'

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        video_data = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[', webpage, 'video data', video_id)

        return self.url_result(
            f"https://players.brightcove.net/{self._BC_ACCOUNT}/{self._BC_PLAYER}_default/index.html?videoId={video_data['brightcoveVideoId']}",
            BrightcoveNewIE,
        )


Review comment (suggestion):
`display_id` more appropriate here since we don't use it for anything other than display
```suggestion
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)
```

Code after:
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_URL_TMPL = 'https://players.brightcove.net/6108484330001/chhIqzukMq_default/index.html?videoId={}'

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)

        video_id = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[',
            webpage, 'video data', display_id)['brightcoveVideoId']

        return self.url_result(self._BC_URL_TMPL.format(video_id), BrightcoveNewIE)
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nowcanal.py (Python)

Code before:
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_PLAYER = 'chhIqzukMq'
    _BC_ACCOUNT = '6108484330001'

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        video_data = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[', webpage, 'video data', video_id)

        return self.url_result(
            f"https://players.brightcove.net/{self._BC_ACCOUNT}/{self._BC_PLAYER}_default/index.html?videoId={video_data['brightcoveVideoId']}",
            BrightcoveNewIE,
        )


Review comment (suggestion):
we don't use `video_data` for anything else, so let's get the BC `video_id` right away
```suggestion
        video_id = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[',
            webpage, 'video data', display_id)['brightcoveVideoId']
```

Code after:
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_URL_TMPL = 'https://players.brightcove.net/6108484330001/chhIqzukMq_default/index.html?videoId={}'

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)

        video_id = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[',
            webpage, 'video data', display_id)['brightcoveVideoId']

        return self.url_result(self._BC_URL_TMPL.format(video_id), BrightcoveNewIE)
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nowcanal.py (Python)

Code before:
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_PLAYER = 'chhIqzukMq'
    _BC_ACCOUNT = '6108484330001'

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        video_data = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[', webpage, 'video data', video_id)

        return self.url_result(
            f"https://players.brightcove.net/{self._BC_ACCOUNT}/{self._BC_PLAYER}_default/index.html?videoId={video_data['brightcoveVideoId']}",
            BrightcoveNewIE,
        )


Review comment (suggestion):
```suggestion
        return self.url_result(self._BC_URL_TMPL.format(video_id), BrightcoveNewIE)
```

Code after:
from .brightcove import BrightcoveNewIE
from .common import InfoExtractor


class NowCanalIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt(?:/[\w-]+)+/detalhe/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_URL_TMPL = 'https://players.brightcove.net/6108484330001/chhIqzukMq_default/index.html?videoId={}'

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)

        video_id = self._search_json(
            r'videoHandler\.addBrightcoveVideoWithJson\(\[',
            webpage, 'video data', display_id)['brightcoveVideoId']

        return self.url_result(self._BC_URL_TMPL.format(video_id), BrightcoveNewIE)