Re-Upload

Nothing
This commit is contained in:
David-123 2023-04-03 22:29:25 +08:00 committed by GitHub
parent 474efd1321
commit 07318a2ef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 47 deletions

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# ↑ For Linux & MacOS to run this program directly if the user currently installed python and third-party packages. # ↑ For Linux & macOS to run this program directly if the user currently installed python and third-party packages.
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# author: David-123 # author: David-123
from modules.raw_input import rinput from modules.inputs import rinput
from modules.information import print_info from modules.information import print_info
from modules.multi_download import mdl from modules.multi_download import mdl
from modules.one_download import download_one_lyric from modules.one_download import download_one_lyric

11
modules/inputs.py Normal file
View File

@ -0,0 +1,11 @@
"""该模块提供几个自定义处理输入函数"""
def rinput(string: str = ''):
"""当调用该函数时同input()一样但是返回一个去除首位空格并全部小写的str"""
return input(string).strip().lower()
def cinput(string: str = ''):
"""当调用该函数时同input()一样但是返回一个去除首尾空格的str"""
return input(string).strip()

View File

@ -5,16 +5,18 @@ import struct
from base64 import b64decode from base64 import b64decode
from Cryptodome.Cipher import AES from Cryptodome.Cipher import AES
from mutagen import File from mutagen import File, flac
from mutagen.id3 import ID3, TPE1, APIC, COMM, TIT2, TALB from mutagen.id3 import ID3, TPE1, APIC, COMM, TIT2, TALB
from modules.clear_screen import clear from modules.clear_screen import clear
from modules.get_song import get_song_lyric from modules.get_song import get_song_lyric
from modules.inputs import cinput, rinput
def load_information_from_song(path): def load_information_from_song(path):
"""从音乐文件中的 Comment 字段获取 163 key 并解密返回歌曲信息""" """从音乐文件中的 Comment 字段获取 163 key 并解密返回歌曲信息"""
file = File(path) # 使用 TinyTag 获取歌曲信息 file = File(path) # 使用 mutagen 获取歌曲信息
if os.path.splitext(path)[-1] == ".mp3": # 当文件为 mp3 时使用 ID3 格式读取
if file.tags.get("COMM::XXX"): if file.tags.get("COMM::XXX"):
if file.tags["COMM::XXX"].text[0][:7] == "163 key": if file.tags["COMM::XXX"].text[0][:7] == "163 key":
ciphertext = file.tags["COMM::XXX"].text[0][22:] ciphertext = file.tags["COMM::XXX"].text[0][22:]
@ -22,6 +24,16 @@ def load_information_from_song(path):
return "not_support" return "not_support"
else: else:
return "not_support" return "not_support"
elif os.path.splitext(path)[-1] == ".flac": # 当文件为 flac 时使用 FLAC 格式读取
if file.tags.get("DESCRIPTION"):
if file.tags["DESCRIPTION"][0][:7] == "163 key":
ciphertext = file.tags["DESCRIPTION"][0][22:]
else:
return "not_support"
else:
return "not_support"
else:
return "not_support"
def unpad(s): # 创建清理针对于网易云的 AES-128-ECB 解密后末尾占位符的函数 def unpad(s): # 创建清理针对于网易云的 AES-128-ECB 解密后末尾占位符的函数
if type(s[-1]) == int: if type(s[-1]) == int:
@ -30,6 +42,7 @@ def load_information_from_song(path):
end = ord(s[-1]) end = ord(s[-1])
return s[0:-end] return s[0:-end]
# return s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] 更加清晰的理解 ↑ # return s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] 更加清晰的理解 ↑
cryptor = AES.new(b"#14ljk_!\\]&0U<'(", AES.MODE_ECB) # 使用密钥创建解密器 cryptor = AES.new(b"#14ljk_!\\]&0U<'(", AES.MODE_ECB) # 使用密钥创建解密器
# 下方这一行将密文 ciphertext 转换为 bytes 后进行 base64 解码, 得到加密过的 AES 密文 # 下方这一行将密文 ciphertext 转换为 bytes 后进行 base64 解码, 得到加密过的 AES 密文
@ -114,7 +127,8 @@ def load_and_decrypt_from_ncm(file_path, targetdir): # nondanee的源代码,
f.close() f.close()
# 对解密后的文件进行信息补全 # 对解密后的文件进行信息补全
audio = ID3(os.path.splitext(file_path)[0]+"."+meta_data["format"]) if meta_data["format"] == "mp3": # 针对 mp3 使用 ID3 进行信息补全
audio = ID3(os.path.join(targetdir, os.path.splitext(file_path.split("/")[-1])[0] + ".mp3"))
artists = [] artists = []
for i in meta_data["artist"]: for i in meta_data["artist"]:
artists.append(i[0]) artists.append(i[0])
@ -124,13 +138,23 @@ def load_and_decrypt_from_ncm(file_path, targetdir): # nondanee的源代码,
audio["TIT2"] = TIT2(encoding=3, text=[meta_data["musicName"]]) # 插入歌曲名 audio["TIT2"] = TIT2(encoding=3, text=[meta_data["musicName"]]) # 插入歌曲名
audio["TALB"] = TALB(encoding=3, text=[meta_data["album"]]) # 插入专辑名 audio["TALB"] = TALB(encoding=3, text=[meta_data["album"]]) # 插入专辑名
audio.save() audio.save()
elif meta_data["format"] == "flac": # 针对 flac 使用 FLAC 进行信息补全
audio = flac.FLAC(os.path.join(targetdir, os.path.splitext(file_path.split("/")[-1])[0] + ".flac"))
artists = []
for i in meta_data["artist"]:
artists.append(i[0])
audio["artist"] = artists[:] # 插入歌手
audio["title"] = [meta_data["musicName"]] # 插入歌曲名
audio["album"] = [meta_data["album"]] # 插入专辑名
audio["description"] = comment.decode("utf-8") # 插入 163 key 注释
audio.save()
return meta_data return meta_data
def get_lyric_from_folder(lyric_path: str): def get_lyric_from_folder(lyric_path: str):
clear() clear()
path = input("请输入歌曲的保存文件夹(绝对路径):").strip() path = cinput("请输入歌曲的保存文件夹(绝对路径):")
if not os.path.exists(path): if not os.path.exists(path):
input("路径不存在.\n按回车返回...") input("路径不存在.\n按回车返回...")
return return
@ -164,7 +188,7 @@ def get_lyric_from_folder(lyric_path: str):
print(f"\n发现{len(ncm_files)}个ncm加密文件!") print(f"\n发现{len(ncm_files)}个ncm加密文件!")
print("请问解密后的文件保存在哪里?\n" print("请问解密后的文件保存在哪里?\n"
"[1] 保存在相同文件夹内\n[2] 保存在程序设定的下载文件夹中\n[3] 保存在自定义文件夹内\n[q] 取消解密,下载歌词时将忽略这些文件") "[1] 保存在相同文件夹内\n[2] 保存在程序设定的下载文件夹中\n[3] 保存在自定义文件夹内\n[q] 取消解密,下载歌词时将忽略这些文件")
select = input("请选择: ").strip().lower() select = rinput("请选择: ")
if select == 'q': if select == 'q':
target_path = "NOT_DECRYPT" target_path = "NOT_DECRYPT"
break break
@ -182,28 +206,29 @@ def get_lyric_from_folder(lyric_path: str):
if target_path != "NOT_DECRYPT": if target_path != "NOT_DECRYPT":
for i in range(0, len(ncm_files)): for i in range(0, len(ncm_files)):
print("破解进度: %d/%d ~ %s" % (i+1, len(ncm_files), ncm_files[i])) print("破解进度: %d/%d ~ %s" % (i + 1, len(ncm_files), ncm_files[i]))
try: try:
result = load_and_decrypt_from_ncm(os.path.join(path, ncm_files[i]), target_path) result = load_and_decrypt_from_ncm(os.path.join(path, ncm_files[i]), target_path)
except AssertionError: except AssertionError:
print(f"\t- 文件 \"{ncm_files[i]}\" 破解失败!\n\t 可能是文件不完整或者重命名了别的文件?跳过...") print(f"\t- 文件 \"{ncm_files[i]}\" 破解失败!\n\t 可能是文件不完整或者重命名了别的文件?跳过...")
fails += 1 fails += 1
continue continue
print("\t--> %s" % os.path.splitext(ncm_files[i])[0]+"."+result["format"]) print("\t--> %s" % os.path.splitext(ncm_files[i])[0] + "." + result["format"])
musics.append({"id": result['musicId'], "name": result["musicName"], "artists": result["artist"]}) musics.append({"id": result['musicId'], "name": result["musicName"], "artists": result["artist"]})
# 汇报索引结果 # 汇报索引结果
print(f"\n索引完毕!共找到{fails + len(musics) + len(ncm_files)}个目标文件\n{len(musics)}个文件已载入\n{fails}个文件失败") print(
f"\n索引完毕!共找到{fails + len(musics) + len(ncm_files)}个目标文件\n{len(musics)}个文件已载入\n{fails}个文件失败")
if ncm_files: if ncm_files:
if target_path == "NOT_DECRYPT": if target_path == "NOT_DECRYPT":
print(f"{len(ncm_files)}个文件放弃加载") print(f"{len(ncm_files)}个文件放弃加载")
while True: while True:
print("\n你希望如何保存这些歌曲的歌词?\n[1]保存到刚刚输入的绝对路径中\n[2]保存到程序设定的下载路径中") print("\n你希望如何保存这些歌曲的歌词?\n[1]保存到刚刚输入的绝对路径中\n[2]保存到程序设定的下载路径中")
r = input("请选择: ").strip().lower() r = rinput("请选择: ")
if r == "1": if r == "1":
lyric_path = path
break break
elif r == "2": elif r == "2":
path = lyric_path
break break
else: else:
try: try:
@ -215,16 +240,16 @@ def get_lyric_from_folder(lyric_path: str):
clear() clear()
for i in range(0, len(musics)): # 根据索引结果获取歌词 for i in range(0, len(musics)): # 根据索引结果获取歌词
print("\n进度: %d/%d" % (i + 1, len(musics))) print("\n进度: %d/%d" % (i + 1, len(musics)))
if get_song_lyric(musics[i], path, allinfo=True) == "dl_err_connection": if get_song_lyric(musics[i], lyric_path, allinfo=True) == "dl_err_connection":
input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...")
if ncm_files: if ncm_files:
if target_path != "NOT_DECRYPT": if target_path != "NOT_DECRYPT":
agree = input("是否删除原ncm文件? (y/n)").strip().lower() agree = rinput("是否删除原ncm文件? (y/n)")
if agree == "y": if agree == "y":
for i in range(0, len(ncm_files)): for i in range(0, len(ncm_files)):
print("删除进度: %d/%d ~ %s" % (i+1, len(ncm_files), ncm_files[i])) print("删除进度: %d/%d\n -> %s\033[F" % (i + 1, len(ncm_files), ncm_files[i]), end="")
os.remove(os.path.join(path, ncm_files[i])) os.remove(os.path.join(path, ncm_files[i]))
else: else:
print("取消.") print("取消.", end="")
input("按回车返回...") input("\n\033[K按回车返回...")
return return

