Re-Upload
Nothing
This commit is contained in:
parent
474efd1321
commit
07318a2ef8
4
main.py
4
main.py
@ -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
11
modules/inputs.py
Normal 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()
|
@ -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
|
||||||
@ -193,17 +217,18 @@ def get_lyric_from_folder(lyric_path: str):
|
|||||||
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
|
||||||
|
@ -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("按回车键返回...")
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
Loading…
Reference in New Issue
Block a user