]>
Raphaël G. Git Repositories - youtubedl/blob - youtube_dl/extractor/ivi.py
   2 from __future__ 
import unicode_literals
 
   8 from .common 
import InfoExtractor
 
  16 class IviIE(InfoExtractor
): 
  19     _VALID_URL 
= r
'https?://(?:www\.)?ivi\.(?:ru|tv)/(?:watch/(?:[^/]+/)?|video/player\?.*?videoId=)(?P<id>\d+)' 
  21     _GEO_COUNTRIES 
= ['RU'] 
  22     _LIGHT_KEY 
= b
'\xf1\x02\x32\xb7\xbc\x5c\x7a\xe8\xf7\x96\xc1\x33\x2b\x27\xa1\x8c' 
  23     _LIGHT_URL 
= 'https://api.ivi.ru/light/' 
  28             'url': 'http://www.ivi.ru/watch/53141', 
  29             'md5': '6ff5be2254e796ed346251d117196cf4', 
  33                 'title': 'Иван Васильевич меняет профессию', 
  34                 'description': 'md5:b924063ea1677c8fe343d8a72ac2195f', 
  36                 'thumbnail': r
're:^https?://.*\.jpg$', 
  38             'skip': 'Only works from Russia', 
  42             'url': 'http://www.ivi.ru/watch/dvoe_iz_lartsa/9549', 
  43             'md5': '221f56b35e3ed815fde2df71032f4b3e', 
  47                 'title': 'Двое из ларца - Дело Гольдберга (1 часть)', 
  48                 'series': 'Двое из ларца', 
  51                 'episode': 'Дело Гольдберга (1 часть)', 
  54                 'thumbnail': r
're:^https?://.*\.jpg$', 
  56             'skip': 'Only works from Russia', 
  59             # with MP4-HD720 format 
  60             'url': 'http://www.ivi.ru/watch/146500', 
  61             'md5': 'd63d35cdbfa1ea61a5eafec7cc523e1e', 
  66                 'description': 'md5:ffca9372399976a2d260a407cc74cce6', 
  68                 'thumbnail': r
're:^https?://.*\.jpg$', 
  70             'skip': 'Only works from Russia', 
  73             'url': 'https://www.ivi.tv/watch/33560/', 
  74             'only_matching': True, 
  80         'MP4-low-mobile', 'MP4-mobile', 'FLV-lo', 'MP4-lo', 'FLV-hi', 'MP4-hi', 
  81         'MP4-SHQ', 'MP4-HD720', 'MP4-HD1080') 
  83     def _real_extract(self
, url
): 
  84         video_id 
= self
._match
_id
(url
) 
  87             'method': 'da.content.get', 
  91                     'referrer': 'http://www.ivi.ru/watch/%s' % video_id
, 
  97         bundled 
= hasattr(sys
, 'frozen') 
  99         for site 
in (353, 183): 
 100             content_data 
= (data 
% site
).encode() 
 105                     from Cryptodome
.Cipher 
import Blowfish
 
 106                     from Cryptodome
.Hash 
import CMAC
 
 107                     pycryptodomex_found 
= True 
 109                     pycryptodomex_found 
= False 
 112                 timestamp 
= (self
._download
_json
( 
 113                     self
._LIGHT
_URL
, video_id
, 
 114                     'Downloading timestamp JSON', data
=json
.dumps({ 
 115                         'method': 'da.timestamp.get', 
 117                     }).encode(), fatal
=False) or {}).get('result') 
 123                     'sign': CMAC
.new(self
._LIGHT
_KEY
, timestamp
.encode() + content_data
, Blowfish
).hexdigest(), 
 128             video_json 
= self
._download
_json
( 
 129                 self
._LIGHT
_URL
, video_id
, 
 130                 'Downloading video JSON', data
=content_data
, query
=query
) 
 132             error 
= video_json
.get('error') 
 134                 origin 
= error
.get('origin') 
 135                 message 
= error
.get('message') or error
.get('user_message') 
 136                 extractor_msg 
= 'Unable to download video %s' 
 137                 if origin 
== 'NotAllowedForLocation': 
 138                     self
.raise_geo_restricted(message
, self
._GEO
_COUNTRIES
) 
 139                 elif origin 
== 'NoRedisValidData': 
 140                     extractor_msg 
