feat: 刷新失活 qqmusic_key

This commit is contained in:
Luren 2025-03-27 04:38:10 +00:00
parent e13b7e3831
commit 77737d18e6
2 changed files with 137 additions and 189 deletions

View File

@ -133,6 +133,7 @@ module:
user: # 用户数据可以通过浏览器获取需要vip账号来获取会员歌曲如果没有请留为空值qqmusic_key可以从Cookie中/客户端的请求体中comm.authst获取 user: # 用户数据可以通过浏览器获取需要vip账号来获取会员歌曲如果没有请留为空值qqmusic_key可以从Cookie中/客户端的请求体中comm.authst获取
qqmusic_key: "" qqmusic_key: ""
uin: "" # key对应的QQ号 uin: "" # key对应的QQ号
refresh_key: "" # 刷新失活 qqmusic_key
refresh_login: # 刷新登录相关配置enable是否启动interval刷新间隔 refresh_login: # 刷新登录相关配置enable是否启动interval刷新间隔
enable: false enable: false
interval: 86000 interval: 86000
@ -209,6 +210,7 @@ module:
tx: tx:
- qqmusic_key: "" - qqmusic_key: ""
uin: "" uin: ""
refresh_key: ""
refresh_login: # cookie池中对于此账号刷新登录的配置账号间互不干扰 refresh_login: # cookie池中对于此账号刷新登录的配置账号间互不干扰
enable: false enable: false
interval: 86000 interval: 86000

View File

