[ie/wistia] Support password-protected videos (#11100)
[yt-dlp3.git] / yt_dlp / extractor / rtvslo.py
blob9c2e6fb6b52e73e596f03e5603756ed1281a3767
1 import re
3 from .common import InfoExtractor
4 from ..utils import (
5 ExtractorError,
6 int_or_none,
7 parse_duration,
8 traverse_obj,
9 unified_timestamp,
10 url_or_none,
11 urljoin,
15 class RTVSLOIE(InfoExtractor):
16 IE_NAME = 'rtvslo.si'
17 _VALID_URL = r'''(?x)
18 https?://(?:
19 (?:365|4d)\.rtvslo.si/arhiv/[^/?#&;]+|
20 (?:www\.)?rtvslo\.si/rtv365/arhiv
21 )/(?P<id>\d+)'''
22 _GEO_COUNTRIES = ['SI']
24 _API_BASE = 'https://api.rtvslo.si/ava/{}/{}?client_id=82013fb3a531d5414f478747c1aca622'
25 SUB_LANGS_MAP = {'Slovenski': 'sl'}
27 _TESTS = [{
28 'url': 'https://www.rtvslo.si/rtv365/arhiv/174842550?s=tv',
29 'info_dict': {
30 'id': '174842550',
31 'ext': 'mp4',
32 'release_timestamp': 1643140032,
33 'upload_date': '20220125',
34 'series': 'Dnevnik',
35 'thumbnail': 'https://img.rtvcdn.si/_up/ava/ava_misc/show_logos/92/dnevnik_3_wide2.jpg',
36 'description': 'md5:76a18692757aeb8f0f51221106277dd2',
37 'timestamp': 1643137046,
38 'title': 'Dnevnik',
39 'series_id': '92',
40 'release_date': '20220125',
41 'duration': 1789,
43 }, {
44 'url': 'https://365.rtvslo.si/arhiv/utrip/174843754',
45 'info_dict': {
46 'id': '174843754',
47 'ext': 'mp4',
48 'series_id': '94',
49 'release_date': '20220129',
50 'timestamp': 1643484455,
51 'title': 'Utrip',
52 'duration': 813,
53 'thumbnail': 'https://img.rtvcdn.si/_up/ava/ava_misc/show_logos/94/utrip_1_wide2.jpg',
54 'description': 'md5:77f2892630c7b17bb7a5bb84319020c9',
55 'release_timestamp': 1643485825,
56 'upload_date': '20220129',
57 'series': 'Utrip',
59 }, {
60 'url': 'https://365.rtvslo.si/arhiv/il-giornale-della-sera/174844609',
61 'info_dict': {
62 'id': '174844609',
63 'ext': 'mp3',
64 'series_id': '106615841',
65 'title': 'Il giornale della sera',
66 'duration': 1328,
67 'series': 'Il giornale della sera',
68 'timestamp': 1643743800,
69 'release_timestamp': 1643745424,
70 'thumbnail': 'https://img.rtvcdn.si/_up/ava/ava_misc/show_logos/il-giornale-della-sera_wide2.jpg',
71 'upload_date': '20220201',
72 'tbr': 128000,
73 'release_date': '20220201',
75 }, {
76 'url': 'https://365.rtvslo.si/arhiv/razred-zase/148350750',
77 'info_dict': {
78 'id': '148350750',
79 'ext': 'mp4',
80 'title': 'Prvi šolski dan, mozaična oddaja za mlade',
81 'series': 'Razred zase',
82 'series_id': '148185730',
83 'duration': 1481,
84 'upload_date': '20121019',
85 'timestamp': 1350672122,
86 'release_date': '20121019',
87 'release_timestamp': 1350672122,
88 'thumbnail': 'https://img.rtvcdn.si/_up/ava/ava_misc/show_logos/148185730/razred_zase_2014_logo_4d_wide2.jpg',
90 }, {
91 'url': 'https://4d.rtvslo.si/arhiv/dnevnik/174842550',
92 'only_matching': True,
95 def _real_extract(self, url):
96 v_id = self._match_id(url)
97 meta = self._download_json(self._API_BASE.format('getRecordingDrm', v_id), v_id)['response']
99 thumbs = [{'id': k, 'url': v, 'http_headers': {'Accept': 'image/jpeg'}}
100 for k, v in (meta.get('images') or {}).items()]
102 subs = {}
103 for s in traverse_obj(meta, 'subs', 'subtitles', default=[]):
104 lang = self.SUB_LANGS_MAP.get(s.get('language'), s.get('language') or 'und')
105 subs.setdefault(lang, []).append({
106 'url': s.get('file'),
107 'ext': traverse_obj(s, 'format', expected_type=str.lower),
110 jwt = meta.get('jwt')
111 if not jwt:
112 raise ExtractorError('Site did not provide an authentication token, cannot proceed.')
114 media = self._download_json(self._API_BASE.format('getMedia', v_id), v_id, query={'jwt': jwt})['response']
116 formats = []
117 skip_protocols = ['smil', 'f4m', 'dash']
118 adaptive_url = traverse_obj(media, ('addaptiveMedia', 'hls_sec'), expected_type=url_or_none)
119 if adaptive_url:
120 formats = self._extract_wowza_formats(adaptive_url, v_id, skip_protocols=skip_protocols)
122 adaptive_url = traverse_obj(media, ('addaptiveMedia_sl', 'hls_sec'), expected_type=url_or_none)
123 if adaptive_url:
124 for f in self._extract_wowza_formats(adaptive_url, v_id, skip_protocols=skip_protocols):
125 formats.append({
126 **f,
127 'format_id': 'sign-' + f['format_id'],
128 'format_note': 'Sign language interpretation', 'preference': -10,
129 'language': (
130 'slv' if f.get('language') == 'eng' and f.get('acodec') != 'none'
131 else f.get('language')),
134 for mediafile in traverse_obj(media, ('mediaFiles', lambda _, v: url_or_none(v['streams']['https']))):
135 formats.append(traverse_obj(mediafile, {
136 'url': ('streams', 'https'),
137 'ext': ('mediaType', {str.lower}),
138 'width': ('width', {int_or_none}),
139 'height': ('height', {int_or_none}),
140 'tbr': ('bitrate', {int_or_none}),
141 'filesize': ('filesize', {int_or_none}),
144 for mediafile in traverse_obj(media, ('mediaFiles', lambda _, v: url_or_none(v['streams']['hls_sec']))):
145 formats.extend(self._extract_wowza_formats(
146 mediafile['streams']['hls_sec'], v_id, skip_protocols=skip_protocols))
148 if any('intermission.mp4' in x['url'] for x in formats):
149 self.raise_geo_restricted(countries=self._GEO_COUNTRIES, metadata_available=True)
150 if any('dummy_720p.mp4' in x.get('manifest_url', '') for x in formats) and meta.get('stub') == 'error':
151 raise ExtractorError(f'{self.IE_NAME} said: Clip not available', expected=True)
153 return {
154 'id': v_id,
155 'webpage_url': ''.join(traverse_obj(meta, ('canonical', ('domain', 'path')))),
156 'title': meta.get('title'),
157 'formats': formats,
158 'subtitles': subs,
159 'thumbnails': thumbs,
160 'description': meta.get('description'),
161 'timestamp': unified_timestamp(traverse_obj(meta, 'broadcastDate', ('broadcastDates', 0))),
162 'release_timestamp': unified_timestamp(meta.get('recordingDate')),
163 'duration': meta.get('duration') or parse_duration(meta.get('length')),
164 'tags': meta.get('genre'),
165 'series': meta.get('showName'),
166 'series_id': meta.get('showId'),
170 class RTVSLOShowIE(InfoExtractor):
171 IE_NAME = 'rtvslo.si:show'
172 _VALID_URL = r'https?://(?:365|4d)\.rtvslo.si/oddaja/[^/?#&]+/(?P<id>\d+)'
174 _TESTS = [{
175 'url': 'https://365.rtvslo.si/oddaja/ekipa-bled/173250997',
176 'info_dict': {
177 'id': '173250997',
178 'title': 'Ekipa Bled',
180 'playlist_count': 18,
183 def _real_extract(self, url):
184 playlist_id = self._match_id(url)
185 webpage = self._download_webpage(url, playlist_id)
187 return self.playlist_from_matches(
188 re.findall(r'<a [^>]*\bhref="(/arhiv/[^"]+)"', webpage),
189 playlist_id, self._html_extract_title(webpage),
190 getter=lambda x: urljoin('https://365.rtvslo.si', x), ie=RTVSLOIE)