NeteaseMusicLyricDownloader/modules/get_song.py

123 lines
4.0 KiB
Python
Raw Normal View History

2022-04-02 22:50:52 +08:00
"""集合 下载歌词 以及 获取歌曲信息 的功能"""
import os
2022-04-02 22:50:52 +08:00
from json import loads
from requests import post
from requests.exceptions import ConnectionError
from time import sleep
def wait_retry():
print("api提示操作频繁等待恢复...")
while True:
try:
tmp = post(f"http://music.163.com/api/song/detail/?&ids=[1]")
except ConnectionError:
return "dl_err_connection"
else:
if loads(tmp.text)["code"] == 200:
return "continue"
sleep(1)
def get_song_info_raw(types: list, id: str):
"""获取歌曲信息
types 提供一个list,将会返回内部所有符合要求的信息类型\n
id 提供一个歌曲id(str),将会把歌曲的`types`信息返回"""
print("id:%s" % id)
try:
response = post(f"http://music.163.com/api/song/detail/?&ids=[{id}]")
except ConnectionError:
return "dl_err_connection"
else:
info = loads(response.text)
if info["code"] == 406: # 判断当操作频繁时继续获取直到可以返回值为200为止
result = wait_retry()
if result == "continue":
pass
elif result == "dl_err_connection":
return "dl_err_connection"
else:
raise Exception("Unknown exception...")
if not info.get("songs"): # 判断是否存在该歌曲
print("这首歌没有找到,跳过...")
return "song_nf"
else:
need = {}
for i in types: # 通过传入的变量 types 获取信息(根据返回的信息分析得到的下面这句语句)
need.setdefault(i, info["songs"][0][i])
return need
2022-07-20 13:15:39 +08:00
def get_song_lyric(id: str | int | dict, path: str, allinfo: bool = False):
2022-04-02 22:50:52 +08:00
"""获取歌词
``id`` 提供一个歌曲id
2022-07-20 13:15:39 +08:00
``path`` 提供歌曲下载的路径
``allinfo`` 若此项为 True ,则提供的id格式必须为 {"id": int | str, "name": str, "artists": [[str, ...], ...]} (dict)"""
if allinfo:
sinfo = id
id = id["id"]
else:
sinfo = get_song_info_raw(["name", "artists"], id)
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"]
replaces = { # 处理非法字符所用的替换字典(根据网易云下载的文件分析得到)
"|": "",
":": "",
"<": "",
">": "",
"?": "",
"/": "",
"\\": "",
"*": "",
'"': ""
}
for k, v in replaces.items():
name = name.replace(k, v)
artists = artists.replace(k, v)
2022-04-02 22:50:52 +08:00
2022-07-20 13:15:39 +08:00
print(f"歌曲:{name} - {artists}")
filename = f"{name} - {artists}.lrc"
2022-04-02 22:50:52 +08:00
2022-07-20 13:15:39 +08:00
try:
response = post(f"http://music.163.com/api/song/media?id={id}")
except ConnectionError:
return "dl_err_connection"
else:
info = loads(response.text)
if info["code"] == 406: # 此处与上方一样,防止因为请求限制而跳过下载
result = wait_retry()
if result == "continue":
pass
elif result == "dl_err_connection":
return "dl_err_connection"
else:
raise Exception("Unknown exception...")
2022-04-02 22:50:52 +08:00
2022-07-20 13:15:39 +08:00
tmp = loads(response.text)
if tmp.get("nolyric") or not tmp.get('lyric'):
print("这首歌没有歌词,跳过...")
return
else:
with open(os.path.join(path, filename), "w", encoding="utf-8") as f:
2022-07-20 13:15:39 +08:00
f.write(tmp["lyric"])
print(f"歌词下载完成!被保存在{os.path.join(path, filename)}")
2022-07-20 13:15:39 +08:00
return