@ -7,206 +7,152 @@
# ---------------------------------------- # ----------------------------------------
# This file is part of the "lx-music-api-server" project. # This file is part of the "lx-music-api-server" project.
from common import Httpx, variable from common import Httpx, variable, scheduler, config, log
from common import scheduler
from common import config
from common import log
from .utils import sign from .utils import sign
import ujson as json import ujson as json
from typing import Dict, Any, Optional
logger = log.log('qqmusic_refresh_login') logger = log.log("qqmusic_refresh_login")
async def refresh(): def _build_request_body(user_info: Dict[str, Any]) -> Dict[str, Any]:
if (not config.read_config('module.tx.user.qqmusic_key')): """构建统一请求体结构"""
return return {
if (not config.read_config('module.tx.user.refresh_login.enable')): "comm": {
return "fPersonality": "0",
print(config.read_config('module.tx.user.qqmusic_key')) "tmeLoginType": "2"
if (config.read_config('module.tx.user.qqmusic_key').startswith('W_X')): if user_info["qqmusic_key"].startswith("Q_H_L")
options = { else "1",
'method': 'POST', "qq": str(user_info["uin"]),
'body': json.dumps({ "authst": user_info["qqmusic_key"],
"comm": { "ct": "11",
"fPersonality": "0", "cv": "12080008",
"tmeLoginType": "1", "v": "12080008",
"tmeLoginMethod": "1", "tmeAppID": "qqmusic",
"qq": "", },
"authst": "", "req1": {
"ct": "11", "module": "music.login.LoginServer",
"cv": "12080008", "method": "Login",
"v": "12080008", "param": {
"tmeAppID": "qqmusic" "str_musicid": str(user_info["uin"]),
}, "musickey": user_info["qqmusic_key"],
"req1": { "refresh_key": user_info.get("refresh_key", ""),
"module": "music.login.LoginServer", },
"method": "Login", },
"param": { }
"code": "",
"openid": "",
"refresh_token": "", async def _update_user_config(
"str_musicid": str(config.read_config('module.tx.user.uin')), user_info: Dict[str, Any], new_data: Dict[str, Any]
"musickey": config.read_config('module.tx.user.qqmusic_key'), ) -> None:
"unionid": "", """统一更新用户配置"""
"refresh_key": "", updates = {
"loginMode": 2 "uin": str(new_data.get("musicid", user_info["uin"])),
} "qqmusic_key": new_data.get("musickey", user_info["qqmusic_key"]),
} "refresh_key": new_data.get("refresh_key", user_info.get("refresh_key", "")),
}) }
}
signature = sign(options['body']) if variable.use_cookie_pool:
req = await Httpx.AsyncRequest(f'https://u.y.qq.com/cgi-bin/musics.fcg?sign={signature}', options) user_list = config.read_config("module.cookiepool.tx")
body = req.json() target_user = next((u for u in user_list if u["uin"] == user_info["uin"]), None)
if (body['req1']['code'] != 0): if target_user:
logger.warning('刷新登录失败, code: ' + target_user.update(updates)
str(body['req1']['code']) + f'\n响应体: {body}') config.write_config("module.cookiepool.tx", user_list)
return
else:
logger.info('刷新登录成功')
config.write_config('module.tx.user.uin',
str(body['req1']['data']['musicid']))
logger.info('已通过相应数据更新uin')
config.write_config('module.tx.user.qqmusic_key',
body['req1']['data']['musickey'])
logger.info('已通过相应数据更新qqmusic_key')
elif (config.read_config('module.tx.user.qqmusic_key').startswith('Q_H_L')):
options = {
'method': 'POST',
'body': json.dumps({
'req1': {
'module': 'QQConnectLogin.LoginServer',
'method': 'QQLogin',
'param': {
'expired_in': 7776000,
'musicid': int(config.read_config('module.tx.user.uin')),
'musickey': config.read_config('module.tx.user.qqmusic_key')
}
}
})
}
signature = sign(options['body'])
req = await Httpx.AsyncRequest(f'https://u6.y.qq.com/cgi-bin/musics.fcg?sign={signature}', options)
body = req.json()
if (body['req1']['code'] != 0):
logger.warning('刷新登录失败, code: ' +
str(body['req1']['code']) + f'\n响应体: {body}')
return
else:
logger.info('刷新登录成功')
config.write_config('module.tx.user.uin',
str(body['req1']['data']['musicid']))
logger.info('已通过相应数据更新uin')
config.write_config('module.tx.user.qqmusic_key',
body['req1']['data']['musickey'])
logger.info('已通过相应数据更新qqmusic_key')
else: else:
logger.error('未知的qqmusic_key格式') for key, value in updates.items():
config.write_config(f"module.tx.user.{key}", value)
if (not variable.use_cookie_pool):
# changed refresh login config path
txconfig = config.read_config('module.tx')
refresh_login_info = txconfig.get('refresh_login')
if (refresh_login_info):
txconfig['user']['refresh_login'] = refresh_login_info
txconfig.pop('refresh_login')
config.write_config('module.tx', txconfig)
if (config.read_config('module.tx.user.refresh_login.enable') and not variable.use_cookie_pool): async def _process_refresh(user_info: Dict[str, Any]) -> Optional[bool]:
scheduler.append('qqmusic_refresh_login', refresh, """统一处理刷新逻辑"""
config.read_config('module.tx.user.refresh_login.interval')) try:
# 构建请求参数
request_body = _build_request_body(user_info)
signature = sign(json.dumps(request_body))
async def refresh_login_for_pool(user_info): # 发送请求
if (user_info['qqmusic_key'].startswith('W_X')): response = await Httpx.AsyncRequest(
options = { f"https://u.y.qq.com/cgi-bin/musics.fcg?sign={signature}",
'method': 'POST', {
'body': json.dumps({ "method": "POST",
"comm": { "body": json.dumps(request_body),
"fPersonality": "0", "headers": {
"tmeLoginType": "1", "Content-Type": "application/json",
"tmeLoginMethod": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"qq": "",
"authst": "",
"ct": "11",
"cv": "12080008",
"v": "12080008",
"tmeAppID": "qqmusic"
}, },
"req1": { },
"module": "music.login.LoginServer", )
"method": "Login",
"param": { response_data = response.json()
"code": "", if response_data.get("req1", {}).get("code") != 0:
"openid": "",
"refresh_token": "",
"str_musicid": str(user_info['uin']),
"musickey": user_info['qqmusic_key'],
"unionid": "",
"refresh_key": "",
"loginMode": 2
}
}
})
}
signature = sign(options['body'])
req = await Httpx.AsyncRequest(f'https://u.y.qq.com/cgi-bin/musics.fcg?sign={signature}', options)
body = req.json()
if (body['req1']['code'] != 0):
logger.warning(f'为QQ音乐账号({user_info["uin"]})刷新登录失败, code: ' +
str(body['req1']['code']) + f'\n响应体: {body}')
return
else:
logger.info(f'为QQ音乐账号(WeChat_{user_info["uin"]})刷新登录成功')
user_list = config.read_config('module.cookiepool.tx')
user_list[user_list.index(
user_info)]['qqmusic_key'] = body['req1']['data']['musickey']
user_list[user_list.index(
user_info)]['uin'] = str(body['req1']['data']['musicid'])
config.write_config('module.cookiepool.tx', user_list)
logger.info(f'为QQ音乐账号(WeChat_{user_info["uin"]})数据更新完毕')
return
elif (user_info['qqmusic_key'].startswith('Q_H_L')):
options = {
'method': 'POST',
'body': json.dumps({
'req1': {
'module': 'QQConnectLogin.LoginServer',
'method': 'QQLogin',
'param': {
'expired_in': 7776000,
'musicid': int(user_info['uin']),
'musickey': user_info['qqmusic_key']
}
}
})
}
signature = sign(options['body'])
req = await Httpx.AsyncRequest(f'https://u6.y.qq.com/cgi-bin/musics.fcg?sign={signature}', options)
body = req.json()
if (body['req1']['code'] != 0):
logger.warning( logger.warning(
f'为QQ音乐账号({user_info["uin"]})刷新登录失败, code: ' + str(body['req1']['code']) + f'\n响应体: {body}') f"刷新失败 [账号: {user_info['uin']} 代码: {response_data['req1']['code']}]"
return )
else: return False
logger.info(f'为QQ音乐账号(QQ_{user_info["uin"]})刷新登录成功')
user_list = config.read_config('module.cookiepool.tx') # 更新配置
user_list[user_list.index( await _update_user_config(user_info, response_data["req1"]["data"])
user_info)]['qqmusic_key'] = body['req1']['data']['musickey'] logger.info(f"刷新成功 [账号: {user_info['uin']}]")
user_list[user_list.index( return True
user_info)]['uin'] = str(body['req1']['data']['musicid'])
config.write_config('module.cookiepool.tx', user_list) except json.JSONDecodeError:
logger.info(f'为QQ音乐账号(QQ_{user_info["uin"]})数据更新完毕') logger.error(
return "响应解析失败 [账号: %s] 原始响应: %s",
else: user_info["uin"],
logger.warning(f'为QQ音乐账号({user_info["uin"]})刷新登录失败: 未知或不支持的key类型') response.text[:100],
)
except KeyError as e:
logger.error(
"响应数据格式异常 [账号: %s] 缺失字段: %s", user_info["uin"], str(e)
)
except Exception as e:
logger.error(
"刷新过程异常 [账号: %s] 错误信息: %s",
user_info["uin"],
str(e),
exc_info=True,
)
return False
async def refresh() -> None:
"""主刷新入口非Cookie池模式"""
if not config.read_config("module.tx.user.refresh_login.enable"):
return return
await _process_refresh(
def reg_refresh_login_pool_task(): {
user_info_pool = config.read_config('module.cookiepool.tx') "uin": config.read_config("module.tx.user.uin"),
for user_info in user_info_pool: "qqmusic_key": config.read_config("module.tx.user.qqmusic_key"),
if (user_info['refresh_login'].get('enable')): "refresh_key": config.read_config("module.tx.user.refresh_key"),
scheduler.append( }
f'qqmusic_refresh_login_pooled_{user_info["uin"]}', refresh_login_for_pool, user_info['refresh_login']['interval'], args = {'user_info': user_info}) )
if (variable.use_cookie_pool): async def refresh_login_for_pool(user_info: Dict[str, Any]) -> None:
reg_refresh_login_pool_task() """Cookie池刷新入口"""
if user_info.get("refresh_login", {}).get("enable", False):
await _process_refresh(user_info)
def _setup_scheduler() -> None:
"""初始化定时任务"""
if variable.use_cookie_pool:
user_list = config.read_config("module.cookiepool.tx")
for user in user_list:
if user.get("refresh_login", {}).get("enable", False):
scheduler.append(
f"qq_refresh_{user['uin']}",
refresh_login_for_pool,
user["refresh_login"].get("interval", 3600),
args={"user_info": user},
)
elif config.read_config("module.tx.user.refresh_login.enable"):
scheduler.append(
"qqmusic_main_refresh",
refresh,
config.read_config("module.tx.user.refresh_login.interval"),
)
# 初始化定时任务
_setup_scheduler()