feat: 账号池功能 & feat: 优化黑名单检查性能 & feat: scheduler支持传参

This commit is contained in:
helloplhm-qwq
2024-01-05 17:18:33 +08:00
parent ef4b4bfa24
commit c08b45586c
11 changed files with 242 additions and 60 deletions

View File

@ -65,6 +65,8 @@ default = {
"_proxy-desc": "代理配置HTTP与HTTPS协议需分开配置", "_proxy-desc": "代理配置HTTP与HTTPS协议需分开配置",
"log_file": True, "log_file": True,
"_log_file-desc": "是否开启日志文件", "_log_file-desc": "是否开启日志文件",
'cookiepool': False,
'_cookiepool-desc': '是否开启cookie池这将允许用户配置多个cookie并在请求时随机使用一个启用后请在module.cookiepool中配置cookie在user处配置的cookie会被忽略cookiepool中格式统一为列表嵌套user处的cookie的字典',
"allow_download_script": True, "allow_download_script": True,
'_allow_download_script-desc': '是否允许直接从服务端下载脚本,开启后可以直接访问 /script?key=你的请求key 下载脚本', '_allow_download_script-desc': '是否允许直接从服务端下载脚本,开启后可以直接访问 /script?key=你的请求key 下载脚本',
"download_config": { "download_config": {
@ -174,15 +176,15 @@ default = {
"desc": "用户数据可以通过浏览器获取需要vip账号来获取会员歌曲如果没有请留为空值qqmusic_key可以从Cookie中/客户端的请求体中comm.authst获取", "desc": "用户数据可以通过浏览器获取需要vip账号来获取会员歌曲如果没有请留为空值qqmusic_key可以从Cookie中/客户端的请求体中comm.authst获取",
"qqmusic_key": "", "qqmusic_key": "",
"uin": "", "uin": "",
"_uin-desc": "key对应的QQ号" "_uin-desc": "key对应的QQ号",
},
"cdnaddr": "http://ws.stream.qqmusic.qq.com/",
'refresh_login': { 'refresh_login': {
'desc': '刷新登录相关配置enable是否启动interval刷新间隔', 'desc': '刷新登录相关配置enable是否启动interval刷新间隔',
'enable': False, 'enable': False,
'interval': 86000 'interval': 86000
} }
}, },
"cdnaddr": "http://ws.stream.qqmusic.qq.com/",
},
"wy": { "wy": {
"desc": "网易云音乐相关配置", "desc": "网易云音乐相关配置",
"user": { "user": {
@ -200,6 +202,39 @@ default = {
"useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36", "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36",
}, },
}, },
'cookiepool': {
'kg': [
{
'userid': '0',
'token': '',
'mid': '114514',
},
],
'tx': [
{
'qqmusic_key': '',
'uin': '',
'refresh_login': {
'desc': 'cookie池中对于此账号刷新登录的配置账号间互不干扰',
'enable': False,
'interval': 86000,
}
}
],
'wy': [
{
'cookie': '',
}
],
'mg': [
{
'aversionid': '',
'token': '',
'osversion': '10',
'useragent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
}
],
},
}, },
} }
@ -413,7 +448,7 @@ def write_config(key, value):
current[keys[-1]] = value current[keys[-1]] = value
variable.config = config variable.config = config
with open('config.json', 'w', encoding='utf-8') as f: with open('config.json', 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False) json.dump(config, f, indent=2, ensure_ascii=False, escape_forward_slashes=False)
f.close() f.close()
def read_default_config(key): def read_default_config(key):
@ -511,7 +546,7 @@ def initConfig():
logger.warning('配置文件并不是一个有效的字典,使用默认值') logger.warning('配置文件并不是一个有效的字典,使用默认值')
variable.config = default variable.config = default
with open("./config.json", "w", encoding="utf-8") as f: with open("./config.json", "w", encoding="utf-8") as f:
f.write(json.dumps(variable.config, indent=2, ensure_ascii=False)) f.write(json.dumps(variable.config, indent=2, ensure_ascii=False, escape_forward_slashes=False))
f.close() f.close()
except: except:
if os.path.getsize("./config.json") != 0: if os.path.getsize("./config.json") != 0:
@ -552,11 +587,17 @@ value TEXT)''')
logger.debug('数据库初始化成功') logger.debug('数据库初始化成功')
# print # handle data
if (load_data() == {}): all_data_keys = {'banList': [], 'requestTime': {}, 'banListRaw': []}
data = load_data()
if (data == {}):
write_data('banList', []) write_data('banList', [])
write_data('requestTime', {}) write_data('requestTime', {})
logger.info('数据库内容为空,已写入默认值') logger.info('数据库内容为空,已写入默认值')
for k, v in all_data_keys.items():
if (k not in data):
write_data(k, v)
logger.info(f'数据库中不存在{k},已创建')
# 处理代理配置 # 处理代理配置
if (read_config('common.proxy.enable')): if (read_config('common.proxy.enable')):
@ -568,6 +609,36 @@ value TEXT)''')
logger.info('HTTPS协议代理地址: ' + read_config('common.proxy.https_value')) logger.info('HTTPS协议代理地址: ' + read_config('common.proxy.https_value'))
logger.info('代理功能已开启,请确保代理地址正确,否则无法连接网络') logger.info('代理功能已开启,请确保代理地址正确,否则无法连接网络')
# cookie池
if (read_config('common.cookiepool')):
logger.info('已启用cookie池功能请确定配置的cookie都能正确获取链接')
logger.info('传统的源 - 单用户cookie配置将被忽略')
logger.info('所以即使某个源你只有一个cookie也请填写到cookiepool对应的源中否则将无法使用该cookie')
variable.use_cookie_pool = True
# 移除已经过期的封禁数据
banlist = read_data('banList')
banlistRaw = read_data('banListRaw')
count = 0
for b in banlist:
if (b['expire'] and (time.time() > b['expire_time'])):
count += 1
banlist.remove(b)
if (b['ip'] in banlistRaw):
banlistRaw.remove(b['ip'])
write_data('banList', banlist)
write_data('banListRaw', banlistRaw)
if (count != 0):
logger.info(f'已移除{count}条过期封禁数据')
# 处理旧版数据库的banListRaw
banlist = read_data('banList')
banlistRaw = read_data('banListRaw')
if (banlist != [] and banlistRaw == []):
for b in banlist:
banlistRaw.append(b['ip'])
return
def ban_ip(ip_addr, ban_time=-1): def ban_ip(ip_addr, ban_time=-1):
if read_config('security.banlist.enable'): if read_config('security.banlist.enable'):
banList = read_data('banList') banList = read_data('banList')
@ -586,13 +657,17 @@ def ban_ip(ip_addr, ban_time=-1):
def check_ip_banned(ip_addr): def check_ip_banned(ip_addr):
if read_config('security.banlist.enable'): if read_config('security.banlist.enable'):
banList = read_data('banList') banList = read_data('banList')
for ban in banList: banlistRaw = read_data('banListRaw')
if (ban['ip'] == ip_addr): if (ip_addr in banlistRaw):
if (ban['expire']): for b in banList:
if (ban['expire_time'] > int(time.time())): if (b['ip'] == ip_addr):
if (b['expire']):
if (b['expire_time'] > int(time.time())):
return True return True
else: else:
banList.remove(ban) banList.remove(b)
banlistRaw.remove(b['ip'])
write_data('banListRaw', banlistRaw)
write_data('banList', banList) write_data('banList', banList)
return False return False
else: else:
@ -600,6 +675,8 @@ def check_ip_banned(ip_addr):
else: else:
return False return False
return False return False
else:
return False
else: else:
if (variable.banList_suggest <= 10): if (variable.banList_suggest <= 10):
variable.banList_suggest += 1 variable.banList_suggest += 1

