"),
msg = $("
"),
myDate = new Date();
msg.html(text);
div.text(myDate.toLocaleString());
div.append(msg);
switch (_type) {
case 'warning':
div.addClass('chatLogWarning')
break;
case 'success':
div.addClass('chatLogSuccess')
break;
case 'error':
div.addClass('chatLogError')
break;
case 'prize':
div.addClass('chatLogWinPrize')
break;
default:
div.addClass('chatLogDefault')
};
JQmenuWindow.append(div);
if (layerLogWindow_ScrollY >= layerLogWindow_ScrollHeight)
layerLogWindow.scrollTop(layerLogWindow.prop("scrollHeight"));
},
GroupSign: {
fullLevalMedalUidList: [],
getGroups: () => {
//获取应援团列表
return BAPI.Group.my_groups().then((response) => {
MYDEBUG('GroupSign.getGroups: API.Group.my_groups', response);
if (response.code === 0) return $.Deferred().resolve(response.data.list);
else {
window.toast(`[自动应援团签到]获取应援团列表失败 ${response.msg}`, 'error');
return delayCall(() => MY_API.GroupSign.getGroups());
}
});
},
signInList: (list, i = 0) => {
// 应援团签到
if (i >= list.length) return $.Deferred().resolve();
const obj = list[i];
// 自己不能给自己的应援团应援,不给20或40级粉丝牌的应援团签到
if (obj.owner_uid == Live_info.uid || MY_API.GroupSign.fullLevalMedalUidList == Live_info.uid) return MY_API.GroupSign.signInList(list, i + 1);
return BAPI.Group.sign_in(obj.group_id, obj.owner_uid).then((response) => {
MYDEBUG('GroupSign.signInList: API.Group.sign_in', response);
let p = $.Deferred();
if (response.code === 0) {
if (response.data.add_num > 0) { // || response.data.status === 1
MYDEBUG(`[自动应援团签到] 应援团(group_id=${obj.group_id},owner_uid=${obj.owner_uid})签到成功,当前勋章亲密度+${response.data.add_num}`);
p.resolve();
}
else if (response.data.add_num == 0) {
window.toast(`[自动应援团签到]应援团(group_id=${obj.group_id},owner_uid=${obj.owner_uid})已签到`, 'caution');
p.resolve();
}
else {
p.reject();
}
} else {
window.toast(`[自动应援团签到] 应援团(group_id=${obj.group_id},owner_uid=${obj.owner_uid})签到失败 ${response.msg}`, 'caution');
p.reject();
return delayCall(() => MY_API.GroupSign.signInList(list, i));
}
return $.when(MY_API.GroupSign.signInList(list, i + 1), p);
});
},
run: () => {
// 执行应援团任务
try {
if (!MY_API.CONFIG.AUTO_GROUP_SIGN || otherScriptsRunning) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.AUTO_GROUP_SIGH_TS)) {
runTomorrow(() => MY_API.GroupSign.run(), 8, 1, '应援团签到');
return $.Deferred().resolve();
} else if (getCHSdate().getHours() < 8 && MY_API.CACHE.AUTO_GROUP_SIGH_TS !== 0) {
runToday(() => MY_API.GroupSign.run(), 8, 1, '应援团签到');
return $.Deferred().resolve();
}
window.toast(`[应援团签到] 开始签到`, 'info');
return MY_API.GroupSign.getGroups().then((list) => {
for (const i of medal_info.medal_list) {
if (i.medal_level === 20 || i.medal_level === 40)
MY_API.GroupSign.fullLevalMedalUidList.push(i.target_id)
}
return MY_API.GroupSign.signInList(list).then(() => {
window.toast(`[应援团签到] 今日签到已完成`, 'success');
MY_API.CACHE.AUTO_GROUP_SIGH_TS = ts_ms();
MY_API.saveCache();
runTomorrow(() => MY_API.GroupSign.run(), 8, 1, '应援团签到');
return $.Deferred().resolve();
});
});
} catch (err) {
window.toast('[自动应援团签到]运行时出现异常,已停止', 'error');
MYERROR(`自动应援团签到出错`, err);
return $.Deferred().reject();
}
}
},
DailyReward: {
// 每日任务
coin_exp: 0,
login: () => {
if (!MY_API.CONFIG.LOGIN) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.MainSite_login_TS)) {
runMidnight(() => MY_API.DailyReward.login(), '主站任务 - 登录');
return $.Deferred().resolve();
}
return BAPI.DailyReward.login().then((response) => {
MYDEBUG('DailyReward.login: API.DailyReward.login');
if (response.code === 0) {
window.toast('[自动每日奖励][每日登录]完成', 'success');
MY_API.CACHE.MainSite_login_TS = ts_ms();
MY_API.saveCache();
runMidnight(() => MY_API.DailyReward.login(), '主站任务 - 登录');
}
else {
window.toast(`[自动每日奖励][每日登录]失败 ${response.message}`, 'error');
return delayCall(() => MY_API.DailyReward.login());
}
});
},
watch: (aid, cid) => {
if (!MY_API.CONFIG.WATCH) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.MainSite_watch_TS)) {
return $.Deferred().resolve();
}
return BAPI.DailyReward.watch(aid, cid, Live_info.uid, ts_s()).then((response) => {
MYDEBUG('DailyReward.watch: API.DailyReward.watch', response);
if (response.code === 0) {
window.toast(`[自动每日奖励][每日观看]完成(av=${aid})`, 'success');
MY_API.CACHE.MainSite_watch_TS = ts_ms();
MY_API.saveCache();
} else {
window.toast(`[自动每日奖励][每日观看]失败 aid=${aid}, cid=${cid} ${response.msg}`, 'error');
return delayCall(() => MY_API.DailyReward.watch(aid, cid));
}
});
},
coin: (cards, n, i = 0, one = false) => {
if (!MY_API.CONFIG.COIN) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.MainSite_coin_TS)) {
return $.Deferred().resolve();
}
if (MY_API.DailyReward.coin_exp >= MY_API.CONFIG.COIN_NUMBER * 10) {
window.toast('[自动每日奖励][每日投币]今日投币已完成', 'info');
MY_API.CACHE.MainSite_coin_TS = ts_ms();
MY_API.saveCache();
return $.Deferred().resolve();
}
if (i >= cards.length) {
window.toast('[自动每日奖励][每日投币]动态里可投币的视频不足', 'caution');
return $.Deferred().resolve();
}
const obj = JSON.parse(cards[i].card);
let num = Math.min(2, n);
if (one) num = 1;
return BAPI.x.getCoinInfo('', 'jsonp', obj.aid, ts_ms()).then(re => {
MYDEBUG(`API.x.getCoinInfo aid = ${obj.aid}`, re);
if (re.code === 0) {
let p = $.Deferred();
setTimeout(() => p.resolve(), 500);
return p.then(() => {
if (re.data.multiply === 2) {
MYDEBUG('API.x.getCoinInfo', `已投币两个 aid = ${obj.aid}`)
return MY_API.DailyReward.coin(vlist, n, i + 1);
}
else {
if (re.data.multiply === 1) num = 1;
return BAPI.DailyReward.coin(obj.aid, num).then((response) => {
MYDEBUG('DailyReward.coin: API.DailyReward.coin', response);
if (response.code === 0) {
MY_API.DailyReward.coin_exp += num * 10;
window.toast(`[自动每日奖励][每日投币]投币成功(av=${obj.aid},num=${num})`, 'success');
return MY_API.DailyReward.coin(cards, n - num, i + 1);
} else if (response.code === -110) {
window.toast('[自动每日奖励][每日投币]未绑定手机,已停止', 'error');
return $.Deferred().reject();
} else if (response.code === 34003) {
// 非法的投币数量
if (one) return MY_API.DailyReward.coin(cards, n, i + 1);
return MY_API.DailyReward.coin(cards, n, i, true);
} else if (response.code === 34005) {
// 塞满啦!先看看库存吧~
return MY_API.DailyReward.coin(cards, n, i + 1);
} else if (response.code === -104) {
//硬币余额不足
window.toast('[自动每日奖励][每日投币]剩余硬币不足,已停止', 'warning');
return $.Deferred().reject();
}
window.toast(`[自动每日奖励][每日投币]出错 ${response.msg}`, 'error');
return delayCall(() => MY_API.DailyReward.coin(cards, n, i))
});
}
});
} else {
window.toast(`[自动每日奖励][每日投币]获取视频(aid=${obj.aid})投币状态出错 ${response.msg}`, 'error');
return delayCall(() => MY_API.DailyReward.coin(cards, n, i))
}
})
},
coin_uid: (vlist, n, pagenum, uidIndex, i = 0, one = false) => {
if (!MY_API.CONFIG.COIN) return $.Deferred().resolve();
if (MY_API.DailyReward.coin_exp >= MY_API.CONFIG.COIN_NUMBER * 10) {
window.toast('[自动每日奖励][每日投币]今日投币已完成', 'info');
MY_API.CACHE.MainSite_coin_TS = ts_ms();
MY_API.saveCache();
return $.Deferred().resolve();
}
if (i >= vlist.length) {
return MY_API.DailyReward.UserSpace(uidIndex, 30, 0, pagenum + 1, '', 'pubdate', 'jsonp');
}
const obj = vlist[i], uid = MY_API.CONFIG.COIN_UID[uidIndex];
if (obj.hasOwnProperty('is_union_video') && obj.is_union_video === 1 && obj.mid != uid) {
MYDEBUG('DailyReward.coin_uid', `联合投稿且UP不是指定UID用户 aid = ${obj.aid}`)
return MY_API.DailyReward.coin_uid(vlist, n, pagenum, uidIndex, i + 1);
}
let num = Math.min(2, n);
if (one) num = 1;
return BAPI.x.getCoinInfo('', 'jsonp', obj.aid, ts_ms()).then(re => {
if (re.code === 0) {
let p = $.Deferred();
setTimeout(() => p.resolve(), 500);
return p.then(() => {
if (re.data.multiply === 2) {
MYDEBUG('API.x.getCoinInfo', `已投币两个 aid = ${obj.aid}`)
return MY_API.DailyReward.coin_uid(vlist, n, pagenum, uidIndex, i + 1);
}
else {
if (re.data.multiply === 1) num = 1;
return BAPI.DailyReward.coin(obj.aid, num).then((response) => {
MYDEBUG('DailyReward.coin_uid: API.DailyReward.coin_uid', response);
if (response.code === 0) {
MY_API.DailyReward.coin_exp += num * 10;
window.toast(`[自动每日奖励][每日投币]投币成功(av=${obj.aid},num=${num})`, 'success');
return MY_API.DailyReward.coin_uid(vlist, n - num, pagenum, uidIndex, i + 1);
} else if (response.code === -110) {
window.toast('[自动每日奖励][每日投币]未绑定手机,已停止', 'error');
return $.Deferred().reject();
} else if (response.code === 34003) {
// 非法的投币数量
if (one) return MY_API.DailyReward.coin_uid(vlist, n, pagenum, uidIndex, i + 1);
return MY_API.DailyReward.coin_uid(vlist, n, i, pagenum, uidIndex, true);
} else if (response.code === 34005) {
// 塞满啦!先看看库存吧~
return MY_API.DailyReward.coin_uid(vlist, n, pagenum, uidIndex, i + 1);
} else if (response.code === -104) {
// 硬币余额不足
window.toast('[自动每日奖励][每日投币]剩余硬币不足,已停止', 'warning');
return $.Deferred().reject();
}
window.toast(`[自动每日奖励][每日投币] 出错 ${response.msg}`, 'caution');
return delayCall(() => MY_API.DailyReward.coin_uid(vlist, n, pagenum, uidIndex, i))
});
}
});
} else {
window.toast(`[自动每日奖励][每日投币]获取视频(aid=${obj.aid})投币状态出错 ${response.msg}`, 'error');
return delayCall(() => MY_API.DailyReward.coin(cards, n, i))
}
});
},
share: (aid) => {
if (!MY_API.CONFIG.SHARE) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.MainSite_share_TS)) {
return $.Deferred().resolve();
}
return BAPI.DailyReward.share(aid).then((response) => {
MYDEBUG('DailyReward.share: API.DailyReward.share', response);
if (response.code === 0) {
window.toast(`[自动每日奖励][每日分享]分享成功(av=${aid})`, 'success');
} else if (response.code === 71000) {
// 重复分享
window.toast('[自动每日奖励][每日分享]今日分享已完成', 'info');
} else {
window.toast(`[自动每日奖励][每日分享] 出错 ${response.msg}`, 'caution');
return delayCall(() => MY_API.DailyReward.share(aid));
}
MY_API.CACHE.MainSite_share_TS = ts_ms();
MY_API.saveCache();
});
},
dynamic: async () => {
if (!MY_API.CONFIG.COIN && !MY_API.CONFIG.WATCH && !MY_API.CONFIG.SHARE)
return $.Deferred().resolve();
if ((!MY_API.CONFIG.WATCH || (MY_API.CONFIG.WATCH && !checkNewDay(MY_API.CACHE.MainSite_watch_TS))) && (!MY_API.CONFIG.SHARE || (MY_API.CONFIG.SHARE && !checkNewDay(MY_API.CACHE.MainSite_share_TS))) && (!MY_API.CONFIG.COIN || (MY_API.CONFIG.COIN && !checkNewDay(MY_API.CACHE.MainSite_coin_TS))))
return runMidnight(() => MY_API.DailyReward.dynamic(), `主站任务 - ${MY_API.CONFIG.WATCH ? '观看视频' : ''} ${MY_API.CONFIG.SHARE ? '分享视频' : ''} ${MY_API.CONFIG.COIN ? '投币' : ''}`);
MY_API.DailyReward.coin_exp = await BAPI.DailyReward.exp().then((response) => {
MYDEBUG('DailyReward.run: API.DailyReward.exp', response);
if (response.code === 0) {
return response.number;
} else {
window.toast(`[自动每日奖励] 获取今日已获得的投币经验出错 ${response.message}`, 'caution');
return delayCall(() => MY_API.DailyReward.run());
}
});
const coinNum = MY_API.CONFIG.COIN_NUMBER - MY_API.DailyReward.coin_exp / 10;
const throwCoinNum = await BAPI.getuserinfo().then((re) => {
MYDEBUG('DailyReward.dynamic: API.getuserinfo', re);
if (re.code === "REPONSE_OK") {
if (re.data.biliCoin < coinNum) return re.data.biliCoin
else return coinNum
} else {
window.toast(`[自动每日奖励][每日投币] 获取用户信息失败 ${response.message}`, 'error');
}
});
if (throwCoinNum < coinNum) window.toast(`[自动每日奖励][每日投币]剩余硬币不足,仅能投${throwCoinNum}个币`, 'warning');
return BAPI.dynamic_svr.dynamic_new(Live_info.uid, 8).then((response) => {
MYDEBUG('DailyReward.dynamic: API.dynamic_svr.dynamic_new', response);
if (response.code === 0) {
if (response.data.cards) {
const obj = JSON.parse(response.data.cards[0].card);
const p1 = MY_API.DailyReward.watch(obj.aid, obj.cid);
let p2;
if (MY_API.CONFIG.COIN_UID == 0 || MY_API.CONFIG.COIN_TYPE == 'COIN_DYN') {
p2 = MY_API.DailyReward.coin(response.data.cards, Math.max(throwCoinNum, 0));
} else {
p2 = MY_API.DailyReward.UserSpace(0, 30, 0, 1, '', 'pubdate', 'jsonp');
}
const p3 = MY_API.DailyReward.share(obj.aid);
return $.when(p1, p2, p3).then(() => runMidnight(() => MY_API.DailyReward.dynamic(), `主站任务 - ${MY_API.CONFIG.WATCH ? '观看视频' : ''} ${MY_API.CONFIG.SHARE ? '分享视频' : ''} ${MY_API.CONFIG.COIN ? '投币' : ''}`));
} else {
window.toast('[自动每日奖励]"动态-投稿视频"中暂无动态', 'info');
}
} else {
window.toast(`[自动每日奖励]获取"动态-投稿视频"失败 ${response.msg}`, 'caution');
return delayCall(() => MY_API.DailyReward.dynamic());
}
});
},
UserSpace: (uidIndex, ps, tid, pn, keyword, order, jsonp) => {
if (!checkNewDay(MY_API.CACHE.MainSite_coin_TS)) {
return $.Deferred().resolve();
}
return BAPI.x.getUserSpace(MY_API.CONFIG.COIN_UID[uidIndex], ps, tid, pn, keyword, order, jsonp).then((response) => {
MYDEBUG('DailyReward.UserSpace: API.dynamic_svr.UserSpace', response);
if (response.code === 0) {
if (response.data.list.vlist) {
const throwCoinNum = MY_API.CONFIG.COIN_NUMBER - MY_API.DailyReward.coin_exp / 10;
return MY_API.DailyReward.coin_uid(response.data.list.vlist, Math.max(throwCoinNum, 0), pn, uidIndex);
} else if (uidIndex < MY_API.CONFIG.COIN_UID.length - 1) {
const throwCoinNum = MY_API.CONFIG.COIN_NUMBER - MY_API.DailyReward.coin_exp / 10;
return MY_API.DailyReward.coin_uid(response.data.list.vlist, Math.max(throwCoinNum, 0), pn, uidIndex + 1);
} else {
window.toast(`[自动每日奖励]"UID = ${String(MY_API.CONFIG.COIN_UID)}的空间-投稿视频"中暂无视频`, 'info');
}
}
else {
window.toast(`[自动每日奖励]获取UID = ${MY_API.CONFIG.COIN_UID[uidIndex]}的"空间-投稿视频"失败 ${response.msg}`, 'caution');
return delayCall(() => MY_API.DailyReward.UserSpace(uid, ps, tid, pn, keyword, order, jsonp));
}
});
},
run: () => {
if ((!MY_API.CONFIG.LOGIN && !MY_API.CONFIG.COIN && !MY_API.CONFIG.WATCH && !MY_API.CONFIG.SHARE) || otherScriptsRunning) return $.Deferred().resolve();
MY_API.DailyReward.login();
MY_API.DailyReward.dynamic();
}
},
LiveReward: {
dailySignIn: () => {
if (!MY_API.CONFIG.LIVE_SIGN) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.Live_sign_TS)) return runMidnight(() => MY_API.LiveReward.dailySignIn(), '直播区 - 直播签到');
return BAPI.xlive.dosign().then((response) => {
MYDEBUG('LiveReward.dailySignIn: API.xlive.dosign', response);
if (response.code === 0) {
window.toast('[自动直播签到]完成', 'success');
$('.hinter').remove(); // 移除签到按钮和小红点
$('.checkin-btn').remove();
} else if (response.code === 1011040) {
window.toast('[自动直播签到]今日直播签到已完成', 'info')
} else {
window.toast(`[自动直播签到]失败 ${response.message},尝试点击签到按钮`, 'caution');
$('.checkin-btn').click();
return delayCall(() => MY_API.LiveReward.dailySignIn());
}
MY_API.CACHE.Live_sign_TS = ts_ms();
MY_API.saveCache();
runMidnight(() => MY_API.LiveReward.dailySignIn(), '直播区 - 直播签到');
});
},
likeLiveRoom: async (medal_list) => {
if (!MY_API.CONFIG.LIKE_LIVEROOM) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.Live_like_TS)) return runMidnight(() => MY_API.LiveReward.likeLiveRoom(), '直播区 - 点赞');
const likeTimes = 1;
window.toast('[点赞直播间] 开始点赞直播间', 'info');
for (let i = 0; i < likeTimes; i++) {
for (const medal of medal_list) {
await BAPI.xlive.likeInteract(medal.real_roomid).then((response) => {
MYDEBUG(`API.xlive.likeInteract(${medal.real_roomid}) response`, response);
if (response.code !== 0) window.toast(`[点赞直播间] 直播间${medal.real_roomid}点赞失败 ${response.message}`, 'caution');
});
await sleep(MY_API.CONFIG.LIKE_LIVEROOM_INTERVAL);
}
}
window.toast('[点赞直播间] 今日点赞完成', 'success');
MY_API.CACHE.Live_like_TS = ts_ms();
MY_API.saveCache();
runMidnight(() => MY_API.LiveReward.likeLiveRoom(), '直播区 - 点赞');
},
WatchLive: async (medal_list) => {
if (!MY_API.CONFIG.WatchLive) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.Live_watch_TS)) return runMidnight(() => MY_API.LiveReward.WatchLive(), '直播区 - 观看直播');
window.toast('[观看直播] 开始模拟观看直播', 'info');
let pReturn = $.Deferred();
for (let f = 0; f < medal_list.length; f++) {
const funsMedalData = medal_list[f];
let roomHeart = new RoomHeart(funsMedalData.real_roomid, MY_API.CONFIG.WatchLiveTime)
await roomHeart.start()
if (f === medal_list.length - 1) roomHeart.doneFunc = () => {
window.toast('[观看直播] 今日观看任务已完成', 'success');
pReturn.resolve();
}
await sleep(MY_API.CONFIG.WatchLiveInterval);
}
await pReturn;
MY_API.CACHE.Live_watch_TS = ts_ms();
MY_API.saveCache();
runMidnight(() => MY_API.LiveReward.WatchLive(), '直播区 - 观看直播');
},
run: () => {
if ((!MY_API.CONFIG.LIVE_SIGN && !MY_API.CONFIG.WatchLive && !MY_API.CONFIG.LIKE_LIVEROOM) || otherScriptsRunning) return $.Deferred().resolve();
let runTasksMedalList;
if (medal_info.status.state() === "resolved") {
if (MY_API.CONFIG.LIVE_TASKS_METHOD === 'LIVE_TASKS_WHITE')
runTasksMedalList = medal_info.medal_list.filter(r => MY_API.CONFIG.LIVE_TASKS_ROOM.findIndex(m => m == r.roomid) > -1 && r.roomid && r.level < 20);
else {
runTasksMedalList = medal_info.medal_list.filter(r => MY_API.CONFIG.LIVE_TASKS_ROOM.findIndex(m => m == r.roomid) === -1 && r.roomid && r.level < 20);
}
} else {
window.toast('[观看直播] [点赞直播间] 粉丝勋章列表未被完全获取,暂停运行', 'error');
return medal_info.status.then(() => { MY_API.LiveReward.WatchLive(); MY_API.LiveReward.likeLiveRoom(); });
}
MY_API.LiveReward.dailySignIn();
MY_API.LiveReward.WatchLive(runTasksMedalList);
MY_API.LiveReward.likeLiveRoom(runTasksMedalList);
}
},
Exchange: {
coin2silver: (num) => {
return BAPI.xlive.revenue.coin2silver(num).then((response) => {
MYDEBUG('Exchange.coin2silver: API.Exchange.coin2silver', response);
if (response.code === 0) {
window.toast(`[硬币换银瓜子] ${response.message},获得${response.data.silver}银瓜子`, 'success');
} else {
// 其它状态码待补充
window.toast(`[银瓜子换硬币] 失败 ${response.message}`, 'caution');
return delayCall(() => MY_API.Exchange.coin2silver(num));
}
});
},
silver2coin: () => {
return BAPI.xlive.revenue.silver2coin().then((response) => {
MYDEBUG('Exchange.silver2coin: API.Exchange.silver2coin', response);
if (response.code === 0) {
window.toast(`[银瓜子换硬币] ${response.message}`, 'success'); // 兑换成功
} else if (response.code === 403) {
window.toast(`[银瓜子换硬币] ${response.message}`, 'info'); // 每天最多能兑换 1 个 or 银瓜子余额不足
} else {
window.toast(`[银瓜子换硬币] 失败 ${response.message}`, 'caution');
return delayCall(() => MY_API.Exchange.silver2coin());
}
});
},
runC2S: () => {
if (!MY_API.CONFIG.COIN2SILVER || otherScriptsRunning) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.Coin2Sliver_TS)) {
// 同一天,不再兑换瓜子
runMidnight(() => MY_API.Exchange.runC2S(), '硬币换瓜子');
return $.Deferred().resolve();
}
return MY_API.Exchange.coin2silver(MY_API.CONFIG.COIN2SILVER_NUM).then(() => {
MY_API.CACHE.Coin2Sliver_TS = ts_ms();
MY_API.saveCache();
runMidnight(() => MY_API.Exchange.runC2S(), '硬币换瓜子');
}, () => delayCall(() => MY_API.Exchange.runC2S()))
},
runS2C: () => {
try {
if (!MY_API.CONFIG.SILVER2COIN || otherScriptsRunning) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.Silver2Coin_TS)) {
// 同一天,不再兑换硬币
runMidnight(() => MY_API.Exchange.runS2C(), '瓜子换硬币');
return $.Deferred().resolve();
}
return MY_API.Exchange.silver2coin().then(() => {
MY_API.CACHE.Silver2Coin_TS = ts_ms();
MY_API.saveCache();
runMidnight(() => MY_API.Exchange.runS2C(), '瓜子换硬币');
}, () => delayCall(() => MY_API.Exchange.runS2C()));
} catch (err) {
window.toast('[银瓜子换硬币]运行时出现异常,已停止', 'error');
MYERROR(`银瓜子换硬币出错`, err);
return $.Deferred().reject();
}
}
},
Gift: {
run_timer: undefined, // 可用来取消下次运行的计划 clearTimeout(MY_API.Gift.run_timer)
ruid: undefined, // 包裹内礼物的ruid
room_id: undefined, // 送礼目标房间号
medal_list: undefined, // 勋章列表
bag_list: undefined, // 包裹
giftFeed_list: {}, // 每种礼物所对应的亲密度
remain_feed: undefined, // 该勋章今日剩余亲密度
over: undefined, // 是否结束送礼
allowGiftList: undefined, // 允许被送出礼物的id
/**
* 获取礼物包裹
*/
getBagList: async () => {
return BAPI.gift.bag_list().then((response) => {
MYDEBUG('Gift.getBagList: API.gift.bag_list', response);
if (response.code === 0) {
MY_API.Gift.bag_list = response.data.list;
} else {
window.toast(`[自动送礼]获取包裹列表失败,${response.message}`, 'error');
return delayCall(() => MY_API.Gift.getBagList());
}
});
},
/**
* 通过礼物id获取礼物的亲密度
* @param {Number} gift_id 礼物id
*/
getFeedByGiftID: (gift_id) => {
for (let i = Live_info.gift_list.length - 1; i >= 0; --i) {
if (Live_info.gift_list[i].id === gift_id) {
return Math.ceil(Live_info.gift_list[i].price / 100);
}
}
return 0;
},
/**
* 排序粉丝勋章
* @param {Object} medals
*/
sort_medals: (medals) => {
if (MY_API.CONFIG.GIFT_SORT == 'GIFT_SORT_HIGH') {
medals.sort((a, b) => {
if (b.level - a.level == 0) {
return b.intimacy - a.intimacy;
}
return b.level - a.level;
});
} else {
medals.sort((a, b) => {
if (a.level - b.level == 0) {
return a.intimacy - b.intimacy;
}
return a.level - b.level;
});
}
if (MY_API.CONFIG.AUTO_GIFT_ROOMID) {
let sortRooms = [...MY_API.CONFIG.AUTO_GIFT_ROOMID];
sortRooms.reverse();
for (let froom of sortRooms) {
let rindex = medals.findIndex(r => r.roomid == froom);
if (rindex != -1) {
let tmp = medals[rindex];
medals.splice(rindex, 1);
medals.unshift(tmp);
}
}
}
return medals;
},
run: async (noTimeCheck = false) => {
/**
* 一轮送礼结束后运行的函数
*/
const waitForNextRun = () => {
window.toast('[自动送礼] 本次送礼结束', 'info');
SEND_GIFT_NOW = false;
if (MY_API.CONFIG.GIFT_METHOD == "GIFT_SEND_TIME") {
let alternateTime = getIntervalTime(MY_API.CONFIG.GIFT_SEND_HOUR, MY_API.CONFIG.GIFT_SEND_MINUTE);
MY_API.Gift.run_timer = setTimeout(() => MY_API.Gift.run(true), alternateTime);
let runTime = new Date(ts_ms() + alternateTime).toLocaleString();
MYDEBUG("[自动送礼]", `将在${runTime}进行自动送礼`);
MY_API.CACHE.Gift_TS = ts_ms();
MY_API.saveCache();
} else {
let alternateTime = MY_API.CONFIG.GIFT_INTERVAL * 60 * 1000;
MY_API.Gift.run_timer = setTimeout(() => MY_API.Gift.run(true), alternateTime);
MYDEBUG("[自动送礼]", `将在${MY_API.CONFIG.GIFT_INTERVAL}分钟后进行自动送礼`);
MY_API.CACHE.GiftInterval_TS = ts_ms();
MY_API.saveCache();
}
};
/**
* 处理用户输入的【允许被送出的礼物类型】,将礼物名转换为id
*/
const handleGiftList = () => {
MY_API.Gift.allowGiftList = [...MY_API.CONFIG.GIFT_ALLOW_TYPE];
MYDEBUG('[自动送礼]', `处理前的礼物列表 ${MY_API.Gift.allowGiftList}`);
for (let i = 0; i < MY_API.Gift.allowGiftList.length; i++) {
const listItem = MY_API.Gift.allowGiftList[i];
let matchItem;
if (isNaN(listItem)) {
// 如果填了礼物名,转换为id
matchItem = Live_info.gift_list.find(item => item.name === listItem);
if (matchItem) MY_API.Gift.allowGiftList[i] = String(matchItem.id);
}
}
MYDEBUG('[自动送礼]', `处理后得到的礼物id列表 ${MY_API.Gift.allowGiftList}`)
};
/**
* 获取礼物列表中的每种礼物所对应的亲密度,把结果保存至 giftFeed_list。
* 格式:{ id1: feed1, id2: feed2, ... }
*/
const getGiftFeed = () => {
for (const i of MY_API.Gift.bag_list) {
if (!MY_API.Gift.giftFeed_list.hasOwnProperty(i.gift_id)) {
MY_API.Gift.giftFeed_list[i.gift_id] = MY_API.Gift.getFeedByGiftID(i.gift_id);
}
}
}
/**
* 处理包裹。
* 1. 根据礼物到期时间过滤包裹
* 2. 按礼物亲密度由高到低排序
* 3. 按过期时间由早到晚排序
* @param filter 是否按设置过滤礼物
*/
const handleBagList = (filter = true) => {
let bag_list;
if (!MY_API.CONFIG.SEND_ALL_GIFT && filter) {
// 送之前查一次有没有可送的
bag_list = MY_API.Gift.bag_list.filter(r => MY_API.Gift.allowGiftList.includes(String(r.gift_id)) && r.gift_num > 0 &&
(r.expire_at * 1000 - ts_ms()) / 86400000 <= MY_API.CONFIG.GIFT_LIMIT);
MYDEBUG("[自动送礼] if分支 过滤后的礼物", bag_list);
if (bag_list.length === 0) {
MY_API.Gift.over = true;
return;
}
} else {
bag_list = MY_API.Gift.bag_list.filter(r => r.gift_num > 0 && r.expire_at != 0);
MYDEBUG("[自动送礼] else分支 过滤后的礼物", bag_list);
if (bag_list.length === 0) {
MY_API.Gift.over = true;
return;
}
}
// 按礼物亲密度由高到低排序
for (const i of bag_list) {
i.gift_feed = MY_API.Gift.giftFeed_list[i.gift_id];
}
bag_list.sort(function (a, b) { return b.gift_feed - a.gift_feed });
// 按过期时间由早到晚
bag_list.sort(function (a, b) {
if (b.gift_feed === a.gift_feed) {
return a.expire_at - b.expire_at
}
});
MY_API.Gift.bag_list = [...bag_list];
MYDEBUG('Gift.bag_list (sorted)', MY_API.Gift.bag_list);
};
/**
* 处理粉丝勋章
* @param {Object} MY_API.Gift.medal_list
*/
const handleMedalList = () => {
MY_API.Gift.medal_list = MY_API.Gift.medal_list.filter(it => it.day_limit - it.today_feed > 0 && it.level < 20 && it.roomid);
MY_API.Gift.medal_list = MY_API.Gift.sort_medals(MY_API.Gift.medal_list);
// 排除直播间
if (MY_API.CONFIG.GIFT_SEND_METHOD === "GIFT_SEND_BLACK") {
// 黑名单
MY_API.Gift.medal_list = MY_API.Gift.medal_list.filter(Er => MY_API.CONFIG.GIFT_SEND_ROOM.findIndex(exp => exp == Er.roomid) == -1);
} else {
// 白名单
MY_API.Gift.medal_list = MY_API.Gift.medal_list.filter(Er => MY_API.CONFIG.GIFT_SEND_ROOM.findIndex(exp => exp == Er.roomid) > -1);
}
}
/**
* 判断包裹内是否还有礼物
* @returns {Boolean} 有礼物 true, 无礼物 false
*/
const checkRemainGift = () => {
return MY_API.Gift.bag_list.some(g => g.gift_num > 0) ? true : false;
};
try {
if ((!MY_API.CONFIG.AUTO_GIFT) || otherScriptsRunning) return $.Deferred().resolve();
if (MY_API.MEDAL_DANMU.isRunning) {
// 【粉丝牌打卡】任务运行中
return setTimeout(() => MY_API.Gift.run(), 3e3);
}
if (MY_API.Gift.run_timer) clearTimeout(MY_API.Gift.run_timer);
if (MY_API.CONFIG.GIFT_METHOD == "GIFT_SEND_TIME" && !isTime(MY_API.CONFIG.GIFT_SEND_HOUR, MY_API.CONFIG.GIFT_SEND_MINUTE) && !SEND_GIFT_NOW && !noTimeCheck) {
// 定时送礼
let alternateTime = getIntervalTime(MY_API.CONFIG.GIFT_SEND_HOUR, MY_API.CONFIG.GIFT_SEND_MINUTE);
MY_API.Gift.run_timer = setTimeout(() => MY_API.Gift.run(true), alternateTime);
let runTime = new Date(ts_ms() + alternateTime).toLocaleString();
MYDEBUG("[自动送礼]", `将在${runTime}进行自动送礼`);
return $.Deferred().resolve();
} else if (MY_API.CONFIG.GIFT_METHOD == "GIFT_INTERVAL" && !SEND_GIFT_NOW && !noTimeCheck) {
// 间隔__分钟送礼
let GiftInterval = MY_API.CONFIG.GIFT_INTERVAL * 60e3;
if (MY_API.CACHE.GiftInterval_TS) {
const interval = ts_ms() - MY_API.CACHE.GiftInterval_TS;
if (interval < GiftInterval) {
let intervalTime = GiftInterval - interval;
MY_API.Gift.run_timer = setTimeout(() => MY_API.Gift.run(true), intervalTime);
MYDEBUG("[自动送礼]", `将在${intervalTime}毫秒后进行自动送礼`);
return $.Deferred().resolve();
}
}
else {
MY_API.CACHE.GiftInterval_TS = ts_ms();
MY_API.saveCache();
}
}
if (medal_info.status.state() === "resolved") MY_API.Gift.medal_list = [...medal_info.medal_list];
else {
window.toast('[自动送礼] 粉丝勋章列表未被完全获取,暂停运行', 'error');
return medal_info.status.then(() => MY_API.Gift.run());
}
MYDEBUG('Gift.run: Gift.getMedalList().then: Gift.medal_list', MY_API.Gift.medal_list);
MY_API.Gift.over = false; // 开始运行前先把停止运行设为 false
handleGiftList();
await MY_API.Gift.getBagList();
await getGiftFeed();
handleBagList(false);
if (MY_API.Gift.over) return waitForNextRun();
if (MY_API.Gift.medal_list.length > 0) {
handleMedalList();
handleBagList();
if (MY_API.Gift.over) return waitForNextRun();
for (const v of MY_API.Gift.medal_list) {
if (!checkRemainGift()) {
MY_API.Gift.over = true;
break;
}
const response = await BAPI.room.room_init(parseInt(v.roomid, 10)).then(re => {
MYDEBUG(`[自动送礼] API.room.room_init(${v.roomid})`, re);
if (re.code !== 0) throw re.msg;
return re;
});
MY_API.Gift.room_id = parseInt(response.data.room_id, 10);
MY_API.Gift.ruid = v.target_id;
MY_API.Gift.remain_feed = v.day_limit - v.today_feed;
if (MY_API.Gift.remain_feed > 0) {
window.toast(`[自动送礼]勋章[${v.medal_name}] 今日亲密度未满[${v.today_feed}/${v.day_limit}],预计需要[${MY_API.Gift.remain_feed}]送礼开始`, 'info');
await MY_API.Gift.sendGift(v);
} else {
window.toast(`[自动送礼]勋章[${v.medal_name}] 今日亲密度已满`, 'info');
}
}
}
if (!MY_API.Gift.over) await MY_API.Gift.sendRemainGift(MY_API.CONFIG.SPARE_GIFT_ROOM);
return waitForNextRun();
} catch (err) {
window.toast('[自动送礼] 运行时出现异常,已停止', 'error');
MYERROR(`自动送礼出错`, err);
return delayCall(() => MY_API.Gift.run());
}
},
sendGift: async (medal) => {
for (const v of MY_API.Gift.bag_list) {
if (MY_API.Gift.remain_feed <= 0) {
return window.toast(`[自动送礼]勋章[${medal.medal_name}]送礼结束,今日亲密度已满[${medal.today_feed}/${medal.day_limit}]`, 'info');
}
if (v.gift_num === 0) continue; // 如果这一礼物送完了则跳到下一个礼物
const feed = MY_API.Gift.giftFeed_list[v.gift_id];
if (feed > 0) {
let feed_num = Math.floor(MY_API.Gift.remain_feed / feed);
if (feed_num === 0) continue; // 当前礼物亲密度大于勋章今日剩余亲密度
if (feed_num > v.gift_num) feed_num = v.gift_num;
MYDEBUG(`[自动送礼]送出礼物类型${v.gift_name},该项礼物数量${v.gift_num},送出礼物数量${feed_num}`);
await BAPI.gift.bag_send(Live_info.uid, v.gift_id, MY_API.Gift.ruid, feed_num, v.bag_id, MY_API.Gift.room_id, Live_info.rnd).then((response) => {
MYDEBUG('Gift.sendGift: API.gift.bag_send', response);
if (response.code === 0) {
v.gift_num -= feed_num;
medal.today_feed += feed_num * feed;
MY_API.Gift.remain_feed -= feed_num * feed;
window.toast(`[自动送礼]勋章[${medal.medal_name}] 送礼成功,送出${feed_num}个${v.gift_name},[${medal.today_feed}/${medal.day_limit}]距离今日亲密度上限还需[${MY_API.Gift.remain_feed}]`, 'success');
} else if (response.code === 200028) {
// 当前直播间无法赠送礼物哦~
window.toast(`[自动送礼]勋章[${medal.medal_name}] 送礼失败:${response.msg}`, 'caution');
}
else {
window.toast(`[自动送礼]勋章[${medal.medal_name}] 送礼异常:${response.msg}`, 'caution');
return delayCall(() => MY_API.Gift.sendGift(medal));
}
});
}
}
},
sendRemainGift: async (ROOM_ID) => {
if (ROOM_ID == 0) return $.Deferred().resolve();
let UID = undefined;
await BAPI.room.room_init(ROOM_ID).then((response) => {
MYDEBUG('API.room.room_init', response);
if (response.code === 0) UID = response.data.uid;
else {
window.toast(`[自动送礼]【剩余礼物】检查房间出错 ${response.message}`);
return delayCall(() => BAPI.room.room_init(ROOM_ID));
}
})
let bag_list = MY_API.Gift.bag_list.filter(r => MY_API.Gift.allowGiftList.includes(String(r.gift_id)) && r.gift_num > 0 &&
(r.expire_at * 1000 - ts_ms()) / 86400000 <= 1);
if (bag_list.length === 0) return;
MYDEBUG('[自动送礼]【剩余礼物】bag_list', bag_list);
for (const v of bag_list) {
if (v.gift_num <= 0) continue;
const feed = MY_API.Gift.giftFeed_list[v.gift_id];
if (feed > 0) {
let feed_num = v.gift_num;
await BAPI.gift.bag_send(Live_info.uid, v.gift_id, UID, feed_num, v.bag_id, ROOM_ID, Live_info.rnd).then((response) => {
MYDEBUG('Gift.sendGift: API.gift.bag_send', response);
if (response.code === 0) {
v.gift_num -= feed_num;
window.toast(`[自动送礼]【剩余礼物】房间[${ROOM_ID}] 送礼成功,送出${feed_num}个${v.gift_name}`, 'success');
} else if (response.code === 200028) {
// 当前直播间无法赠送礼物哦~
window.toast(`[自动送礼]勋章[${medal.medal_name}] 送礼失败:${response.msg}`, 'caution');
} else {
window.toast(`[自动送礼]【剩余礼物】房间[${ROOM_ID}] 送礼异常:${response.msg}`, 'caution');
return delayCall(() => MY_API.Gift.sendGift(medal));
}
});
}
}
}
},
AUTO_DANMU: {
setValue: (array, index) => {
if (MY_API.CONFIG[array][index] === undefined && index > 0)
return MY_API.AUTO_DANMU.setValue(array, index - 1);
else return MY_API.CONFIG[array][index];
},
sendDanmu: async (danmuContent, roomId) => {
let realRoomId = roomId;
if (Number(roomId) <= 10000) {
realRoomId = await BAPI.room.get_info(roomId).then((res) => {
MYDEBUG(`API.room.get_info roomId=${roomId} res`, res); // 可能是短号,要用长号发弹幕
if (res.code === 0) {
return res.data.room_id;
} else {
window.toast(`[自动发弹幕]房间号【${roomId}】信息获取失败 ${res.message}`, 'error');
return roomId
}
});
}
return BAPI.sendLiveDanmu(danmuContent, realRoomId).then((response) => {
MYDEBUG(`[自动发弹幕]弹幕发送内容【${danmuContent}】,房间号【${roomId}】`, response);
if (response.code === 0) {
window.toast(`[自动发弹幕]弹幕【${danmuContent}】(房间号【${roomId}】)发送成功`, 'success');
} else {
window.toast(`[自动发弹幕]弹幕【${danmuContent}】(房间号【${roomId}】)出错 ${response.msg}`, 'caution');
}
})
},
getMaxLength: () => {
let maxLength = undefined;
const contentLength = MY_API.CONFIG.DANMU_CONTENT.length,
roomidLength = MY_API.CONFIG.DANMU_ROOMID.length,
intervalTimeLength = MY_API.CONFIG.DANMU_INTERVAL_TIME.length;
if (contentLength >= roomidLength) maxLength = contentLength;
else maxLength = roomidLength;
if (maxLength < intervalTimeLength)
maxLength = intervalTimeLength;
return maxLength
},
run: async () => {
if (!MY_API.CONFIG.AUTO_DANMU || otherScriptsRunning) return $.Deferred().resolve();
if (MY_API.MEDAL_DANMU.isRunning || MY_API.AppUserTask.isRunning) {
// 【粉丝牌打卡】【APP用户任务】任务运行中
return setTimeout(() => MY_API.AUTO_DANMU.run(), 3e3);
}
danmuTaskRunning = true;
if (SEND_DANMU_NOW) {
for (let i = 0; i < MY_API.CONFIG.DANMU_CONTENT.length; i++) {
let danmu_content = MY_API.AUTO_DANMU.setValue('DANMU_CONTENT', i),
danmu_roomid = parseInt(MY_API.AUTO_DANMU.setValue('DANMU_ROOMID', i));
await MY_API.AUTO_DANMU.sendDanmu(danmu_content, danmu_roomid);
await sleep(1000);
}
SEND_DANMU_NOW = false;
} else {
let maxLength = MY_API.AUTO_DANMU.getMaxLength();
for (let i = 0; i < maxLength; i++) {
let danmu_content = MY_API.AUTO_DANMU.setValue('DANMU_CONTENT', i),
danmu_roomid = parseInt(MY_API.AUTO_DANMU.setValue('DANMU_ROOMID', i)),
danmu_intervalTime = MY_API.AUTO_DANMU.setValue('DANMU_INTERVAL_TIME', i), // 设置-发送时间
lastSendTime = undefined, // 上次发弹幕的时间戳(毫秒)
jsonCache = MY_API.CACHE.AUTO_SEND_DANMU_TS,
objIndex = undefined, // 弹幕缓存下标
isTimeData = undefined, // 是否是时间点数据(eg 9:01)
intervalTime = undefined, // 据上次发弹幕的时间(毫秒)
danmu_intervalTime_Ts = undefined, // 间隔时间
sleepTime = 0;
function getDanmuCache() {
for (let i = 0; i < jsonCache.length; i++) {
const obj = jsonCache[i];
if (obj.roomid == danmu_roomid && obj.content == danmu_content) {
lastSendTime = obj.sendTs
objIndex = i;
break;
}
}
}
if (danmu_intervalTime.indexOf(':') > -1) { // 时间
isTimeData = true;
const danmu_time = danmu_intervalTime.split(':'); // 小时,分钟,秒
const hour = parseInt(danmu_time[0]), minute = parseInt(danmu_time[1]), second = parseInt(danmu_time[2]);
if (!isTime(hour, minute, second)) sleepTime = getIntervalTime(hour, minute, second);
else sleepTime = 86400000;
}
else {
isTimeData = false;
danmu_intervalTime = danmu_intervalTime.toLowerCase();
if (danmu_intervalTime.indexOf('h') > -1 || danmu_intervalTime.indexOf('m') > -1 || danmu_intervalTime.indexOf('s') > -1) {
const hourArray = danmu_intervalTime.split('h'); // 1h5m3s
const minuteArray = (hourArray[1] === undefined) ? hourArray[0].split('m') : hourArray[1].split('m');
const secondArray = (minuteArray[1] === undefined) ? minuteArray[0].split('s') : minuteArray[1].split('s');
const hour = hourArray[0],
minute = minuteArray[0],
second = secondArray[0];
const finalHour = isNaN(hour) ? 0 : hour || 0,
finalMinute = isNaN(minute) ? 0 : minute || 0,
finalSecond = isNaN(second) ? 0 : second || 0;
danmu_intervalTime_Ts = finalHour * 3600000 + finalMinute * 60000 + finalSecond * 1000;
} else { // 没有h或m或s则默认是分钟
danmu_intervalTime_Ts = danmu_intervalTime * 60000;
}
}
MYDEBUG('[自动发弹幕]MY_API.CACHE.AUTO_SEND_DANMU_TS => jsoncache', jsonCache);
getDanmuCache();
if (!isTimeData) {
if (lastSendTime) intervalTime = ts_ms() - lastSendTime;
else intervalTime = ts_ms();
}
const setCache = () => {
const newJson = {
roomid: danmu_roomid,
content: danmu_content,
sendTs: ts_ms()
};
getDanmuCache();
if (objIndex === undefined) {
jsonCache.push(newJson);
} else {
jsonCache[objIndex].sendTs = ts_ms();
}
MY_API.CACHE.AUTO_SEND_DANMU_TS = jsonCache;
return MY_API.saveCache(false);
};
const sendNextDanmu = (intervalTS, isTime) => {
if (!isTime) setCache();
return setTimeout(async () => {
await MY_API.AUTO_DANMU.sendDanmu(danmu_content, danmu_roomid);
if (!isTime) setCache();
return sendNextDanmu(intervalTS, isTime);
}, intervalTS);
}
if (!isTimeData && intervalTime >= danmu_intervalTime_Ts) {
// 非时间点数据,距上次发送的时间大于间隔时间
await MY_API.AUTO_DANMU.sendDanmu(danmu_content, danmu_roomid);
MYDEBUG(`[自动发弹幕]弹幕发送内容【${danmu_content}】,房间号【${danmu_roomid}】,距下次发送还有`, danmu_intervalTime);
sendNextDanmu(danmu_intervalTime_Ts, isTimeData);
} else if (isTimeData && !sleepTime) {
// 时间点数据,立刻发送
await MY_API.AUTO_DANMU.sendDanmu(danmu_content, danmu_roomid);
MYDEBUG(`[自动发弹幕]弹幕发送内容【${danmu_content}】,房间号【${danmu_roomid}】,距下次发送还有`, '24小时');
sendNextDanmu(sleepTime, isTimeData);
}
else {
// 时间点数据,需等待一段时间再发送
MYDEBUG(`[自动发弹幕]弹幕发送内容【${danmu_content}】,房间号【${danmu_roomid}】,距下次发送还有`, `${(!isTimeData) ? (danmu_intervalTime_Ts - intervalTime) / 60000 : sleepTime / 60000}分钟`);
setTimeout(async () => {
await MY_API.AUTO_DANMU.sendDanmu(danmu_content, danmu_roomid);
sendNextDanmu((isTimeData) ? 86400000 : danmu_intervalTime_Ts, isTimeData);
}, (isTimeData) ? sleepTime : danmu_intervalTime_Ts - intervalTime);
}
await sleep(1500);
}
}
danmuTaskRunning = false;
}
},
AUTO_CHECK_DANMU: {
sendDanmu: {},
initEmitter: () => {
danmuEmitter.on('danmu', (msg) => {
let timer = setTimeout(() => {
window.toast(`弹幕【${msg}】疑似发送失败`, 'caution');
delete MY_API.AUTO_CHECK_DANMU.sendDanmu[timer];
}, MY_API.CONFIG.AUTO_CHECK_DANMU_TIMEOUT);
MY_API.AUTO_CHECK_DANMU.sendDanmu[timer] = msg;
})
},
run: () => {
if (!SP_CONFIG.AUTO_CHECK_DANMU) return;
MY_API.AUTO_CHECK_DANMU.initEmitter();
W.bliveproxy.addCommandHandler("DANMU_MSG", (command) => {
if (MY_API.AUTO_CHECK_DANMU.sendDanmu === {}) return;
const info = command.info;
if (info[2][0] === Live_info.uid) {
for (const d in MY_API.AUTO_CHECK_DANMU.sendDanmu) {
if (MY_API.AUTO_CHECK_DANMU.sendDanmu[d] === info[1]) {
MYDEBUG(`[检查弹幕是否发送成功] 已找到弹幕(timer = ${d})`, MY_API.AUTO_CHECK_DANMU.sendDanmu[d])
clearTimeout(d);
delete MY_API.AUTO_CHECK_DANMU.sendDanmu[d];
}
}
}
});
}
},
MEDAL_DANMU: {
isRunning: false,
medal_list: [],
sendDanmu: async (danmuContent, roomId, medal_name) => {
return BAPI.sendLiveDanmu(danmuContent, roomId).then((response) => {
MYDEBUG(`API.sendLiveDanmu(弹幕 = ${danmuContent}, roomid = ${roomId})`, response);
if (response.code === 0) {
return MYDEBUG(`[粉丝牌打卡弹幕] 弹幕发送内容【${danmuContent}】,房间号【${roomId}】,真实房间号【${roomId}】,粉丝勋章【${medal_name}】`, response);
} else {
return window.toast(`[粉丝牌打卡弹幕] 弹幕【${danmuContent}】(房间号【${roomId}】,粉丝勋章【${medal_name}】)出错 ${response.message}`, 'caution');
}
})
},
run: async () => {
if (!MY_API.CONFIG.MEDAL_DANMU || otherScriptsRunning) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.Live_medalDanmu_TS)) {
runMidnight(() => MY_API.MEDAL_DANMU.run(), '粉丝勋章打卡弹幕');
return $.Deferred().resolve();
}
if (medal_info.status.state() === "resolved") MY_API.MEDAL_DANMU.medal_list = [...medal_info.medal_list];
else {
window.toast('[粉丝牌打卡] 粉丝勋章列表未被完全获取,暂停运行', 'error');
return medal_info.status.then(() => MY_API.MEDAL_DANMU.run());
}
MY_API.MEDAL_DANMU.isRunning = true;
let lightMedalList;
if (MY_API.CONFIG.LIVE_TASKS_METHOD === 'LIVE_TASKS_WHITE')
lightMedalList = MY_API.MEDAL_DANMU.medal_list.filter(r => MY_API.CONFIG.LIVE_TASKS_ROOM.findIndex(m => m == r.roomid) > -1 && r.roomid);
else {
lightMedalList = MY_API.MEDAL_DANMU.medal_list.filter(r => MY_API.CONFIG.LIVE_TASKS_ROOM.findIndex(m => m == r.roomid) === -1 && r.roomid);
}
MYDEBUG('[粉丝牌打卡] 过滤后的粉丝勋章房间列表', lightMedalList);
let danmuContentIndex = 0;
const configDanmuLength = MY_API.CONFIG.MEDAL_DANMU_CONTENT.length;
// 第一轮
for (const up of lightMedalList) {
if (danmuContentIndex >= configDanmuLength) danmuContentIndex = 0;
const medal_name = up.medal_name,
roomid = up.real_roomid,
danmuContent = MY_API.CONFIG.MEDAL_DANMU_CONTENT[danmuContentIndex];
await MY_API.MEDAL_DANMU.sendDanmu(danmuContent, roomid, medal_name);
danmuContentIndex++;
await sleep(MY_API.CONFIG.MEDAL_DANMU_INTERVAL * 1000);
}
MY_API.MEDAL_DANMU.isRunning = false;
window.toast('[粉丝牌打卡弹幕] 今日已完成', 'success');
MY_API.CACHE.Live_medalDanmu_TS = ts_ms();
MY_API.saveCache();
return runTomorrow(() => MY_API.MEDAL_DANMU.run(), 0, 2, '粉丝勋章打卡弹幕');
}
},
DANMU_MODIFY: {
maxLength: 0,
configJson: {
DANMU_MODIFY_REGEX: [],
DANMU_MODIFY_UID: [],
DANMU_MODIFY_POOL: [],
DANMU_MODIFY_SIZE: [],
DANMU_MODIFY_COLOR: []
},
handleConfig: () => {
for (const i in MY_API.DANMU_MODIFY.configJson) {
MY_API.DANMU_MODIFY.configJson[i] = MY_API.CONFIG[i];
}
for (const i in MY_API.DANMU_MODIFY.configJson) {
if (MY_API.DANMU_MODIFY.configJson[i].length > MY_API.DANMU_MODIFY.maxLength)
MY_API.DANMU_MODIFY.maxLength = MY_API.DANMU_MODIFY.configJson[i].length;
}
for (const i in MY_API.DANMU_MODIFY.configJson) {
if (MY_API.DANMU_MODIFY.configJson[i].length < MY_API.DANMU_MODIFY.maxLength) {
let lastIndex = MY_API.DANMU_MODIFY.configJson[i].length - 1;
for (let c = lastIndex; c < MY_API.DANMU_MODIFY.maxLength - 1; c++) {
MY_API.DANMU_MODIFY.configJson[i].push(MY_API.DANMU_MODIFY.configJson[i][lastIndex])
}
}
}
},
check: (info) => {
for (let i = 0; i < MY_API.DANMU_MODIFY.maxLength; i++) {
let regex,
uid = info[2][0],
danmu = info[1];
try { regex = eval(MY_API.DANMU_MODIFY.configJson.DANMU_MODIFY_REGEX[i]) }
catch (e) { MYDEBUG('bliveproxy', `正则表达式出错 ${MY_API.DANMU_MODIFY.configJson.DANMU_MODIFY_REGEX[i]}`); regex = /^【/; }
if (regex.test(danmu) || MY_API.DANMU_MODIFY.configJson.DANMU_MODIFY_UID[i] == uid) return i;
}
return -1;
},
run: () => {
if (!SP_CONFIG.DANMU_MODIFY) return $.Deferred().resolve();
MY_API.DANMU_MODIFY.handleConfig();
// MYDEBUG('MY_API.DANMU_MODIFY.configJson', MY_API.DANMU_MODIFY.configJson);
W.bliveproxy.addCommandHandler('DANMU_MSG', command => {
if (!SP_CONFIG.DANMU_MODIFY) return $.Deferred().resolve();
let info = command.info;
MYDEBUG('bliveproxy DANMU_MSG', info);
let index = MY_API.DANMU_MODIFY.check(info);
if (index === -1) return $.Deferred().resolve();
// 显示模式
info[0][1] = MY_API.DANMU_MODIFY.configJson.DANMU_MODIFY_POOL[index];
// 尺寸
info[0][2] *= MY_API.DANMU_MODIFY.configJson.DANMU_MODIFY_SIZE[index];
// 颜色
info[0][3] = Number("0x" + MY_API.DANMU_MODIFY.configJson.DANMU_MODIFY_COLOR[index].replace("#", ""));
})
}
},
GET_PRIVILEGE: {
check_cache: () => {
if (ts_ms() >= MY_API.CACHE.NextVipPrivilege_TS) return true;
else return false;
},
save_cache: (expire_time) => {
const newTs = (expire_time + 2) * 1000;
if (newTs < MY_API.CACHE.NextVipPrivilege_TS || !MY_API.CACHE.NextVipPrivilege_TS) {
MY_API.CACHE.NextVipPrivilege_TS = newTs;
return MY_API.saveCache(false);
}
},
get_info: () => {
return BAPI.x.vip.privilege.my().then(response => {
MYDEBUG(`API.x.vip.privilege.my response`, response);
if (response.code === 0) return response.data.list;
else window.toast(`[大会员] 获取权益状态失败 ${response.message}`, 'error');
return false;
})
},
receive: (type) => {
return BAPI.x.vip.privilege.receive(type).then(response => {
MYDEBUG(`API.x.vip.privilege.receive response`, response);
if (response.code === 0) return true;
else window.toast(`[大会员] 领取权益失败(type=${type}) ${response.message}`, 'warning');
return false;
})
},
run: async () => {
if (!MY_API.CONFIG.GET_PRIVILEGE || otherScriptsRunning || Live_info.vipStatus === 0 || ts_ms() < MY_API.CACHE.NextVipPrivilege_TS) return $.Deferred().resolve();
let privilege_info = await MY_API.GET_PRIVILEGE.get_info();
if (!privilege_info) return $.Deferred().resolve();
let flag = false;
for (const i of privilege_info) {
if (i.state === 0) {
flag = await MY_API.GET_PRIVILEGE.receive(i.type, i.expire_time);
}
}
if (flag) window.toast("[大会员] 权益已领取", "success");
if (privilege_info.every(obj => obj.state === 1)) {
let min_expire_time = privilege_info[0].expire_time;
for (let i = 1; i < privilege_info.length; i++) {
if (privilege_info[i].expire_time < min_expire_time) min_expire_time = privilege_info[i].expire_time;
}
MY_API.GET_PRIVILEGE.save_cache(min_expire_time);
}
return $.Deferred().resolve();
}
},
AppUserTask: {
isRunning: false,
getRemainProgress: async () => {
return BAPI.xlive.app.getUserTaskProgress(userToken.access_token).then(response => {
MYDEBUG('API.xlive.app.getUserTaskProgress', response);
if (response.code === 0) {
const progress = response.data.progress;
const target = response.data.target;
return target - progress;
} else {
MYERROR('[APP用户任务] 获取进度失败', response.message);
return -1;
}
})
},
getUserTaskRewards: async () => {
return BAPI.xlive.app.userTaskReceiveRewards(userToken.access_token).then(response => {
MYDEBUG('API.xlive.app.userTaskReceiveRewards', response);
if (response.code === 0) {
return MY_API.chatLog(`[APP用户任务] 领取奖励成功
获得${response.data.num}个电池`, 'success')
} else {
return MY_API.chatLog(`[APP用户任务] 领取奖励失败
${response.message}`, 'error')
}
})
},
sendDanmu: async (remainProgress) => {
const content = remainProgress < MY_API.CONFIG.MEDAL_DANMU_CONTENT.length ? MY_API.CONFIG.MEDAL_DANMU_CONTENT[remainProgress] : ('打卡' + remainProgress);
return BAPI.xlive.app.sendmsg(userToken.access_token, content, 22474988, Live_info.uid).then(response => {
MYDEBUG(`API.sendLiveDanmu(弹幕 = ${content}, roomid = 22474988,)`, response);
if (response.code === 0) {
return MYDEBUG(`[APP用户任务] 弹幕发送内容【${content}】,房间号【22474988,】`, response);
} else {
return MY_API.chatLog(`[APP用户任务] 弹幕【${content}】(房间号【22474988,】)出错 ${response.message}`, 'error');
}
});
},
completeTask: async (remainProgress) => {
while (remainProgress > 0) {
await MY_API.AppUserTask.sendDanmu(remainProgress--);
await sleep(5000);
}
},
run: async () => {
if (!MY_API.CONFIG.APP_TASK || otherScriptsRunning) return $.Deferred().resolve();
if (!checkNewDay(MY_API.CACHE.AppTaskRewards)) return runMidnight(() => MY_API.LiveReward.WatchLive(), 'APP用户任务');
if (MY_API.MEDAL_DANMU.isRunning) {
// 【粉丝牌打卡】任务运行中
return setTimeout(() => MY_API.AppUserTask.run(), 3e3);
}
if (await setToken() === undefined)
return;
MY_API.AppUserTask.isRunning = true;
MYDEBUG('appToken userToken.access_token.length', userToken.access_token.length);
let remainProgress = await MY_API.AppUserTask.getRemainProgress();
if (remainProgress === -1) return MY_API.AppUserTask.isRunning = false;
await MY_API.AppUserTask.completeTask(remainProgress);
await MY_API.AppUserTask.getUserTaskRewards();
MY_API.CACHE.AppTaskRewards = ts_ms();
MY_API.saveCache();
MY_API.AppUserTask.isRunning = false;
return runMidnight(() => MY_API.LiveReward.WatchLive(), 'APP用户任务')
}
}
};
MY_API.init().then(() => {
try {
let runNext = $.Deferred();
if (SP_CONFIG.showEula) {
const eula = GM_getResourceText('eula');
myopen({
title: `${GM_info.script.name}最终用户许可协议`,
btn: ['同意协议并继续', '不同意'],
closeBtn: 0,
area: [String($(window).width() * 0.618) + 'px', String($(window).height() * 0.8) + 'px'],
content: eula,
yes: function (index) {
SP_CONFIG.showEula = false;
saveSpConfig();
layer.close(index);
runNext.resolve();
},
btn2: function () {
mymsg('脚本已停止运行', {
time: 3000,
icon: 2
});
window.toast('由于未同意最终用户许可协议,脚本已停止运行。', 'caution');
SP_CONFIG.showEula = true;
saveSpConfig();
runNext.reject();
}
});
} else runNext.resolve();
runNext.then(() => {
if (parseInt(Live_info.uid) === 0 || isNaN(parseInt(Live_info.uid)))
return window.toast('未登录,请先登录再使用脚本', 'caution');
// 新版本提示信息
if (MY_API.CONFIG.UPDATE_TIP) MY_API.newMessage(GM_info.script.version);
MYDEBUG('MY_API.CONFIG', MY_API.CONFIG);
main(MY_API);
});
}
catch (e) {
MYERROR('初始化错误', e);
}
});
}
async function main(API) {
// 检查更新
// checkUpdate(GM_info.script.version);
// 修复版本更新产生的兼容性问题
fixVersionDifferences(API, GM_info.script.version);
runExactMidnight(() => clearStat(), '重置统计');
API.creatSetBox(); // 创建设置框
API.removeUnnecessary(); // 移除页面元素
API.DANMU_MODIFY.run(); // 弹幕修改
const taskList = [
// 每日任务
API.MEDAL_DANMU.run, // 粉丝牌打卡弹幕
API.GroupSign.run, // 应援团签到
API.DailyReward.run, // 每日任务
API.LiveReward.run, // 直播每日任务
API.AppUserTask.run, // APP用户任务(发5条弹幕领1电池)
API.Exchange.runS2C, // 银瓜子换硬币
API.Exchange.runC2S, // 硬币换银瓜子
// 其它任务
API.AUTO_DANMU.run, // 自动发弹幕
API.Gift.run, // 送礼物
API.GET_PRIVILEGE.run, // 领取大会员权益
API.AUTO_CHECK_DANMU.run, // 检查弹幕是否发送成功
];
otherScriptsRunningCheck.then(() => runAllTasks(5000, 200, taskList));
if (API.CONFIG.TIME_RELOAD) reset(API.CONFIG.TIME_RELOAD_MINUTE * 60000);// 刷新直播间
function reset(delay) {
let resetTimer = setTimeout(() => {
if (API.CONFIG.WatchLive && checkNewDay(API.CACHE.LiveReward_TS)) {
MYDEBUG('[刷新直播间]', '正在运行观看直播任务,10分钟后再次检查');
clearTimeout(resetTimer);
return reset(600e3);
}
const resetTime = sleepCheck(API.CONFIG);
if (resetTime) {
MYDEBUG('[刷新直播间]', `处于休眠时间段,将在${resetTime}毫秒后刷新直播间`);
clearTimeout(resetTimer);
return reset(resetTime);
}
W.location.reload();
}, delay);
};
}
function checkUpdate(version) {
if (!checkNewDay(noticeJson.lastCheckUpdateTs)) return;
const headers = {
"Accept": `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9`,
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7"
};
XHR({
GM: true,
anonymous: true,
method: "GET",
url: "https://andywang.top:3001/api/v1/notice",
headers: headers,
responseType: "json"
}).then(response => {
MYDEBUG("检查更新 checkUpdate", response);
if (!response || response.response.status !== 200)
return MYERROR(`[检查更新] 获取notice.json出错`);
noticeJson = response.body.data;
noticeJson.lastCheckUpdateTs = ts_ms();
GM_setValue(`noticeJson`, noticeJson);
const scriptVersion = noticeJson.version;
const greasyforkOpenTabOptions = { active: true, insert: true, setParent: true };
if (versionStringCompare(version, scriptVersion) === -1) { // version < scriptVersion
// 需要更新
let updateSource, updateURL;
if (GM_info.script.updateURL === null) {
updateSource = "Greasy Fork"
updateURL = "https://greasyfork.org/scripts/406048-b%E7%AB%99%E7%9B%B4%E6%92%AD%E9%97%B4%E6%8C%82%E6%9C%BA%E5%8A%A9%E6%89%8B";
} else {
updateSource = "BLTH-server";
updateURL = "https://andywang.top:3001/api/v1/BLTH.user.js";
}
let index = myconfirm(`检测到新版本 ${scriptVersion}。
是否从 ${updateSource} 更新脚本?`, {
title: '更新脚本',
btn: ['是', '否']
}, function () {
// 更新
if (updateSource === "Greasy Fork") {
layer.close(index);
GM_openInTab(updateURL, greasyforkOpenTabOptions);
}
else {
updateBLTH(updateURL);
mymsg('正在更新...', { time: 2000 });
}
}, function () {
// 不更新
});
}
})
}
/**
* 获取粉丝勋章列表和真实直播间号
* @param {Number} page
* @returns
*/
async function getMedalList(page = 1) {
if (page === 1) medal_info = { status: $.Deferred(), medal_list: [] };
let end = false;
while (true) {
await BAPI.xlive.app.medal(page).then((response) => {
MYDEBUG('before init() getMedalList: API.i.medal', response);
if (response.code === 0) {
for (let i = 0; i < response.data.items.length; i++) {
if (response.data.items[i].roomid && response.data.items[i].roomid <= 100000) {
BAPI.room.get_info(response.data.items[i].roomid).then((res) => {
if (res.code === 0) {
response.data.items[i].real_roomid = res.data.room_id;
} else {
MYERROR(`获取直播间${response.data.items[i].roomid}的真实房间号出错`);
}
})
} else {
response.data.items[i].real_roomid = response.data.items[i].roomid;
}
}
medal_info.medal_list = medal_info.medal_list.concat(response.data.items);
if (response.data.page_info.cur_page < response.data.page_info.total_page) page++;
else { medal_info.status.resolve(); end = true }
} else if (response.code === 1024) {
window.toast(`获取粉丝勋章列表超时 ${response.message} 部分功能将无法正常运行`, 'error');
delayCall(() => getMedalList(page));
end = true;
} else {
window.toast(`获取粉丝勋章列表失败 ${response.message} 部分功能将无法正常运行`, 'error');
delayCall(() => getMedalList(page));
end = true;
}
});
if (end) {
runTomorrow(() => getMedalList(), 0, 1, "获取粉丝勋章列表");
break;
}
await sleep(200);
}
};
/**
* 比较版本号大小
* @param {string} ver1
* @param {string} ver2
* @returns {boolean} 若 ver1 > ver2 返回 1, ver1 = ver2 返回 0, ver1 < ver2, 返回 -1
*/
function versionStringCompare(ver1 = '0', ver2 = '0') {
function changeVersion2Num(ver) {
return ver.match(/\d.*/)[0].split('.').reduce((total, value, index) => total + (0.01 ** index) * Number(value), 0);
}
const verNum1 = changeVersion2Num(ver1),
verNum2 = changeVersion2Num(ver2);
if (verNum1 > verNum2) return 1
else if (verNum1 < verNum2) return -1
else return 0;
}
/**
* 模拟鼠标移动
*/
function mouseMove() {
MYDEBUG('屏蔽挂机检测', "触发一次MouseEvent(mousemove)")
document.dispatchEvent(new MouseEvent('mousemove', {
screenX: Math.floor(Math.random() * screen.availWidth),
screenY: Math.floor(Math.random() * screen.availHeight),
clientX: Math.floor(Math.random() * W.innerWidth),
clientY: Math.floor(Math.random() * W.innerHeight),
ctrlKey: Math.random() > 0.8,
shiftKey: Math.random() > 0.8,
altKey: Math.random() > 0.9,
metaKey: false,
button: 0,
buttons: 0,
relatedTarget: null,
region: null,
detail: 0,
view: W,
sourceCapabilities: W.InputDeviceCapabilities ? new W.InputDeviceCapabilities({ fireTouchEvents: false }) : null,
bubbles: true,
cancelable: true,
composed: true
}));
}
/**
* 执行所有任务
* @param {Number} sleep 休眠时间
* @param {Number} interval 任务间隔
* @param {list} task 任务
*/
function runAllTasks(sleep, interval, task) {
let num = 0;
setTimeout(() => {
for (const i of task) {
setTimeout(() => i(), interval * num++);
}
}, sleep);
}
/**
* 修复因版本差异造成的错误
* @param API MY_API
*/
function fixVersionDifferences(API, version) {
// 添加新的修复后需修改版本号
if (versionStringCompare(SP_CONFIG.storageLastFixVersion, "6.0.1") >= 0) return;
// 修复变量类型错误
const configFixList = ['AUTO_GIFT_ROOMID', 'COIN_UID'];
if (!configFixList.every(i => Array.isArray(API.CONFIG[i]))) {
for (const i of configFixList) {
if (!Array.isArray(API.CONFIG[i])) {
API.CONFIG[i] = String(API.CONFIG[i]).split(",");
}
}
}
// 修复变量值差异
if (API.CONFIG.GIFT_SORT == 'high') API.CONFIG.GIFT_SORT = 'GIFT_SORT_HIGH';
else if (API.CONFIG.GIFT_SORT == 'low') API.CONFIG.GIFT_SORT = 'GIFT_SORT_LOW'
if (API.CONFIG.MEDAL_DANMU_ROOM)
API.CONFIG.LIVE_TASKS_ROOM = API.CONFIG.MEDAL_DANMU_ROOM;
if (API.CONFIG.MEDAL_DANMU_METHOD)
API.CONFIG.LIVE_TASKS_METHOD = 'LIVE_TASKS_' + API.CONFIG.MEDAL_DANMU_METHOD.split('_').pop();
// localStorage fix
localStorage.removeItem("im_deviceid_IGIFTMSG");
// save settings
SP_CONFIG.storageLastFixVersion = version;
API.saveConfig(false);
API.saveCache();
saveSpConfig();
}
/**
* 保存特殊设置
*/
function saveSpConfig(printLog = true) {
if (printLog) MYDEBUG('SP_CONFIG已保存', SP_CONFIG);
return GM_setValue(`SP_CONFIG`, SP_CONFIG);
}
/**
* layer动画
* @param {jqdom} jqdom
* @param {boolean} bool
*/
function animChange(jqdom, bool) {
if (bool) {
// show => hide
jqdom.removeClass('layer-anim');
jqdom.removeClass('layer-anim-00');
jqdom.addClass('layer-anim');
jqdom.addClass('layer-anim-close');
} else {
// hide => show
jqdom.removeClass('layer-anim');
jqdom.removeClass('layer-anim-close');
jqdom.addClass('layer-anim');
jqdom.addClass('layer-anim-00');
}
}
/**
* 合并两个对象,只合并 obj1 中不包含(或为undefined, null)但 obj2 中有的属性
* 删除 obj1 有但 obj2 中没有的属性
*/
function mergeObject(obj1, obj2) {
function combine(object1, object2) {
for (let i in object2) {
if (object1[i] === undefined || object1[i] === null) object1[i] = object2[i];
else if (!Array.isArray(object1[i]) && typeof object1[i] === 'object') combine(object1[i], object2[i]);
}
}
function del(object1, object2) {
for (let i in object1) {
if (object2[i] === undefined || object2[i] === null) delete object1[i];
else if (!Array.isArray(object1[i]) && typeof object1[i] === 'object') del(object1[i], object2[i]);
}
}
combine(obj1, obj2);
del(obj1, obj2);
}
/**
* 通过检查某些特性是否存在判断浏览器版本
* @returns {Array} 0: 提示字符串 1: 等级字符串
*/
function checkBrowserVersion() {
if (typeof Array.prototype.findIndex === "undefined")
return ["浏览器版本过低,挂机助手停止运行", "error"];
else if (typeof String.prototype.replaceAll === 'undefined')
return ["浏览器版本略低,挂机助手可以正常运行但建议升级浏览器到最新版", "info"];
else
return ["ok", "info"]
}
/**
* 保存文件到本地
* @param fileName 文件名
* @param fileContent 文件内容
*/
function downFile(fileName, fileContent) {
let elementA = document.createElement("a");
elementA.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(fileContent))
);
elementA.setAttribute("download", fileName);
elementA.style.display = "none";
document.body.appendChild(elementA);
elementA.click();
document.body.removeChild(elementA);
}
/**
* 更新 BLTH 脚本
* @param {*} link 更新地址
*/
function updateBLTH(link) {
let elementA = document.createElement("a");
elementA.setAttribute("href", link);
elementA.style.display = "none";
document.body.appendChild(elementA);
elementA.click();
document.body.removeChild(elementA);
}
/**
* 导出配置文件
* @param MY_API_CONFIG MY_API.CONFIG
* @param SP_CONFIG SP_CONFIG
*/
function exportConfig(MY_API_CONFIG, SP_CONFIG) {
const exportJson = {
VERSION: GM_info.script.version,
MY_API_CONFIG: MY_API_CONFIG,
SP_CONFIG: SP_CONFIG
};
return downFile('BLTH_CONFIG.json', exportJson);
}
/**
* 导入配置文件
*/
function importConfig() {
let selectedFile = document.getElementById("BLTH_config_file").files[0];
let reader = new FileReader();
reader.onload = function () {
MYDEBUG("importConfig 文件读取结果:", this.result);
try {
readConfigArray[0] = JSON.parse(decodeURIComponent(this.result));
if (typeof readConfigArray[0] == 'object' && readConfigArray[0]) {
const list = ["VERSION", "MY_API_CONFIG", "SP_CONFIG"];
for (const i of list) {
if (!readConfigArray[0].hasOwnProperty(i)) return wrongFile();
}
if (versionStringCompare("5.6.6.3", readConfigArray[0]["VERSION"]) === 1) // 5.6.6.3 > VERSION
return wrongFile('该配置文件版本过低')
return readConfigArray[1].resolve();
} else {
return wrongFile();
}
} catch (e) {
MYDEBUG('importConfig error:', e);
return wrongFile();
}
};
reader.readAsText(selectedFile);
function wrongFile(msg = '文件格式错误') {
return mymsg(msg, {
time: 2500,
icon: 2
});
}
}
/**
* (23,50) 获取与目标时间在一天内的间隔时间,24小时制(毫秒)
* @param hour 整数 小时
* @param minute 整数 分钟
* @param second 整数 秒(可不填)
* @returns {number} intervalTime
*/
function getIntervalTime(hour, minute, second) {
const myDate = new Date();
const h = myDate.getHours();
const m = myDate.getMinutes();
const s = myDate.getSeconds();
const TargetTime = hour * 3600 * 1e3 + minute * 60 * 1e3 + (!second ? 0 : second * 1e3)
const nowTime = h * 3600 * 1e3 + m * 60 * 1e3 + s * 1e3;
const intervalTime = TargetTime - nowTime;
MYDEBUG("[getIntervalTime]获取间隔时间", `${intervalTime}毫秒`);
if (intervalTime < 0) {
return 24 * 3600 * 1e3 + intervalTime
}
else {
return intervalTime
}
}
/**
* (23,50) 当前时间是否为23:50
* @param hour 整数 小时
* @param minute 整数 分钟
* @param second 整数 秒(可不填)
* @returns {boolean}
*/
function isTime(hour, minute, second) {
let myDate = new Date();
let h = myDate.getHours();
let m = myDate.getMinutes();
let s = myDate.getSeconds();
if ((h == hour && m == minute && !second) || (h == hour && m == minute && s == second)) {
return true
} else {
MYDEBUG("isTime 错误时间", `目标时间${hour}时${minute}分${second || 0}秒,当前时间${h}时${m}分${s}秒`);
return false
}
}
/**
* (2,10,0,1) 当前是否在两点0分到十点1分之间
* @param sH 整数 起始小时
* @param eH 整数 终止小时
* @param sM 整数 起始分钟
* @param eM 整数 终止分钟
* @returns {boolean}
*/
function inTimeArea(sH, eH, sM, eM) {
if (sH > 23 || eH > 24 || sH < 0 || eH < 1 || sM > 59 || sM < 0 || eM > 59 || eM < 0) {
return false
}
const hourMs = 3600000, minMs = 60000,
myDate = new Date(),
nowHour = myDate.getHours(),
nowMin = myDate.getMinutes(),
nowTimeTs = nowHour * hourMs + nowMin * minMs,
targetStartTs = sH * hourMs + sM * minMs,
targetEndTs = eH * hourMs + eM * minMs;
if (targetStartTs < targetEndTs) {
if (nowTimeTs >= targetStartTs && nowTimeTs < targetEndTs)
return true;
else return false;
} else {
if (nowTimeTs >= targetStartTs || nowTimeTs < targetEndTs)
return true
else return false;
}
};
/**
* 暂停
* @param millisecond
* @returns {Promise} resolve
*/
function sleep(millisecond) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, millisecond)
})
}
/**
* 检查是否为新一天
* 注:并无要求被检查时间戳大于当前时间戳
* @param ts 被检查的时间戳
* @param type 检查标准 北京时间(默认): Beijing 本地时间: local
* @returns {boolean}
*/
function checkNewDay(ts, type = 'Beijing') {
if (ts == 0) return true;
let t = new Date(ts);
let d = type === 'Beijing' ? getCHSdate() : new Date();
let td = t.getDate();
let dd = d.getDate();
let now_ts = d.getTime();
return dd !== td || now_ts - ts > 86400000;
};
/**
* 唯一运行检测
*/
function onlyScriptCheck() {
try {
let UNIQUE_CHECK_CACHE = localStorage.getItem("UNIQUE_CHECK_CACHE") || 0;
const t = ts_ms();
if (t - UNIQUE_CHECK_CACHE >= 0 && t - UNIQUE_CHECK_CACHE <= 11e3) {
// 其他脚本正在运行
window.toast('检测到其他直播间页面的挂机助手正在运行,无需重复运行的功能将停止运行', 'caution');
otherScriptsRunning = true;
return otherScriptsRunningCheck.resolve();
}
let timer_unique;
const uniqueMark = () => {
timer_unique = setTimeout(() => uniqueMark(), 10e3);
UNIQUE_CHECK_CACHE = ts_ms();
localStorage.setItem("UNIQUE_CHECK_CACHE", UNIQUE_CHECK_CACHE)
};
W.addEventListener('unload', () => {
clearTimeout(timer_unique);
localStorage.setItem("UNIQUE_CHECK_CACHE", 0);
});
uniqueMark();
return otherScriptsRunningCheck.resolve();
}
catch (e) {
MYDEBUG('重复运行检测出错', e);
return otherScriptsRunningCheck.reject();
}
}
/**
* 防抖
* @param {function} func
* @param {number} wait
* @returns {function}
*/
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout)
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
};
};
/**
* 发起xmlhttpRequest请求(GM函数和浏览器原生)
* @param XHROptions
* @returns {object} resolve({response: res, body: res.response})
*/
function XHR(XHROptions) {
return new Promise(resolve => {
const onerror = (error) => {
MYERROR('XHR出错', XHROptions, error);
resolve(undefined);
};
if (XHROptions.GM) {
if (XHROptions.method === 'POST') {
if (XHROptions.headers === undefined)
XHROptions.headers = {};
if (XHROptions.headers['Content-Type'] === undefined)
XHROptions.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
}
XHROptions.timeout = 30 * 1000;
XHROptions.onload = res => resolve({ response: res, body: res.response });
XHROptions.onerror = onerror;
XHROptions.ontimeout = onerror;
GM_xmlhttpRequest(XHROptions);
}
else {
const xhr = new XMLHttpRequest();
xhr.open(XHROptions.method, XHROptions.url);
if (XHROptions.method === 'POST' && xhr.getResponseHeader('Content-Type') === null)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
if (XHROptions.cookie)
xhr.withCredentials = true;
if (XHROptions.responseType !== undefined)
xhr.responseType = XHROptions.responseType;
xhr.timeout = 30 * 1000;
xhr.onload = ev => {
const res = ev.target;
resolve({ response: res, body: res.response });
};
xhr.onerror = onerror;
xhr.ontimeout = onerror;
xhr.send(XHROptions.data);
}
});
};
/**
* 包装layer的prompt方法
* @param obj
* @param func
* @returns index
*/
function myprompt(obj, func) {
if (SP_CONFIG.darkMode) {
if (obj.title) obj.title = '' + obj.title + ''
}
let index = layer.prompt(obj, func);
if (SP_CONFIG.darkMode) {
layer.style(index, {
'background-color': '#1c1c1c'
});
}
return index;
}
/**
* 包装layer的msg方法
* @param msg
* @param obj
* @returns index
*/
function mymsg(msg, obj) {
let index = layer.msg(msg, obj);
if (SP_CONFIG.darkMode) {
layer.style(index, {
'background-color': '#1c1c1c',
'color': '#a2a7ae'
});
}
return index;
}
/**
* 包装layer的open方法
* @param obj
* @returns index
*/
function myopen(obj) {
if (SP_CONFIG.darkMode) {
if (obj.title) obj.title = '' + obj.title + ''
}
let index = layer.open(obj);
if (SP_CONFIG.darkMode) {
layer.style(index, {
'background-color': '#1c1c1c',
'color': '#a2a7ae'
});
}
return index;
}
/**
* 包装layer的confirm方法
* @param msg
* @param obj
* @param func
* @returns index
*/
function myconfirm(msg, obj, ...func) {
if (SP_CONFIG.darkMode) {
if (obj.title) obj.title = '' + obj.title + ''
}
let index = layer.confirm(msg, obj, ...func);
if (SP_CONFIG.darkMode) {
layer.style(index, {
'background-color': '#1c1c1c',
'color': '#a2a7ae'
});
}
return index;
}
/**
* 包装layer的tips方法
* @param content
* @param element
* @param obj
*/
function mytips(content, element, obj = {}) {
const contentCss = { "border-radius": "20px", "background-color": "#00c4f8" },
tipsGTCss = { "border-right-color": "#00c4f8" };
function _successFn(dom, index) {
const layerContent = dom.children('.layui-layer-content'),
layerTipsGT = layerContent.children('.layui-layer-TipsG.layui-layer-TipsT');
layerContent.css(contentCss);
layerTipsGT.css(tipsGTCss);
}
if (!obj.success) obj.success = _successFn;
else obj.success = function () { obj.success(); _successFn() };
layer.tips(content, element, obj);
}
})();