🎞️ 新增 BiliBili 抢购脚本 (NobyDa)
This commit is contained in:
parent
7e0cb9b4e1
commit
bc3809055b
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
哔哩哔哩漫画签到
|
||||
|
||||
脚本兼容: QuantumultX, Surge, Loon
|
||||
电报频道:@NobyDa
|
||||
问题反馈:@NobyDa_bot
|
||||
如果转载,请注明出处
|
||||
|
||||
说明:
|
||||
打开哔哩哔哩漫画后 (AppStore中国区),单击"我的", 如果通知获取cookie成功, 则可以使用此脚本.
|
||||
|
||||
脚本将在每天上午9点执行。 您可以修改执行时间。
|
||||
|
||||
~~~~~~~~~~~~~~~~
|
||||
Surge 4.2.0+ :
|
||||
|
||||
[Script]
|
||||
Bili漫画签到 = type=cron,cronexp=0 9 * * *,wake-system=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js
|
||||
|
||||
Bili漫画Cookie = type=http-request,pattern=^https:\/\/passport\.biligame\.com\/api\/login\/sso.+?version%22%3A%22(3|4|5),script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js
|
||||
|
||||
[MITM]
|
||||
hostname = passport.biligame.com
|
||||
~~~~~~~~~~~~~~~~
|
||||
QX 1.0.10+ :
|
||||
|
||||
[task_local]
|
||||
0 9 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=Bili漫画签到
|
||||
|
||||
[rewrite_local]
|
||||
#获取Bili漫画Cookie
|
||||
^https:\/\/passport\.biligame\.com\/api\/login\/sso.+?version%22%3A%22(3|4|5) url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js
|
||||
|
||||
[mitm]
|
||||
hostname = passport.biligame.com
|
||||
~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
|
||||
const $nobyda = nobyda();
|
||||
|
||||
if ($nobyda.isRequest) {
|
||||
GetCookie()
|
||||
} else {
|
||||
checkin()
|
||||
}
|
||||
|
||||
function checkin() {
|
||||
const bilibili = {
|
||||
url: 'https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn',
|
||||
headers: {
|
||||
Cookie: $nobyda.read("CookieBM"),
|
||||
},
|
||||
body: "platform=ios"
|
||||
};
|
||||
$nobyda.post(bilibili, function (error, response, data) {
|
||||
if (!error) {
|
||||
if (parseInt(response.status) == 200) {
|
||||
console.log("bilibili success response : \n" + data)
|
||||
$nobyda.notify("哔哩哔哩漫画 - 签到成功!🎉", "", "")
|
||||
} else {
|
||||
console.log("bilibili failed response : \n" + data)
|
||||
if (data.match(/duplicate/)) {
|
||||
$nobyda.notify("哔哩哔哩漫画 - 今日已签过 ⚠️", "", "")
|
||||
} else if (data.match(/uid must/)) {
|
||||
$nobyda.notify("哔哩哔哩漫画 - Cookie无效 ‼️‼️", "", "")
|
||||
} else {
|
||||
$nobyda.notify("哔哩哔哩漫画 - 签到失败 ‼️", "", data)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$nobyda.notify("哔哩哔哩漫画 - 签到接口请求失败", "", error)
|
||||
}
|
||||
$nobyda.end()
|
||||
})
|
||||
}
|
||||
|
||||
function GetCookie() {
|
||||
var CookieName = "B站漫画";
|
||||
var CookieKey = "CookieBM";
|
||||
var regex = /SESSDATA=.+?;/;
|
||||
if ($request.headers) {
|
||||
var header = $request.headers['Cookie'] ? $request.headers['Cookie'] : "";
|
||||
if (header.indexOf("SESSDATA=") != -1) {
|
||||
var CookieValue = regex.exec(header)[0];
|
||||
if ($nobyda.read(CookieKey)) {
|
||||
if ($nobyda.read(CookieKey) != CookieValue) {
|
||||
var cookie = $nobyda.write(CookieValue, CookieKey);
|
||||
if (!cookie) {
|
||||
$nobyda.notify("更新" + CookieName + "Cookie失败‼️", "", "");
|
||||
} else {
|
||||
$nobyda.notify("更新" + CookieName + "Cookie成功 🎉", "", "");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var cookie = $nobyda.write(CookieValue, CookieKey);
|
||||
if (!cookie) {
|
||||
$nobyda.notify("首次写入" + CookieName + "Cookie失败‼️", "", "");
|
||||
} else {
|
||||
$nobyda.notify("首次写入" + CookieName + "Cookie成功 🎉", "", "");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$nobyda.notify("写入" + CookieName + "Cookie失败‼️", "", "Cookie关键值缺失");
|
||||
}
|
||||
} else {
|
||||
$nobyda.notify("写入" + CookieName + "Cookie失败‼️", "", "配置错误, 无法读取请求头,");
|
||||
}
|
||||
$nobyda.end()
|
||||
}
|
||||
|
||||
function nobyda() {
|
||||
const isRequest = typeof $request != "undefined"
|
||||
const isSurge = typeof $httpClient != "undefined"
|
||||
const isQuanX = typeof $task != "undefined"
|
||||
const notify = (title, subtitle, message) => {
|
||||
if (isQuanX) $notify(title, subtitle, message)
|
||||
if (isSurge) $notification.post(title, subtitle, message)
|
||||
}
|
||||
const write = (value, key) => {
|
||||
if (isQuanX) return $prefs.setValueForKey(value, key)
|
||||
if (isSurge) return $persistentStore.write(value, key)
|
||||
}
|
||||
const read = (key) => {
|
||||
if (isQuanX) return $prefs.valueForKey(key)
|
||||
if (isSurge) return $persistentStore.read(key)
|
||||
}
|
||||
const post = (options, callback) => {
|
||||
if (isQuanX) {
|
||||
if (typeof options == "string") options = {url: options}
|
||||
options["method"] = "POST"
|
||||
$task.fetch(options).then(response => {
|
||||
response["status"] = response.statusCode
|
||||
callback(null, response, response.body)
|
||||
}, reason => callback(reason.error, null, null))
|
||||
}
|
||||
if (isSurge) $httpClient.post(options, callback)
|
||||
}
|
||||
const end = () => {
|
||||
if (isQuanX) return $done({})
|
||||
if (isSurge) isRequest ? $done({}) : $done()
|
||||
}
|
||||
return {isRequest, isQuanX, isSurge, notify, write, read, post, end}
|
||||
};
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
哔哩哔哩漫画, 积分商城自动抢购脚本
|
||||
|
||||
脚本兼容: Surge, QuantumultX, Loon
|
||||
|
||||
*************************
|
||||
【 抢购脚本注意事项 】:
|
||||
*************************
|
||||
|
||||
该脚本需要使用签到脚本获取Cookie后方可使用.
|
||||
默认兑换积分商城中的"积分兑换", 兑换数量为用户积分可兑换的最大值 (可于BoxJs内修改)
|
||||
默认执行时间为中午12:00:10、12:00:20、12:00:30
|
||||
|
||||
BoxJs订阅地址: https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json
|
||||
|
||||
*************************
|
||||
【 Surge & Loon 脚本配置 】:
|
||||
*************************
|
||||
|
||||
[Script]
|
||||
cron "10,20,30 0 12 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, wake-system=1, timeout=60
|
||||
|
||||
*************************
|
||||
【 QX 1.0.10+ 脚本配置 】 :
|
||||
*************************
|
||||
|
||||
[task_local]
|
||||
10,20,30 0 12 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, tag=哔哩哔哩漫画抢券, enabled=true
|
||||
|
||||
*/
|
||||
|
||||
// 新建一个实例对象, 把兼容函数定义到$中, 以便统一调用
|
||||
let $ = new nobyda();
|
||||
|
||||
// 读取兑换商品名, 默认兑换积分商城中的"积分兑换"; 该接口为BoxJs预留, 以便修改
|
||||
let productName = $.read('BM_ProductName') || '积分兑换';
|
||||
|
||||
// 读取兑换数量, 默认兑换最大值; 该接口为BoxJs预留, 以便修改
|
||||
let productNum = $.read('BM_ProductNum');
|
||||
|
||||
// 读取循环抢购次数, 默认100次; 该接口为BoxJs预留, 以便修改
|
||||
let exchangeNum = $.read('BM_ExchangeNum') || '100';
|
||||
|
||||
// 读取哔哩哔哩漫画签到脚本所使用的Cookie
|
||||
let cookie = $.read('CookieBM');
|
||||
|
||||
// 预留的空对象, 便于函数之间读取数据
|
||||
let user = {};
|
||||
|
||||
(async function() { // 立即运行的匿名异步函数
|
||||
// 使用await关键字声明, 表示以同步方式执行异步函数, 可以简单理解为顺序执行
|
||||
await Promise.all([ //该方法用于将多个实例包装成一个新的实例, 可以简单理解为同时调用函数, 以进一步提高执行速度
|
||||
GetUserPoint(), //查询积分函数
|
||||
ListProduct() //查询商品函数
|
||||
]);
|
||||
await ExchangeProduct(); //上面的查询都完成后, 则执行抢购
|
||||
$.done(); //抢购完成后调用Surge、QX内部特有的函数, 用于退出脚本执行
|
||||
})();
|
||||
|
||||
function GetUserPoint() {
|
||||
const pointUrl = { //查询积分接口
|
||||
url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint',
|
||||
headers: { //请求头
|
||||
'Cookie': cookie //用户鉴权Cookie
|
||||
}
|
||||
}
|
||||
return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数
|
||||
$.post(pointUrl, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果
|
||||
try { //使用try方法捕获可能出现的代码异常
|
||||
if (error) {
|
||||
throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常
|
||||
} else {
|
||||
const body = JSON.parse(data); //解析响应体json并转化为对象
|
||||
if (body.code == 0 && body.data) { //如果响应体为预期格式
|
||||
user.point = parseInt(body.data.point); //把查询的积分赋值到全局变量user中
|
||||
console.log(`\n当前积分: ${body.data.point}`); //打印日志
|
||||
} else { //否则抛出一个异常
|
||||
throw new Error(body.msg || data);
|
||||
}
|
||||
}
|
||||
} catch (e) { //接住try代码块中抛出的异常, 并打印日志
|
||||
console.log(`\n查询积分: 失败\n出现错误: ${e.message}`);
|
||||
} finally { //finally语句在try和catch之后无论有无异常都会执行
|
||||
resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成查询积分
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function ListProduct() {
|
||||
const listUrl = { //查询商品接口
|
||||
url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct',
|
||||
headers: {}
|
||||
}
|
||||
return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数
|
||||
$.post(listUrl, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果
|
||||
try { //使用try方法捕获可能出现的代码异常
|
||||
if (error) {
|
||||
throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常
|
||||
} else {
|
||||
const body = JSON.parse(data); //解析响应体json并转化为对象
|
||||
if (body.code == 0 && body.data.length >= 1) { //如果接口正常返回商品信息
|
||||
// 按全局变量所填写的商品名进行过滤, 并把商品信息赋值到全局变量user中
|
||||
user.list = body.data.filter(t => t.title == productName).pop();
|
||||
if (!user.list) {
|
||||
throw new Error('请检查商品名'); //如果填错商品名则抛出一个异常
|
||||
} else { //否则打印日志
|
||||
console.log(`\n查询商品: ${productName}\n商品库存: ${user.list.remain_amount}`)
|
||||
}
|
||||
} else { //否则抛出一个异常
|
||||
throw new Error('无商品列表');
|
||||
}
|
||||
}
|
||||
} catch (e) { //接住try代码块中抛出的异常并打印日志
|
||||
console.log(`\n查询商品: ${productName}\n出现错误: ${e.message}`);
|
||||
} finally { //finally语句在try和catch之后无论有无异常都会执行
|
||||
resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成查询商品
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function ExchangeProduct() {
|
||||
return new Promise(async (resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数, 该实例函数带有async关键字, 表示里面有异步操作, 例如可使用await得到异步结果
|
||||
if (user.list && user.list.remain_amount && user.point >= 100) { //如果商品有库存并且用户积分大于100则进行抢购
|
||||
//兑换商品数量(用户积分 除与 商品单价得到兑换数量), 并转成整数; 默认兑换最大数量
|
||||
const num = parseInt(productNum || (user.point / user.list.real_cost));
|
||||
const exchangeUrl = {
|
||||
url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange', //兑换商品接口
|
||||
headers: { //请求头
|
||||
'Content-Type': 'application/json', //声明请求体数据格式
|
||||
'Cookie': cookie //用户鉴权Cookie
|
||||
},
|
||||
body: JSON.stringify({ //请求体转成字符串类型
|
||||
product_id: user.list.id, //兑换的商品id
|
||||
product_num: num, //兑换的商品数量
|
||||
point: num * user.list.real_cost //消耗的积分总数 (兑换数量乘单价得到积分总数)
|
||||
})
|
||||
};
|
||||
for (let i = 0; i < parseInt(exchangeNum); i++) { //根据全局变量定义的次数, 暴力循环抢购
|
||||
// 循环内调用另一个抢购函数, 并传入请求、第几次循环、兑换数量等参数,
|
||||
// 使用await关键字声明, 表示需要等待每一次的执行结果
|
||||
const run = await startExchange(exchangeUrl, i, num);
|
||||
if (run) {
|
||||
break; //如果函数返回布尔值true, 则跳出循环, 脚本结束
|
||||
}
|
||||
}
|
||||
} else { //商品无库存或用户积分小于100等情况, 则不执行抢购, 脚本结束
|
||||
console.log(`\n抢购终止: 不具备兑换条件`); //打印日志
|
||||
}
|
||||
resolve(); //将主函数的Promise对象状态标记为"成功", 表示已完成抢购任务
|
||||
})
|
||||
}
|
||||
|
||||
function startExchange(url, item, amount) {
|
||||
return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数
|
||||
$.post(url, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果
|
||||
try { //使用try方法捕获可能出现的代码异常
|
||||
if (error) {
|
||||
throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常
|
||||
} else {
|
||||
const body = JSON.parse(data); //解析响应体json并转化为对象
|
||||
if (body.code == 0) { //如果抢购成功, 则输出日志和通知
|
||||
console.log(`\n抢购成功: 第${item+1}次\n抢购数量: ${amount}\n消耗积分: ${amount * user.list.real_cost}`);
|
||||
$.notify('哔哩哔哩漫画抢券', '', `"${productName}"抢购成功, 数量: ${amount}, 消耗积分: ${amount * user.list.real_cost}`);
|
||||
resolve(true); //将Promise对象的状态标记为"成功", 然后返回一个布尔值true用于跳出循环
|
||||
} else {
|
||||
throw new Error(body.msg || '未知'); //抢购失败则抛出异常
|
||||
}
|
||||
}
|
||||
} catch (e) { //接住try代码块中抛出的异常并打印日志
|
||||
console.log(`\n抢购失败: 第${item+1}次\n失败原因: ${e.message}`);
|
||||
resolve(); //将Promise对象的状态标记为"成功", 但不返回任何值, 表示继续循环抢购
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function nobyda() {
|
||||
const isSurge = typeof $httpClient != "undefined";
|
||||
const isQuanX = typeof $task != "undefined";
|
||||
const isNode = typeof require == "function";
|
||||
const node = (() => {
|
||||
if (isNode) {
|
||||
const request = require('request');
|
||||
return {
|
||||
request
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})()
|
||||
const adapterStatus = (response) => {
|
||||
if (response) {
|
||||
if (response.status) {
|
||||
response["statusCode"] = response.status
|
||||
} else if (response.statusCode) {
|
||||
response["status"] = response.statusCode
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
this.read = (key) => {
|
||||
if (isQuanX) return $prefs.valueForKey(key)
|
||||
if (isSurge) return $persistentStore.read(key)
|
||||
}
|
||||
this.notify = (title, subtitle, message) => {
|
||||
if (isQuanX) $notify(title, subtitle, message)
|
||||
if (isSurge) $notification.post(title, subtitle, message)
|
||||
if (isNode) console.log(`${title}\n${subtitle}\n${message}`)
|
||||
}
|
||||
this.post = (options, callback) => {
|
||||
options.headers['User-Agent'] = 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/609.3.5.0.2 (KHTML, like Gecko) Mobile/17G80 BiliApp/822 mobi_app/ios_comic channel/AppStore BiliComic/822'
|
||||
if (isQuanX) {
|
||||
if (typeof options == "string") options = {
|
||||
url: options
|
||||
}
|
||||
options["method"] = "POST"
|
||||
$task.fetch(options).then(response => {
|
||||
callback(null, adapterStatus(response), response.body)
|
||||
}, reason => callback(reason.error, null, null))
|
||||
}
|
||||
if (isSurge) {
|
||||
options.headers['X-Surge-Skip-Scripting'] = false
|
||||
$httpClient.post(options, (error, response, body) => {
|
||||
callback(error, adapterStatus(response), body)
|
||||
})
|
||||
}
|
||||
if (isNode) {
|
||||
node.request.post(options, (error, response, body) => {
|
||||
callback(error, adapterStatus(response), body)
|
||||
})
|
||||
}
|
||||
}
|
||||
this.done = () => {
|
||||
if (isQuanX || isSurge) {
|
||||
$done()
|
||||
}
|
||||
}
|
||||
};
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue