3 from .common
import InfoExtractor
15 class RTVSLOIE(InfoExtractor
):
19 (?:365|4d)\.rtvslo.si/arhiv/[^/?#&;]+|
20 (?:www\.)?rtvslo\.si/rtv365/arhiv
22 _GEO_COUNTRIES
= ['SI']
24 _API_BASE
= 'https://api.rtvslo.si/ava/{}/{}?client_id=82013fb3a531d5414f478747c1aca622'
25 SUB_LANGS_MAP
= {'Slovenski': 'sl'}
28 'url': 'https://www.rtvslo.si/rtv365/arhiv/174842550?s=tv',
32 'release_timestamp': 1643140032,
33 'upload_date': '20220125',
35 'thumbnail': 'https://img.rtvcdn.si/_up/ava/ava_misc/show_logos/92/dnevnik_3_wide2.jpg',
36 'description': 'md5:76a18692757aeb8f0f51221106277dd2',
37 'timestamp': 1643137046,
40 'release_date': '20220125',
44 'url': 'https://365.rtvslo.si/arhiv/utrip/174843754',
49 'release_date': '20220129',
50 'timestamp': 1643484455,
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',
60 'url': 'https://365.rtvslo.si/arhiv/il-giornale-della-sera/174844609',
64 'series_id': '106615841',
65 'title': 'Il giornale della sera',
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',
73 'release_date': '20220201',
76 'url': 'https://365.rtvslo.si/arhiv/razred-zase/148350750',
80 'title': 'Prvi šolski dan, mozaična oddaja za mlade',
81 'series': 'Razred zase',
82 'series_id': '148185730',
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',
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()]
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')
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']
117 skip_protocols
= ['smil', 'f4m', 'dash']
118 adaptive_url
= traverse_obj(media
, ('addaptiveMedia', 'hls_sec'), expected_type
=url_or_none
)
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
)
124 for f
in self
._extract
_wowza
_formats
(adaptive_url
, v_id
, skip_protocols
=skip_protocols
):
127 'format_id': 'sign-' + f
['format_id'],
128 'format_note': 'Sign language interpretation', 'preference': -10,
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)
155 'webpage_url': ''.join(traverse_obj(meta
, ('canonical', ('domain', 'path')))),
156 'title': meta
.get('title'),
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+)'
175 'url': 'https://365.rtvslo.si/oddaja/ekipa-bled/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
)