View File

@ -20,7 +20,7 @@ logger = log('lx_script')
async def get_response(retry = 0): async def get_response(retry = 0):
if (retry > 10): if (retry > 10):
raise Exception('请求源脚本内容失败') logger.warning('请求源脚本内容失败')
baseurl = 'https://raw.githubusercontent.com/lxmusics/lx-music-api-server/main/lx-music-source-example.js' baseurl = 'https://raw.githubusercontent.com/lxmusics/lx-music-api-server/main/lx-music-source-example.js'
try: try:
if (iscn and (retry % 2) == 0): if (iscn and (retry % 2) == 0):
@ -39,7 +39,7 @@ async def get_script():
f.close() f.close()
logger.info('更新源脚本成功') logger.info('更新源脚本成功')
else: else:
raise Exception('请求源脚本内容失败') logger.warning('请求源脚本内容失败')
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')):

View File

@ -21,11 +21,12 @@ global tasks
tasks = [] tasks = []
class taskWrapper: class taskWrapper:
def __init__(self, name, function, interval = 86400, latest_execute = 0): def __init__(self, name, function, interval = 86400, args = {}, latest_execute = 0):
self.function = function self.function = function
self.interval = interval self.interval = interval
self.name = name self.name = name
self.latest_execute = latest_execute self.latest_execute = latest_execute
self.args = args
def check_available(self): def check_available(self):
return (time.time() - self.latest_execute) >= self.interval return (time.time() - self.latest_execute) >= self.interval
@ -33,16 +34,16 @@ class taskWrapper:
async def run(self): async def run(self):
try: try:
logger.info(f"task {self.name} run start") logger.info(f"task {self.name} run start")
await self.function() await self.function(**self.args)
logger.info(f'task {self.name} run success, next execute: {timestamp_format(self.interval + self.latest_execute)}') logger.info(f'task {self.name} run success, next execute: {timestamp_format(self.interval + self.latest_execute)}')
except Exception as e: except Exception as e:
logger.error(f"task {self.name} run failed, waiting for next execute...") logger.error(f"task {self.name} run failed, waiting for next execute...")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
def append(name, task, interval = 86400): def append(name, task, interval = 86400, args = {}):
global tasks global tasks
wrapper = taskWrapper(name, task, interval, args)
logger.debug(f"new task ({name}) registered") logger.debug(f"new task ({name}) registered")
wrapper = taskWrapper(name, task, interval)
return tasks.append(wrapper) return tasks.append(wrapper)
# 在 thread_runner 函数中修改循环逻辑 # 在 thread_runner 函数中修改循环逻辑
@ -51,7 +52,7 @@ async def thread_runner():
while not running_event.is_set(): while not running_event.is_set():
tasks_runner = [] tasks_runner = []
for t in tasks: for t in tasks:
if t.check_available() and not running_event.is_set(): if (t.check_available() and not running_event.is_set()):
t.latest_execute = int(time.time()) t.latest_execute = int(time.time())
tasks_runner.append(t.run()) tasks_runner.append(t.run())
if (tasks_runner): if (tasks_runner):

