2 from __future__ 
import unicode_literals
 
   6 from .common 
import InfoExtractor
 
   7 from ..compat 
import compat_str
 
  18 class SVTBaseIE(InfoExtractor
): 
  19     _GEO_COUNTRIES 
= ['SE'] 
  21     def _extract_video(self
, video_info
, video_id
): 
  22         is_live 
= dict_get(video_info
, ('live', 'simulcast'), default
=False) 
  23         m3u8_protocol 
= 'm3u8' if is_live 
else 'm3u8_native' 
  25         for vr 
in video_info
['videoReferences']: 
  26             player_type 
= vr
.get('playerType') or vr
.get('format') 
  28             ext 
= determine_ext(vurl
) 
  30                 formats
.extend(self
._extract
_m
3u8_formats
( 
  32                     ext
='mp4', entry_protocol
=m3u8_protocol
, 
  33                     m3u8_id
=player_type
, fatal
=False)) 
  35                 formats
.extend(self
._extract
_f
4m
_formats
( 
  36                     vurl 
+ '?hdcore=3.3.0', video_id
, 
  37                     f4m_id
=player_type
, fatal
=False)) 
  39                 if player_type 
== 'dashhbbtv': 
  40                     formats
.extend(self
._extract
_mpd
_formats
( 
  41                         vurl
, video_id
, mpd_id
=player_type
, fatal
=False)) 
  44                     'format_id': player_type
, 
  47         if not formats 
and video_info
.get('rights', {}).get('geoBlockedSweden'): 
  48             self
.raise_geo_restricted( 
  49                 'This video is only available in Sweden', 
  50                 countries
=self
._GEO
_COUNTRIES
) 
  51         self
._sort
_formats
(formats
) 
  54         subtitle_references 
= dict_get(video_info
, ('subtitles', 'subtitleReferences')) 
  55         if isinstance(subtitle_references
, list): 
  56             for sr 
in subtitle_references
: 
  57                 subtitle_url 
= sr
.get('url') 
  58                 subtitle_lang 
= sr
.get('language', 'sv') 
  60                     if determine_ext(subtitle_url
) == 'm3u8': 
  61                         # TODO(yan12125): handle WebVTT in m3u8 manifests 
  64                     subtitles
.setdefault(subtitle_lang
, []).append({'url': subtitle_url
}) 
  66         title 
= video_info
.get('title') 
  68         series 
= video_info
.get('programTitle') 
  69         season_number 
= int_or_none(video_info
.get('season')) 
  70         episode 
= video_info
.get('episodeTitle') 
  71         episode_number 
= int_or_none(video_info
.get('episodeNumber')) 
  73         duration 
= int_or_none(dict_get(video_info
, ('materialLength', 'contentDuration'))) 
  76             video_info
, ('inappropriateForChildren', 'blockedForChildren'), 
  77             skip_false_values
=False) 
  79             age_limit 
= 18 if adult 
else 0 
  85             'subtitles': subtitles
, 
  87             'age_limit': age_limit
, 
  89             'season_number': season_number
, 
  91             'episode_number': episode_number
, 
  96 class SVTIE(SVTBaseIE
): 
  97     _VALID_URL 
= r
'https?://(?:www\.)?svt\.se/wd\?(?:.*?&)?widgetId=(?P<widget_id>\d+)&.*?\barticleId=(?P<id>\d+)' 
  99         'url': 'http://www.svt.se/wd?widgetId=23991§ionId=541&articleId=2900353&type=embed&contextSectionId=123&autostart=false', 
 100         'md5': '33e9a5d8f646523ce0868ecfb0eed77d', 
 104             'title': 'Stjärnorna skojar till det - under SVT-intervjun', 
 111     def _extract_url(webpage
): 
 113             r
'(?:<iframe src|href)="(?P<url>%s[^"]*)"' % SVTIE
._VALID
_URL
, webpage
) 
 115             return mobj
.group('url') 
 117     def _real_extract(self
, url
): 
 118         mobj 
= re
.match(self
._VALID
_URL
, url
) 
 119         widget_id 
= mobj
.group('widget_id') 
 120         article_id 
= mobj
.group('id') 
 122         info 
