2 from __future__ 
import unicode_literals
 
   8 from .common 
import InfoExtractor
 
   9 from ..compat 
import compat_urllib_parse_unquote
 
  18 class MailRuIE(InfoExtractor
): 
  20     IE_DESC 
= 'Видео@Mail.Ru' 
  23                         (?:(?:www|m)\.)?my\.mail\.ru/ 
  25                             video/.*\#video=/?(?P<idv1>(?:[^/]+/){3}\d+)| 
  26                             (?:(?P<idv2prefix>(?:[^/]+/){2})video/(?P<idv2suffix>[^/]+/\d+))\.html| 
  27                             (?:video/embed|\+/video/meta)/(?P<metaid>\d+) 
  32             'url': 'http://my.mail.ru/video/top#video=/mail/sonypicturesrus/75/76', 
  33             'md5': 'dea205f03120046894db4ebb6159879a', 
  37                 'title': 'Новый Человек-Паук. Высокое напряжение. Восстание Электро', 
  38                 'timestamp': 1393235077, 
  39                 'upload_date': '20140224', 
  40                 'uploader': 'sonypicturesrus', 
  41                 'uploader_id': 'sonypicturesrus@mail.ru', 
  44             'skip': 'Not accessible from Travis CI server', 
  47             'url': 'http://my.mail.ru/corp/hitech/video/news_hi-tech_mail_ru/1263.html', 
  48             'md5': '00a91a58c3402204dcced523777b475f', 
  50                 'id': '46843144_1263', 
  52                 'title': 'Samsung Galaxy S5 Hammer Smash Fail Battery Explosion', 
  53                 'timestamp': 1397039888, 
  54                 'upload_date': '20140409', 
  56                 'uploader_id': 'hitech@corp.mail.ru', 
  59             'skip': 'Not accessible from Travis CI server', 
  62             # only available via metaUrl API 
  63             'url': 'http://my.mail.ru/mail/720pizle/video/_myvideo/502.html', 
  64             'md5': '3b26d2491c6949d031a32b96bd97c096', 
  69                 'timestamp': 1449094163, 
  70                 'upload_date': '20151202', 
  71                 'uploader': '720pizle@mail.ru', 
  72                 'uploader_id': '720pizle@mail.ru', 
  75             'skip': 'Not accessible from Travis CI server', 
  78             'url': 'http://m.my.mail.ru/mail/3sktvtr/video/_myvideo/138.html', 
  79             'only_matching': True, 
  82             'url': 'https://my.mail.ru/video/embed/7949340477499637815', 
  83             'only_matching': True, 
  86             'url': 'http://my.mail.ru/+/video/meta/7949340477499637815', 
  87             'only_matching': True, 
  91     def _real_extract(self
, url
): 
  92         mobj 
= re
.match(self
._VALID
_URL
, url
) 
  93         meta_id 
= mobj
.group('metaid') 
  97             meta_url 
= 'https://my.mail.ru/+/video/meta/%s' % meta_id
 
  99             video_id 
= mobj
.group('idv1') 
 101                 video_id 
= mobj
.group('idv2prefix') + mobj
.group('idv2suffix') 
 102             webpage 
= self
._download
_webpage
(url
, video_id
) 
 103             page_config 
= self
._parse
_json
(self
._search
_regex
( 
 104                 r
'(?s)<script[^>]+class="sp-video__page-config"[^>]*>(.+?)</script>', 
 105                 webpage
, 'page config', default
='{}'), video_id
, fatal
=False) 
 107                 meta_url 
= page_config
.get('metaUrl') or page_config
.get('video', {}).get('metaUrl') 
 113             video_data 
