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

Code before:
            self.raise_geo_restricted(countries=self._GEO_COUNTRIES, metadata_available=True)
        if any('dummy_720p.mp4' in x.get('manifest_url', '') for x in formats) and meta.get('stub') == 'error':
            raise ExtractorError(f'{self.IE_NAME} said: Clip not available', expected=True)

        return {
            'id': v_id,
            'webpage_url': ''.join(traverse_obj(meta, ('canonical', ('domain', 'path')))),
            'title': meta.get('title'),
            'formats': formats,
            'subtitles': subs,
            'thumbnails': thumbs,
            'description': meta.get('description'),
            'timestamp': unified_timestamp(traverse_obj(meta, 'broadcastDate', ('broadcastDates', 0))),
            'release_timestamp': unified_timestamp(meta.get('recordingDate')),
            'duration': meta.get('duration') or parse_duration(meta.get('length')),
            'tags': meta.get('genre'),
            'series': meta.get('showName'),
            'series_id': meta.get('showId'),
        }

    def _get_show_urls(self, url, v_id):
        html = self._download_webpage(url, v_id)
        all_urls = set(re.findall(r'<a.*href=\"(/arhiv/.+)\".*aria-label=.*>', html))
        parsed = urlparse(url)
        res = re.findall(r'<title>(.*)</title>', html)
        title = res[0] if len(res) != 0 else None
        return title, [f'{parsed.scheme}://{parsed.netloc}{url}' for url in all_urls]

    def _real_extract(self, url):
        url_id = self._match_id(url)
        if 'oddaja' in url:
            # supplied URL is a shows homepage / like a channel or playlist
            title, urls = self._get_show_urls(url, url_id)
            entries = [self._get_video_info(self._match_id(url)) for url in urls]
            entries.sort(key=lambda x: x['id'])
            return {
                '_type': 'playlist',
                'id': url_id,
                'title': title,
                'entries': entries,
                'playlist_count': len(urls)
            }
        else:
            return self._get_video_info(url_id)


Review comment (refactor):
```suggestion
        title = self._html_extract_title(html, v_id)
```

Code after:
            'thumbnails': thumbs,
            'description': meta.get('description'),
            'timestamp': unified_timestamp(traverse_obj(meta, 'broadcastDate', ('broadcastDates', 0))),
            'release_timestamp': unified_timestamp(meta.get('recordingDate')),
            'duration': meta.get('duration') or parse_duration(meta.get('length')),
            'tags': meta.get('genre'),
            'series': meta.get('showName'),
            'series_id': meta.get('showId'),
        }


class RTVSLOShowIE(InfoExtractor):
    IE_NAME = 'rtvslo.si:show'
    _VALID_URL = r'https?://(?:365|4d)\.rtvslo.si/oddaja/[^/?#&]+/(?P<id>\d+)'

    _TESTS = [{
        'url': 'https://365.rtvslo.si/oddaja/ekipa-bled/173250997',
        'info_dict': {
            'id': '173250997',
            'title': 'Ekipa Bled',
        },
        'playlist_count': 18,
    }]

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

        return self.playlist_from_matches(
            re.findall(r'<a [^>]*\bhref="(/arhiv/[^"]+)"', webpage),
            playlist_id, self._html_extract_title(webpage),
            getter=lambda x: urljoin('https://365.rtvslo.si', x), ie=RTVSLOIE)