diff --git a/common/config.py b/common/config.py index c722ef7..a4ba80c 100644 --- a/common/config.py +++ b/common/config.py @@ -60,7 +60,7 @@ class ConfigReadException(Exception): "proxy": { "enable": False, "http_addr": "http://127.0.0.1:7890", - "https_addr": "https://127.0.0.1:7890", + "https_addr": "http://127.0.0.1:7890", }, "_proxy-desc": "代理配置,HTTP与HTTPS协议需分开配置", "log_file": True, diff --git a/common/natives/__init__.py b/common/natives/__init__.py new file mode 100644 index 0000000..818df7f --- /dev/null +++ b/common/natives/__init__.py @@ -0,0 +1,10 @@ +# ---------------------------------------- +# - mode: python - +# - author: helloplhm-qwq - +# - name: __init__.py - +# - project: lx-music-api-server - +# - license: MIT - +# ---------------------------------------- +# This file is part of the "lx-music-api-server" project. + +from . import qdes \ No newline at end of file diff --git a/common/qdes.py b/common/qdes.py new file mode 100644 index 0000000..a43f9b5 --- /dev/null +++ b/common/qdes.py @@ -0,0 +1,32 @@ +# ---------------------------------------- +# - mode: python - +# - author: helloplhm-qwq - +# - name: qdes.py - +# - project: lx-music-api-server - +# - license: MIT - +# ---------------------------------------- +# This file is part of the "lx-music-api-server" project. + +from .log import log +from . import variable +import binascii +import zlib + +logger = log('qdes') + +try: + from .natives import qdes + variable.qdes_lib_loaded = True +except: + try: + import qdes + variable.qdes_lib_loaded = True + except: + logger.warning('QRC解密库qdes加载失败, 可能为不支持当前系统, QRC相关的逐字歌词获取将无法使用') + +def qdes_decrypt(qrc): + if variable.qdes_lib_loaded: + decoded = zlib.decompress(qdes.LyricDecode(binascii.unhexlify(qrc.encode('utf-8')))).decode('utf-8') + return decoded + else: + raise ModuleNotFoundError('qdes解密库未被加载') \ No newline at end of file diff --git a/common/variable.py b/common/variable.py index 0752b7d..5a9a198 100644 --- a/common/variable.py +++ b/common/variable.py @@ -7,13 +7,13 @@ # ---------------------------------------- # This file is part of the "lx-music-api-server" project. -import os -import ujson as json +import os as _os +import ujson as _json def _read_config_file(): try: with open("./config.json", "r", encoding = "utf-8") as f: - return json.load(f) + return _json.load(f) except: pass @@ -42,8 +42,9 @@ def _read_config(key): log_file = log_file if (not isinstance(log_file := _read_config("common.log_file"), type(None))) else True running = True config = {} -workdir = os.getcwd() +workdir = _os.getcwd() banList_suggest = 0 iscn = True fake_ip = None -aioSession = None \ No newline at end of file +aioSession = None +qdes_lib_loaded = False \ No newline at end of file diff --git a/main.py b/main.py index c286743..1b593ac 100644 --- a/main.py +++ b/main.py @@ -97,7 +97,10 @@ async def handle(request): return handleResult({"code": 1, "msg": "lxm请求头验证失败", "data": None}, 403) try: - return handleResult(await getattr(modules, method)(source, songId, quality)) + if (method in dir(modules)): + return handleResult(await getattr(modules, method)(source, songId, quality)) + else: + return handleResult(await modules.other(method, source, songId, quality)) except: logger.error(traceback.format_exc()) return handleResult({'code': 4, 'msg': '内部服务器错误', 'data': None}, 500) diff --git a/modules/__init__.py b/modules/__init__.py index 1f8a957..1035941 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -123,9 +123,9 @@ async def url(source, songId, quality): 'data': None, } -async def info(source, songid, _): +async def other(method, source, songid, _): try: - func = require('modules.' + source + '.info') + func = require('modules.' + source + '.' + method) except: return { 'code': 1, @@ -145,25 +145,3 @@ async def info(source, songid, _): 'msg': e.args[0], 'data': None, } - -async def mv(source, mvId, _): - try: - func = require('modules.' + source + '.mv') - except: - return { - 'code': 1, - 'msg': '未知的源或不支持的方法', - 'data': None, - } - try: - result = await func(mvId) - return { - 'code': 0, - 'msg': 'success', - 'data': result - } - except FailedException as e: - return { - 'code': 2, - 'msg': e.args[0], - } \ No newline at end of file diff --git a/modules/tx/__init__.py b/modules/tx/__init__.py index 9b571a6..88e4212 100644 --- a/modules/tx/__init__.py +++ b/modules/tx/__init__.py @@ -10,6 +10,7 @@ from .player import url from .musicInfo import getMusicInfo as _getInfo from .utils import formatSinger +from .lyric import getLyric as _getLyric from common import utils @@ -75,5 +76,6 @@ async def info(songid): 'bpm': req['track_info']['bpm'], } - +async def lyric(songId): + return await _getLyric(songId) diff --git a/modules/tx/lyric.py b/modules/tx/lyric.py index acd2a99..4bc37e7 100644 --- a/modules/tx/lyric.py +++ b/modules/tx/lyric.py @@ -1,3 +1,18 @@ +# ---------------------------------------- +# - mode: python - +# - author: helloplhm-qwq - +# - name: lyric.py - +# - project: lx-music-api-server - +# - license: MIT - +# ---------------------------------------- +# This file is part of the "lx-music-api-server" project. + +from .utils import signRequest +from .musicInfo import getMusicInfo +from common.exceptions import FailedException +from common.utils import createBase64Decode +from common import variable +from common import qdes import re class ParseTools: @@ -130,26 +145,26 @@ def fix_tlrc_time_tag(self, tlrc, lrc): tlrc_lines = tlrc.split('\n') lrc_lines = lrc.split('\n') new_lrc = [] + time_tag_rxp = r'^\[[\d:.]+\]' + for line in tlrc_lines: - result = self.rxps['lineTime2'].search(line) + result = re.match(time_tag_rxp, line) if not result: continue - words = re.sub(self.rxps['lineTime2'], '', line) + words = re.sub(time_tag_rxp, '', line) if not words.strip(): continue - time = result.group(1) - if '.' in time: - time += ''.ljust(3 - len(time.split('.')[1]), '0') - t1 = self.get_intv(time) + tag = re.sub(r'\[\d+:\d+\.\d+\]', '', result.group(0)) + while lrc_lines: lrc_line = lrc_lines.pop(0) - lrc_line_result = self.rxps['lineTime2'].search(lrc_line) + lrc_line_result = re.match(time_tag_rxp, lrc_line) if not lrc_line_result: continue - t2 = self.get_intv(lrc_line_result.group(1)) - if abs(t1 - t2) < 100: - new_lrc.append(re.sub(self.rxps['lineTime2'], lrc_line_result.group(0), line)) + if tag in lrc_line_result.group(0): + new_lrc.append(re.sub(time_tag_rxp, lrc_line_result.group(0), line)) break + return '\n'.join(new_lrc) def parse(self, lrc, tlrc, rlrc): @@ -169,3 +184,74 @@ def parse(self, lrc, tlrc, rlrc): info['tlyric'] = self.fix_tlrc_time_tag(tlrc, info['lyric']) return info + +global_parser = ParseTools() + +def parseLyric(l, t = '', r = ''): + return global_parser.parse(l, t, r) + +async def getLyric(songId): + # mid and Numberid + if (re.match("^[0-9]+$", str(songId))): + songId = int(songId) + else: + try: + getNumberIDRequest = await getMusicInfo(songId) + except: + raise FailedException('歌曲信息获取失败') + songId = getNumberIDRequest['track_info']['id'] + req = await signRequest({ + "comm": { + "ct": '19', + "cv": '1859', + "uin": '0', + }, + "req": { + "method": 'GetPlayLyricInfo', + "module": 'music.musichallSong.PlayLyricInfo', + "param": { + "format": 'json', + "crypt": 1 if variable.qdes_lib_loaded else 0, + "ct": 19, + "cv": 1873, + "interval": 0, + "lrc_t": 0, + "qrc": 1 if variable.qdes_lib_loaded else 0, + "qrc_t": 0, + "roma": 1 if variable.qdes_lib_loaded else 0, + "roma_t": 0, + "songID": songId, + "trans": 1, + "trans_t": 0, + "type": -1, + } + } + }) + body = req.json() + if ((body['code'] != 0) or (body['req']['code'] != 0)): + raise FailedException('歌词获取失败') + if (variable.qdes_lib_loaded): + l = body['req']['data']['lyric'] + t = body['req']['data']['trans'] + r = body['req']['data']['roma'] + if (l.startswith('789C') and len(l) < 200): # unsupported format + raise FailedException('纯音乐短歌词不受支持') + dl = qdes.qdes_decrypt(l) + if (t): + dt = qdes.qdes_decrypt(t) + else: + dt = '' + if (r): + dr = qdes.qdes_decrypt(r) + else: + dr = '' + return global_parser.parse(dl, dt, dr) + else: # 不获取QRC时的歌词不被加密,解码base64,不进行parse,不支持逐字和罗马音,歌词数据没有毫秒 + l = body['req']['data']['lyric'] + t = body['req']['data']['trans'] + return { + 'lyric': createBase64Decode(l).decode('utf-8'), + 'tlyric': createBase64Decode(t).decode('utf-8'), + 'rlyric': '', + 'lxlyric': '', + }