]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/extractor/limelight.py
422be25288f66a83c32e370e833d6690d83ab54b
   2 from __future__ 
import unicode_literals
 
   6 from .common 
import InfoExtractor
 
   7 from ..compat 
import compat_HTTPError
 
  17 class LimelightBaseIE(InfoExtractor
): 
  18     _PLAYLIST_SERVICE_URL 
= 'http://production-ps.lvp.llnw.net/r/PlaylistService/%s/%s/%s' 
  19     _API_URL 
= 'http://api.video.limelight.com/rest/organizations/%s/%s/%s/%s.json' 
  21     def _call_playlist_service(self
, item_id
, method
, fatal
=True, referer
=None): 
  24             headers
['Referer'] = referer
 
  26             return self
._download
_json
( 
  27                 self
._PLAYLIST
_SERVICE
_URL 
% (self
._PLAYLIST
_SERVICE
_PATH
, item_id
, method
), 
  28                 item_id
, 'Downloading PlaylistService %s JSON' % method
, fatal
=fatal
, headers
=headers
) 
  29         except ExtractorError 
as e
: 
  30             if isinstance(e
.cause
, compat_HTTPError
) and e
.cause
.code 
== 403: 
  31                 error 
= self
._parse
_json
(e
.cause
.read().decode(), item_id
)['detail']['contentAccessPermission'] 
  32                 if error 
== 'CountryDisabled': 
  33                     self
.raise_geo_restricted() 
  34                 raise ExtractorError(error
, expected
=True) 
  37     def _call_api(self
, organization_id
, item_id
, method
): 
  38         return self
._download
_json
( 
  39             self
._API
_URL 
% (organization_id
, self
._API
_PATH
, item_id
, method
), 
  40             item_id
, 'Downloading API %s JSON' % method
) 
  42     def _extract(self
, item_id
, pc_method
, mobile_method
, meta_method
, referer
=None): 
  43         pc 
= self
._call
_playlist
_service
(item_id
, pc_method
, referer
=referer
) 
  44         metadata 
= self
._call
_api
(pc
['orgId'], item_id
, meta_method
) 
  45         mobile 
= self
._call
_playlist
_service
(item_id
, mobile_method
, fatal
=False, referer
=referer
) 
  46         return pc
, mobile
, metadata
 
  48     def _extract_info(self
, streams
, mobile_urls
, properties
): 
  49         video_id 
= properties
['media_id'] 
  52         for stream 
in streams
: 
  53             stream_url 
= stream
.get('url') 
  54             if not stream_url 
or stream
.get('drmProtected') or stream_url 
in urls
: 
  56             urls
.append(stream_url
) 
  57             ext 
= determine_ext(stream_url
) 
  59                 formats
.extend(self
._extract
_f
4m
_formats
( 
  60                     stream_url
, video_id
, f4m_id
='hds', fatal
=False)) 
  64                     'abr': float_or_none(stream
.get('audioBitRate')), 
  65                     'vbr': float_or_none(stream
.get('videoBitRate')), 
  66                     'fps': float_or_none(stream
.get('videoFrameRate')), 
  67                     'width': int_or_none(stream
.get('videoWidthInPixels')), 
  68                     'height': int_or_none(stream
.get('videoHeightInPixels')), 
  71                 rtmp 
= re
.search(r
'^(?P<url>rtmpe?://(?P<host>[^/]+)/(?P<app>.+))/(?P<playpath>mp4:.+)$', stream_url
) 
  74                     if stream
.get('videoBitRate'): 
  75                         format_id 
+= '-%d' % int_or_none(stream
['videoBitRate']) 
  76                     http_format_id 
= format_id
.replace('rtmp', 'http') 
  79                         ('delvenetworks.com', 'cpl.delvenetworks.com'), 
  80                         ('video.llnw.net', 's2.content.video.llnw.net'), 
  82                     for cdn_host
, http_host 
in CDN_HOSTS
: 
  83                         if cdn_host 
not in rtmp
.group('host').lower(): 
  85                         http_url 
= 'http://%s/%s' % (http_host
, rtmp
.group('playpath')[4:]) 
  87                         if self