= self
._download
_json
( 
 123             'http://www.svt.se/wd?widgetId=%s&articleId=%s&format=json&type=embed&output=json' % (widget_id
, article_id
), 
 126         info_dict 
= self
._extract
_video
(info
['video'], article_id
) 
 127         info_dict
['title'] = info
['context']['title'] 
 131 class SVTPlayBaseIE(SVTBaseIE
): 
 132     _SVTPLAY_RE 
= r
'root\s*\[\s*(["\'])_
*svtplay\
1\s
*\
]\s
*=\s
*(?P
<json
>{.+?
})\s
*;\s
*\n' 
 135 class SVTPlayIE(SVTPlayBaseIE): 
 136     IE_DESC = 'SVT Play 
and Öppet arkiv
' 
 137     _VALID_URL = r'''(?x) 
 139                         svt:(?P<svt_id>[^/?#&]+)| 
 140                         https?://(?:www\.)?(?:svtplay|oppetarkiv)\.se/(?:video|klipp|kanaler)/(?P<id>[^/?#&]+) 
 144         'url
': 'http
://www
.svtplay
.se
/video
/5996901/flygplan
-till
-haile
-selassie
/flygplan
-till
-haile
-selassie
-2', 
 145         'md5
': '2b6704fe4a28801e1a098bbf3c5ac611
', 
 149             'title
': 'Flygplan till Haile Selassie
', 
 151             'thumbnail
': r're
:^https?
://.*[\
.-]jpg$
', 
 160         # geo restricted to Sweden 
 161         'url
': 'http
://www
.oppetarkiv
.se
/video
/5219710/trollflojten
', 
 162         'only_matching
': True, 
 164         'url
': 'http
://www
.svtplay
.se
/klipp
/9023742/stopptid
-om
-bjorn
-borg
', 
 165         'only_matching
': True, 
 167         'url
': 'https
://www
.svtplay
.se
/kanaler
/svt1
', 
 168         'only_matching
': True, 
 170         'url
': 'svt
:1376446-003A
', 
 171         'only_matching
': True, 
 173         'url
': 'svt
:14278044', 
 174         'only_matching
': True, 
 177     def _adjust_title(self, info): 
 179             info['title
'] = self._live_title(info['title
']) 
 181     def _extract_by_video_id(self, video_id, webpage=None): 
 182         data = self._download_json( 
 183             'https
://api
.svt
.se
/videoplayer
-api
/video
/%s' % video_id, 
 184             video_id, headers=self.geo_verification_headers()) 
 185         info_dict = self._extract_video(data, video_id) 
 186         if not info_dict.get('title
'): 
 187             title = dict_get(info_dict, ('episode
', 'series
')) 
 188             if not title and webpage: 
 190                     r'\s
*\|\s
*.+?$
', '', self._og_search_title(webpage)) 
 193             info_dict['title
'] = title 
 194         self._adjust_title(info_dict) 
 197     def _real_extract(self, url): 
 198         mobj = re.match(self._VALID_URL, url) 
 199         video_id, svt_id = mobj.group('id', 'svt_id
') 
 202             return self._extract_by_video_id(svt_id) 
 204         webpage = self._download_webpage(url, video_id) 
 206         data = self._parse_json( 
 208                 self._SVTPLAY_RE, webpage, 'embedded data
', default='{}', 
 210             video_id, fatal=False) 
 212         thumbnail = self._og_search_thumbnail(webpage) 
 215             video_info = try_get( 
 216                 data, lambda x: x['context
']['dispatcher
']['stores
']['VideoTitlePageStore
']['data
']['video
'], 
 219                 info_dict = self._extract_video(video_info, video_id) 
 221                     'title
': data['context
']['dispatcher
']['stores
']['MetaStore
']['title
'], 
 222                     'thumbnail
': thumbnail, 
 224                 self._adjust_title(info_dict) 
 227         svt_id = self._search_regex( 
 228             r'<video
[^
>]+data
-video
-id=["\']([\da-zA-Z-]+)', 
 231         return self._extract_by_video_id(svt_id, webpage) 
 234 class SVTSeriesIE(SVTPlayBaseIE): 
 235     _VALID_URL = r'https?://(?:www\.)?svtplay\.se/(?P<id>[^/?&#]+)(?:.+?\btab=(?P<season_slug>[^&#]+))?' 
 237         'url': 'https://www.svtplay.se/rederiet', 
 241             'description': 'md5:d9fdfff17f5d8f73468176ecd2836039', 
 243         'playlist_mincount': 318, 
 245         'url': 'https://www.svtplay.se/rederiet?tab=season-2-14445680', 
 247             'id': 'season-2-14445680', 
 248             'title': 'Rederiet - Säsong 2', 
 249             'description': 'md5:d9fdfff17f5d8f73468176ecd2836039', 
 251         'playlist_mincount': 12, 
 255     def suitable(cls, url): 
 256         return False if SVTIE.suitable(url) or SVTPlayIE.suitable(url) else super(SVTSeriesIE, cls).suitable(url) 
 258     def _real_extract(self, url): 
 259         series_slug, season_id = re.match(self._VALID_URL, url).groups() 
 261         series = self._download_json( 
 262             'https://api.svt.se/contento/graphql', series_slug, 
 263             'Downloading series page', query={ 
 265   listablesBySlug(slugs: ["%s"]) { 
 266     associatedContent(include: [productionPeriod, season]) { 
 283             })['data']['listablesBySlug'][0] 
 288         for season in series['associatedContent']: 
 289             if not isinstance(season, dict): 
 292                 if season.get('id') != season_id: 
 294                 season_name = season.get('name') 
 295             items = season.get('items') 
 296             if not isinstance(items, list): 
 299                 video = item.get('item') or {} 
 300                 content_id = video.get('videoSvtId') 
 301                 if not content_id or not isinstance(content_id, compat_str): 
 303                 entries.append(self.url_result( 
 304                     'svt:' + content_id, SVTPlayIE.ie_key(), content_id)) 
 306         title = series.get('name') 
 307         season_name = season_name or season_id 
 309         if title and season_name: 
 310             title = '%s - %s' % (title, season_name) 
 314         return self.playlist_result( 
 315             entries, season_id or series.get('id'), title, 
 316             dict_get(series, ('longDescription', 'shortDescription'))) 
 319 class SVTPageIE(InfoExtractor): 
 320     _VALID_URL = r'https?://(?:www\.)?svt\.se/(?P<path>(?:[^/]+/)*(?P<id>[^/?&#]+))' 
 322         'url': 'https://www.svt.se/sport/ishockey/bakom-masken-lehners-kamp-mot-mental-ohalsa', 
 325             'title': 'Bakom masken – Lehners kamp mot mental ohälsa', 
 329         'url': 'https://www.svt.se/nyheter/utrikes/svenska-andrea-ar-en-mil-fran-branderna-i-kalifornien', 
 332             'title': 'Svenska Andrea redo att fly sitt hem i Kalifornien', 
 337         'url': 'http://www.svt.se/sport/ishockey/jagr-tacklar-giroux-under-intervjun', 
 341             'title': 'Stjärnorna skojar till det - under SVT-intervjun', 
 346         'url': 'https://www.svt.se/nyheter/lokalt/vast/svt-testar-tar-nagon-upp-skrapet-1', 
 347         'only_matching': True, 
 349         'url': 'https://www.svt.se/vader/manadskronikor/maj2018', 
 350         'only_matching': True, 
 354     def suitable(cls, url): 
 355         return False if SVTIE.suitable(url) else super(SVTPageIE, cls).suitable(url) 
 357     def _real_extract(self, url): 
 358         path, display_id = re.match(self._VALID_URL, url).groups() 
 360         article = self._download_json( 
 361             'https://api.svt.se/nss-api/page/' + path, display_id, 
 362             query={'q': 'articles'})['articles']['content'][0] 
 366         def _process_content(content): 
 367             if content.get('_type') in ('VIDEOCLIP', 'VIDEOEPISODE'): 
 368                 video_id = compat_str(content['image']['svtId']) 
 369                 entries.append(self.url_result( 
 370                     'svt:' + video_id, SVTPlayIE.ie_key(), video_id)) 
 372         for media in article.get('media', []): 
 373             _process_content(media) 
 375         for obj in article.get('structuredBody', []): 
 376             _process_content(obj.get('content') or {}) 
 378         return self.playlist_result( 
 379             entries, str_or_none(article.get('id')), 
 380             strip_or_none(article.get('title')))