1 from .common
import InfoExtractor
13 class SRGSSRIE(InfoExtractor
):
16 https?://tp\.srgssr\.ch/p(?:/[^/]+)+\?urn=urn|
30 _GEO_COUNTRIES
= ['CH']
33 'AGERATING12': 'To protect children under the age of 12, this video is only available between 8 p.m. and 6 a.m.',
34 'AGERATING18': 'To protect children under the age of 18, this video is only available between 11 p.m. and 5 a.m.',
35 # 'ENDDATE': 'For legal reasons, this video was only available for a specified period of time.',
36 'GEOBLOCK': 'For legal reasons, this video is only available in Switzerland.',
37 'LEGAL': 'The video cannot be transmitted for legal reasons.',
38 'STARTDATE': 'This video is not yet available. Please try again later.',
40 _DEFAULT_LANGUAGE_CODES
= {
48 def _get_tokenized_src(self
, url
, video_id
, format_id
):
49 token
= self
._download
_json
(
50 'http://tp.srgssr.ch/akahd/token?acl=*',
51 video_id
, f
'Downloading {format_id} token', fatal
=False) or {}
52 auth_params
= try_get(token
, lambda x
: x
['token']['authparams'])
54 url
+= ('?' if '?' not in url
else '&') + auth_params
57 def _get_media_data(self
, bu
, media_type
, media_id
):
58 query
= {'onlyChapters': True} if media_type
== 'video' else {}
59 full_media_data
= self
._download
_json
(
60 f
'https://il.srgssr.ch/integrationlayer/2.0/{bu}/mediaComposition/{media_type}/{media_id}.json',
61 media_id
, query
=query
)['chapterList']
64 x
for x
in full_media_data
if x
.get('id') == media_id
)
66 raise ExtractorError('No media information found')
68 block_reason
= media_data
.get('blockReason')
69 if block_reason
and block_reason
in self
._ERRORS
:
70 message
= self
._ERRORS
[block_reason
]
71 if block_reason
== 'GEOBLOCK':
72 self
.raise_geo_restricted(
73 msg
=message
, countries
=self
._GEO
_COUNTRIES
)
75 f
'{self.IE_NAME} said: {message}', expected
=True)
79 def _real_extract(self
, url
):
80 bu
, media_type
, media_id
= self
._match
_valid
_url
(url
).groups()
81 media_data
= self
._get
_media
_data
(bu
, media_type
, media_id
)
82 title
= media_data
['title']
86 q
= qualities(['SD', 'HD'])
87 for source
in (media_data
.get('resourceList') or []):
88 format_url
= source
.get('url')
91 protocol
= source
.get('protocol')
92 quality
= source
.get('quality')
93 format_id
= join_nonempty(protocol
, source
.get('encoding'), quality
)
95 if protocol
in ('HDS', 'HLS'):
96 if source
.get('tokenType') == 'AKAMAI':
97 format_url
= self
._get
_tokenized
_src
(
98 format_url
, media_id
, format_id
)
99 fmts
, subs
= self
._extract
_akamai
_formats
_and
_subtitles
(
100 format_url
, media_id
)
102 subtitles
= self
._merge
_subtitles
(subtitles
, subs
)
103 elif protocol
== 'HLS':
104 m3u8_fmts
, m3u8_subs
= self
._extract
_m
3u8_formats
_and
_subtitles
(
105 format_url
, media_id
, 'mp4', 'm3u8_native',
106 m3u8_id
=format_id
, fatal
=False)
107 formats
.extend(m3u8_fmts
)
108 subtitles
= self
._merge
_subtitles
(subtitles
, m3u8_subs
)
109 elif protocol
in ('HTTP', 'HTTPS'):
111 'format_id': format_id
,
113 'quality': q(quality
),
116 # This is needed because for audio medias the podcast url is usually
117 # always included, even if is only an audio segment and not the
119 if int_or_none(media_data
.get('position')) == 0:
121 podcast_url
= media_data
.get(f
'podcast{p}dUrl')
126 'format_id': 'PODCAST-' + quality
,
128 'quality': q(quality
),
131 if media_type
== 'video':
132 for sub
in (media_data
.get('subtitleList') or []):
133 sub_url
= sub
.get('url')
136 lang
= sub
.get('locale') or self
._DEFAULT
_LANGUAGE
_CODES
[bu
]
137 subtitles
.setdefault(lang
, []).append({
144 'description': media_data
.get('description'),
145 'timestamp': parse_iso8601(media_data
.get('date')),
146 'thumbnail': media_data
.get('imageUrl'),
147 'duration': float_or_none(media_data
.get('duration'), 1000),
148 'subtitles': subtitles
,
153 class SRGSSRPlayIE(InfoExtractor
):
154 IE_DESC
= 'srf.ch, rts.ch, rsi.ch, rtr.ch and swissinfo.ch play sites'
155 _VALID_URL
= r
'''(?x)
158 (?P<bu>srf|rts|rsi|rtr|swissinfo)\.ch/play/(?:tv|radio)/
160 [^/]+/(?P<type>video|audio)/[^?]+|
161 popup(?P<type_2>video|audio)player
163 \?.*?\b(?:id=|urn=urn:[^:]+:video:)(?P<id>[0-9a-f\-]{36}|\d+)
167 'url': 'http://www.srf.ch/play/tv/10vor10/video/snowden-beantragt-asyl-in-russland?id=28e1a57d-5b76-4399-8ab3-9097f071e6c5',
168 'md5': '6db2226ba97f62ad42ce09783680046c',
170 'id': '28e1a57d-5b76-4399-8ab3-9097f071e6c5',
172 'upload_date': '20130701',
173 'title': 'Snowden beantragt Asyl in Russland',
174 'timestamp': 1372708215,
176 'thumbnail': r
're:^https?://.*1383719781\.png$',
178 'expected_warnings': ['Unable to download f4m manifest'],
180 'url': 'http://www.rtr.ch/play/radio/actualitad/audio/saira-tujetsch-tuttina-cuntinuar-cun-sedrun-muster-turissem?id=63cb0778-27f8-49af-9284-8c7a8c6d15fc',
182 'id': '63cb0778-27f8-49af-9284-8c7a8c6d15fc',
184 'upload_date': '20151013',
185 'title': 'Saira: Tujetsch - tuttina cuntinuar cun Sedrun Mustér Turissem',
186 'timestamp': 1444709160,
191 'skip_download': True,
194 'url': 'http://www.rts.ch/play/tv/-/video/le-19h30?id=6348260',
195 'md5': '67a2a9ae4e8e62a68d0e9820cc9782df',
198 'display_id': '6348260',
202 'upload_date': '20141201',
203 'timestamp': 1417458600,
204 'thumbnail': r
're:^https?://.*\.image',
208 'skip_download': True,
211 'url': 'http://play.swissinfo.ch/play/tv/business/video/why-people-were-against-tax-reforms?id=42960270',
215 'title': 'Why people were against tax reforms',
216 'description': 'md5:7ac442c558e9630e947427469c4b824d',
218 'upload_date': '20170215',
219 'timestamp': 1487173560,
220 'thumbnail': r
're:https?://www\.swissinfo\.ch/srgscalableimage/42961964',
221 'subtitles': 'count:9',
224 'skip_download': True,
227 'url': 'https://www.srf.ch/play/tv/popupvideoplayer?id=c4dba0ca-e75b-43b2-a34f-f708a4932e01',
228 'only_matching': True,
230 'url': 'https://www.srf.ch/play/tv/10vor10/video/snowden-beantragt-asyl-in-russland?urn=urn:srf:video:28e1a57d-5b76-4399-8ab3-9097f071e6c5',
231 'only_matching': True,
233 'url': 'https://www.rts.ch/play/tv/19h30/video/le-19h30?urn=urn:rts:video:6348260',
234 'only_matching': True,
236 # audio segment, has podcastSdUrl of the full episode
237 'url': 'https://www.srf.ch/play/radio/popupaudioplayer?id=50b20dc8-f05b-4972-bf03-e438ff2833eb',
238 'only_matching': True,
241 def _real_extract(self
, url
):
242 mobj
= self
._match
_valid
_url
(url
)
243 bu
= mobj
.group('bu')
244 media_type
= mobj
.group('type') or mobj
.group('type_2')
245 media_id
= mobj
.group('id')
246 return self
.url_result(f
'srgssr:{bu[:3]}:{media_type}:{media_id}', 'SRGSSR')