._is
_valid
_url
(http_url
, video_id
, http_format_id
): 
  91                                 'format_id': http_format_id
, 
  93                             formats
.append(http_fmt
) 
  97                         'url': rtmp
.group('url'), 
  98                         'play_path': rtmp
.group('playpath'), 
  99                         'app': rtmp
.group('app'), 
 101                         'format_id': format_id
, 
 105         for mobile_url 
in mobile_urls
: 
 106             media_url 
= mobile_url
.get('mobileUrl') 
 107             format_id 
= mobile_url
.get('targetMediaPlatform') 
 108             if not media_url 
or format_id 
in ('Widevine', 'SmoothStreaming') or media_url 
in urls
: 
 110             urls
.append(media_url
) 
 111             ext 
= determine_ext(media_url
) 
 113                 formats
.extend(self
._extract
_m
3u8_formats
( 
 114                     media_url
, video_id
, 'mp4', 'm3u8_native', 
 115                     m3u8_id
=format_id
, fatal
=False)) 
 117                 formats
.extend(self
._extract
_f
4m
_formats
( 
 118                     stream_url
, video_id
, f4m_id
=format_id
, fatal
=False)) 
 122                     'format_id': format_id
, 
 127         self
._sort
_formats
(formats
) 
 129         title 
= properties
['title'] 
 130         description 
= properties
.get('description') 
 131         timestamp 
= int_or_none(properties
.get('publish_date') or properties
.get('create_date')) 
 132         duration 
= float_or_none(properties
.get('duration_in_milliseconds'), 1000) 
 133         filesize 
= int_or_none(properties
.get('total_storage_in_bytes')) 
 134         categories 
= [properties
.get('category')] 
 135         tags 
= properties
.get('tags', []) 
 137             'url': thumbnail
['url'], 
 138             'width': int_or_none(thumbnail
.get('width')), 
 139             'height': int_or_none(thumbnail
.get('height')), 
 140         } for thumbnail 
in properties
.get('thumbnails', []) if thumbnail
.get('url')] 
 143         for caption 
in properties
.get('captions', []): 
 144             lang 
= caption
.get('language_code') 
 145             subtitles_url 
= caption
.get('url') 
 146             if lang 
and subtitles_url
: 
 147                 subtitles
