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

Code before:
            'format_id': join_nonempty(extension, note),
        }

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

        title_result = traverse_obj(webpage, ({html_get_element(cls='opening-header__title')}, {self._TITLE_RE.match}))
        json_lds = list(self._yield_json_ld(webpage, video_id, fatal=False))

        return {
            'id': video_id,
            'title': traverse_obj(title_result, ('title', {str.strip})) or None,
            # This metadata could be interpreted otherwise, but it fits "series" the most
            'series': traverse_obj(title_result, ('series', {str.strip})) or None,
            'description': join_nonempty(*traverse_obj(webpage, [(
                {html_get_element(cls='opening-intro')},
                [{html_get_element(tag='bpb-accordion-item')}, {html_get_element(cls='text-content')}],
            ), {clean_html}]), delim='\n\n') or None,
            'creator': self._html_search_meta('author', webpage),
            'uploader': self._html_search_meta('publisher', webpage),
            'release_date': unified_strdate(self._html_search_meta('date', webpage)),
            'tags': traverse_obj(json_lds, (..., 'keywords', {lambda x: x.split(',')}, ...)),
            **traverse_obj(self._parse_vue_attributes('bpb-player', webpage, video_id), {
                'formats': (':sources', ..., {self._process_source}),
                'thumbnail': ('poster', {lambda x: urljoin(self.BASE_URL, x)}),
            }),
        }


Review comment (suggestion):
as suggested above:
```suggestion
                'thumbnail': ('poster', {lambda x: urljoin(url, x)}),
```

Code after:
            'quality': 10 if note == 'high' else 0,
            'format_note': note,
            'format_id': join_nonempty(extension, note),
        }

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

        title_result = traverse_obj(webpage, ({html_get_element(cls='opening-header__title')}, {self._TITLE_RE.match}))
        json_lds = list(self._yield_json_ld(webpage, video_id, fatal=False))

        return {
            'id': video_id,
            'title': traverse_obj(title_result, ('title', {str.strip})) or None,
            # This metadata could be interpreted otherwise, but it fits "series" the most
            'series': traverse_obj(title_result, ('series', {str.strip})) or None,
            'description': join_nonempty(*traverse_obj(webpage, [(
                {html_get_element(cls='opening-intro')},
                [{html_get_element(tag='bpb-accordion-item')}, {html_get_element(cls='text-content')}],
            ), {clean_html}]), delim='\n\n') or None,
            'creator': self._html_search_meta('author', webpage),
            'uploader': self._html_search_meta('publisher', webpage),
            'release_date': unified_strdate(self._html_search_meta('date', webpage)),
            'tags': traverse_obj(json_lds, (..., 'keywords', {lambda x: x.split(',')}, ...)),
            **traverse_obj(self._parse_vue_attributes('bpb-player', webpage, video_id), {
                'formats': (':sources', ..., {self._process_source}),
                'thumbnail': ('poster', {lambda x: urljoin(url, x)}),
            }),
        }