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

Code before:
                })

        for sub in traverse_obj(data, ('media', 'textTracks', lambda _, v: url_or_none(v['src']))):
            subtitles.setdefault(sub.get('language') or 'und', []).append({
                'url': sub['src'],
                'name': sub.get('label'),
            })

        chapters = traverse_obj(data, (
            'media', 'chapters', lambda _, v: float(v['startTime']) is not None, {
                'start_time': ('startTime', {functools.partial(float_or_none, scale=1000)}),
                'end_time': ('endTime', {functools.partial(float_or_none, scale=1000)}),
                'title': ('name', {str}),
            }))
        # Filter out pointless single chapters with start_time==0 and no end_time
        if len(chapters) == 1 and not (chapters[0].get('start_time') or chapters[0].get('end_time')):
            chapters = []

        return {
            **traverse_obj(data, {
                'title': ('title', {str}),
                'description': ('description', {str.strip}),
                'thumbnail': ('image', 'url', {url_or_none}, {functools.partial(update_url, query=None)}),
                'timestamp': ('publishedAt', {functools.partial(float_or_none, scale=1000)}),
                'media_type': ('media', 'clipType', {str}),
                'is_live': ('streamType', {lambda x: x == 'Live'}),
                'series': ('showName', {str}),
                'season_number': ('media', 'season', {int_or_none}),
                'duration': ('media', 'duration', {float_or_none}),
                'location': ('media', 'region', {str}),
                'tags': ('tags', ..., 'name', {str}),
                'genres': ('media', 'genre', all),
                'categories': ('categories', ..., 'name', {str}),
            }),
            'id': video_id,
            'formats': formats,
            'subtitles': subtitles,
            'chapters': chapters,
        }


class CBCPlayerPlaylistIE(InfoExtractor):
    IE_NAME = 'cbc.ca:player:playlist'
    _VALID_URL = r'https?://(?:www\.)?cbc\.ca/(?:player/)(?!play/)(?P<id>[^?#]+)'
    _TESTS = [{
        'url': 'https://www.cbc.ca/player/news/TV%20Shows/The%20National/Latest%20Broadcast',
        'playlist_mincount': 25,
        'info_dict': {
            'id': 'news/tv shows/the national/latest broadcast',
        },
    }, {

Review comment (suggestion):
```suggestion
                'is_live': ('media', 'streamType', {lambda x: x == 'Live'}),
```

Code after:
                continue
            asset_data = self._download_json(asset_key, video_id, f'Downloading {asset_type} JSON')
            ext = mimetype2ext(self._parse_param(asset_data, 'contentType'))
            if ext == 'm3u8':
                fmts, subs = self._extract_m3u8_formats_and_subtitles(
                    asset_data['url'], video_id, 'mp4', m3u8_id='hls', live=is_live)
                formats.extend(fmts)
                # Avoid slow/error-prone webvtt-over-m3u8 if direct https vtt is available
                if not subtitles:
                    self._merge_subtitles(subs, target=subtitles)
                if is_live or not fmts:
                    continue
                # Check for direct https mp4 format
                best_video_fmt = traverse_obj(fmts, (
                    lambda _, v: v.get('vcodec') != 'none' and v['tbr'], all,
                    {functools.partial(sorted, key=lambda x: x['tbr'])}, -1, {dict})) or {}
                base_url = self._search_regex(
                    r'(https?://[^?#]+?/)hdntl=', best_video_fmt.get('url'), 'base url', default=None)
                if not base_url or '/live/' in base_url:
                    continue
                mp4_url = base_url + replace_extension(url_basename(best_video_fmt['url']), 'mp4')
                if self._request_webpage(
                        HEADRequest(mp4_url), video_id, 'Checking for https format',
                        errnote=False, fatal=False):
                    formats.append({
                        **best_video_fmt,
                        'url': mp4_url,
                        'format_id': 'https-mp4',
                        'protocol': 'https',
                        'manifest_url': None,
                        'acodec': None,
                    })
            else:
                formats.append({
                    'url': asset_data['url'],
                    'ext': ext,
                    'vcodec': 'none' if self._parse_param(asset_data, 'mediaType') == 'audio' else None,
                })

        chapters = traverse_obj(data, (
            'media', 'chapters', lambda _, v: float(v['startTime']) is not None, {
                'start_time': ('startTime', {functools.partial(float_or_none, scale=1000)}),
                'end_time': ('endTime', {functools.partial(float_or_none, scale=1000)}),
                'title': ('name', {str}),
            }))
        # Filter out pointless single chapters with start_time==0 and no end_time
        if len(chapters) == 1 and not (chapters[0].get('start_time') or chapters[0].get('end_time')):
            chapters = []

        return {
            **traverse_obj(data, {