]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/extractor/tvnow.py
2 from __future__
import unicode_literals
6 from .common
import InfoExtractor
7 from ..compat
import compat_str
18 class TVNowBaseIE(InfoExtractor
):
20 'id', 'title', 'free', 'geoblocked', 'articleLong', 'articleShort',
21 'broadcastStartDate', 'isDrm', 'duration', 'season', 'episode',
22 'manifest.dashclear', 'manifest.hlsclear', 'manifest.smoothclear',
23 'format.title', 'format.defaultImage169Format', 'format.defaultImage169Logo')
25 def _call_api(self
, path
, video_id
, query
):
26 return self
._download
_json
(
27 'https://api.tvnow.de/v3/' + path
,
28 video_id
, query
=query
)
30 def _extract_video(self
, info
, display_id
):
31 video_id
= compat_str(info
['id'])
35 for manifest_url
in (info
.get('manifest') or {}).values():
38 manifest_url
= update_url_query(manifest_url
, {'filter': ''})
39 path
= self
._search
_regex
(r
'https?://[^/]+/(.+?)\.ism/', manifest_url
, 'path')
44 def url_repl(proto
, suffix
):
46 r
'(?:hls|dash|hss)([.-])', proto
+ r
'\1', re
.sub(
47 r
'\.ism/(?:[^.]*\.(?:m3u8|mpd)|[Mm]anifest)',
48 '.ism/' + suffix
, manifest_url
))
50 formats
= self
._extract
_mpd
_formats
(
51 url_repl('dash', '.mpd'), video_id
,
52 mpd_id
='dash', fatal
=False)
53 formats
.extend(self
._extract
_ism
_formats
(
54 url_repl('hss', 'Manifest'),
55 video_id
, ism_id
='mss', fatal
=False))
56 formats
.extend(self
._extract
_m
3u8_formats
(
57 url_repl('hls', '.m3u8'), video_id
, 'mp4',
58 'm3u8_native', m3u8_id
='hls', fatal
=False))
64 'Video %s is DRM protected' % video_id
, expected
=True)
65 if info
.get('geoblocked'):
66 raise self
.raise_geo_restricted()
67 if not info
.get('free', True):
69 'Video %s is not available for free' % video_id
, expected
=True)
70 self
._sort
_formats
(formats
)
72 description
= info
.get('articleLong') or info
.get('articleShort')
73 timestamp
= parse_iso8601(info
.get('broadcastStartDate'), ' ')
74 duration
= parse_duration(info
.get('duration'))
76 f
= info
.get('format', {})
79 'url': 'https://aistvnow-a.akamaihd.net/tvnow/movie/%s' % video_id
,
81 thumbnail
= f
.get('defaultImage169Format') or f
.get('defaultImage169Logo')
89 'display_id': display_id
,
91 'description': description
,
92 'thumbnails': thumbnails
,
93 'timestamp': timestamp
,
95 'series': f
.get('title'),
96 'season_number': int_or_none(info
.get('season')),
97 'episode_number': int_or_none(info
.get('episode')),
103 class TVNowIE(TVNowBaseIE
):
104 _VALID_URL
= r
'''(?x)
106 (?:www\.)?tvnow\.(?:de|at|ch)/(?P<station>[^/]+)/
108 (?!(?:list|jahr)(?:/|$))(?P<id>[^/?\#&]+)
112 'url': 'https://www.tvnow.de/rtl2/grip-das-motormagazin/der-neue-porsche-911-gt-3/player',
115 'display_id': 'grip-das-motormagazin/der-neue-porsche-911-gt-3',
117 'title': 'Der neue Porsche 911 GT 3',
118 'description': 'md5:6143220c661f9b0aae73b245e5d898bb',
119 'thumbnail': r
're:^https?://.*\.jpg$',
120 'timestamp': 1495994400,
121 'upload_date': '20170528',
123 'series': 'GRIP - Das Motormagazin',
125 'episode_number': 405,
126 'episode': 'Der neue Porsche 911 GT 3',
130 'url': 'https://www.tvnow.de/rtl2/armes-deutschland/episode-0008/player',
131 'only_matching': True,
134 'url': 'https://www.tvnow.de/nitro/alarm-fuer-cobra-11-die-autobahnpolizei/auf-eigene-faust-pilot/player',
135 'only_matching': True,
138 'url': 'https://www.tvnow.de/superrtl/die-lustigsten-schlamassel-der-welt/u-a-ketchup-effekt/player',
139 'only_matching': True,
142 'url': 'https://www.tvnow.de/ntv/startup-news/goetter-in-weiss/player',
143 'only_matching': True,
146 'url': 'https://www.tvnow.de/vox/auto-mobil/neues-vom-automobilmarkt-2017-11-19-17-00-00/player',
147 'only_matching': True,
150 'url': 'https://www.tvnow.de/rtlplus/op-ruft-dr-bruckner/die-vernaehte-frau/player',
151 'only_matching': True,
153 'url': 'https://www.tvnow.de/rtl2/grip-das-motormagazin/der-neue-porsche-911-gt-3',
154 'only_matching': True,
157 def _real_extract(self
, url
):
158 mobj
= re
.match(self
._VALID
_URL
, url
)
159 display_id
= '%s/%s' % mobj
.group(2, 3)
161 info
= self
._call
_api
(
162 'movies/' + display_id
, display_id
, query
={
163 'fields': ','.join(self
._VIDEO
_FIELDS
),
164 'station': mobj
.group(1),
167 return self
._extract
_video
(info
, display_id
)
170 class TVNowListBaseIE(TVNowBaseIE
):
171 _SHOW_VALID_URL
= r
'''(?x)
174 (?:www\.)?tvnow\.(?:de|at|ch)/[^/]+/
179 def _extract_list_info(self
, display_id
, show_id
):
180 fields
= list(self
._SHOW
_FIELDS
)
181 fields
.extend('formatTabs.%s' % field
for field
in self
._SEASON
_FIELDS
)
183 'formatTabs.formatTabPages.container.movies.%s' % field
184 for field
in self
._VIDEO
_FIELDS
)
185 return self
._call
_api
(
186 'formats/seo', display_id
, query
={
187 'fields': ','.join(fields
),
188 'name': show_id
+ '.php'
192 class TVNowListIE(TVNowListBaseIE
):
193 _VALID_URL
= r
'%s/(?:list|jahr)/(?P<id>[^?\#&]+)' % TVNowListBaseIE
._SHOW
_VALID
_URL
195 _SHOW_FIELDS
= ('title', )
196 _SEASON_FIELDS
= ('id', 'headline', 'seoheadline', )
197 _VIDEO_FIELDS
= ('id', 'headline', 'seoUrl', )
200 'url': 'https://www.tvnow.de/rtl/30-minuten-deutschland/list/aktuell',
203 'title': '30 Minuten Deutschland - Aktuell',
205 'playlist_mincount': 1,
207 'url': 'https://www.tvnow.de/vox/ab-ins-beet/list/staffel-14',
208 'only_matching': True,
210 'url': 'https://www.tvnow.de/rtl2/grip-das-motormagazin/jahr/2018/3',
211 'only_matching': True,
215 def suitable(cls
, url
):
216 return (False if TVNowIE
.suitable(url
)
217 else super(TVNowListIE
, cls
).suitable(url
))
219 def _real_extract(self
, url
):
220 base_url
, show_id
, season_id
= re
.match(self
._VALID
_URL
, url
).groups()
222 list_info
= self
._extract
_list
_info
(season_id
, show_id
)
225 season
for season
in list_info
['formatTabs']['items']
226 if season
.get('seoheadline') == season_id
)
228 title
= list_info
.get('title')
229 headline
= season
.get('headline')
230 if title
and headline
:
231 title
= '%s - %s' % (title
, headline
)
233 title
= headline
or title
236 for container
in season
['formatTabPages']['items']:
238 container
, lambda x
: x
['container']['movies']['items'],
241 seo_url
= info
.get('seoUrl')
244 video_id
= info
.get('id')
245 entries
.append(self
.url_result(
246 '%s/%s/player' % (base_url
, seo_url
), TVNowIE
.ie_key(),
247 compat_str(video_id
) if video_id
else None))
249 return self
.playlist_result(
250 entries
, compat_str(season
.get('id') or season_id
), title
)
253 class TVNowShowIE(TVNowListBaseIE
):
254 _VALID_URL
= TVNowListBaseIE
._SHOW
_VALID
_URL
256 _SHOW_FIELDS
= ('id', 'title', )
257 _SEASON_FIELDS
= ('id', 'headline', 'seoheadline', )
261 'url': 'https://www.tvnow.at/vox/ab-ins-beet',
264 'title': 'Ab ins Beet!',
266 'playlist_mincount': 7,
268 'url': 'https://www.tvnow.at/vox/ab-ins-beet/list',
269 'only_matching': True,
271 'url': 'https://www.tvnow.de/rtl2/grip-das-motormagazin/jahr/',
272 'only_matching': True,
276 def suitable(cls
, url
):
277 return (False if TVNowIE
.suitable(url
) or TVNowListIE
.suitable(url
)
278 else super(TVNowShowIE
, cls
).suitable(url
))
280 def _real_extract(self
, url
):
281 base_url
, show_id
= re
.match(self
._VALID
_URL
, url
).groups()
283 list_info
= self
._extract
_list
_info
(show_id
, show_id
)
286 for season_info
in list_info
['formatTabs']['items']:
287 season_url
= season_info
.get('seoheadline')
290 season_id
= season_info
.get('id')
291 entries
.append(self
.url_result(
292 '%s/list/%s' % (base_url
, season_url
), TVNowListIE
.ie_key(),
293 compat_str(season_id
) if season_id
else None,
294 season_info
.get('headline')))
296 return self
.playlist_result(entries
, show_id
, list_info
.get('title'))