View File

@ -1,6 +1,6 @@
import re import re
from modules.clear_screen import clear from modules.clear_screen import clear
from modules.raw_input import rinput from modules.inputs import rinput
from modules.get_song import get_song_lyric from modules.get_song import get_song_lyric
@ -18,9 +18,7 @@ def mdl(path: str):
else: else:
try: try:
int(r) int(r)
except ValueError: except ValueError:
tmp = re.search(r"song\?id=[0-9]*", r) tmp = re.search(r"song\?id=[0-9]*", r)
if tmp: if tmp:
r = tmp.group()[8:] r = tmp.group()[8:]
@ -31,7 +29,8 @@ def mdl(path: str):
print("\t#%d id:%s - 已添加!" % (len(ids), r)) print("\t#%d id:%s - 已添加!" % (len(ids), r))
clear() clear()
for i in range(0, len(ids)): for i in range(0, len(ids)):
print("\n进度: %d/%d" % (i+1, len(ids))) print("进度: %d/%d" % (i+1, len(ids)))
if get_song_lyric(ids[i], path) == "dl_err_connection": r = get_song_lyric(ids[i], path)
if r == "dl_err_connection":
input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...")
input("按回车键返回...") input("按回车键返回...")

View File

@ -1,5 +1,5 @@
import re import re
from modules.raw_input import rinput from modules.inputs import rinput
from modules.get_song import get_song_lyric from modules.get_song import get_song_lyric
from modules.clear_screen import clear from modules.clear_screen import clear

