koishi-plugin-bilibili-notify
Version:
Koishi bilibili notify plugin
405 lines (404 loc) • 19.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Config = exports.name = exports.inject = void 0;
exports.apply = apply;
/* eslint-disable @typescript-eslint/ban-types */
const koishi_1 = require("koishi");
// import plugins
// import Authority from './authority'
const comRegister_1 = __importDefault(require("./comRegister"));
const Database = __importStar(require("./database"));
// import Service
const generateImg_1 = __importDefault(require("./generateImg"));
const biliAPI_1 = __importDefault(require("./biliAPI"));
exports.inject = ['puppeteer', 'database', 'notifier'];
exports.name = 'bilibili-notify';
let globalConfig;
exports.Config = koishi_1.Schema.object({
require: koishi_1.Schema.object({}).description('必填设置'),
key: koishi_1.Schema.string()
.pattern(/^[0-9a-f]{32}$/)
.role('secret')
.required()
.description('请输入一个32位小写字母的十六进制密钥(例如:9b8db7ae562b9864efefe06289cc5530),使用此密钥将你的B站登录信息存储在数据库中,请一定保存好此密钥。如果你忘记了此密钥,必须重新登录。你可以自行生成,或到这个网站生成:https://www.sexauth.com/'),
master: koishi_1.Schema.intersect([
koishi_1.Schema.object({
enable: koishi_1.Schema.boolean()
.default(false)
.description('是否开启主人账号功能,如果您的机器人没有私聊权限请不要开启此功能。开启后如果机器人运行错误会向您进行报告')
}).description('主人账号'),
koishi_1.Schema.union([
koishi_1.Schema.object({
enable: koishi_1.Schema.const(true).required(),
platform: koishi_1.Schema.union(['qq', 'qqguild', 'onebot', 'discord', 'red', 'telegram', 'satori', 'chronocat', 'lark'])
.description('请选择您的私人机器人平台,目前支持QQ、QQ群、OneBot、Discord、RedBot、Telegram、Satori、ChronoCat、Lark。从2.0版本开始,只能在一个平台下使用本插件'),
masterAccount: koishi_1.Schema.string()
.role('secret')
.required()
.description('主人账号,在Q群使用可直接使用QQ号,若在其他平台使用,请使用inspect插件获取自身ID'),
masterAccountGuildId: koishi_1.Schema.string()
.role('secret')
.description('主人账号所在的群组ID,只有在QQ频道、Discord这样的环境才需要填写,请使用inspect插件获取群组ID'),
}),
koishi_1.Schema.object({})
])
]),
basicSettings: koishi_1.Schema.object({}).description('基本设置'),
unlockSubLimits: koishi_1.Schema.boolean()
.default(false)
.description('解锁3个直播订阅限制,默认只允许订阅3位UP主。订阅过多用户可能有导致IP暂时被封禁的风险'),
automaticResend: koishi_1.Schema.boolean()
.default(true)
.description('是否开启自动重发功能,默认开启。开启后,如果推送失败,将会自动重发,尝试三次。关闭后,推送失败将不会再重发,直到下一次推送'),
renderType: koishi_1.Schema.union(['render', 'page'])
.role('')
.default('render')
.description('渲染类型,默认为render模式,渲染速度更快,但会出现乱码问题,若出现乱码问题,请切换到page模式。若使用自定义字体,建议选择render模式'),
userAgent: koishi_1.Schema.string()
.required()
.description('设置请求头User-Agen,请求出现-352时可以尝试修改,UA获取方法可参考:https://blog.csdn.net/qq_44503987/article/details/104929111'),
subTitle: koishi_1.Schema.object({}).description('手动订阅'),
sub: koishi_1.Schema.array(koishi_1.Schema.object({
uid: koishi_1.Schema.string().description('订阅用户UID'),
dynamic: koishi_1.Schema.boolean().description('是否订阅用户动态'),
live: koishi_1.Schema.boolean().description('是否订阅用户直播'),
target: koishi_1.Schema.array(koishi_1.Schema.object({
channelIdArr: koishi_1.Schema.array(koishi_1.Schema.object({
channelId: koishi_1.Schema.string().description('频道/群组号'),
dynamic: koishi_1.Schema.boolean().description('该频道/群组是否推送动态信息'),
live: koishi_1.Schema.boolean().description('该频道/群组是否推送直播通知'),
atAll: koishi_1.Schema.boolean().description('推送开播通知时是否艾特全体成员')
})).description('频道/群组信息'),
platform: koishi_1.Schema.string().description('推送平台')
})).description('订阅用户需要发送的频道/群组信息')
})).role('table').description('手动输入订阅信息,方便自定义订阅内容,这里的订阅内容不会存入数据库。uid: 订阅用户UID,dynamic: 是否需要订阅动态,live: 是否需要订阅直播'),
dynamic: koishi_1.Schema.object({}).description('动态推送设置'),
dynamicUrl: koishi_1.Schema.boolean()
.default(false)
.description('发送动态时是否同时发送链接。注意:如果使用的是QQ官方机器人不能开启此项!'),
dynamicCheckNumber: koishi_1.Schema.number()
.min(2)
.max(10)
.role('slider')
.step(1)
.default(5)
.description('设定每次检查动态的数量。若订阅的UP主经常在短时间内连着发多条动态可以将该值提高,若订阅的UP主有置顶动态,在计算该值时应+1。默认值为5条'),
dynamicLoopTime: koishi_1.Schema.union(['1分钟', '2分钟', '3分钟', '5分钟', '10分钟', '20分钟'])
.role('')
.default('2分钟')
.description('设定多久检测一次动态。若需动态的时效性,可以设置为1分钟。若订阅的UP主经常在短时间内连着发多条动态应该将该值提高,否则会出现动态漏推送和晚推送的问题,默认值为2分钟'),
live: koishi_1.Schema.object({}).description('直播推送设置'),
changeMasterInfoApi: koishi_1.Schema.boolean()
.default(false)
.description('是否切换获取主播信息API,在遇到错误getMasterInfo()时可以尝试切换'),
liveStartAtAll: koishi_1.Schema.boolean()
.default(false)
.description('直播开始时艾特全体成员,默认关闭'),
restartPush: koishi_1.Schema.boolean()
.default(true)
.description('插件重启后,如果订阅的主播正在直播,是否进行一次推送,默认开启'),
pushTime: koishi_1.Schema.number()
.min(0)
.max(12)
.step(0.5)
.default(1)
.description('设定隔多长时间推送一次直播状态,单位为小时,默认为一小时'),
customLiveStart: koishi_1.Schema.string()
.default('-name开播啦 -link')
.description('自定义开播提示语,-name代表UP昵称,-link代表直播间链接(如果使用的是QQ官方机器人,请不要使用)。例如-name开播啦,会发送为xxxUP开播啦'),
customLive: koishi_1.Schema.string()
.description('自定义直播中提示语,-name代表UP昵称,-time代表开播时长,-link代表直播间链接(如果使用的是QQ官方机器人,请不要使用)。例如-name正在直播,会发送为xxxUP正在直播xxx'),
customLiveEnd: koishi_1.Schema.string()
.default('-name下播啦,本次直播了-time')
.description('自定义下播提示语,-name代表UP昵称,-time代表开播时长。例如-name下播啦,本次直播了-time,会发送为xxxUP下播啦,直播时长为xx小时xx分钟xx秒'),
hideDesc: koishi_1.Schema.boolean()
.default(false)
.description('是否隐藏UP主直播间简介,开启后推送的直播卡片将不再展示简介'),
style: koishi_1.Schema.object({}).description('美化设置'),
removeBorder: koishi_1.Schema.boolean()
.default(false)
.description('移除推送卡片边框'),
cardColorStart: koishi_1.Schema.string()
.pattern(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)
.default('#F38AB5')
.description('推送卡片的开始渐变背景色,请填入16进制颜色代码,参考网站:https://webkul.github.io/coolhue/'),
cardColorEnd: koishi_1.Schema.string()
.pattern(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)
.default('#F9CCDF')
.description('推送卡片的结束渐变背景色,请填入16进制颜色代码,参考网站:https://colorate.azurewebsites.net/'),
enableLargeFont: koishi_1.Schema.boolean()
.default(false)
.description('是否开启动态推送卡片大字体模式,默认为小字体。小字体更漂亮,但阅读比较吃力,大字体更易阅读,但相对没这么好看'),
font: koishi_1.Schema.string()
.description('推送卡片的字体样式,如果你想用你自己的字体可以在此填写,例如:Microsoft YaHei'),
filter: koishi_1.Schema.intersect([
koishi_1.Schema.object({
enable: koishi_1.Schema.boolean()
.default(false)
.description('是否开启动态屏蔽功能')
}).description('屏蔽设置'),
koishi_1.Schema.union([
koishi_1.Schema.object({
enable: koishi_1.Schema.const(true).required().experimental(),
notify: koishi_1.Schema.boolean()
.default(false)
.description('动态被屏蔽是否发送提示'),
regex: koishi_1.Schema.string()
.description('正则表达式屏蔽'),
keywords: koishi_1.Schema.array(String)
.description('关键字屏蔽,一个关键字为一项'),
forward: koishi_1.Schema.boolean()
.default(false)
.description("是否屏蔽转发动态"),
}),
koishi_1.Schema.object({})
])
]),
debug: koishi_1.Schema.object({}).description('调试设置'),
dynamicDebugMode: koishi_1.Schema.boolean()
.default(false)
.description('动态调试模式,开启后会在控制台输出动态推送的详细信息,用于调试')
.experimental()
});
class ServerManager extends koishi_1.Service {
// 服务
servers = [];
// 渲染模式
renderType;
// 动态循环时间
dynamicLoopTime;
constructor(ctx) {
super(ctx, 'sm');
// 插件运行相关指令
const sysCom = ctx.command('sys', 'bili-notify插件运行相关指令', { permissions: ['authority:5'] });
sysCom
.subcommand('.restart', '重启插件')
.usage('重启插件')
.example('sys restart')
.action(async () => {
this.logger.info('调用sys restart指令');
if (await this.restartPlugin()) {
return '插件重启成功';
}
return '插件重启失败';
});
sysCom
.subcommand('.stop', '停止插件')
.usage('停止插件')
.example('sys stop')
.action(async () => {
this.logger.info('调用sys stop指令');
if (await this.disposePlugin()) {
return '插件已停止';
}
return '停止插件失败';
});
sysCom
.subcommand('.start', '启动插件')
.usage('启动插件')
.example('sys start')
.action(async () => {
this.logger.info('调用sys start指令');
if (await this.registerPlugin()) {
return '插件启动成功';
}
return '插件启动失败';
});
}
start() {
// 加载配置
// 根据用户设置的渲染模式设置
switch (globalConfig.renderType) {
case 'render':
this.renderType = 0;
break;
case 'page':
this.renderType = 1;
break;
}
// 转换为具体时间
switch (globalConfig.dynamicLoopTime) {
case '1分钟':
this.dynamicLoopTime = 60;
break;
case '2分钟':
this.dynamicLoopTime = 120;
break;
case '3分钟':
this.dynamicLoopTime = 180;
break;
case '5分钟':
this.dynamicLoopTime = 300;
break;
case '10分钟':
this.dynamicLoopTime = 600;
break;
case '20分钟':
this.dynamicLoopTime = 1200;
break;
}
// 注册插件
if (this.registerPlugin()) {
this.logger.info('插件启动成功');
}
else {
this.logger.error('插件启动失败');
}
}
registerPlugin = () => {
// 如果已经有服务则返回false
if (this.servers.length !== 0)
return false;
// 注册插件
try {
// BA = BiliAPI
const ba = this.ctx.plugin(biliAPI_1.default, {
userAgent: globalConfig.userAgent,
key: globalConfig.key
});
// GI = GenerateImg
const gi = this.ctx.plugin(generateImg_1.default, {
renderType: this.renderType,
filter: globalConfig.filter,
removeBorder: globalConfig.removeBorder,
cardColorStart: globalConfig.cardColorStart,
cardColorEnd: globalConfig.cardColorEnd,
hideDesc: globalConfig.hideDesc,
enableLargeFont: globalConfig.enableLargeFont,
font: globalConfig.font
});
// CR = ComRegister
const cr = this.ctx.plugin(comRegister_1.default, {
sub: globalConfig.sub,
master: globalConfig.master,
unlockSubLimits: globalConfig.unlockSubLimits,
automaticResend: globalConfig.automaticResend,
changeMasterInfoApi: globalConfig.changeMasterInfoApi,
liveStartAtAll: globalConfig.liveStartAtAll,
restartPush: globalConfig.restartPush,
pushTime: globalConfig.pushTime,
customLiveStart: globalConfig.customLiveStart,
customLive: globalConfig.customLive,
customLiveEnd: globalConfig.customLiveEnd,
dynamicCheckNumber: globalConfig.dynamicCheckNumber,
dynamicLoopTime: this.dynamicLoopTime,
dynamicUrl: globalConfig.dynamicUrl,
filter: globalConfig.filter,
dynamicDebugMode: globalConfig.dynamicDebugMode
});
// 添加服务
this.servers.push(ba);
this.servers.push(gi);
this.servers.push(cr);
}
catch (e) {
this.logger.error('插件注册失败', e);
return false;
}
// 成功返回true
return true;
};
disposePlugin = async () => {
// 如果没有服务则返回false
if (this.servers.length === 0)
return false;
// 遍历服务
await new Promise(resolve => {
this.servers.forEach(fork => {
fork.dispose();
});
// 清空服务
this.servers = [];
resolve('ok');
});
// 成功返回true
return true;
};
restartPlugin = async () => {
// 如果没有服务则返回false
if (this.servers.length === 0)
return false;
// 停用插件
await this.disposePlugin();
// 隔一秒启动插件
return new Promise(resolve => {
this.ctx.setTimeout(() => {
try {
this.registerPlugin();
}
catch (e) {
this.logger.error('重启插件失败', e);
resolve(false);
}
resolve(true);
}, 1000);
});
};
}
function apply(ctx, config) {
// 设置config
globalConfig = config;
// 设置提示
ctx.notifier.create({
content: '从2.0.0-alpha.9以前版本更新需重新订阅'
});
ctx.notifier.create({
content: '请使用Auth插件创建超级管理员账号,没有权限将无法使用该插件提供的指令。'
});
if (config.unlockSubLimits) { // 用户允许订阅超过三个用户
// 设置警告
ctx.notifier.create({
type: 'danger',
content: '过多的订阅可能会导致IP暂时被封禁!'
});
}
// load database
ctx.plugin(Database);
// Register ServerManager
ctx.plugin(ServerManager);
// 当用户输入“恶魔兔,启动!”时,执行 help 指令
ctx.middleware((session, next) => {
if (session.content === '恶魔兔,启动!') {
return session.send('启动不了一点');
}
else {
return next();
}
});
}