Skip to content

Commit

Permalink
v.2.1.2
Browse files Browse the repository at this point in the history
匹配方案优化
  • Loading branch information
NingmengLemon committed Jun 8, 2022
1 parent cda7a37 commit b0ff4d1
Show file tree
Hide file tree
Showing 6 changed files with 1,520 additions and 43 deletions.
118 changes: 76 additions & 42 deletions CMLD.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
import tkinter as tk
from tkinter import filedialog
from functools import wraps
import key163
from tinytag import TinyTag

version = '2.1.1'
version = '2.1.2'

encoding = 'utf-8'
root_window = tk.Tk()
Expand Down Expand Up @@ -115,6 +117,9 @@ def get_lyrics(mid):
lyrics = lyrics_trans = None
return lyrics,lyrics_trans

def parse_tag(file):
return TinyTag.get(file).as_dict()

def parse_filename(fn):
fn = fn.split(' - ',1)
if len(fn) == 2:
Expand All @@ -125,6 +130,27 @@ def parse_filename(fn):
artists = []
return title,artists

def get_fileinfo(file):
#tag
tags = parse_tag(file)
#163key
if tags['comment']:
if tags['comment'].startswith("163 key(Don't modify):"):
key = tags['comment'][22:]
key = key163.parse_163key(key)
return key['musicName'],[i[0] for i in key['artist']],key['musicId']
#common
if tags['title'] and tags['artist']:
return tags['title'],tags['artist'].split('/'),None
#filename
t,a = parse_filename(os.path.splitext(os.path.split(file)[1])[0])
if t and a:
return t,a,None
elif t and not a and tags['title']:
return tags['title'],None,None
else:
return t,None,None