= self
._download
_json
( 
 114                 meta_url
, video_id 
or meta_id
, 'Downloading video meta JSON', 
 117         # Fallback old approach 
 119             video_data 
= self
._download
_json
( 
 120                 'http://api.video.mail.ru/videos/%s.json?new=1' % video_id
, 
 121                 video_id
, 'Downloading video JSON') 
 124         for f 
in video_data
['videos']: 
 125             video_url 
= f
.get('url') 
 128             format_id 
= f
.get('key') 
 129             height 
= int_or_none(self
._search
_regex
( 
 130                 r
'^(\d+)[pP]$', format_id
, 'height', default
=None)) if format_id 
else None 
 133                 'format_id': format_id
, 
 136         self
._sort
_formats
(formats
) 
 138         meta_data 
= video_data
['meta'] 
 139         title 
= remove_end(meta_data
['title'], '.mp4') 
 141         author 
= video_data
.get('author') 
 142         uploader 
= author
.get('name') 
 143         uploader_id 
= author
.get('id') or author
.get('email') 
 144         view_count 
= int_or_none(video_data
.get('viewsCount') or video_data
.get('views_count')) 
 146         acc_id 
= meta_data
.get('accId') 
 147         item_id 
= meta_data
.get('itemId') 
 148         content_id 
= '%s_%s' % (acc_id
, item_id
) if acc_id 
and item_id 
else video_id
 
 150         thumbnail 
= meta_data
.get('poster') 
 151         duration 
= int_or_none(meta_data
.get('duration')) 
 152         timestamp 
= int_or_none(meta_data
.get('timestamp')) 
 157             'thumbnail': thumbnail
, 
 158             'timestamp': timestamp
, 
 159             'uploader': uploader
, 
 160             'uploader_id': uploader_id
, 
 161             'duration': duration
, 
 162             'view_count': view_count
, 
 167 class MailRuMusicSearchBaseIE(InfoExtractor
): 
 168     def _search(self
, query
, url
, audio_id
, limit
=100, offset
=0): 
 169         search 
= self
._download
_json
( 
 170             'https://my.mail.ru/cgi-bin/my/ajax', audio_id
, 
 171             'Downloading songs JSON page %d' % (offset 
// limit 
+ 1), 
 174                 'X-Requested-With': 'XMLHttpRequest', 
 178                 'func_name': 'music.search', 
 183                 'arg_search_params': json
.dumps({ 
 190                 'arg_offset': offset
, 
 192         return next(e 
for e 
in search 
if isinstance(e
, dict)) 
 195     def _extract_track(t
, fatal
=True): 
 196         audio_url 
= t
['URL'] if fatal 
else t
.get('URL') 
 200         audio_id 
= t
['File'] if fatal 
else t
.get('File') 
 204         thumbnail 
= t
.get('AlbumCoverURL') or t
.get('FiledAlbumCover') 
 205         uploader 
= t
.get('OwnerName') or t
.get('OwnerName_Text_HTML') 
 206         uploader_id 
= t
.get('UploaderID') 
 207         duration 
= int_or_none(t
.get('DurationInSeconds')) or parse_duration( 
 208             t
.get('Duration') or t
.get('DurationStr')) 
 209         view_count 
= int_or_none(t
.get('PlayCount') or t
.get('PlayCount_hr')) 
 211         track 
= t
.get('Name') or t
.get('Name_Text_HTML') 
 212         artist 
= t
.get('Author') or t
.get('Author_Text_HTML') 
 215             title 
= '%s - %s' % (artist
, track
) if artist 
else track
 
 220             'extractor_key': MailRuMusicIE
.ie_key(), 
 223             'thumbnail': thumbnail
, 
 224             'uploader': uploader
, 
 225             'uploader_id': uploader_id
, 
 226             'duration': duration
, 
 227             'view_count': view_count
, 
 229             'abr': int_or_none(t
.get('BitRate')), 
 232             'album': t
.get('Album'), 
 237 class MailRuMusicIE(MailRuMusicSearchBaseIE
): 
 238     IE_NAME 
= 'mailru:music' 
 239     IE_DESC 
= 'Музыка@Mail.Ru' 
 240     _VALID_URL 
= r
'https?://my\.mail\.ru/music/songs/[^/?#&]+-(?P<id>[\da-f]+)' 
 242         'url': 'https://my.mail.ru/music/songs/%D0%BC8%D0%BB8%D1%82%D1%85-l-a-h-luciferian-aesthetics-of-herrschaft-single-2017-4e31f7125d0dfaef505d947642366893', 
 243         'md5': '0f8c22ef8c5d665b13ac709e63025610', 
 245             'id': '4e31f7125d0dfaef505d947642366893', 
 247             'title': 'L.A.H. (Luciferian Aesthetics of Herrschaft) single, 2017 - М8Л8ТХ', 
 248             'uploader': 'Игорь Мудрый', 
 249             'uploader_id': '1459196328', 
 254             'track': 'L.A.H. (Luciferian Aesthetics of Herrschaft) single, 2017', 
 259     def _real_extract(self
, url
): 
 260         audio_id 
= self
._match
_id
(url
) 
 262         webpage 
= self
._download
_webpage
(url
, audio_id
) 
 264         title 
= self
._og
_search
_title
(webpage
) 
 265         music_data 
= self
._search
(title
, url
, audio_id
)['MusicData'] 
 266         t 
= next(t 
for t 
in music_data 
if t
.get('File') == audio_id
) 
 268         info 
= self
._extract
_track
(t
) 
 269         info
['title'] = title
 
 273 class MailRuMusicSearchIE(MailRuMusicSearchBaseIE
): 
 274     IE_NAME 
= 'mailru:music:search' 
 275     IE_DESC 
= 'Музыка@Mail.Ru' 
 276     _VALID_URL 
= r
'https?://my\.mail\.ru/music/search/(?P<id>[^/?#&]+)' 
 278         'url': 'https://my.mail.ru/music/search/black%20shadow', 
 280             'id': 'black shadow', 
 282         'playlist_mincount': 532, 
 285     def _real_extract(self
, url
): 
 286         query 
= compat_urllib_parse_unquote(self
._match
_id
(url
)) 
 293         for _ 
in itertools
.count(1): 
 294             search 
= self
._search
(query
, url
, query
, LIMIT
, offset
) 
 296             music_data 
= search
.get('MusicData') 
 297             if not music_data 
or not isinstance(music_data
, list): 
 301                 track 
= self
._extract
_track
(t
, fatal
=False) 
 303                     entries
.append(track
) 
 306                 search
, lambda x
: x
['Results']['music']['Total'], int) 
 308             if total 
is not None: 
 314         return self
.playlist_result(entries
, query
)