2 from __future__ 
import unicode_literals
 
   7 from .common 
import InfoExtractor
 
  11     compat_urllib_parse_urlparse
, 
  23 class RutubeBaseIE(InfoExtractor
): 
  24     def _extract_video(self
, video
, video_id
=None, require_title
=True): 
  25         title 
= video
['title'] if require_title 
else video
.get('title') 
  27         age_limit 
= video
.get('is_adult') 
  28         if age_limit 
is not None: 
  29             age_limit 
= 18 if age_limit 
is True else 0 
  31         uploader_id 
= try_get(video
, lambda x
: x
['author']['id']) 
  32         category 
= try_get(video
, lambda x
: x
['category']['name']) 
  35             'id': video
.get('id') or video_id
, 
  37             'description': video
.get('description'), 
  38             'thumbnail': video
.get('thumbnail_url'), 
  39             'duration': int_or_none(video
.get('duration')), 
  40             'uploader': try_get(video
, lambda x
: x
['author']['name']), 
  41             'uploader_id': compat_str(uploader_id
) if uploader_id 
else None, 
  42             'timestamp': unified_timestamp(video
.get('created_ts')), 
  43             'category': [category
] if category 
else None, 
  44             'age_limit': age_limit
, 
  45             'view_count': int_or_none(video
.get('hits')), 
  46             'comment_count': int_or_none(video
.get('comments_count')), 
  47             'is_live': bool_or_none(video
.get('is_livestream')), 
  51 class RutubeIE(RutubeBaseIE
): 
  53     IE_DESC 
= 'Rutube videos' 
  54     _VALID_URL 
= r
'https?://rutube\.ru/(?:video|(?:play/)?embed)/(?P<id>[\da-z]{32})' 
  57         'url': 'http://rutube.ru/video/3eac3b4561676c17df9132a9a1e62e3e/', 
  58         'md5': '79938ade01294ef7e27574890d0d3769', 
  60             'id': '3eac3b4561676c17df9132a9a1e62e3e', 
  62             'title': 'Раненный кенгуру забежал в аптеку', 
  63             'description': 'http://www.ntdtv.ru ', 
  65             'uploader': 'NTDRussian', 
  66             'uploader_id': '29790', 
  67             'timestamp': 1381943602, 
  68             'upload_date': '20131016', 
  72         'url': 'http://rutube.ru/play/embed/a10e53b86e8f349080f718582ce4c661', 
  73         'only_matching': True, 
  75         'url': 'http://rutube.ru/embed/a10e53b86e8f349080f718582ce4c661', 
  76         'only_matching': True, 
  78         'url': 'http://rutube.ru/video/3eac3b4561676c17df9132a9a1e62e3e/?pl_id=4252', 
  79         'only_matching': True, 
  81         'url': 'https://rutube.ru/video/10b3a03fc01d5bbcc632a2f3514e8aab/?pl_type=source', 
  82         'only_matching': True, 
  86     def suitable(cls
, url
): 
  87         return False if RutubePlaylistIE
