NeteaseMusicLyricDownloader/modules/functions/mainly/get_song.py

135 lines
5.0 KiB
Python
Raw Permalink Normal View History

2022-04-02 22:50:52 +08:00
"""集合 下载歌词 以及 获取歌曲信息 的功能"""
import os
2022-04-02 22:50:52 +08:00
from requests import post
from requests.exceptions import ConnectionError
from time import sleep
from colorama import Fore, Style
2022-04-02 22:50:52 +08:00
from modules.utils.bar import CompactBar, bprint
2023-06-22 02:14:17 +08:00
from modules.utils.dump import regular_filename
2022-04-02 22:50:52 +08:00
def wait_retry(kind, identify, bar=None):
bprint("api提示操作频繁等待恢复...", bar)
if kind == "information":
url = f"https://music.163.com/api/song/detail/?&ids=[{identify}]"
elif kind == "lyric":
url = f"https://music.163.com/api/song/media?id={identify}"
else:
return "unknown_kind"
2022-04-02 22:50:52 +08:00
while True:
try:
tmp = post(url).json()
2022-04-02 22:50:52 +08:00
except ConnectionError:
return "dl_err_connection"
else:
if tmp["code"] == 200:
return tmp
2022-04-02 22:50:52 +08:00
sleep(1)
def get_song_info_raw(types: list, identify: str, bar: CompactBar = None):
2022-04-02 22:50:52 +08:00
"""获取歌曲信息
``types`` 提供一个list,将会返回内部所有符合要求的信息类型\n
``identify`` 提供一个歌曲id(str),将会把歌曲的`types`信息返回"""
bprint(Fore.CYAN + "ID:%s" % identify, bar)
2022-04-02 22:50:52 +08:00
try:
info = post(f"https://music.163.com/api/song/detail/?&ids=[{identify}]").json()
2022-04-02 22:50:52 +08:00
except ConnectionError:
return "dl_err_connection"
else:
if info["code"] == 406: # 判断当操作频繁时继续获取直到可以返回值为200为止
result = wait_retry("information", identify, bar=bar)
if type(result) == dict:
info = result
2022-04-02 22:50:52 +08:00
elif result == "dl_err_connection":
return "dl_err_connection"
else:
raise Exception("Unknown exception...")
if not info.get("songs"): # 判断是否存在该歌曲
bprint(Fore.LIGHTBLACK_EX + "\t-> 这首歌没有找到,跳过...", bar)
2022-04-02 22:50:52 +08:00
return "song_nf"
else:
need = {}
for i in types: # 通过传入的变量 types 获取信息(根据返回的信息分析得到的下面这句语句)
need.setdefault(i, info["songs"][0][i])
return need
def get_song_lyric(identify: str | int | dict,
path: str,
lyric_format="%(name)s - %(artists)s",
allinfo: bool = False,
bar: CompactBar = None,
save_lyrics_time: bool = True):
2022-04-02 22:50:52 +08:00
"""获取歌词
``identify`` 提供一个歌曲id
2022-07-20 13:15:39 +08:00
``path`` 提供歌曲下载的路径
``lyric_format`` 提供歌词保存的格式
``allinfo`` 若此项为 True ,则提供的identify格式必须为存储在网易云下载文件中meta_data的格式
``bar`` 若获取歌词时下方有进度条, 则应当传入此参数"""
2022-07-20 13:15:39 +08:00
if allinfo:
sinfo = identify
identify = identify["id"]
bprint(Fore.CYAN + f"ID: {identify}", bar)
2022-07-20 13:15:39 +08:00
else:
sinfo = get_song_info_raw(["name", "artists"], identify, bar)
2022-07-20 13:15:39 +08:00
if sinfo == "dl_err_connection": # 处理各式各样的事件
return "dl_err_connection"
elif sinfo == "song_nf":
return "song_nf"
# 整理歌曲数据,获取歌词
artists = ""
if allinfo:
for i in sinfo["artists"]:
artists += f"{i[0]},"
else:
2022-04-02 22:50:52 +08:00
for i in sinfo["artists"]:
artists += f"{i['name']},"
2022-07-20 13:15:39 +08:00
artists = artists[:-1]
2022-04-02 22:50:52 +08:00
2022-07-20 13:15:39 +08:00
name = sinfo["name"]
2023-04-17 02:41:06 +08:00
if not name:
bprint(Fore.RED + "歌曲错误!这是网易云的问题,请不要找作者", bar)
2023-04-17 02:41:06 +08:00
return "song_err"
2023-06-22 02:14:17 +08:00
name = regular_filename(name)
artists = regular_filename(artists)
2022-04-02 22:50:52 +08:00
bprint(Fore.YELLOW + "\t-> 歌曲:" + Style.RESET_ALL + f"{name} - {artists}", bar)
filename = f"{lyric_format % {'name': name, 'artists': artists}}.lrc"
2022-04-02 22:50:52 +08:00
2022-07-20 13:15:39 +08:00
try:
info = post(f"https://music.163.com/api/song/media?id={identify}").json()
2022-07-20 13:15:39 +08:00
except ConnectionError:
return "dl_err_connection"
else:
if info["code"] == 406: # 此处与上方一样,防止因为请求限制而跳过下载
result = wait_retry("lyric", identify, bar=bar)
if type(result) == dict:
info = result
2022-07-20 13:15:39 +08:00
elif result == "dl_err_connection":
return "dl_err_connection"
else:
raise Exception("Unknown exception...")
2022-04-02 22:50:52 +08:00
if info.get("nolyric") or not info.get('lyric'):
bprint(Fore.LIGHTBLACK_EX + "\t--> 这首歌没有歌词,跳过...\n", bar)
2022-07-20 13:15:39 +08:00
return
else:
with open(os.path.join(path, filename), "w", encoding="utf-8") as f:
if not save_lyrics_time:
for lyric in info["lyric"].split("\n"):
print(lyric)
f.write("".join(lyric.split("]")[1:]))
f.write('\n')
else:
f.write(info["lyric"])
bprint(Fore.GREEN + "\t--> 歌词下载完成!文件被保存在" + Style.RESET_ALL + f"{os.path.join(path, filename)}\n", bar)
2022-07-20 13:15:39 +08:00
return