Skip to content

Commit

Permalink
Merge branch 'main' of github.com:lxmusics/lx-music-api-server-python
Browse files Browse the repository at this point in the history
  • Loading branch information
lerdb committed Jan 31, 2024
2 parents 42fd543 + 09f34fd commit d1e23d9
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 8 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ test.py
logs
config.json
*.log
*.bak
*.tmp

# VSCode
.history
Expand Down
19 changes: 19 additions & 0 deletions common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ class ConfigReadException(Exception):
"_clientver-desc": "客户端versioncode,pidversionsecret可能随此值而变化",
"pidversionsecret": "57ae12eb6890223e355ccfcb74edf70d",
"_pidversionsecret-desc": "获取URL时所用的key值计算验证值",
"pid": "2",
},
"tracker": {
"desc": "trackerapi请求配置,不懂请保持默认,修改请统一为字符串格式",
Expand All @@ -187,6 +188,15 @@ class ConfigReadException(Exception):
"token": "",
"userid": "0",
"mid": "114514",
"lite_sign_in": {
"desc": "是否启用概念版自动签到,仅在appid=3116时运行",
"enable": False,
"interval": 86400,
"mixsongmid": {
"desc": "mix_songmid的获取方式, 默认auto, 可以改成一个数字手动",
"value": "auto"
}
}
}
},
"tx": {
Expand Down Expand Up @@ -257,6 +267,15 @@ class ConfigReadException(Exception):
'userid': '0',
'token': '',
'mid': '114514',
"lite_sign_in": {
"desc": "是否启用概念版自动签到,仅在appid=3116时运行",
"enable": False,
"interval": 86400,
"mixsongmid": {
"desc": "mix_songmid的获取方式, 默认auto, 可以改成一个数字手动",
"value": "auto"
}
}
},
],
'tx': [
Expand Down
5 changes: 2 additions & 3 deletions common/lx_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from . import Httpx
from . import config
from . import scheduler
from .variable import iscn
from .log import log
from aiohttp.web import Response
import ujson as json
Expand Down Expand Up @@ -70,12 +69,12 @@ async def get_script():

async def generate_script_response(request):
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:
with open('./lx-music-source-example.js', 'r', encoding='utf-8') as f:
script = f.read()
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')
newScriptLines = []
for line in scriptLines:
Expand Down
10 changes: 7 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,14 @@ async def handle_request(request):
return handleResult({'code': 6, 'msg': '未找到您所请求的资源', 'data': None}, 404)

resp = await handler(request)
if (isinstance(resp, str)):
resp = Response(body = resp, content_type='text/plain', status = 200)
elif (isinstance(resp, (list, dict))):
if (isinstance(resp, (str, list, dict))):
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)):
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}')
Expand Down
1 change: 1 addition & 0 deletions modules/kg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .mv import getMvInfo as _getMvInfo
from .mv import getMvPlayURL as _getMvUrl
from .search import getSongSearchResult as _songsearch
from . import lite_signin
from common.exceptions import FailedException
from common import Httpx
from common import utils
Expand Down
167 changes: 167 additions & 0 deletions modules/kg/lite_signin.py
Original file line number Diff line number Diff line change
@@ -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()
2 changes: 1 addition & 1 deletion modules/kg/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async def url(songId, quality):
'album_audio_id': albumaudioid,
'behavior': 'play',
'clienttime': int(time.time()),
'pid': 2,
'pid': tools.pid,
'key': getKey(thash, user_info),
'dfid': '-',
'pidversion': 3001
Expand Down
3 changes: 2 additions & 1 deletion modules/kg/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"version": config.read_config("module.kg.tracker.version"),
"extra_params": config.read_config("module.kg.tracker.extra_params"),
"appid": config.read_config("module.kg.client.appid"),
"pid": config.read_config("module.kg.client.pid"),
'qualityHashMap': {
'128k': 'hash_128',
'320k': 'hash_320',
Expand All @@ -43,7 +44,7 @@ def buildSignatureParams(dictionary, body = ""):
joined_str = ''.join([f'{k}={v}' for k, v in dictionary.items()])
return joined_str + body

def buildRequestParams(dictionary):
def buildRequestParams(dictionary: dict):
joined_str = '&'.join([f'{k}={v}' for k, v in dictionary.items()])
return joined_str

Expand Down

0 comments on commit d1e23d9

Please sign in to comment.