= 'Video %s does not exist' 
 144                     raise ExtractorError( 
 145                         'This feature does not work from bundled exe. Run youtube-dl from sources.', 
 147                 elif not pycryptodomex_found
: 
 148                     raise ExtractorError( 
 149                         'pycryptodomex not found. Please install it.', 
 152                     extractor_msg 
+= ': ' + message
 
 153                 raise ExtractorError(extractor_msg 
% video_id
, expected
=True) 
 157         result 
= video_json
['result'] 
 158         title 
= result
['title'] 
 160         quality 
= qualities(self
._KNOWN
_FORMATS
) 
 163         for f 
in result
.get('files', []): 
 165             content_format 
= f
.get('content_format') 
 166             if not f_url 
or '-MDRM-' in content_format 
or '-FPS-' in content_format
: 
 170                 'format_id': content_format
, 
 171                 'quality': quality(content_format
), 
 172                 'filesize': int_or_none(f
.get('size_in_bytes')), 
 174         self
._sort
_formats
(formats
) 
 176         compilation 
= result
.get('compilation') 
 177         episode 
= title 
if compilation 
else None 
 179         title 
= '%s - %s' % (compilation
, title
) if compilation 
is not None else title
 
 182             'url': preview
['url'], 
 183             'id': preview
.get('content_format'), 
 184         } for preview 
in result
.get('preview', []) if preview
.get('url')] 
 186         webpage 
= self
._download
_webpage
(url
, video_id
) 
 188         season 
= self
._search
_regex
( 
 189             r
'<li[^>]+class="season active"[^>]*><a[^>]+>([^<]+)', 
 190             webpage
, 'season', default
=None) 
 191         season_number 
= int_or_none(self
._search
_regex
( 
 192             r
'<li[^>]+class="season active"[^>]*><a[^>]+data-season(?:-index)?="(\d+)"', 
 193             webpage
, 'season number', default
=None)) 
 195         episode_number 
= int_or_none(self
._search
_regex
( 
 196             r
'[^>]+itemprop="episode"[^>]*>\s*<meta[^>]+itemprop="episodeNumber"[^>]+content="(\d+)', 
 197             webpage
, 'episode number', default
=None)) 
 199         description 
= self
._og
_search
_description
(webpage
, default
=None) or self
._html
_search
_meta
( 
 200             'description', webpage
, 'description', default
=None) 
 205             'series': compilation
, 
 207             'season_number': season_number
, 
 209             'episode_number': episode_number
, 
 210             'thumbnails': thumbnails
, 
 211             'description': description
, 
 212             'duration': int_or_none(result
.get('duration')), 
 217 class IviCompilationIE(InfoExtractor
): 
 218     IE_DESC 
= 'ivi.ru compilations' 
 219     IE_NAME 
= 'ivi:compilation' 
 220     _VALID_URL 
= r
'https?://(?:www\.)?ivi\.ru/watch/(?!\d+)(?P<compilationid>[a-z\d_-]+)(?:/season(?P<seasonid>\d+))?$' 
 222         'url': 'http://www.ivi.ru/watch/dvoe_iz_lartsa', 
 224             'id': 'dvoe_iz_lartsa', 
 225             'title': 'Двое из ларца (2006 - 2008)', 
 227         'playlist_mincount': 24, 
 229         'url': 'http://www.ivi.ru/watch/dvoe_iz_lartsa/season1', 
 231             'id': 'dvoe_iz_lartsa/season1', 
 232             'title': 'Двое из ларца (2006 - 2008) 1 сезон', 
 234         'playlist_mincount': 12, 
 237     def _extract_entries(self
, html
, compilation_id
): 
 240                 'http://www.ivi.ru/watch/%s/%s' % (compilation_id
, serie
), IviIE
.ie_key()) 
 241             for serie 
in re
.findall( 
 242                 r
'<a\b[^>]+\bhref=["\']/watch
/%s/(\d
+)["\']' % compilation_id, html)] 
 244     def _real_extract(self, url): 
 245         mobj = re.match(self._VALID_URL, url) 
 246         compilation_id = mobj.group('compilationid') 
 247         season_id = mobj.group('seasonid') 
 249         if season_id is not None:  # Season link 
 250             season_page = self._download_webpage( 
 251                 url, compilation_id, 'Downloading season %s web page' % season_id) 
 252             playlist_id = '%s/season%s' % (compilation_id, season_id) 
 253             playlist_title = self._html_search_meta('title', season_page, 'title') 
 254             entries = self._extract_entries(season_page, compilation_id) 
 255         else:  # Compilation link 
 256             compilation_page = self._download_webpage(url, compilation_id, 'Downloading compilation web page') 
 257             playlist_id = compilation_id 
 258             playlist_title = self._html_search_meta('title', compilation_page, 'title') 
 259             seasons = re.findall( 
 260                 r'<a href="/watch
/%s/season(\d
+)' % compilation_id, compilation_page) 
 261             if not seasons:  # No seasons in this compilation 
 262                 entries = self._extract_entries(compilation_page, compilation_id) 
 265                 for season_id in seasons: 
 266                     season_page = self._download_webpage( 
 267                         'http
://www
.ivi
.ru
/watch
/%s/season
%s' % (compilation_id, season_id), 
 268                         compilation_id, 'Downloading season 
%s web page
' % season_id) 
 269                     entries.extend(self._extract_entries(season_page, compilation_id)) 
 271         return self.playlist_result(entries, playlist_id, playlist_title)