.setdefault(lang
, []).append({ 
 148                     'url': subtitles_url
, 
 150         closed_captions_url 
= properties
.get('closed_captions_url') 
 151         if closed_captions_url
: 
 152             subtitles
.setdefault('en', []).append({ 
 153                 'url': closed_captions_url
, 
 160             'description': description
, 
 162             'timestamp': timestamp
, 
 163             'duration': duration
, 
 164             'filesize': filesize
, 
 165             'categories': categories
, 
 167             'thumbnails': thumbnails
, 
 168             'subtitles': subtitles
, 
 172 class LimelightMediaIE(LimelightBaseIE
): 
 173     IE_NAME 
= 'limelight' 
 174     _VALID_URL 
= r
'''(?x) 
 179                                     link\.videoplatform\.limelight\.com/media/| 
 180                                     assets\.delvenetworks\.com/player/loader\.swf 
 187         'url': 'http://link.videoplatform.limelight.com/media/?mediaId=3ffd040b522b4485b6d84effc750cd86', 
 189             'id': '3ffd040b522b4485b6d84effc750cd86', 
 191             'title': 'HaP and the HB Prince Trailer', 
 192             'description': 'md5:8005b944181778e313d95c1237ddb640', 
 193             'thumbnail': r
're:^https?://.*\.jpeg$', 
 195             'timestamp': 1244136834, 
 196             'upload_date': '20090604', 
 200             'skip_download': True, 
 203         # video with subtitles 
 204         'url': 'limelight:media:a3e00274d4564ec4a9b29b9466432335', 
 205         'md5': '2fa3bad9ac321e23860ca23bc2c69e3d', 
 207             'id': 'a3e00274d4564ec4a9b29b9466432335', 
 209             'title': '3Play Media Overview Video', 
 210             'thumbnail': r
're:^https?://.*\.jpeg$', 
 212             'timestamp': 1338929955, 
 213             'upload_date': '20120605', 
 214             'subtitles': 'mincount:9', 
 217         'url': 'https://assets.delvenetworks.com/player/loader.swf?mediaId=8018a574f08d416e95ceaccae4ba0452', 
 218         'only_matching': True, 
 220     _PLAYLIST_SERVICE_PATH 
= 'media' 
 223     def _real_extract(self
, url
): 
 224         url
, smuggled_data 
= unsmuggle_url(url
, {}) 
 225         video_id 
= self
._match
_id
(url
) 
 226         self
._initialize
_geo
_bypass
(smuggled_data
.get('geo_countries')) 
 228         pc
, mobile
, metadata 
= self
._extract
( 
 229             video_id
, 'getPlaylistByMediaId', 
 230             'getMobilePlaylistByMediaId', 'properties', 
 231             smuggled_data
.get('source_url')) 
 233         return self
._extract
_info
( 
 234             pc
['playlistItems'][0].get('streams', []), 
 235             mobile
['mediaList'][0].get('mobileUrls', []) if mobile 
else [], 
 239 class LimelightChannelIE(LimelightBaseIE
): 
 240     IE_NAME 
= 'limelight:channel' 
 241     _VALID_URL 
= r
'''(?x) 
 246                                     link\.videoplatform\.limelight\.com/media/| 
 247                                     assets\.delvenetworks\.com/player/loader\.swf 
 254         'url': 'http://link.videoplatform.limelight.com/media/?channelId=ab6a524c379342f9b23642917020c082', 
 256             'id': 'ab6a524c379342f9b23642917020c082', 
 257             'title': 'Javascript Sample Code', 
 259         'playlist_mincount': 3, 
 261         'url': 'http://assets.delvenetworks.com/player/loader.swf?channelId=ab6a524c379342f9b23642917020c082', 
 262         'only_matching': True, 
 264     _PLAYLIST_SERVICE_PATH 
= 'channel' 
 265     _API_PATH 
= 'channels' 
 267     def _real_extract(self
, url
): 
 268         url
, smuggled_data 
= unsmuggle_url(url
, {}) 
 269         channel_id 
= self
._match
_id
(url
) 
 271         pc
, mobile
, medias 
= self
._extract
( 
 272             channel_id
, 'getPlaylistByChannelId', 
 273             'getMobilePlaylistWithNItemsByChannelId?begin=0&count=-1', 
 274             'media', smuggled_data
.get('source_url')) 
 278                 pc
['playlistItems'][i
].get('streams', []), 
 279                 mobile
['mediaList'][i
].get('mobileUrls', []) if mobile 
else [], 
 280                 medias
['media_list'][i
]) 
 281             for i 
in range(len(medias
['media_list']))] 
 283         return self
.playlist_result(entries
, channel_id
, pc
['title']) 
 286 class LimelightChannelListIE(LimelightBaseIE
): 
 287     IE_NAME 
= 'limelight:channel_list' 
 288     _VALID_URL 
= r
'''(?x) 
 290                             limelight:channel_list:| 
 293                                     link\.videoplatform\.limelight\.com/media/| 
 294                                     assets\.delvenetworks\.com/player/loader\.swf 
 296                                 \?.*?\bchannelListId= 
 301         'url': 'http://link.videoplatform.limelight.com/media/?channelListId=301b117890c4465c8179ede21fd92e2b', 
 303             'id': '301b117890c4465c8179ede21fd92e2b', 
 304             'title': 'Website - Hero Player', 
 306         'playlist_mincount': 2, 
 308         'url': 'https://assets.delvenetworks.com/player/loader.swf?channelListId=301b117890c4465c8179ede21fd92e2b', 
 309         'only_matching': True, 
 311     _PLAYLIST_SERVICE_PATH 
= 'channel_list' 
 313     def _real_extract(self
, url
): 
 314         channel_list_id 
= self
._match
_id
(url
) 
 316         channel_list 
= self
._call
_playlist
_service
(channel_list_id
, 'getMobileChannelListById') 
 319             self
.url_result('limelight:channel:%s' % channel
['id'], 'LimelightChannel') 
 320             for channel 
in channel_list
['channelList']] 
 322         return self
.playlist_result(entries
, channel_list_id
, channel_list
['title'])