# coding: utf-8 from __future__ import unicode_literals from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, ) class ZingMp3BaseIE(InfoExtractor): _VALID_URL_TMPL = r'https?://(?:mp3\.zing|zingmp3)\.vn/(?:%s)/[^/]+/(?P\w+)\.html' _GEO_COUNTRIES = ['VN'] def _extract_item(self, item, fatal): item_id = item['id'] title = item.get('name') or item['title'] formats = [] for k, v in (item.get('source') or {}).items(): if not v: continue if k in ('mp4', 'hls'): for res, video_url in v.items(): if not video_url: continue if k == 'hls': formats.extend(self._extract_m3u8_formats( video_url, item_id, 'mp4', 'm3u8_native', m3u8_id=k, fatal=False)) elif k == 'mp4': formats.append({ 'format_id': 'mp4-' + res, 'url': video_url, 'height': int_or_none(self._search_regex( r'^(\d+)p', res, 'resolution', default=None)), }) else: formats.append({ 'ext': 'mp3', 'format_id': k, 'tbr': int_or_none(k), 'url': self._proto_relative_url(v), 'vcodec': 'none', }) if not formats: if not fatal: return msg = item['msg'] if msg == 'Sorry, this content is not available in your country.': self.raise_geo_restricted(countries=self._GEO_COUNTRIES) raise ExtractorError(msg, expected=True) self._sort_formats(formats) subtitles = None lyric = item.get('lyric') if lyric: subtitles = { 'origin': [{ 'url': lyric, }], } album = item.get('album') or {} return { 'id': item_id, 'title': title, 'formats': formats, 'thumbnail': item.get('thumbnail'), 'subtitles': subtitles, 'duration': int_or_none(item.get('duration')), 'track': title, 'artist': item.get('artists_names'), 'album': album.get('name') or album.get('title'), 'album_artist': album.get('artists_names'), } def _real_extract(self, url): page_id = self._match_id(url) webpage = self._download_webpage( url.replace('://zingmp3.vn/', '://mp3.zing.vn/'), page_id, query={'play_song': 1}) data_path = self._search_regex( r'data-xml="([^"]+)', webpage, 'data path') return self._process_data(self._download_json( 'https://mp3.zing.vn/xhr' + data_path, page_id)['data']) class ZingMp3IE(ZingMp3BaseIE): _VALID_URL = ZingMp3BaseIE._VALID_URL_TMPL % 'bai-hat|video-clip' _TESTS = [{ 'url': 'http://mp3.zing.vn/bai-hat/Xa-Mai-Xa-Bao-Thy/ZWZB9WAB.html', 'md5': 'ead7ae13693b3205cbc89536a077daed', 'info_dict': { 'id': 'ZWZB9WAB', 'title': 'Xa Mãi Xa', 'ext': 'mp3', 'thumbnail': r're:^https?://.+\.jpg', 'subtitles': { 'origin': [{ 'ext': 'lrc', }] }, 'duration': 255, 'track': 'Xa Mãi Xa', 'artist': 'Bảo Thy', 'album': 'Special Album', 'album_artist': 'Bảo Thy', }, }, { 'url': 'https://mp3.zing.vn/video-clip/Suong-Hoa-Dua-Loi-K-ICM-RYO/ZO8ZF7C7.html', 'md5': 'e9c972b693aa88301ef981c8151c4343', 'info_dict': { 'id': 'ZO8ZF7C7', 'title': 'Sương Hoa Đưa Lối', 'ext': 'mp4', 'thumbnail': r're:^https?://.+\.jpg', 'duration': 207, 'track': 'Sương Hoa Đưa Lối', 'artist': 'K-ICM, RYO', }, }, { 'url': 'https://zingmp3.vn/bai-hat/Xa-Mai-Xa-Bao-Thy/ZWZB9WAB.html', 'only_matching': True, }] IE_NAME = 'zingmp3' IE_DESC = 'mp3.zing.vn' def _process_data(self, data): return self._extract_item(data, True) class ZingMp3AlbumIE(ZingMp3BaseIE): _VALID_URL = ZingMp3BaseIE._VALID_URL_TMPL % 'album|playlist' _TESTS = [{ 'url': 'http://mp3.zing.vn/album/Lau-Dai-Tinh-Ai-Bang-Kieu-Minh-Tuyet/ZWZBWDAF.html', 'info_dict': { '_type': 'playlist', 'id': 'ZWZBWDAF', 'title': 'Lâu Đài Tình Ái', }, 'playlist_count': 10, }, { 'url': 'http://mp3.zing.vn/playlist/Duong-Hong-Loan-apollobee/IWCAACCB.html', 'only_matching': True, }, { 'url': 'https://zingmp3.vn/album/Lau-Dai-Tinh-Ai-Bang-Kieu-Minh-Tuyet/ZWZBWDAF.html', 'only_matching': True, }] IE_NAME = 'zingmp3:album' def _process_data(self, data): def entries(): for item in (data.get('items') or []): entry = self._extract_item(item, False) if entry: yield entry info = data.get('info') or {} return self.playlist_result( entries(), info.get('id'), info.get('name') or info.get('title'))