View File

@ -1,9 +1,8 @@
"""集合设置参数""" """集合设置参数"""
import os import os
import re
from modules.clear_screen import clear from modules.clear_screen import clear
from modules.raw_input import rinput, cinput from modules.inputs import rinput, cinput
from modules.save_load_settings import save_settings from modules.save_load_settings import save_settings
@ -13,33 +12,59 @@ def settings_menu(self):
clear() clear()
print(f"[NeteaseMusicLyricDownloader] {self.version}\n" print(f"[NeteaseMusicLyricDownloader] {self.version}\n"
"[设置菜单]\n" "[设置菜单]\n"
"[0] 返回上级\n[1] 设置歌曲保存路径\n[2] 清空输出文件夹内的所有歌词\n[s] 将设置保存到文件") "[0] 返回上级\n[1] 歌曲保存路径\n[2] 清空输出文件夹内的内容\n[3] 歌词文件保存格式\n[4] 部分动态效果\n"
"[s] 将设置保存到文件")
r = rinput("请选择:") r = rinput("请选择:")
if r == "0": if r == "0":
return return
elif r == "1": elif r == "1":
__set_lyric_path(self) __set_lyric_path(self)
elif r == "2": elif r == "2":
__remove_lyric_files(self.settings.lyric_path) __remove_output_files(self)
elif r == "3":
pass
elif r == "4":
pass
elif r == "s": elif r == "s":
__save_settings(self) __save_settings(self)
else: else:
input("输入无效!按回车键继续...") input("输入无效!按回车键继续...")
def __remove_lyric_files(path): def __remove_output_files(self):
while True:
clear() clear()
print(f"[NeteaseMusicLyricDownloader] {self.version}\n"
"[设置菜单 - 删除文件]\n"
"[0] 返回上级\n[1] 清除歌词文件\n[2] 清除歌曲文件")
r = rinput("请选择:") # 选择清除的文件格式
if r == "0":
return
elif r == "1":
dellist = [".lrc"]
break
elif r == "2":
dellist = [".mp3", ".flac"]
break
else:
input("输入无效!\n按回车键继续...")
files = [] files = []
for i in os.listdir(path): for i in os.listdir(self.settings.lyric_path): # 列出所有文件
if re.match(r".*(\.lrc)$", i): if os.path.splitext(i)[-1] in dellist: # 匹配文件
files.append(i) files.append(i) # 将匹配到的文件加入到列表, 等待删除
if len(files) != 0: if len(files) != 0:
if len(files) > 50:
special_text = "\033[F"
else:
special_text = "\n"
for i in range(0, len(files)): for i in range(0, len(files)):
print("正在删除(%d/%d): %s" % (i+1, len(files), files[i])) print("删除进度: %d/%d\n -> %s%s" % (i+1, len(files), files[i], special_text), end="") # 删除进度提示
os.remove(path+files[i]) os.remove(self.settings.lyric_path+files[i])
input("删除完毕!\n按回车继续...") input("\n\033[K删除完毕!\n按回车继续...")
return
else: else:
input("文件夹内没有要删除的东西\n按回车继续...") input("文件夹内没有要删除的东西\n按回车继续...")
return
def __set_lyric_path(self): def __set_lyric_path(self):
@ -59,6 +84,11 @@ def __set_lyric_path(self):
os.mkdir(path) os.mkdir(path)
self.settings.lyric_path = r self.settings.lyric_path = r
input("设置成功!\n按回车继续...") input("设置成功!\n按回车继续...")
return
def __set_lyric_format(self):
pass
def __save_settings(self): def __save_settings(self):