View File

@ -50,3 +50,4 @@ iscn = True
fake_ip = None fake_ip = None
aioSession = None aioSession = None
qdes_lib_loaded = False qdes_lib_loaded = False
use_cookie_pool = False

View File

@ -6,8 +6,9 @@
# - license: MIT - # - license: MIT -
# ---------------------------------------- # ----------------------------------------
# This file is part of the "lx-music-api-server" project. # This file is part of the "lx-music-api-server" project.
import random
from common.exceptions import FailedException from common.exceptions import FailedException
from common import utils from common import config, utils, variable
from .utils import getKey, signRequest, tools from .utils import getKey, signRequest, tools
from .musicInfo import getMusicInfo from .musicInfo import getMusicInfo
import time import time
@ -25,20 +26,21 @@ async def url(songId, quality):
if (not albumaudioid): if (not albumaudioid):
albumaudioid = "" albumaudioid = ""
thash = thash.lower() thash = thash.lower()
user_info = config.read_config('module.kg.user') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.kg'))
params = { params = {
'album_id': albumid, 'album_id': albumid,
'userid': tools.userid, 'userid': user_info['userid'],
'area_code': 1, 'area_code': 1,
'hash': thash, 'hash': thash,
'module': '', 'module': '',
'mid': tools.mid, 'mid': user_info['mid'],
'appid': tools.appid, 'appid': tools.appid,
'ssa_flag': 'is_fromtrack', 'ssa_flag': 'is_fromtrack',
'clientver': tools.clientver, 'clientver': tools.clientver,
'open_time': time.strftime("%Y%m%d"), 'open_time': time.strftime("%Y%m%d"),
'vipType': 6, 'vipType': 6,
'ptype': 0, 'ptype': 0,
'token': tools.token, 'token': user_info['token'],
'auth': '', 'auth': '',
'mtype': 0, 'mtype': 0,
'album_audio_id': albumaudioid, 'album_audio_id': albumaudioid,

View File

@ -21,9 +21,6 @@ tools = createObject({
"x-router": config.read_config("module.kg.tracker.x-router"), "x-router": config.read_config("module.kg.tracker.x-router"),
"url": config.read_config("module.kg.tracker.host") + config.read_config("module.kg.tracker.path"), "url": config.read_config("module.kg.tracker.host") + config.read_config("module.kg.tracker.path"),
"version": config.read_config("module.kg.tracker.version"), "version": config.read_config("module.kg.tracker.version"),
"userid": config.read_config("module.kg.user.userid"),
"token": config.read_config("module.kg.user.token"),
"mid": config.read_config("module.kg.user.mid"),
"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"),
'qualityHashMap': { 'qualityHashMap': {

View File

@ -7,8 +7,10 @@
# ---------------------------------------- # ----------------------------------------
# This file is part of the "lx-music-api-server" project. # This file is part of the "lx-music-api-server" project.
import random
from common import Httpx from common import Httpx
from common import config from common import config
from common import variable
from common.exceptions import FailedException from common.exceptions import FailedException
tools = { tools = {
@ -25,24 +27,21 @@ tools = {
'SQ': 'flac', 'SQ': 'flac',
'ZQ': 'flac24bit', 'ZQ': 'flac24bit',
}, },
'token': config.read_config('module.mg.user.token'),
'aversionid': config.read_config('module.mg.user.aversionid'),
'useragent': config.read_config('module.mg.user.useragent'),
'osversion': config.read_config('module.mg.user.osversion'),
} }
async def url(songId, quality): async def url(songId, quality):
user_info = config.read_config('module.mg.user') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.mg'))
req = await Httpx.AsyncRequest(tools['url'].replace('__quality__', tools['qualityMap'][quality]).replace('__songId__', songId), { req = await Httpx.AsyncRequest(tools['url'].replace('__quality__', tools['qualityMap'][quality]).replace('__songId__', songId), {
'method': 'GET', 'method': 'GET',
'headers': { 'headers': {
'User-Agent': tools['useragent'], 'User-Agent': user_info['useragent'],
'aversionid': tools['aversionid'], 'aversionid': user_info['aversionid'],
'token': tools['token'], 'token': user_info['token'],
'channel': '0146832', 'channel': '0146832',
'language': 'Chinese', 'language': 'Chinese',
'ua': 'Android_migu', 'ua': 'Android_migu',
'mode': 'android', 'mode': 'android',
'os': 'Android ' + tools['osversion'], 'os': 'Android ' + user_info['osversion'],
}, },
}) })
try: try:

View File

@ -8,33 +8,35 @@
# This file is part of the "lx-music-api-server" project. # This file is part of the "lx-music-api-server" project.
from common.exceptions import FailedException from common.exceptions import FailedException
from common import config, utils from common import config, utils, variable
from .musicInfo import getMusicInfo from .musicInfo import getMusicInfo
from .utils import tools from .utils import tools
from .utils import signRequest from .utils import signRequest
import random
createObject = utils.CreateObject createObject = utils.CreateObject
async def url(songId, quality): async def url(songId, quality):
infoBody = await getMusicInfo(songId) infoBody = await getMusicInfo(songId)
strMediaMid = infoBody['track_info']['file']['media_mid'] strMediaMid = infoBody['track_info']['file']['media_mid']
user_info = config.read_config('module.tx.user') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.tx'))
requestBody = { requestBody = {
'req_0': { 'req_0': {
'module': 'vkey.GetVkeyServer', 'module': 'vkey.GetVkeyServer',
'method': 'CgiGetVkey', 'method': 'CgiGetVkey',
'param': { 'param': {
'filename': [f"{tools.fileInfo[quality]['h']}{strMediaMid}{tools.fileInfo[quality]['e']}"], 'filename': [f"{tools.fileInfo[quality]['h']}{strMediaMid}{tools.fileInfo[quality]['e']}"],
'guid': tools.guid, 'guid': user_info['guid'],
'songmid': [songId], 'songmid': [songId],
'songtype': [0], 'songtype': [0],
'uin': tools.uin, 'uin': user_info['uin'],
'loginflag': 1, 'loginflag': 1,
'platform': '20', 'platform': '20',
}, },
}, },
'comm': { 'comm': {
"qq": config.read_config('module.tx.user.uin'), "qq": user_info['uin'],
"authst": config.read_config('module.tx.user.qqmusic_key'), "authst": user_info['qqmusic_key'],
"ct": "26", "ct": "26",
"cv": "2010101", "cv": "2010101",
"v": "2010101" "v": "2010101"

View File

@ -7,7 +7,7 @@
# ---------------------------------------- # ----------------------------------------
# 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 from common import Httpx, variable
from common import scheduler from common import scheduler
from common import config from common import config
from common import log from common import log
@ -16,10 +16,11 @@ import ujson as json
logger = log.log('qqmusic_refresh_login') logger = log.log('qqmusic_refresh_login')
async def refresh(): async def refresh():
if (not config.read_config('module.tx.user.qqmusic_key')): if (not config.read_config('module.tx.user.qqmusic_key')):
return return
if (not config.read_config('module.tx.refresh_login.enable')): if (not config.read_config('module.tx.user.refresh_login.enable')):
return return
if (config.read_config('module.tx.user.qqmusic_key').startswith('W_X')): if (config.read_config('module.tx.user.qqmusic_key').startswith('W_X')):
options = { options = {
@ -100,6 +101,110 @@ async def refresh():
else: else:
logger.error('未知的qqmusic_key格式') logger.error('未知的qqmusic_key格式')
if (config.read_config('module.tx.refresh_login.enable')): if (config.read_config('module.tx.refresh_login.enable') and not variable.use_cookie_pool):
# changed refresh login config path
txconfig = config.read_config('module.tx')
refresh_login_info = txconfig['refresh_login']
txconfig['user']['refresh_login'] = refresh_login_info
txconfig.pop('refresh_login')
config.write_config('module.tx', txconfig)
scheduler.append('qqmusic_refresh_login', refresh, scheduler.append('qqmusic_refresh_login', refresh,
config.read_config('module.tx.refresh_login.interval')) config.read_config('module.tx.user.refresh_login.interval'))
async def refresh_login_for_pool(user_info):
if (user_info['qqmusic_key'].startswith('W_X')):
options = {
'method': 'POST',
'body': json.dumps({
"comm": {
"fPersonality": "0",
"tmeLoginType": "1",
"tmeLoginMethod": "1",
"qq": "",
"authst": "",
"ct": "11",
"cv": "12080008",
"v": "12080008",
"tmeAppID": "qqmusic"
},
"req1": {
"module": "music.login.LoginServer",
"method": "Login",
"param": {
"code": "",
"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'] = 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(
f'为QQ音乐账号({user_info["uin"]})刷新登录失败, code: ' + str(body['req1']['code']) + f'\n响应体: {body}')
return
else:
logger.info(f'为QQ音乐账号(QQ_{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'] = body['req1']['data']['musicid']
config.write_config('module.cookiepool.tx', user_list)
logger.info(f'为QQ音乐账号(QQ_{user_info["uin"]})数据更新完毕')
return
else:
logger.warning(f'为QQ音乐账号({user_info["uin"]})刷新登录失败: 未知或不支持的key类型')
return
def reg_refresh_login_pool_task():
user_info_pool = config.read_config('module.cookiepool.tx')
for user_info in user_info_pool:
if (user_info['refresh_login'].get('enable')):
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):
reg_refresh_login_pool_task()

View File

@ -50,8 +50,6 @@ tools = createObject({
'Q000': 'dolby', 'Q000': 'dolby',
'AI00': 'master' 'AI00': 'master'
}, },
"loginuin": config.read_config("module.tx.user.uin"),
"guid": config.read_config("module.tx.vkeyserver.guid"),
"cdnaddr": config.read_config("module.tx.cdnaddr") if config.read_config("module.tx.cdnaddr") else 'http://ws.stream.qqmusic.qq.com/', "cdnaddr": config.read_config("module.tx.cdnaddr") if config.read_config("module.tx.cdnaddr") else 'http://ws.stream.qqmusic.qq.com/',
}) })

View File

@ -7,7 +7,8 @@
# ---------------------------------------- # ----------------------------------------
# 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 import random
from common import Httpx, variable
from common import config from common import config
from common.exceptions import FailedException from common.exceptions import FailedException
from .encrypt import eapiEncrypt from .encrypt import eapiEncrypt
@ -32,7 +33,6 @@ tools = {
"jysky": "sky", "jysky": "sky",
"jymaster": "master", "jymaster": "master",
}, },
'cookie': config.read_config('module.wy.user.cookie'),
} }
async def url(songId, quality): async def url(songId, quality):
@ -41,7 +41,7 @@ async def url(songId, quality):
req = await Httpx.AsyncRequest(requestUrl, { req = await Httpx.AsyncRequest(requestUrl, {
'method': 'POST', 'method': 'POST',
'headers': { 'headers': {
'Cookie': tools['cookie'], 'Cookie': config.read_config('module.wy.cookie') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.wy')),
}, },
'form': eapiEncrypt(path, json.dumps({ 'form': eapiEncrypt(path, json.dumps({
"ids": json.dumps([songId]), "ids": json.dumps([songId]),