.suitable(url
) else super(RutubeIE
, cls
).suitable(url
) 
  90     def _extract_urls(webpage
): 
  91         return [mobj
.group('url') for mobj 
in re
.finditer( 
  92             r
'<iframe[^>]+?src=(["\'])(?P
<url
>(?
:https?
:)?
//rutube\
.ru
/embed
/[\da
-z
]{32}
.*?
)\
1', 
  95     def _real_extract(self, url): 
  96         video_id = self._match_id(url) 
  98         video = self._download_json( 
  99             'http
://rutube
.ru
/api
/video
/%s/?format
=json
' % video_id, 
 100             video_id, 'Downloading video JSON
') 
 102         info = self._extract_video(video, video_id) 
 104         options = self._download_json( 
 105             'http
://rutube
.ru
/api
/play
/options
/%s/?format
=json
' % video_id, 
 106             video_id, 'Downloading options JSON
', 
 107             headers=self.geo_verification_headers()) 
 110         for format_id, format_url in options['video_balancer
'].items(): 
 111             ext = determine_ext(format_url) 
 113                 formats.extend(self._extract_m3u8_formats( 
 114                     format_url, video_id, 'mp4
', m3u8_id=format_id, fatal=False)) 
 116                 formats.extend(self._extract_f4m_formats( 
 117                     format_url, video_id, f4m_id=format_id, fatal=False)) 
 121                     'format_id
': format_id, 
 123         self._sort_formats(formats) 
 125         info['formats
'] = formats 
 129 class RutubeEmbedIE(InfoExtractor): 
 130     IE_NAME = 'rutube
:embed
' 
 131     IE_DESC = 'Rutube embedded videos
' 
 132     _VALID_URL = r'https?
://rutube\
.ru
/(?
:video|play
)/embed
/(?P
<id>[0-9]+)' 
 135         'url
': 'http
://rutube
.ru
/video
/embed
/6722881?vk_puid37
=&vk_puid38
=', 
 137             'id': 'a10e53b86e8f349080f718582ce4c661
', 
 139             'timestamp
': 1387830582, 
 140             'upload_date
': '20131223', 
 141             'uploader_id
': '297833', 
 142             'description
': 'Видео группы ★http
://vk
.com
/foxkidsreset★ музей Fox Kids и Jetix
<br
/><br
/> восстановлено и сделано в шикоформате subziro89 http
://vk
.com
/subziro89
', 
 143             'uploader
': 'subziro89 ILya
', 
 144             'title
': 'Мистический городок Эйри в Индиан 
5 серия озвучка subziro89
', 
 147             'skip_download
': True, 
 150         'url
': 'http
://rutube
.ru
/play
/embed
/8083783', 
 151         'only_matching
': True, 
 154     def _real_extract(self, url): 
 155         embed_id = self._match_id(url) 
 156         webpage = self._download_webpage(url, embed_id) 
 158         canonical_url = self._html_search_regex( 
 159             r'<link\s
+rel
="canonical"\s
+href
="([^"]+?
)"', webpage, 
 161         return self.url_result(canonical_url, RutubeIE.ie_key()) 
 164 class RutubePlaylistBaseIE(RutubeBaseIE): 
 165     def _next_page_url(self, page_num, playlist_id, *args, **kwargs): 
 166         return self._PAGE_TEMPLATE % (playlist_id, page_num) 
 168     def _entries(self, playlist_id, *args, **kwargs): 
 170         for pagenum in itertools.count(1): 
 171             page = self._download_json( 
 172                 next_page_url or self._next_page_url( 
 173                     pagenum, playlist_id, *args, **kwargs), 
 174                 playlist_id, 'Downloading page %s' % pagenum) 
 176             results = page.get('results') 
 177             if not results or not isinstance(results, list): 
 180             for result in results: 
 181                 video_url = url_or_none(result.get('video_url')) 
 184                 entry = self._extract_video(result, require_title=False) 
 188                     'ie_key': RutubeIE.ie_key(), 
 192             next_page_url = page.get('next') 
 193             if not next_page_url or not page.get('has_next'): 
 196     def _extract_playlist(self, playlist_id, *args, **kwargs): 
 197         return self.playlist_result( 
 198             self._entries(playlist_id, *args, **kwargs), 
 199             playlist_id, kwargs.get('playlist_name')) 
 201     def _real_extract(self, url): 
 202         return self._extract_playlist(self._match_id(url)) 
 205 class RutubeChannelIE(RutubePlaylistBaseIE): 
 206     IE_NAME = 'rutube:channel' 
 207     IE_DESC = 'Rutube channels' 
 208     _VALID_URL = r'https?://rutube\.ru/tags/video/(?P<id>\d+)' 
 210         'url': 'http://rutube.ru/tags/video/1800/', 
 214         'playlist_mincount': 68, 
 217     _PAGE_TEMPLATE = 'http://rutube.ru/api/tags/video/%s/?page=%s&format=json' 
 220 class RutubeMovieIE(RutubePlaylistBaseIE): 
 221     IE_NAME = 'rutube:movie' 
 222     IE_DESC = 'Rutube movies' 
 223     _VALID_URL = r'https?://rutube\.ru/metainfo/tv/(?P<id>\d+)' 
 226     _MOVIE_TEMPLATE = 'http://rutube.ru/api/metainfo/tv/%s/?format=json' 
 227     _PAGE_TEMPLATE = 'http://rutube.ru/api/metainfo/tv/%s/video?page=%s&format=json' 
 229     def _real_extract(self, url): 
 230         movie_id = self._match_id(url) 
 231         movie = self._download_json( 
 232             self._MOVIE_TEMPLATE % movie_id, movie_id, 
 233             'Downloading movie JSON') 
 234         return self._extract_playlist( 
 235             movie_id, playlist_name=movie.get('name')) 
 238 class RutubePersonIE(RutubePlaylistBaseIE): 
 239     IE_NAME = 'rutube:person' 
 240     IE_DESC = 'Rutube person videos' 
 241     _VALID_URL = r'https?://rutube\.ru/video/person/(?P<id>\d+)' 
 243         'url': 'http://rutube.ru/video/person/313878/', 
 247         'playlist_mincount': 37, 
 250     _PAGE_TEMPLATE = 'http://rutube.ru/api/video/person/%s/?page=%s&format=json' 
 253 class RutubePlaylistIE(RutubePlaylistBaseIE): 
 254     IE_NAME = 'rutube:playlist' 
 255     IE_DESC = 'Rutube playlists' 
 256     _VALID_URL = r'https?://rutube\.ru/(?:video|(?:play/)?embed)/[\da-z]{32}/\?.*?\bpl_id=(?P<id>\d+)' 
 258         'url': 'https://rutube.ru/video/cecd58ed7d531fc0f3d795d51cee9026/?pl_id=3097&pl_type=tag', 
 262         'playlist_count': 27, 
 264         'url': 'https://rutube.ru/video/10b3a03fc01d5bbcc632a2f3514e8aab/?pl_id=4252&pl_type=source', 
 265         'only_matching': True, 
 268     _PAGE_TEMPLATE = 'http://rutube.ru/api/playlist/%s/%s/?page=%s&format=json' 
 271     def suitable(cls, url): 
 272         if not super(RutubePlaylistIE, cls).suitable(url): 
 274         params = compat_parse_qs(compat_urllib_parse_urlparse(url).query) 
 275         return params.get('pl_type', [None])[0] and int_or_none(params.get('pl_id', [None])[0]) 
 277     def _next_page_url(self, page_num, playlist_id, item_kind): 
 278         return self._PAGE_TEMPLATE % (item_kind, playlist_id, page_num) 
 280     def _real_extract(self, url): 
 281         qs = compat_parse_qs(compat_urllib_parse_urlparse(url).query) 
 282         playlist_kind = qs['pl_type'][0] 
 283         playlist_id = qs['pl_id'][0] 
 284         return self._extract_playlist(playlist_id, item_kind=playlist_kind)