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

Code before:
                    'ext': mimetype2ext(source.get('mimeType'), default=None),
                    'format_id': join_nonempty('http', source_type, profile),
                    **parse_resolution(profile),
                })

        self._remove_duplicate_formats(formats)
        return formats, subtitles

    def _get_direct_subtitles(self, caption_json):
        subs = {}
        for caption in traverse_obj(caption_json, lambda _, v: url_or_none(v['vttUrl'])):
            subs.setdefault(caption.get('language') or 'und', []).append({
                'url': caption['vttUrl'],
                'name': caption.get('name'),
            })

        return subs

    def _get_additional_metadata(self, video_id):
        additional_metadata = self._download_json(
            f'https://play.vidyard.com/video/{video_id}', video_id,
            note='Downloading additional metadata', fatal=False)
        return traverse_obj(additional_metadata, {
            'title': ('name', {str}),
            'duration': ('seconds', {int_or_none}),
            'thumbnail': ('thumbnailUrl', {url_or_none}),
            'chapters': ('videoSections', lambda _, v: float_or_none(v['milliseconds']) is not None, {
                'title': ('title', {str}),
                'start_time': ('milliseconds', {float_or_none(scale=1000)}),
            }),
        })

    def _fetch_video_json(self, video_id):
        return self._download_json(
            f'https://play.vidyard.com/player/{video_id}.json', video_id)['payload']

    def _process_video_json(self, json_data, video_id):
        formats, subtitles = self._get_formats_and_subtitles(json_data['sources'], video_id)
        self._merge_subtitles(self._get_direct_subtitles(json_data.get('captions')), target=subtitles)

        return {
            **self._get_additional_metadata(json_data['facadeUuid']),
            **traverse_obj(json_data, {
                'id': ('facadeUuid', {str}),
                'display_id': ('videoId', {int}, {str_or_none}),
                'title': ('name', {str}),
                'description': ('description', {str}, {unescapeHTML}, filter),
                'duration': ((
                    ('milliseconds', {float_or_none(scale=1000)}),
                    ('seconds', {int_or_none})), any),
                'thumbnails': ('thumbnailUrls', ('small', 'normal'), {'url': {url_or_none}}),

Review comment (suggestion):
mb
```suggestion
            'thumbnails': ('thumbnailUrl', {'url': {url_or_none}}, all),
```

Code after:
                    'ext': mimetype2ext(source.get('mimeType'), default=None),
                    'format_id': join_nonempty('http', source_type, profile),
                    **parse_resolution(profile),
                })

        self._remove_duplicate_formats(formats)
        return formats, subtitles

    def _get_direct_subtitles(self, caption_json):
        subs = {}
        for caption in traverse_obj(caption_json, lambda _, v: url_or_none(v['vttUrl'])):
            subs.setdefault(caption.get('language') or 'und', []).append({
                'url': caption['vttUrl'],
                'name': caption.get('name'),
            })

        return subs

    def _get_additional_metadata(self, video_id):
        additional_metadata = self._download_json(
            f'https://play.vidyard.com/video/{video_id}', video_id,
            note='Downloading additional metadata', fatal=False)
        return traverse_obj(additional_metadata, {
            'title': ('name', {str}),
            'duration': ('seconds', {int_or_none}),
            'thumbnails': ('thumbnailUrl', {'url': {url_or_none}}, all),
            'chapters': ('videoSections', lambda _, v: float_or_none(v['milliseconds']) is not None, {
                'title': ('title', {str}),
                'start_time': ('milliseconds', {float_or_none(scale=1000)}),
            }),
        })

    def _fetch_video_json(self, video_id):
        return self._download_json(
            f'https://play.vidyard.com/player/{video_id}.json', video_id)['payload']

    def _process_video_json(self, json_data, video_id):
        formats, subtitles = self._get_formats_and_subtitles(json_data['sources'], video_id)
        self._merge_subtitles(self._get_direct_subtitles(json_data.get('captions')), target=subtitles)

        return {
            **self._get_additional_metadata(json_data['facadeUuid']),
            **traverse_obj(json_data, {
                'id': ('facadeUuid', {str}),
                'display_id': ('videoId', {int}, {str_or_none}),
                'title': ('name', {str}),
                'description': ('description', {str}, {unescapeHTML}, filter),
                'duration': ((
                    ('milliseconds', {float_or_none(scale=1000)}),
                    ('seconds', {int_or_none})), any),
                'thumbnails': ('thumbnailUrls', ('small', 'normal'), {'url': {url_or_none}}),