mirror of
https://codeberg.org/polarisfm/youtube-dl
synced 2024-11-26 18:34:32 +01:00
[zingmp3_vn] Add new extractor
This commit is contained in:
parent
189186a9a6
commit
1eccbbbb3f
@ -21,8 +21,7 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
_VALID_URL = r'''(?x)^
|
_VALID_URL = r'''(?x)^
|
||||||
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
||||||
(?P<site>
|
(?P<site>
|
||||||
(?:(zingmp3\.vn)|
|
(zingmp3\.vn)
|
||||||
(mp3\.zing\.vn))
|
|
||||||
)\/(?P<type>bai-hat|video-clip|embed)\/(?P<slug>.*?)\/(?P<id>.*?)\W
|
)\/(?P<type>bai-hat|video-clip|embed)\/(?P<slug>.*?)\/(?P<id>.*?)\W
|
||||||
'''
|
'''
|
||||||
IE_NAME = 'zingmp3_vn'
|
IE_NAME = 'zingmp3_vn'
|
||||||
@ -108,31 +107,26 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
_default_host = "https://zingmp3.vn/"
|
_default_host = "https://zingmp3.vn/"
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
self.convert_oldDomain_to_newDomain(url)
|
|
||||||
mobj = re.search(self._VALID_URL, url)
|
mobj = re.search(self._VALID_URL, url)
|
||||||
video_id = mobj.group('id')
|
video_id = mobj.group('id')
|
||||||
type = mobj.group('type')
|
_type = mobj.group('type')
|
||||||
slug = mobj.group('slug')
|
slug = mobj.group('slug')
|
||||||
return self.extract_info_media(type, slug, video_id)
|
return self.extract_info_media(_type, slug, video_id)
|
||||||
|
|
||||||
def convert_oldDomain_to_newDomain(self,url):
|
def extract_info_media(self, _type, slug, video_id):
|
||||||
if 'mp3.zing.vn' in url:
|
|
||||||
url = url.replace('mp3.zing.vn','zingmp3.vn')
|
|
||||||
return url
|
|
||||||
def extract_info_media(self, type, slug, video_id):
|
|
||||||
formats = []
|
formats = []
|
||||||
name_api = ''
|
name_api = ''
|
||||||
if type == 'bai-hat':
|
if _type == 'bai-hat':
|
||||||
name_api = '/song/get-song-info'
|
name_api = '/song/get-song-info'
|
||||||
elif type == 'embed':
|
elif _type == 'embed':
|
||||||
if slug and slug == 'song':
|
if slug and slug == 'song':
|
||||||
name_api = '/song/get-song-info'
|
name_api = '/song/get-song-info'
|
||||||
elif type == 'video-clip':
|
elif _type == 'video-clip':
|
||||||
name_api = "/video/get-video-detail"
|
name_api = "/video/get-video-detail"
|
||||||
|
|
||||||
api = self.get_api_with_signature(name_api=name_api, video_id=video_id)
|
api = self.get_api_with_signature(name_api=name_api, video_id=video_id)
|
||||||
info = self._download_json(url_or_request=api, video_id=video_id)
|
info = self._download_json(url_or_request=api, video_id=video_id)
|
||||||
if type == 'video-clip' and not self._downloader.params.get("cookiefile"):
|
if _type == 'video-clip' and not self._downloader.params.get("cookiefile"):
|
||||||
# TODO: Have api can get best quality like 1080p, 720p, default if dont have VIP just 480p is best quality.
|
# TODO: Have api can get best quality like 1080p, 720p, default if dont have VIP just 480p is best quality.
|
||||||
# If requests are continuous without downtime,
|
# If requests are continuous without downtime,
|
||||||
# you may be blocked IP for a short period of time,
|
# you may be blocked IP for a short period of time,
|
||||||
@ -195,7 +189,7 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
streaming = data.get('streaming')
|
streaming = data.get('streaming')
|
||||||
|
|
||||||
if streaming.get('msg'):
|
if streaming.get('msg'):
|
||||||
if type == 'video-clip':
|
if _type == 'video-clip':
|
||||||
stream_data = streaming.get('data', dict)
|
stream_data = streaming.get('data', dict)
|
||||||
for protocol, stream in stream_data.items():
|
for protocol, stream in stream_data.items():
|
||||||
if protocol == 'default':
|
if protocol == 'default':
|
||||||
@ -220,9 +214,9 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
else:
|
else:
|
||||||
if streaming.get('msg') != "Success":
|
if streaming.get('msg') != "Success":
|
||||||
self.to_screen(
|
self.to_screen(
|
||||||
f" - {self.IE_NAME} requires authentication.\n"
|
"Zingmp3_vn requires authentication."
|
||||||
f"\t\t- Because This media need VIP account to listen or watch.\n"
|
"Because This media need VIP account to listen or watch."
|
||||||
f"\t\t- You may want to use --cookies.\n\n"
|
"You may want to use --cookies FILE."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
default = streaming.get('default')
|
default = streaming.get('default')
|
||||||
@ -265,11 +259,13 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
'formats': formats
|
'formats': formats
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_api_with_signature(self, name_api, video_id='', alias='', type='', new_release=False):
|
def get_api_with_signature(self, name_api, video_id='', alias='', _type='', new_release=False):
|
||||||
"""
|
"""
|
||||||
- The api of this site has 1 param named sig => signature
|
- The api of this site has 1 param named sig => signature
|
||||||
- It uses the hash function of the variables ctime, id, and name_api.
|
- It uses the hash function of the variables ctime, id, and name_api.
|
||||||
- Sone api don't need id, just need ctime and name_api,
|
- Sone api don't need id, just need ctime and name_api,
|
||||||
|
:param _type:
|
||||||
|
:param alias:
|
||||||
:param name_api:
|
:param name_api:
|
||||||
:param video_id:
|
:param video_id:
|
||||||
:param type:
|
:param type:
|
||||||
@ -280,6 +276,7 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
SECRET_KEY = b'10a01dcf33762d3a204cb96429918ff6'
|
SECRET_KEY = b'10a01dcf33762d3a204cb96429918ff6'
|
||||||
if not name_api:
|
if not name_api:
|
||||||
return
|
return
|
||||||
|
_time = str(int(datetime.datetime.now().timestamp()))
|
||||||
|
|
||||||
def get_hash256(string):
|
def get_hash256(string):
|
||||||
return hashlib.sha256(string.encode('utf-8')).hexdigest()
|
return hashlib.sha256(string.encode('utf-8')).hexdigest()
|
||||||
@ -295,74 +292,69 @@ class Zingmp3_vnIE(InfoExtractor):
|
|||||||
data = "&".join(data)
|
data = "&".join(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_api_by_id(id):
|
def get_api_by_id(_id):
|
||||||
url = f"https://zingmp3.vn/api{name_api}?id={id}&"
|
url = r"https://zingmp3.vn/api%s?id=%s&" % (name_api, _id)
|
||||||
time = str(int(datetime.datetime.now().timestamp()))
|
sha256 = get_hash256(r"ctime=%sid=%s" % (_time, _id))
|
||||||
sha256 = get_hash256(f"ctime={time}id={id}")
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'ctime': time,
|
'ctime': _time,
|
||||||
'api_key': API_KEY,
|
'api_key': API_KEY,
|
||||||
'sig': get_hmac512(f"{name_api}{sha256}")
|
'sig': get_hmac512(r"%s%s" % (name_api, sha256))
|
||||||
}
|
}
|
||||||
return url + get_request_path(data)
|
return url + get_request_path(data)
|
||||||
|
|
||||||
def get_api_chart(type):
|
def get_api_chart(_type):
|
||||||
url = f"https://zingmp3.vn/api{name_api}?type={type}&"
|
url = r"https://zingmp3.vn/api%s?type=%s&" % (name_api, _type)
|
||||||
time = str(int(datetime.datetime.now().timestamp()))
|
sha256 = get_hash256(r"ctime=%s" % (_time))
|
||||||
sha256 = get_hash256(f"ctime={time}")
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'ctime': time,
|
'ctime': _time,
|
||||||
'api_key': API_KEY,
|
'api_key': API_KEY,
|
||||||
'sig': get_hmac512(f"{name_api}{sha256}")
|
'sig': get_hmac512(r"%s%s" % (name_api, sha256))
|
||||||
}
|
}
|
||||||
return url + get_request_path(data)
|
return url + get_request_path(data)
|
||||||
|
|
||||||
def get_api_new_release():
|
def get_api_new_release():
|
||||||
url = f"https://zingmp3.vn/api{name_api}?"
|
url = r"https://zingmp3.vn/api%s?" % (name_api)
|
||||||
time = str(int(datetime.datetime.now().timestamp()))
|
sha256 = get_hash256(r"ctime=%s" % (_time))
|
||||||
sha256 = get_hash256(f"ctime={time}")
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'ctime': time,
|
'ctime': _time,
|
||||||
'api_key': API_KEY,
|
'api_key': API_KEY,
|
||||||
'sig': get_hmac512(f"{name_api}{sha256}")
|
'sig': get_hmac512(r"%s%s" % (name_api, sha256))
|
||||||
}
|
}
|
||||||
return url + get_request_path(data)
|
return url + get_request_path(data)
|
||||||
|
|
||||||
def get_api_download(id):
|
def get_api_download(_id):
|
||||||
url = f"https://download.zingmp3.vn/api{name_api}?id={id}&"
|
url = r"https://download.zingmp3.vn/api%s?id=%s&" % (name_api, _id)
|
||||||
time = str(int(datetime.datetime.now().timestamp()))
|
sha256 = get_hash256(r"ctime=%sid=%s" % (_time, _id))
|
||||||
sha256 = get_hash256(f"ctime={time}id={id}")
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'ctime': time,
|
'ctime': _time,
|
||||||
'api_key': API_KEY,
|
'api_key': API_KEY,
|
||||||
'sig': get_hmac512(f"{name_api}{sha256}")
|
'sig': get_hmac512(r"%s%s" % (name_api, sha256))
|
||||||
}
|
}
|
||||||
return url + get_request_path(data)
|
return url + get_request_path(data)
|
||||||
|
|
||||||
def get_api_info_alias(alias):
|
def get_api_info_alias(alias):
|
||||||
url = f"https://zingmp3.vn/api{name_api}?alias={alias}&"
|
url = r"https://zingmp3.vn/api%s?alias=%s&" % (name_api, alias)
|
||||||
time = str(int(datetime.datetime.now().timestamp()))
|
sha256 = get_hash256(r"ctime=%s" % (_time))
|
||||||
sha256 = get_hash256(f"ctime={time}")
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'ctime': time,
|
'ctime': _time,
|
||||||
'api_key': API_KEY,
|
'api_key': API_KEY,
|
||||||
'sig': get_hmac512(f"{name_api}{sha256}")
|
'sig': get_hmac512(r"%s%s" % (name_api, sha256))
|
||||||
}
|
}
|
||||||
return url + get_request_path(data)
|
return url + get_request_path(data)
|
||||||
|
|
||||||
if 'download' in name_api:
|
if 'download' in name_api:
|
||||||
return get_api_download(id=video_id)
|
return get_api_download(_id=video_id)
|
||||||
if alias:
|
if alias:
|
||||||
return get_api_info_alias(alias)
|
return get_api_info_alias(alias)
|
||||||
if video_id:
|
if video_id:
|
||||||
return get_api_by_id(video_id)
|
return get_api_by_id(video_id)
|
||||||
if type:
|
if _type:
|
||||||
return get_api_chart(type)
|
return get_api_chart(_type)
|
||||||
if new_release:
|
if new_release:
|
||||||
return get_api_new_release()
|
return get_api_new_release()
|
||||||
return
|
return
|
||||||
@ -374,8 +366,7 @@ class Zingmp3_vnPlaylistIE(Zingmp3_vnIE):
|
|||||||
_VALID_URL = r'''(?x)^
|
_VALID_URL = r'''(?x)^
|
||||||
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
||||||
(?P<site>
|
(?P<site>
|
||||||
(?:(zingmp3\.vn)|
|
(zingmp3\.vn)
|
||||||
(mp3\.zing\.vn))
|
|
||||||
)\/(?P<type>album|playlist)\/(?P<slug>.*?)\/(?P<playlist_id>.*?)\W
|
)\/(?P<type>album|playlist)\/(?P<slug>.*?)\/(?P<playlist_id>.*?)\W
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@ -416,7 +407,6 @@ class Zingmp3_vnPlaylistIE(Zingmp3_vnIE):
|
|||||||
name_api = '/playlist/get-playlist-detail'
|
name_api = '/playlist/get-playlist-detail'
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
self.convert_oldDomain_to_newDomain(url)
|
|
||||||
mobj = re.search(self._VALID_URL, url)
|
mobj = re.search(self._VALID_URL, url)
|
||||||
playlist_id = mobj.group('playlist_id')
|
playlist_id = mobj.group('playlist_id')
|
||||||
return self._extract_playlist(id_playlist=playlist_id)
|
return self._extract_playlist(id_playlist=playlist_id)
|
||||||
@ -449,13 +439,12 @@ class Zingmp3_vnUserIE(Zingmp3_vnIE):
|
|||||||
_VALID_URL = r'''(?x)^
|
_VALID_URL = r'''(?x)^
|
||||||
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
||||||
(?P<site>
|
(?P<site>
|
||||||
(?:(zingmp3\.vn)|
|
(zingmp3\.vn)
|
||||||
(mp3\.zing\.vn))
|
|
||||||
)\/(?P<nghe_si>nghe-si\/|)
|
)\/(?P<nghe_si>nghe-si\/|)
|
||||||
(?P<name>.*?)
|
(?P<name>.*?)
|
||||||
(?:$|\/)
|
(?:$|\/)
|
||||||
(?:
|
(?:
|
||||||
(?P<name_chu_de>.*?)\/(?P<id_chu_de>.*?\.)
|
(?P<name_chu_de>.*?)\/(?P<id_chu_de>.*?)\.
|
||||||
|
|
|
|
||||||
(?P<slug_name>.*?$)
|
(?P<slug_name>.*?$)
|
||||||
)
|
)
|
||||||
@ -551,7 +540,6 @@ class Zingmp3_vnUserIE(Zingmp3_vnIE):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
self.convert_oldDomain_to_newDomain(url)
|
|
||||||
mobj = re.search(self._VALID_URL, url)
|
mobj = re.search(self._VALID_URL, url)
|
||||||
name = mobj.group('name')
|
name = mobj.group('name')
|
||||||
slug_name = mobj.group('slug_name')
|
slug_name = mobj.group('slug_name')
|
||||||
@ -562,7 +550,7 @@ class Zingmp3_vnUserIE(Zingmp3_vnIE):
|
|||||||
name_api = self.list_name_api_user.get(slug_name) or None
|
name_api = self.list_name_api_user.get(slug_name) or None
|
||||||
self.id_artist = None
|
self.id_artist = None
|
||||||
if nghe_si:
|
if nghe_si:
|
||||||
webpage = self._download_webpage(url_or_request=f"https://mp3.zing.vn/nghe-si/{name}", video_id=name)
|
webpage = self._download_webpage(url_or_request=r"https://mp3.zing.vn/nghe-si/%s" % (name), video_id=name)
|
||||||
self.id_artist = self._search_regex(r'''(?x)
|
self.id_artist = self._search_regex(r'''(?x)
|
||||||
\<a.*?tracking=\"\_frombox=artist_artistfollow\"
|
\<a.*?tracking=\"\_frombox=artist_artistfollow\"
|
||||||
\s+data-id=\"(?P<id_artist>.*?)\"
|
\s+data-id=\"(?P<id_artist>.*?)\"
|
||||||
@ -580,7 +568,7 @@ class Zingmp3_vnUserIE(Zingmp3_vnIE):
|
|||||||
return self.playlist_result(
|
return self.playlist_result(
|
||||||
entries=self._entries(),
|
entries=self._entries(),
|
||||||
playlist_id=self.id_artist,
|
playlist_id=self.id_artist,
|
||||||
playlist_title=f"{name}-{slug_name}"
|
playlist_title=r"%s-%s" % (name, slug_name)
|
||||||
)
|
)
|
||||||
elif name == 'chu-de':
|
elif name == 'chu-de':
|
||||||
self.IE_NAME = "zingmp3_vn:chu-de"
|
self.IE_NAME = "zingmp3_vn:chu-de"
|
||||||
@ -659,11 +647,11 @@ class Zingmp3_vnUserIE(Zingmp3_vnIE):
|
|||||||
|
|
||||||
class Zingmp3_vnChartIE(Zingmp3_vnIE):
|
class Zingmp3_vnChartIE(Zingmp3_vnIE):
|
||||||
IE_NAME = "zingmp3_vn:#zingchart"
|
IE_NAME = "zingmp3_vn:#zingchart"
|
||||||
|
|
||||||
_VALID_URL = r'''(?x)^
|
_VALID_URL = r'''(?x)^
|
||||||
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
((http[s]?|fpt):)\/?\/(www\.|m\.|)
|
||||||
(?P<site>
|
(?P<site>
|
||||||
(?:(zingmp3\.vn)|
|
(zingmp3\.vn)
|
||||||
(mp3\.zing\.vn))
|
|
||||||
)\/(?P<name>zing-chart-tuan|zing-chart|top-new-release)\/
|
)\/(?P<name>zing-chart-tuan|zing-chart|top-new-release)\/
|
||||||
(?P<slug_name>.*?)(\.|\/)(?P<id_name>.*?\.)?
|
(?P<slug_name>.*?)(\.|\/)(?P<id_name>.*?\.)?
|
||||||
'''
|
'''
|
||||||
@ -720,7 +708,6 @@ class Zingmp3_vnChartIE(Zingmp3_vnIE):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
self.convert_oldDomain_to_newDomain(url)
|
|
||||||
mobj = re.search(self._VALID_URL, url)
|
mobj = re.search(self._VALID_URL, url)
|
||||||
name = mobj.group('name')
|
name = mobj.group('name')
|
||||||
slug_name = mobj.group('slug_name')
|
slug_name = mobj.group('slug_name')
|
||||||
@ -728,7 +715,7 @@ class Zingmp3_vnChartIE(Zingmp3_vnIE):
|
|||||||
if name == 'zing-chart':
|
if name == 'zing-chart':
|
||||||
api = self.get_api_with_signature(
|
api = self.get_api_with_signature(
|
||||||
name_api=self.list_name_api.get(name).get('name'),
|
name_api=self.list_name_api.get(name).get('name'),
|
||||||
type=self.list_name_api.get(name).get(slug_name)
|
_type=self.list_name_api.get(name).get(slug_name)
|
||||||
)
|
)
|
||||||
elif name == 'zing-chart-tuan':
|
elif name == 'zing-chart-tuan':
|
||||||
api = self.get_api_with_signature(
|
api = self.get_api_with_signature(
|
||||||
@ -740,12 +727,19 @@ class Zingmp3_vnChartIE(Zingmp3_vnIE):
|
|||||||
name_api=self.list_name_api.get(name).get('name'),
|
name_api=self.list_name_api.get(name).get('name'),
|
||||||
new_release=True
|
new_release=True
|
||||||
)
|
)
|
||||||
webpage = self._download_webpage(url_or_request=api, video_id=name)
|
count = 0
|
||||||
info = self._parse_json(webpage, name, transform_source=js_to_json)
|
info = None
|
||||||
return self.playlist_result(
|
while count != 3:
|
||||||
entries=self._entries(try_get(info, lambda x: x['data']['items'])),
|
webpage = self._download_webpage(url_or_request=api, video_id=name)
|
||||||
playlist_title=f"{name}-{slug_name}"
|
if webpage:
|
||||||
)
|
info = self._parse_json(webpage, name, transform_source=js_to_json)
|
||||||
|
break
|
||||||
|
count += 1
|
||||||
|
if info:
|
||||||
|
return self.playlist_result(
|
||||||
|
entries=self._entries(try_get(info, lambda x: x['data']['items'])),
|
||||||
|
playlist_title=r"%s-%s" % (name, slug_name)
|
||||||
|
)
|
||||||
|
|
||||||
def _entries(self, items):
|
def _entries(self, items):
|
||||||
for item in items:
|
for item in items:
|
||||||
|
Loading…
Reference in New Issue
Block a user