mirror of
https://github.com/MeoProject/lx-music-api-server.git
synced 2025-05-23 19:17:41 +08:00
Merge branch 'main' of github.com:lxmusics/lx-music-api-server-python
This commit is contained in:
commit
d1e23d94c6
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,6 +23,8 @@ test.py
|
|||||||
logs
|
logs
|
||||||
config.json
|
config.json
|
||||||
*.log
|
*.log
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
|
||||||
# VSCode
|
# VSCode
|
||||||
.history
|
.history
|
||||||
|
@ -168,6 +168,7 @@ default = {
|
|||||||
"_clientver-desc": "客户端versioncode,pidversionsecret可能随此值而变化",
|
"_clientver-desc": "客户端versioncode,pidversionsecret可能随此值而变化",
|
||||||
"pidversionsecret": "57ae12eb6890223e355ccfcb74edf70d",
|
"pidversionsecret": "57ae12eb6890223e355ccfcb74edf70d",
|
||||||
"_pidversionsecret-desc": "获取URL时所用的key值计算验证值",
|
"_pidversionsecret-desc": "获取URL时所用的key值计算验证值",
|
||||||
|
"pid": "2",
|
||||||
},
|
},
|
||||||
"tracker": {
|
"tracker": {
|
||||||
"desc": "trackerapi请求配置,不懂请保持默认,修改请统一为字符串格式",
|
"desc": "trackerapi请求配置,不懂请保持默认,修改请统一为字符串格式",
|
||||||
@ -187,6 +188,15 @@ default = {
|
|||||||
"token": "",
|
"token": "",
|
||||||
"userid": "0",
|
"userid": "0",
|
||||||
"mid": "114514",
|
"mid": "114514",
|
||||||
|
"lite_sign_in": {
|
||||||
|
"desc": "是否启用概念版自动签到,仅在appid=3116时运行",
|
||||||
|
"enable": False,
|
||||||
|
"interval": 86400,
|
||||||
|
"mixsongmid": {
|
||||||
|
"desc": "mix_songmid的获取方式, 默认auto, 可以改成一个数字手动",
|
||||||
|
"value": "auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tx": {
|
"tx": {
|
||||||
@ -257,6 +267,15 @@ default = {
|
|||||||
'userid': '0',
|
'userid': '0',
|
||||||
'token': '',
|
'token': '',
|
||||||
'mid': '114514',
|
'mid': '114514',
|
||||||
|
"lite_sign_in": {
|
||||||
|
"desc": "是否启用概念版自动签到,仅在appid=3116时运行",
|
||||||
|
"enable": False,
|
||||||
|
"interval": 86400,
|
||||||
|
"mixsongmid": {
|
||||||
|
"desc": "mix_songmid的获取方式, 默认auto, 可以改成一个数字手动",
|
||||||
|
"value": "auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'tx': [
|
'tx': [
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
from . import Httpx
|
from . import Httpx
|
||||||
from . import config
|
from . import config
|
||||||
from . import scheduler
|
from . import scheduler
|
||||||
from .variable import iscn
|
|
||||||
from .log import log
|
from .log import log
|
||||||
from aiohttp.web import Response
|
from aiohttp.web import Response
|
||||||
import ujson as json
|
import ujson as json
|
||||||
@ -70,12 +69,12 @@ async def get_script():
|
|||||||
|
|
||||||
async def generate_script_response(request):
|
async def generate_script_response(request):
|
||||||
if (request.query.get('key') != config.read_config('security.key.value') and config.read_config('security.key.enable')):
|
if (request.query.get('key') != config.read_config('security.key.value') and config.read_config('security.key.enable')):
|
||||||
return Response(body = json.dumps({'code': 6, 'msg': 'key验证失败', 'data': None}, indent=2, ensure_ascii=False), content_type='application/json', status = 400)
|
return {'code': 6, 'msg': 'key验证失败', 'data': None}, 403
|
||||||
try:
|
try:
|
||||||
with open('./lx-music-source-example.js', 'r', encoding='utf-8') as f:
|
with open('./lx-music-source-example.js', 'r', encoding='utf-8') as f:
|
||||||
script = f.read()
|
script = f.read()
|
||||||
except:
|
except:
|
||||||
return Response(body = json.dumps({'code': 4, 'msg': '本地无源脚本', 'data': None}, indent=2, ensure_ascii=False), content_type='application/json', status = 500)
|
return {'code': 4, 'msg': '本地无源脚本', 'data': None}, 400
|
||||||
scriptLines = script.split('\n')
|
scriptLines = script.split('\n')
|
||||||
newScriptLines = []
|
newScriptLines = []
|
||||||
for line in scriptLines:
|
for line in scriptLines:
|
||||||
|
10
main.py
10
main.py
@ -91,10 +91,14 @@ async def handle_before_request(app, handler):
|
|||||||
return handleResult({'code': 6, 'msg': '未找到您所请求的资源', 'data': None}, 404)
|
return handleResult({'code': 6, 'msg': '未找到您所请求的资源', 'data': None}, 404)
|
||||||
|
|
||||||
resp = await handler(request)
|
resp = await handler(request)
|
||||||
if (isinstance(resp, str)):
|
if (isinstance(resp, (str, list, dict))):
|
||||||
resp = Response(body = resp, content_type='text/plain', status = 200)
|
|
||||||
elif (isinstance(resp, (list, dict))):
|
|
||||||
resp = handleResult(resp)
|
resp = handleResult(resp)
|
||||||
|
elif (isinstance(resp, tuple) and len(resp) == 2): # flask like response
|
||||||
|
body, status = resp
|
||||||
|
if (isinstance(body, (str, list, dict))):
|
||||||
|
resp = handleResult(body, status)
|
||||||
|
else:
|
||||||
|
resp = Response(body = str(body), content_type='text/plain', status = status)
|
||||||
elif (not isinstance(resp, Response)):
|
elif (not isinstance(resp, Response)):
|
||||||
resp = Response(body = str(resp), content_type='text/plain', status = 200)
|
resp = Response(body = str(resp), content_type='text/plain', status = 200)
|
||||||
aiologger.info(f'{request.remote_addr + ("" if (request.remote == request.remote_addr) else f"|proxy@{request.remote}")} - {request.method} "{request.path}", {resp.status}')
|
aiologger.info(f'{request.remote_addr + ("" if (request.remote == request.remote_addr) else f"|proxy@{request.remote}")} - {request.method} "{request.path}", {resp.status}')
|
||||||
|
@ -17,6 +17,7 @@ from .lyric import lyricSearchByHash as _lyricSearch
|
|||||||
from .mv import getMvInfo as _getMvInfo
|
from .mv import getMvInfo as _getMvInfo
|
||||||
from .mv import getMvPlayURL as _getMvUrl
|
from .mv import getMvPlayURL as _getMvUrl
|
||||||
from .search import getSongSearchResult as _songsearch
|
from .search import getSongSearchResult as _songsearch
|
||||||
|
from . import lite_signin
|
||||||
from common.exceptions import FailedException
|
from common.exceptions import FailedException
|
||||||
from common import Httpx
|
from common import Httpx
|
||||||
from common import utils
|
from common import utils
|
||||||
|
167
modules/kg/lite_signin.py
Normal file
167
modules/kg/lite_signin.py
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
# ----------------------------------------
|
||||||
|
# - mode: python -
|
||||||
|
# - author: helloplhm-qwq -
|
||||||
|
# - name: lite_signin.py -
|
||||||
|
# - project: lx-music-api-server -
|
||||||
|
# - license: MIT -
|
||||||
|
# ----------------------------------------
|
||||||
|
# This file is part of the "lx-music-api-server" project.
|
||||||
|
|
||||||
|
from common.exceptions import FailedException
|
||||||
|
from .utils import buildRequestParams, sign
|
||||||
|
from common import Httpx, config, utils, variable, scheduler, log
|
||||||
|
import random
|
||||||
|
import binascii
|
||||||
|
import time
|
||||||
|
|
||||||
|
logger = log.log('kugou_lite_sign_in')
|
||||||
|
|
||||||
|
|
||||||
|
async def randomMixSongMid():
|
||||||
|
'''
|
||||||
|
通过TOP500榜单获取随机歌曲的mixsongmid
|
||||||
|
'''
|
||||||
|
# 声明榜单url
|
||||||
|
rankUrl = 'http://mobilecdnbj.kugou.com/api/v3/rank/song?version=9108&ranktype=1&plat=0&pagesize=100&area_code=1&page=1&rankid=8888&with_res_tag=0&show_portrait_mv=1'
|
||||||
|
# 请求
|
||||||
|
res = await Httpx.AsyncRequest(rankUrl, {
|
||||||
|
"method": 'GET'
|
||||||
|
})
|
||||||
|
data = res.json()
|
||||||
|
if (data.get('status') != 1):
|
||||||
|
raise FailedException('排行榜获取失败')
|
||||||
|
|
||||||
|
# 随机选择一首歌曲
|
||||||
|
randomSong = random.choice(data['data']['info'])
|
||||||
|
|
||||||
|
# 因为排行榜api不会返回mixsongmid
|
||||||
|
# 所以需要进行一次搜索接口来获取
|
||||||
|
search_req = await Httpx.AsyncRequest(utils.encodeURI(f'https://songsearch.kugou.com/song_search_v2?' + buildRequestParams({
|
||||||
|
"keyword": randomSong['filename'],
|
||||||
|
"page": 1,
|
||||||
|
"pagesize": 1,
|
||||||
|
"userid": 0,
|
||||||
|
"clientver": "",
|
||||||
|
"platform": "WebFilter",
|
||||||
|
"filter": 2,
|
||||||
|
"iscorrection": 1,
|
||||||
|
"privilege_filter": 0
|
||||||
|
})), {
|
||||||
|
"headers": {
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.142.86 Safari/537.36",
|
||||||
|
"Referer": "https://www.kugou.com",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
body = search_req.json()
|
||||||
|
|
||||||
|
if (body.get('status') != 1):
|
||||||
|
raise FailedException('歌曲搜索失败')
|
||||||
|
if (body['data']['total'] == 0 or body['data']['lists'] == []):
|
||||||
|
raise FailedException('歌曲搜索失败')
|
||||||
|
|
||||||
|
return body['data']['lists'][0]['MixSongID']
|
||||||
|
|
||||||
|
|
||||||
|
async def do_account_signin(user_info):
|
||||||
|
'''
|
||||||
|
签到主函数,传入userinfo,响应None就是成功,报错即为不成功
|
||||||
|
'''
|
||||||
|
# 检查用户配置文件,获取mixsongmid
|
||||||
|
mixid = user_info['lite_sign_in']['mixsongmid']['value']
|
||||||
|
if (mixid == 'auto'):
|
||||||
|
mixid = await randomMixSongMid()
|
||||||
|
|
||||||
|
# 声明变量
|
||||||
|
headers = {
|
||||||
|
'User-Agent': f'Android712-AndroidPhone-{config.read_config("module.kg.client.clientver")}-18-0-NetMusic-wifi',
|
||||||
|
'KG-THash': '3e5ec6b',
|
||||||
|
'KG-Rec': '1',
|
||||||
|
'KG-RC': '1',
|
||||||
|
"x-router": "youth.kugou.com"
|
||||||
|
}
|
||||||
|
body = """{"mixsongid":__id__}""".replace("__id__", str(mixid))
|
||||||
|
|
||||||
|
# params = "userid={}&token={}&appid=3116&clientver=10518&clienttime={}&mid={}&uuid={}&dfid=-".format(read_config("common.kg.userid"), read_config("common.kg.token"), int(time.time()), read_config("common.kg.mid"), str(binascii.hexlify(random.randbytes(16)), encoding = "utf-8"))
|
||||||
|
params = {
|
||||||
|
"userid": user_info['userid'],
|
||||||
|
"token": user_info['token'],
|
||||||
|
"appid": 3116,
|
||||||
|
"clientver": config.read_config('module.kg.client.clientver'),
|
||||||
|
"clienttime": int(time.time()),
|
||||||
|
"mid": user_info['mid'],
|
||||||
|
"uuid": str(binascii.hexlify(random.randbytes(16)), encoding="utf-8"),
|
||||||
|
"dfid": "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
params['signature'] = sign(
|
||||||
|
params, body, config.read_config('module.kg.client.signatureKey'))
|
||||||
|
|
||||||
|
# 发送请求
|
||||||
|
req = await Httpx.AsyncRequest(f"https://gateway.kugou.com/v2/report/listen_song?" +
|
||||||
|
buildRequestParams(params), {
|
||||||
|
"method": "POST",
|
||||||
|
"body": body,
|
||||||
|
"headers": headers
|
||||||
|
})
|
||||||
|
req = req.json()
|
||||||
|
|
||||||
|
if req['status'] == 1:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
raise FailedException(req['error_msg'])
|
||||||
|
|
||||||
|
|
||||||
|
def task_handler():
|
||||||
|
# not lite client configure
|
||||||
|
if (int(config.read_config('module.kg.client.appid')) != 3116):
|
||||||
|
return
|
||||||
|
|
||||||
|
# no user
|
||||||
|
if ((not variable.use_cookie_pool) and (not config.read_config('module.kg.user.token'))):
|
||||||
|
return
|
||||||
|
|
||||||
|
# devide cookiepool
|
||||||
|
if (variable.use_cookie_pool):
|
||||||
|
pool = config.read_config('module.cookiepool.kg')
|
||||||
|
for user in pool:
|
||||||
|
index = pool.index(user)
|
||||||
|
if (user.get('lite_sign_in') is None):
|
||||||
|
user['lite_sign_in'] = {
|
||||||
|
"desc": "是否启用概念版自动签到,仅在appid=3116时运行",
|
||||||
|
"enable": False,
|
||||||
|
"interval": 86400,
|
||||||
|
"mixsongmid": {
|
||||||
|
"desc": "mix_songmid的获取方式, 默认auto, 可以改成一个数字手动",
|
||||||
|
"value": "auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pool[index] = user
|
||||||
|
config.write_config('module.cookiepool.kg', pool)
|
||||||
|
logger.info(f'用户池用户(index = {index})配置缺失lite_sign_in字段,已自动写入')
|
||||||
|
|
||||||
|
# refresh
|
||||||
|
pool = config.read_config('module.cookiepool.kg')
|
||||||
|
# add signin schedule task
|
||||||
|
for user in pool:
|
||||||
|
if (user.get('lite_sign_in').get('enable')):
|
||||||
|
scheduler.append(f'kugou_lite_sign_in_{user["userid"]}', do_account_signin, user['lite_sign_in']['interval'], {'user_info': user})
|
||||||
|
else:
|
||||||
|
user_info = config.read_config('module.kg.user')
|
||||||
|
if (user_info.get('lite_sign_in') is None):
|
||||||
|
user_info['lite_sign_in'] = {
|
||||||
|
"desc": "是否启用概念版自动签到,仅在appid=3116时运行",
|
||||||
|
"enable": False,
|
||||||
|
"interval": 86400,
|
||||||
|
"mixsongmid": {
|
||||||
|
"desc": "mix_songmid的获取方式, 默认auto, 可以改成一个数字手动",
|
||||||
|
"value": "auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.write_config('module.kg.user', user_info)
|
||||||
|
logger.info('用户配置缺失lite_sign_in字段,已自动写入')
|
||||||
|
|
||||||
|
if (user_info.get('lite_sign_in').get('enable')):
|
||||||
|
scheduler.append(f'kugou_lite_sign_in', do_account_signin, user_info['lite_sign_in']['interval'], {'user_info': user_info})
|
||||||
|
|
||||||
|
task_handler()
|
@ -46,7 +46,7 @@ async def url(songId, quality):
|
|||||||
'album_audio_id': albumaudioid,
|
'album_audio_id': albumaudioid,
|
||||||
'behavior': 'play',
|
'behavior': 'play',
|
||||||
'clienttime': int(time.time()),
|
'clienttime': int(time.time()),
|
||||||
'pid': 2,
|
'pid': tools.pid,
|
||||||
'key': getKey(thash, user_info),
|
'key': getKey(thash, user_info),
|
||||||
'dfid': '-',
|
'dfid': '-',
|
||||||
'pidversion': 3001
|
'pidversion': 3001
|
||||||
|
@ -23,6 +23,7 @@ tools = createObject({
|
|||||||
"version": config.read_config("module.kg.tracker.version"),
|
"version": config.read_config("module.kg.tracker.version"),
|
||||||
"extra_params": config.read_config("module.kg.tracker.extra_params"),
|
"extra_params": config.read_config("module.kg.tracker.extra_params"),
|
||||||
"appid": config.read_config("module.kg.client.appid"),
|
"appid": config.read_config("module.kg.client.appid"),
|
||||||
|
"pid": config.read_config("module.kg.client.pid"),
|
||||||
'qualityHashMap': {
|
'qualityHashMap': {
|
||||||
'128k': 'hash_128',
|
'128k': 'hash_128',
|
||||||
'320k': 'hash_320',
|
'320k': 'hash_320',
|
||||||
@ -43,7 +44,7 @@ def buildSignatureParams(dictionary, body = ""):
|
|||||||
joined_str = ''.join([f'{k}={v}' for k, v in dictionary.items()])
|
joined_str = ''.join([f'{k}={v}' for k, v in dictionary.items()])
|
||||||
return joined_str + body
|
return joined_str + body
|
||||||
|
|
||||||
def buildRequestParams(dictionary):
|
def buildRequestParams(dictionary: dict):
|
||||||
joined_str = '&'.join([f'{k}={v}' for k, v in dictionary.items()])
|
joined_str = '&'.join([f'{k}={v}' for k, v in dictionary.items()])
|
||||||
return joined_str
|
return joined_str
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user