]>
jfr.im git - yt-dlp.git/blob - youtube_dl/extractor/ard.py
2 from __future__
import unicode_literals
6 from . common
import InfoExtractor
7 from . generic
import GenericIE
11 get_element_by_attribute
,
18 from .. compat
import compat_etree_fromstring
21 class ARDMediathekIE ( InfoExtractor
):
22 IE_NAME
= 'ARD:mediathek'
23 _VALID_URL
= r
'^https?://(?:(?:www\.)?ardmediathek\.de|mediathek\.daserste\.de)/(?:.*/)(?P<video_id>[0-9]+|[^0-9][^/\?]+)[^/\?]*(?:\?.*)?'
26 'url' : 'http://www.ardmediathek.de/tv/Dokumentation-und-Reportage/Ich-liebe-das-Leben-trotzdem/rbb-Fernsehen/Video?documentId=29582122&bcastId=3822114' ,
30 'title' : 'Ich liebe das Leben trotzdem' ,
31 'description' : 'md5:45e4c225c72b27993314b31a84a5261c' ,
36 'skip_download' : True ,
39 'url' : 'http://www.ardmediathek.de/tv/Tatort/Tatort-Scheinwelten-H%C3%B6rfassung-Video/Das-Erste/Video?documentId=29522730&bcastId=602916' ,
40 'md5' : 'f4d98b10759ac06c0072bbcd1f0b9e3e' ,
44 'title' : 'Tatort: Scheinwelten - Hörfassung (Video tgl. ab 20 Uhr)' ,
45 'description' : 'md5:196392e79876d0ac94c94e8cdb2875f1' ,
50 'url' : 'http://www.ardmediathek.de/tv/WDR-H%C3%B6rspiel-Speicher/Tod-eines-Fu%C3%9Fballers/WDR-3/Audio-Podcast?documentId=28488308&bcastId=23074086' ,
51 'md5' : '219d94d8980b4f538c7fcb0865eb7f2c' ,
55 'title' : 'Tod eines Fußballers' ,
56 'description' : 'md5:f6e39f3461f0e1f54bfa48c8875c86ef' ,
60 'url' : 'http://mediathek.daserste.de/sendungen_a-z/328454_anne-will/22429276_vertrauen-ist-gut-spionieren-ist-besser-geht' ,
61 'only_matching' : True ,
64 def _extract_media_info ( self
, media_info_url
, webpage
, video_id
):
65 media_info
= self
._ download
_ json
(
66 media_info_url
, video_id
, 'Downloading media JSON' )
68 formats
= self
._ extract
_ formats
( media_info
, video_id
)
71 if '"fsk"' in webpage
:
73 'This video is only available after 20:00' , expected
= True )
74 elif media_info
. get ( '_geoblocked' ):
75 raise ExtractorError ( 'This video is not available due to geo restriction' , expected
= True )
77 self
._ sort
_ formats
( formats
)
79 duration
= int_or_none ( media_info
. get ( '_duration' ))
80 thumbnail
= media_info
. get ( '_previewImage' )
83 subtitle_url
= media_info
. get ( '_subtitleUrl' )
93 'thumbnail' : thumbnail
,
95 'subtitles' : subtitles
,
98 def _extract_formats ( self
, media_info
, video_id
):
99 type_
= media_info
. get ( '_type' )
100 media_array
= media_info
. get ( '_mediaArray' , [])
102 for num
, media
in enumerate ( media_array
):
103 for stream
in media
. get ( '_mediaStreamArray' , []):
104 stream_urls
= stream
. get ( '_stream' )
107 if not isinstance ( stream_urls
, list ):
108 stream_urls
= [ stream_urls
]
109 quality
= stream
. get ( '_quality' )
110 server
= stream
. get ( '_server' )
111 for stream_url
in stream_urls
:
112 ext
= determine_ext ( stream_url
)
113 if quality
!= 'auto' and ext
in ( 'f4m' , 'm3u8' ):
116 f4m_formats
= self
._ extract
_ f
4 m
_ formats
(
117 stream_url
+ '?hdcore=3.1.1&plugin=aasp-3.1.1.69.124' ,
118 video_id
, preference
=- 1 , f4m_id
= 'hds' , fatal
= False )
120 formats
. extend ( f4m_formats
)
122 m3u8_formats
= self
._ extract
_ m
3u8_ formats
(
123 stream_url
, video_id
, 'mp4' , preference
= 1 , m3u8_id
= 'hls' , fatal
= False )
125 formats
. extend ( m3u8_formats
)
127 if server
and server
. startswith ( 'rtmp' ):
130 'play_path' : stream_url
,
131 'format_id' : 'a %s-r tmp- %s ' % ( num
, quality
),
133 elif stream_url
. startswith ( 'http' ):
136 'format_id' : 'a %s-%s-%s ' % ( num
, ext
, quality
)
140 m
= re
. search ( r
'_(?P<width>\d+)x(?P<height>\d+)\.mp4$' , stream_url
)
143 'width' : int ( m
. group ( 'width' )),
144 'height' : int ( m
. group ( 'height' )),
151 def _real_extract ( self
, url
):
152 # determine video id from url
153 m
= re
. match ( self
._ VALID
_U RL
, url
)
155 numid
= re
. search ( r
'documentId=([0-9]+)' , url
)
157 video_id
= numid
. group ( 1 )
159 video_id
= m
. group ( 'video_id' )
161 webpage
= self
._ download
_ webpage
( url
, video_id
)
163 if '>Der gewünschte Beitrag ist nicht mehr verfügbar.<' in webpage
:
164 raise ExtractorError ( 'Video %s is no longer available' % video_id
, expected
= True )
166 if 'Diese Sendung ist für Jugendliche unter 12 Jahren nicht geeignet. Der Clip ist deshalb nur von 20 bis 6 Uhr verfügbar.' in webpage
:
167 raise ExtractorError ( 'This program is only suitable for those aged 12 and older. Video %s is therefore only available between 20 pm and 6 am.' % video_id
, expected
= True )
169 if re
. search ( r
'[\?&]rss($|[=&])' , url
):
170 doc
= compat_etree_fromstring ( webpage
. encode ( 'utf-8' ))
172 return GenericIE () ._ extract
_ rss
( url
, video_id
, doc
)
174 title
= self
._ html
_ search
_ regex
(
175 [ r
'<h1(?:\s+class="boxTopHeadline")?>(.*?)</h1>' ,
176 r
'<meta name="dcterms.title" content="(.*?)"/>' ,
177 r
'<h4 class="headline">(.*?)</h4>' ],
179 description
= self
._ html
_ search
_ meta
(
180 'dcterms.abstract' , webpage
, 'description' , default
= None )
181 if description
is None :
182 description
= self
._ html
_ search
_ meta
(
183 'description' , webpage
, 'meta description' )
185 # Thumbnail is sometimes not present.
186 # It is in the mobile version, but that seems to use a different URL
187 # structure altogether.
188 thumbnail
= self
._ og
_ search
_ thumbnail
( webpage
, default
= None )
190 media_streams
= re
. findall ( r
'''(?x)
191 mediaCollection\.addMediaStream\([0-9]+,\s*[0-9]+,\s*"[^"]*",\s*
192 "([^"]+)"''' , webpage
)
195 QUALITIES
= qualities ([ 'lo' , 'hi' , 'hq' ])
197 for furl
in set ( media_streams
):
198 if furl
. endswith ( '.f4m' ):
201 fid_m
= re
. match ( r
'.*\.([^.]+)\.[^.]+$' , furl
)
202 fid
= fid_m
. group ( 1 ) if fid_m
else None
204 'quality' : QUALITIES ( fid
),
208 self
._ sort
_ formats
( formats
)
212 else : # request JSON file
213 info
= self
._ extract
_ media
_ info
(
214 'http://www.ardmediathek.de/play/media/ %s ' % video_id
, webpage
, video_id
)
219 'description' : description
,
220 'thumbnail' : thumbnail
,
226 class ARDIE ( InfoExtractor
):
227 _VALID_URL
= '(?P<mainurl>https?://(www\.)?daserste\.de/[^?#]+/videos/(?P<display_id>[^/?#]+)-(?P<id>[0-9]+))\.html'
229 'url' : 'http://www.daserste.de/information/reportage-dokumentation/dokus/videos/die-story-im-ersten-mission-unter-falscher-flagge-100.html' ,
230 'md5' : 'd216c3a86493f9322545e045ddc3eb35' ,
232 'display_id' : 'die-story-im-ersten-mission-unter-falscher-flagge' ,
236 'title' : 'Die Story im Ersten: Mission unter falscher Flagge' ,
237 'upload_date' : '20140804' ,
238 'thumbnail' : 're:^https?://.*\.jpg$' ,
242 def _real_extract ( self
, url
):
243 mobj
= re
. match ( self
._ VALID
_U RL
, url
)
244 display_id
= mobj
. group ( 'display_id' )
246 player_url
= mobj
. group ( 'mainurl' ) + '~playerXml.xml'
247 doc
= self
._ download
_ xml
( player_url
, display_id
)
248 video_node
= doc
. find ( './video' )
249 upload_date
= unified_strdate ( xpath_text (
250 video_node
, './broadcastDate' ))
251 thumbnail
= xpath_text ( video_node
, './/teaserImage//variant/url' )
254 for a
in video_node
. findall ( './/asset' ):
256 'format_id' : a
. attrib
[ 'type' ],
257 'width' : int_or_none ( a
. find ( './frameWidth' ). text
),
258 'height' : int_or_none ( a
. find ( './frameHeight' ). text
),
259 'vbr' : int_or_none ( a
. find ( './bitrateVideo' ). text
),
260 'abr' : int_or_none ( a
. find ( './bitrateAudio' ). text
),
261 'vcodec' : a
. find ( './codecVideo' ). text
,
262 'tbr' : int_or_none ( a
. find ( './totalBitrate' ). text
),
264 if a
. find ( './serverPrefix' ). text
:
265 f
[ 'url' ] = a
. find ( './serverPrefix' ). text
266 f
[ 'playpath' ] = a
. find ( './fileName' ). text
268 f
[ 'url' ] = a
. find ( './fileName' ). text
270 self
._ sort
_ formats
( formats
)
273 'id' : mobj
. group ( 'id' ),
275 'display_id' : display_id
,
276 'title' : video_node
. find ( './title' ). text
,
277 'duration' : parse_duration ( video_node
. find ( './duration' ). text
),
278 'upload_date' : upload_date
,
279 'thumbnail' : thumbnail
,
283 class SportschauIE ( ARDMediathekIE
):
284 IE_NAME
= 'Sportschau'
285 _VALID_URL
= r
'(?P<baseurl>https?://(?:www\.)?sportschau\.de/(?:[^/]+/)+video(?P<id>[^/#?]+))\.html'
287 'url' : 'http://www.sportschau.de/tourdefrance/videoseppeltkokainhatnichtsmitklassischemdopingzutun100.html' ,
289 'id' : 'seppeltkokainhatnichtsmitklassischemdopingzutun100' ,
291 'title' : 'Seppelt: "Kokain hat nichts mit klassischem Doping zu tun"' ,
292 'thumbnail' : 're:^https?://.*\.jpg$' ,
293 'description' : 'Der ARD-Doping Experte Hajo Seppelt gibt seine Einschätzung zum ersten Dopingfall der diesjährigen Tour de France um den Italiener Luca Paolini ab.' ,
297 'skip_download' : True ,
301 def _real_extract ( self
, url
):
302 mobj
= re
. match ( self
._ VALID
_U RL
, url
)
303 video_id
= mobj
. group ( 'id' )
304 base_url
= mobj
. group ( 'baseurl' )
306 webpage
= self
._ download
_ webpage
( url
, video_id
)
307 title
= get_element_by_attribute ( 'class' , 'headline' , webpage
)
308 description
= self
._ html
_ search
_ meta
( 'description' , webpage
, 'description' )
310 info
= self
._ extract
_ media
_ info
(
311 base_url
+ '-mc_defaultQuality-h.json' , webpage
, video_id
)
315 'description' : description
,