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

Code before:
                subtitles.setdefault(lang, []).append({
                    'ext': mimetype2ext(mime),
                    'url': src,
                })

        duration = info.get('duration')
        tp_chapters = info.get('chapters', [])
        chapters = []
        if tp_chapters:
            def _add_chapter(start_time, end_time):
                start_time = float_or_none(start_time, 1000)
                end_time = float_or_none(end_time, 1000)
                if start_time is None or end_time is None:
                    return
                chapters.append({
                    'start_time': start_time,
                    'end_time': end_time,
                })

            for chapter in tp_chapters[:-1]:
                _add_chapter(chapter.get('startTime'), chapter.get('endTime'))
            _add_chapter(tp_chapters[-1].get('startTime'), tp_chapters[-1].get('endTime') or duration)
        info_keywords_str = info.get('keywords', {str_or_none})
        tags = []
        if (info_keywords_str is not None) and (info_keywords_str != ''):
            tags = re.split(', |; |,', info_keywords_str)
        location = None
        series = None
        season_number = None
        # The following can be uncommented as soon as #7838 is merged:
        # media_type = None
        categories = []
        categories_data = info.get('categories') or []
        for x in categories_data:
            if x.get('name') is not None:
                # Sometimes, there will be several kinds of categories
                # in this case, it will have a label field with a value 'category'
                if (x.get('label') is None) or (x.get('label') == 'category'):
                    categories.append(x.get('name'))

        # A number of sites have a prefix in front of some info keys followed by a '$' symbol.
        # Search for known keys with the prefix.
        for key in info.keys():
            if re.match('.*\\$region', key):
                location = info[key]
            if re.match('.*\\$show', key):
                series = info[key]
            if re.match('.*\\$seasonNumber', key):
                season_number = str_to_int(info[key])
            # the following can be uncommented as soon as #7838 is merged:
            # if (re.match('.*\programmingType', key)) or (re.match('.*\type', key)):

Review comment (suggestion):
`info.get('keywords', {str_or_none})` is not correct -- you are trying to use a `traverse_obj`-style transformation as the default for `get()`. If the key `keywords` is not in `info` or if its value is `None`, then `get()` would default to a set containing the `str_or_none` function.

I think what you are trying to do is: `traverse_obj(info, ('keywords', {str_or_none}))`

But `str_or_none` shouldn't be used here anyways, as it would stringify anything -- a dict, a list, etc. you would want to just expect the type with `{str}` instead

And all of this can be simplified if we do this:
```suggestion
        tags = traverse_obj(info, ('keywords', {lambda x: re.split(r'[;,]\s?', x) if x else None}))
```
and this can be easily inlined in the return then

Code after:
                    'url': src,
                })

        duration = info.get('duration')
        tp_chapters = info.get('chapters', [])
        chapters = []
        if tp_chapters:
            def _add_chapter(start_time, end_time):
                start_time = float_or_none(start_time, 1000)
                end_time = float_or_none(end_time, 1000)
                if start_time is None or end_time is None:
                    return
                chapters.append({
                    'start_time': start_time,
                    'end_time': end_time,
                })

            for chapter in tp_chapters[:-1]:
                _add_chapter(chapter.get('startTime'), chapter.get('endTime'))
            _add_chapter(tp_chapters[-1].get('startTime'), tp_chapters[-1].get('endTime') or duration)

        def extract_site_specific_field(field):
            # A number of sites have custom-prefixed keys, e.g. 'cbc$seasonNumber'
            return traverse_obj(info, lambda k, v: v and k.endswith(f'${field}'), get_all=False)

        return {
            'title': info['title'],
            'subtitles': subtitles,
            'description': info['description'],
            'thumbnail': info['defaultThumbnailUrl'],
            'duration': float_or_none(duration, 1000),
            'timestamp': int_or_none(info.get('pubDate'), 1000) or None,
            'uploader': info.get('billingCode'),
            'chapters': chapters,
            'creator': traverse_obj(info, ('author', {str})) or None,
            'categories': traverse_obj(info, (
                'categories', lambda _, v: v.get('label') in ('category', None), 'name', {str})) or None,
            'tags': traverse_obj(info, ('keywords', {lambda x: re.split(r'[;,]\s?', x) if x else None})),
            'location': extract_site_specific_field('region'),
            'series': extract_site_specific_field('show'),
            'season_number': int_or_none(extract_site_specific_field('seasonNumber')),
            'media_type': extract_site_specific_field('programmingType') or extract_site_specific_field('type'),
        }

    def _extract_theplatform_metadata(self, path, video_id):
        info = self._download_theplatform_metadata(path, video_id)
        return self._parse_theplatform_metadata(info)


class ThePlatformIE(ThePlatformBaseIE, AdobePassIE):
    _VALID_URL = r'''(?x)