2 from __future__ 
import unicode_literals
 
   7 from .common 
import InfoExtractor
 
  11     compat_urllib_parse_urlparse
, 
  22 class RutubeBaseIE(InfoExtractor
): 
  23     def _extract_video(self
, video
, video_id
=None, require_title
=True): 
  24         title 
= video
['title'] if require_title 
else video
.get('title') 
  26         age_limit 
= video
.get('is_adult') 
  27         if age_limit 
is not None: 
  28             age_limit 
= 18 if age_limit 
is True else 0 
  30         uploader_id 
= try_get(video
, lambda x
: x
['author']['id']) 
  31         category 
= try_get(video
, lambda x
: x
['category']['name']) 
  34             'id': video
.get('id') or video_id
, 
  36             'description': video
.get('description'), 
  37             'thumbnail': video
.get('thumbnail_url'), 
  38             'duration': int_or_none(video
.get('duration')), 
  39             'uploader': try_get(video
, lambda x
: x
['author']['name']), 
  40             'uploader_id': compat_str(uploader_id
) if uploader_id 
else None, 
  41             'timestamp': unified_timestamp(video
.get('created_ts')), 
  42             'category': [category
] if category 
else None, 
  43             'age_limit': age_limit
, 
  44             'view_count': int_or_none(video
.get('hits')), 
  45             'comment_count': int_or_none(video
.get('comments_count')), 
  46             'is_live': bool_or_none(video
.get('is_livestream')), 
  50 class RutubeIE(RutubeBaseIE
): 
  52     IE_DESC 
= 'Rutube videos' 
  53     _VALID_URL 
= r
'https?://rutube\.ru/(?:video|(?:play/)?embed)/(?P<id>[\da-z]{32})' 
  56         'url': 'http://rutube.ru/video/3eac3b4561676c17df9132a9a1e62e3e/', 
  57         'md5': '79938ade01294ef7e27574890d0d3769', 
  59             'id': '3eac3b4561676c17df9132a9a1e62e3e', 
  61             'title': 'Раненный кенгуру забежал в аптеку', 
  62             'description': 'http://www.ntdtv.ru ', 
  64             'uploader': 'NTDRussian', 
  65             'uploader_id': '29790', 
  66             'timestamp': 1381943602, 
  67             'upload_date': '20131016', 
  71         'url': 'http://rutube.ru/play/embed/a10e53b86e8f349080f718582ce4c661', 
  72         'only_matching': True, 
  74         'url': 'http://rutube.ru/embed/a10e53b86e8f349080f718582ce4c661', 
  75         'only_matching': True, 
  77         'url': 'http://rutube.ru/video/3eac3b4561676c17df9132a9a1e62e3e/?pl_id=4252', 
  78         'only_matching': True, 
  80         'url': 'https://rutube.ru/video/10b3a03fc01d5bbcc632a2f3514e8aab/?pl_type=source', 
  81         'only_matching': True, 
  85     def suitable(cls
, url
): 
  86         return False if RutubePlaylistIE
