Skip to content

Commit

Permalink
feat: QQ音乐歌词功能
Browse files Browse the repository at this point in the history
  • Loading branch information
helloplhm-qwq committed Dec 23, 2023
1 parent 40943f3 commit d4056fc
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 42 deletions.
2 changes: 1 addition & 1 deletion common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions common/natives/__init__.py
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions common/qdes.py
Original file line number Diff line number Diff line change
@@ -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解密库未被加载')
11 changes: 6 additions & 5 deletions common/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
aioSession = None
qdes_lib_loaded = False
5 changes: 4 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
26 changes: 2 additions & 24 deletions modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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],
}
4 changes: 3 additions & 1 deletion modules/tx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -75,5 +76,6 @@ async def info(songid):
'bpm': req['track_info']['bpm'],
}


async def lyric(songId):
return await _getLyric(songId)

106 changes: 96 additions & 10 deletions modules/tx/lyric.py
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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):
Expand All @@ -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': '',
}

0 comments on commit d4056fc

Please sign in to comment.