@auto_retry()
def download_lyrics(mid,topath,trans=False,info=None,lrcs=None):
'''info和lrcs是预处理信息, 从信息获取函数获取的源数据, 为的是避免重复请求'''
Expand Down Expand Up @@ -186,7 +212,7 @@ def main():
'\n (1)Download lyrics via music id.'\
'\n (2)Parse album via album id and download lyrics of each music.'\
'\n (3)Scan local folder and download lyrics of each music file according to their filenames.'\
'\n (4)Choose some files manually and download lyrics for them according to thier filenames.'\
'\n (4)Choose some files in person and download lyrics for them according to thier filenames.'\
'\nChoice:').strip()
if choice == '1':
source = input('Music ID or Url:').strip()
Expand Down Expand Up @@ -265,28 +291,32 @@ def main():
loop_counter += 1
base,extension = os.path.splitext(file)
if extension.lower() in ['.m4a','.mp3','.flac','.aac','.ape','.wma']:
title,artists = parse_filename(base)
data = search_music(title,*artists)
if not data:
print('File "{}" has no match result.'.format(file))
continue
if fuzzy:
titles_to_match = [i['title'] for i in data]
match_res = fuzzy_match(title,titles_to_match)
try:
matched_obj = data[titles_to_match.index(next(match_res))]
print('File "{}" matched music "{}"(id{}).'.format(file,matched_obj['title'],matched_obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=matched_obj) #因为键的命名方法一致, 所以可以直接传入
except StopIteration:
print('File "{}" has no match result.'.format(file))
title,artists,musicid = get_fileinfo(os.path.join(root,file))
if musicid:
print('File "{}" is music "{}"(id{})'.format(file,title,musicid))
download_lyrics(matched_obj['mid'],root,trans=trans)
else:
for obj in data:
if obj['title'] == title and sum([(i in obj['artists']) for i in artists]) == len(artists):
print('File "{}" matched music "{}"(id{}).'.format(file,obj['title'],obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=obj)
break
else:
data = search_music(title,*artists)
if not data:
print('File "{}" has no match result.'.format(file))
continue
if fuzzy:
titles_to_match = [i['title'] for i in data]
match_res = fuzzy_match(title,titles_to_match)
try:
matched_obj = data[titles_to_match.index(next(match_res))]
print('File "{}" matched music "{}"(id{}).'.format(file,matched_obj['title'],matched_obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=matched_obj) #因为键的命名方法一致, 所以可以直接传入
except StopIteration:
print('File "{}" has no match result.'.format(file))
else:
for obj in data:
if obj['title'] == title and sum([(i in obj['artists']) for i in artists]) == len(artists):
print('File "{}" matched music "{}"(id{}).'.format(file,obj['title'],obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=obj)
break
else:
print('File "{}" has no match result.'.format(file))
else:
continue
else:
Expand All @@ -310,28 +340,32 @@ def main():
root,file = os.path.split(fullpath)
base,extension = os.path.splitext(file)
if extension.lower() in ['.m4a','.mp3','.flac','.aac','.ape','.wma']:
title,artists = parse_filename(base)
data = search_music(title,*artists)
if not data:
print('File "{}" has no match result.'.format(file))
continue
if fuzzy:
titles_to_match = [i['title'] for i in data]
match_res = fuzzy_match(title,titles_to_match)
try:
matched_obj = data[titles_to_match.index(next(match_res))]
print('File "{}" matched music "{}"(id{}).'.format(file,matched_obj['title'],matched_obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=matched_obj) #因为键的命名方法一致, 所以可以直接传入
except StopIteration:
print('File "{}" has no match result.'.format(file))
title,artists,musicid = get_fileinfo(os.path.join(root,file))
if musicid:
print('File "{}" is music "{}"(id{})'.format(file,title,musicid))
download_lyrics(musicid,root,trans=trans)
else:
for obj in data:
if obj['title'] == title and sum([(i in obj['artists']) for i in artists]) == len(artists):
print('File "{}" matched music "{}"(id{}).'.format(file,obj['title'],obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=obj)
break
else:
data = search_music(title,*artists)
if not data:
print('File "{}" has no match result.'.format(file))
continue
if fuzzy:
titles_to_match = [i['title'] for i in data]
match_res = fuzzy_match(title,titles_to_match)
try:
matched_obj = data[titles_to_match.index(next(match_res))]
print('File "{}" matched music "{}"(id{}).'.format(file,matched_obj['title'],matched_obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=matched_obj) #因为键的命名方法一致, 所以可以直接传入
except StopIteration:
print('File "{}" has no match result.'.format(file))
else:
for obj in data:
if obj['title'] == title and sum([(i in obj['artists']) for i in artists]) == len(artists):
print('File "{}" matched music "{}"(id{}).'.format(file,obj['title'],obj['mid']))
download_lyrics(matched_obj['mid'],root,trans=trans,info=obj)
break
else:
print('File "{}" has no match result.'.format(file))
else:
continue
else:
Expand Down
4 changes: 3 additions & 1 deletion DevelopmentLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,6 @@ v.2.1.0.20220123
现在能扫描文件夹并匹配合适的歌词,并分为模糊匹配和完全匹配
v.2.1.1.20220521
现在能手动指定文件进行匹配了
修复Bug
修复Bug
v.2.1.2.20220608
现在能根据 Tag信息 及其中的 163 Key 进行匹配了
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,26 @@ CloudMusic Lyric Downloader

项目,复活了……!

## 功能简介

功能 | 备注
------- | ---
通过MusicID或Url下载歌词 |
通过AlbumID或Url解析专辑并下载歌词 |
扫描文件夹并为音频文件匹配下载合适的歌词 | 模糊匹配&完全匹配,灵感来源于fb2k的某个插件
手动指定音频文件并为其匹配下载合适的歌词 | 同上

注意:匹配文件时按 163Key - Tag - 文件名 的优先级进行匹配

## 关于 163 Key:

参考:

[163 key 使用指南](https://www.morfans.cn/archives/2793)

[python_AES-ECB加密、解密方法](https://blog.csdn.net/qq_45664055/article/details/123348485)

## 关于 Music Tag:

引用项目:[TinyTag](https://github.com/devsnd/tinytag)

44 changes: 44 additions & 0 deletions key163.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import json

# https://blog.csdn.net/qq_45664055/article/details/123348485
class EncryptDate:
def __init__(self, key):
# 初始化密钥
self.key = key
# 初始化数据块大小
self.length = AES.block_size
# 初始化AES,ECB模式的实例
self.aes = AES.new(self.key.encode("utf-8"), AES.MODE_ECB)
# 截断函数,去除填充的字符
self.unpad = lambda date: date[0:-ord(date[-1])]

def fill_method(self, aes_str):
'''pkcs7补全'''
pad_pkcs7 = pad(aes_str.encode('utf-8'), AES.block_size, style='pkcs7')

return pad_pkcs7

def encrypt(self, encrData):
# 加密函数,使用pkcs7补全
res = self.aes.encrypt(self.fill_method(encrData))
# 转换为base64
msg = str(base64.b64encode(res), encoding="utf-8")

return msg

def decrypt(self, decrData):
# base64解码
res = base64.decodebytes(decrData.encode("utf-8"))
# 解密函数
msg = self.aes.decrypt(res).decode("utf-8")

return self.unpad(msg)

_e = EncryptDate(key="#14ljk_!\]&0U<'(")

def parse_163key(key):
return json.loads(_e.decrypt(key)[6:])

1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pycryptodome
Loading

0 comments on commit b0ff4d1

Please sign in to comment.