.suitable(url
) else super(RutubeIE
, cls
).suitable(url
) 
  89     def _extract_urls(webpage
): 
  90         return [mobj
.group('url') for mobj 
in re
.finditer( 
  91             r
'<iframe[^>]+?src=(["\'])(?P
<url
>(?
:https?
:)?
//rutube\
.ru
/embed
/[\da
-z
]{32}
.*?
)\
1', 
  94     def _real_extract(self, url): 
  95         video_id = self._match_id(url) 
  97         video = self._download_json( 
  98             'http
://rutube
.ru
/api
/video
/%s/?format
=json
' % video_id, 
  99             video_id, 'Downloading video JSON
') 
 101         info = self._extract_video(video, video_id) 
 103         options = self._download_json( 
 104             'http
://rutube
.ru
/api
/play
/options
/%s/?format
=json
' % video_id, 
 105             video_id, 'Downloading options JSON
') 
 108         for format_id, format_url in options['video_balancer
'].items(): 
 109             ext = determine_ext(format_url) 
 111                 formats.extend(self._extract_m3u8_formats( 
 112                     format_url, video_id, 'mp4
', m3u8_id=format_id, fatal=False)) 
 114                 formats.extend(self._extract_f4m_formats( 
 115                     format_url, video_id, f4m_id=format_id, fatal=False)) 
 119                     'format_id
': format_id, 
 121         self._sort_formats(formats) 
 123         info['formats
'] = formats 
 127 class RutubeEmbedIE(InfoExtractor): 
 128     IE_NAME = 'rutube
:embed
' 
 129     IE_DESC = 'Rutube embedded videos
' 
 130     _VALID_URL = r'https?
://rutube\
.ru
/(?
:video|play
)/embed
/(?P
<id>[0-9]+)' 
 133         'url
': 'http
://rutube
.ru
/video
/embed
/6722881?vk_puid37
=&vk_puid38
=', 
 135             'id': 'a10e53b86e8f349080f718582ce4c661
', 
 137             'timestamp
': 1387830582, 
 138             'upload_date
': '20131223', 
 139             'uploader_id
': '297833', 
 140             'description
': 'Видео группы ★http
://vk
.com
/foxkidsreset★ музей Fox Kids и Jetix
<br
/><br
/> восстановлено и сделано в шикоформате subziro89 http
://vk
.com
/subziro89
', 
 141             'uploader
': 'subziro89 ILya
', 
 142             'title
': 'Мистический городок Эйри в Индиан 
5 серия озвучка subziro89
', 
 145             'skip_download
': True, 
 148         'url
': 'http
://rutube
.ru
/play
/embed
/8083783', 
 149         'only_matching
': True, 
 152     def _real_extract(self, url): 
 153         embed_id = self._match_id(url) 
 154         webpage = self._download_webpage(url, embed_id) 
 156         canonical_url = self._html_search_regex( 
 157             r'<link\s
+rel
="canonical"\s
+href
="([^"]+?
)"', webpage, 
 159         return self.url_result(canonical_url, RutubeIE.ie_key()) 
 162 class RutubePlaylistBaseIE(RutubeBaseIE): 
 163     def _next_page_url(self, page_num, playlist_id, *args, **kwargs): 
 164         return self._PAGE_TEMPLATE % (playlist_id, page_num) 
 166     def _entries(self, playlist_id, *args, **kwargs): 
 168         for pagenum in itertools.count(1): 
 169             page = self._download_json( 
 170                 next_page_url or self._next_page_url( 
 171                     pagenum, playlist_id, *args, **kwargs), 
 172                 playlist_id, 'Downloading page %s' % pagenum) 
 174             results = page.get('results') 
 175             if not results or not isinstance(results, list): 
 178             for result in results: 
 179                 video_url = result.get('video_url') 
 180                 if not video_url or not isinstance(video_url, compat_str): 
 182                 entry = self._extract_video(result, require_title=False) 
 186                     'ie_key': RutubeIE.ie_key(), 
 190             next_page_url = page.get('next') 
 191             if not next_page_url or not page.get('has_next'): 
 194     def _extract_playlist(self, playlist_id, *args, **kwargs): 
 195         return self.playlist_result( 
 196             self._entries(playlist_id, *args, **kwargs), 
 197             playlist_id, kwargs.get('playlist_name')) 
 199     def _real_extract(self, url): 
 200         return self._extract_playlist(self._match_id(url)) 
 203 class RutubeChannelIE(RutubePlaylistBaseIE): 
 204     IE_NAME = 'rutube:channel' 
 205     IE_DESC = 'Rutube channels' 
 206     _VALID_URL = r'https?://rutube\.ru/tags/video/(?P<id>\d+)' 
 208         'url': 'http://rutube.ru/tags/video/1800/', 
 212         'playlist_mincount': 68, 
 215     _PAGE_TEMPLATE = 'http://rutube.ru/api/tags/video/%s/?page=%s&format=json' 
 218 class RutubeMovieIE(RutubePlaylistBaseIE): 
 219     IE_NAME = 'rutube:movie' 
 220     IE_DESC = 'Rutube movies' 
 221     _VALID_URL = r'https?://rutube\.ru/metainfo/tv/(?P<id>\d+)' 
 224     _MOVIE_TEMPLATE = 'http://rutube.ru/api/metainfo/tv/%s/?format=json' 
 225     _PAGE_TEMPLATE = 'http://rutube.ru/api/metainfo/tv/%s/video?page=%s&format=json' 
 227     def _real_extract(self, url): 
 228         movie_id = self._match_id(url) 
 229         movie = self._download_json( 
 230             self._MOVIE_TEMPLATE % movie_id, movie_id, 
 231             'Downloading movie JSON') 
 232         return self._extract_playlist( 
 233             movie_id, playlist_name=movie.get('name')) 
 236 class RutubePersonIE(RutubePlaylistBaseIE): 
 237     IE_NAME = 'rutube:person' 
 238     IE_DESC = 'Rutube person videos' 
 239     _VALID_URL = r'https?://rutube\.ru/video/person/(?P<id>\d+)' 
 241         'url': 'http://rutube.ru/video/person/313878/', 
 245         'playlist_mincount': 37, 
 248     _PAGE_TEMPLATE = 'http://rutube.ru/api/video/person/%s/?page=%s&format=json' 
 251 class RutubePlaylistIE(RutubePlaylistBaseIE): 
 252     IE_NAME = 'rutube:playlist' 
 253     IE_DESC = 'Rutube playlists' 
 254     _VALID_URL = r'https?://rutube\.ru/(?:video|(?:play/)?embed)/[\da-z]{32}/\?.*?\bpl_id=(?P<id>\d+)' 
 256         'url': 'https://rutube.ru/video/cecd58ed7d531fc0f3d795d51cee9026/?pl_id=3097&pl_type=tag', 
 260         'playlist_count': 27, 
 262         'url': 'https://rutube.ru/video/10b3a03fc01d5bbcc632a2f3514e8aab/?pl_id=4252&pl_type=source', 
 263         'only_matching': True, 
 266     _PAGE_TEMPLATE = 'http://rutube.ru/api/playlist/%s/%s/?page=%s&format=json' 
 269     def suitable(cls, url): 
 270         if not super(RutubePlaylistIE, cls).suitable(url): 
 272         params = compat_parse_qs(compat_urllib_parse_urlparse(url).query) 
 273         return params.get('pl_type', [None])[0] and int_or_none(params.get('pl_id', [None])[0]) 
 275     def _next_page_url(self, page_num, playlist_id, item_kind): 
 276         return self._PAGE_TEMPLATE % (item_kind, playlist_id, page_num) 
 278     def _real_extract(self, url): 
 279         qs = compat_parse_qs(compat_urllib_parse_urlparse(url).query) 
 280         playlist_kind = qs['pl_type'][0] 
 281         playlist_id = qs['pl_id'][0] 
 282         return self._extract_playlist(playlist_id, item_kind=playlist_kind)