koishi-plugin-fate
Version:
A koishi plugin for fortune telling and sign in.
1,068 lines (1,052 loc) • 31 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, { get: all[name2], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Config: () => Config,
apply: () => apply,
inject: () => inject,
logger: () => logger,
name: () => name
});
module.exports = __toCommonJS(src_exports);
var import_koishi3 = require("koishi");
// src/core/roll.ts
var Fate = class {
static {
__name(this, "Fate");
}
constructor() {
}
seededRandom(seed) {
const x = Math.sin(seed) * 1e4;
return x - Math.floor(x);
}
async getFortune(uid, maxRange = 100) {
const etime = (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0);
let userId = Number(uid);
const todaySeed = userId * etime % 1000000001;
const todayFate = Math.floor(this.seededRandom(todaySeed) * maxRange);
return todayFate;
}
async getRandomObjects(jsonObject, uid) {
if (!Array.isArray(jsonObject) || jsonObject.length < 4) {
throw new Error("input must be an array containing at least four objects");
}
const seed = await this.getFortune(uid);
const randomIndexes = /* @__PURE__ */ new Set();
let counter = 0;
while (randomIndexes.size < 4) {
const randomIndex = Math.floor(this.seededRandom(seed + counter) * jsonObject.length);
randomIndexes.add(randomIndex);
counter++;
}
return Array.from(randomIndexes).map((index) => jsonObject[index]);
}
async random(min, max, luck = 50) {
let rmin = min;
let rmax = max;
if (max < min) {
rmin = max;
rmax = min;
}
const mean = luck / 100;
const std = 0.12;
let a, b;
do {
a = Math.random();
b = Math.random();
} while (a == 0 || b == 0);
let rand = Math.cos(2 * Math.PI * a) * Math.sqrt(-2 * Math.log(b));
rand = rand * std + mean;
if (rand > 1) {
rand = 2 - rand;
} else if (rand < 0) {
rand = -rand;
}
if (rand > 1) {
rand = 1;
} else if (rand < 0) {
rand = 0;
}
return Math.round(rand * (rmax - rmin) + rmin);
}
};
// src/data/defaults.ts
var defaultLevelInfo = [
{ level: 0, levelExp: 0, levelName: "不知名杂鱼", levelColor: "#838383" },
{ level: 1, levelExp: 500, levelName: "荒野漫步者", levelColor: "#838383" },
{ level: 2, levelExp: 1e3, levelName: "拓荒者", levelColor: "#838383" },
{ level: 3, levelExp: 1500, levelName: "冒险家", levelColor: "#838383" },
{ level: 4, levelExp: 2e3, levelName: "传说的冒险家", levelColor: "#000000" },
{ level: 5, levelExp: 3e3, levelName: "隐秘收藏家", levelColor: "#000000" },
{ level: 6, levelExp: 4e3, levelName: "言灵探索者", levelColor: "#42bc05" },
{ level: 7, levelExp: 5e3, levelName: "水系魔法师", levelColor: "#42bc05" },
{ level: 8, levelExp: 6e3, levelName: "水系魔导师", levelColor: "#42bc05" },
{ level: 9, levelExp: 8e3, levelName: "藏书的魔女", levelColor: "#2003da" },
{ level: 10, levelExp: 1e4, levelName: "人形图书馆", levelColor: "#2003da" },
{ level: 11, levelExp: 15e3, levelName: "文明归档员", levelColor: "#2003da" },
{ level: 12, levelExp: 2e4, levelName: "高塔思索者", levelColor: "#03a4da" },
{ level: 13, levelExp: 25e3, levelName: "未知探索者", levelColor: "#03a4da" },
{ level: 14, levelExp: 3e4, levelName: "背负真相之人", levelColor: "#9d03da" },
{ level: 15, levelExp: 35e3, levelName: "守密人", levelColor: "#9d03da" },
{ level: 16, levelExp: 4e4, levelName: "被缚的倒吊者", levelColor: "#9d03da" },
{ level: 17, levelExp: 45e3, levelName: "崩毁世界之人", levelColor: "#f10171" },
{ level: 18, levelExp: 5e4, levelName: "命运眷顾者", levelColor: "#f10171" },
{ level: 19, levelExp: 1e5, levelName: "文明领航员", levelColor: "#c9b86d" },
{ level: 20, levelExp: 1e6, levelName: "天选之人", levelColor: "#ffd000" }
];
var defaultFortuneInfo = [
{ luck: 0, desc: "走平坦的路但会摔倒的程度" },
{ luck: 5, desc: "吃泡面会没有调味包的程度" },
{ luck: 15, desc: "上厕所会忘记带纸的程度" },
{ luck: 20, desc: "上学/上班路上会堵车的程度" },
{ luck: 25, desc: "点外卖很晚才会送到的程度" },
{ luck: 30, desc: "点外卖会多给予赠品的程度" },
{ luck: 35, desc: "出门能捡到几枚硬币的程度" },
{ luck: 40, desc: "踩到香蕉皮不会滑倒的程度" },
{ luck: 50, desc: "玩滑梯能流畅滑到底的程度" },
{ luck: 60, desc: "晚上走森林不会迷路的程度" },
{ luck: 70, desc: "打游戏能够轻松过关的程度" },
{ luck: 80, desc: "抽卡能够大成功的程度" },
{ luck: 95, desc: "天选之人" }
];
var timeGreetings = [
{ range: [0, 5], message: "晚安" },
{ range: [5, 9], message: "早上好" },
{ range: [9, 11], message: "上午好" },
{ range: [11, 14], message: "中午好" },
{ range: [14, 18], message: "下午好" },
{ range: [18, 20], message: "傍晚好" },
{ range: [20, 24], message: "晚上好" }
];
var defaultEventJson = [
{
name: "看直播",
good: "喜欢的V开歌回啦",
bad: "喜欢的V咕了一整天"
},
{
name: "打轴",
good: "一次性过",
bad: "谁说话这么难懂"
},
{
name: "剪辑",
good: "灵感爆发",
bad: "一团乱麻"
},
{
name: "校对",
good: "变成无情的审轴机器",
bad: "被闪轴闪瞎眼"
},
{
name: "浏览Pixiv",
good: "发现符合xp的涩图",
bad: "找不到想要的涩图"
},
{
name: "打SC",
good: "享受石油佬的乐趣",
bad: "吃土中"
},
{
name: "吃人",
good: "你面前这位有成为神龙的潜质",
bad: "这人会用Aegisub吗?"
},
{
name: "背单词",
good: "这次六级肯定过",
bad: "背完50个忘了45个"
},
{
name: "翘课",
good: "老师不会点名",
bad: "老师准会抽到你来回答问题"
},
{
name: "做作业",
good: "做的每个都对",
bad: "做一个做错一个"
},
{
name: "锻炼一下身体",
good: "身体健康, 更加性福",
bad: "能量没消耗多少, 吃得却更多"
},
{
name: "浏览成人网站",
good: "重拾对生活的信心",
bad: "你会心神不宁"
},
{
name: "修复BUG",
good: "你今天对BUG的嗅觉大大提高",
bad: "新产生的BUG将比修复的更多"
},
{
name: "上AB站",
good: "还需要理由吗?",
bad: "满屏兄贵亮瞎你的眼"
},
{
name: "打LOL",
good: "你将有如神助",
bad: "你会被虐的很惨"
},
{
name: "打DOTA",
good: "天梯5000分不是梦",
bad: "你会遇到猪一样的队友"
},
{
name: "打DOTA2",
good: "Godlike",
bad: "不怕神一样的对手,就怕猪一样的队友"
},
{
name: "穿女装",
good: "你会得到很多炙热的目光",
bad: "被父母看到"
},
{
name: "组模型",
good: "今天的喷漆会很完美",
bad: "精神不集中板件被剪断了"
},
{
name: "熬夜",
good: "夜间的效率更高",
bad: "明天有很重要的事"
},
{
name: "抚摸猫咪",
good: "才不是特意蹭你的呢",
bad: "死开! 愚蠢的人类"
},
{
name: "烹饪",
good: "黑暗料理界就由我来打败",
bad: "难道这就是……仰望星空派?"
},
{
name: "告白",
good: "其实我也喜欢你好久了",
bad: "对不起, 你是一个好人"
},
{
name: "追新番",
good: "完结之前我绝不会死",
bad: "会被剧透"
},
{
name: "日麻",
good: "立直一发自摸!",
bad: "碰喵吃喵杠喵荣喵!"
},
{
name: "音游",
good: "FCACFRPR不过如此",
bad: "又双叒叕LOST了..."
},
{
name: "向大佬请教",
good: "太棒了,学到许多",
bad: "太棒了,什么都没学到"
},
{
name: "早起",
good: "迎接第一缕阳光",
bad: "才4点,再睡一会"
},
{
name: "早睡",
good: "第二天精神饱满",
bad: "失眠数羊画圈圈"
},
{
name: "入正版游戏",
good: "买了痛三天,不买悔三年",
bad: "emmmm,汇率还是……"
},
{
name: "补旧作",
good: "意外地对胃口",
bad: "会踩雷"
},
{
name: "晾晒老婆(抱枕套)",
good: "天気も晴れココロも晴れ",
bad: "引发路人围观"
},
{
name: "不按攻略打",
good: "居然是HAPPY END",
bad: "碰到BAD END"
},
{
name: "观赏CG包",
good: "社保。",
bad: "还不去如看游戏剧情"
},
{
name: "研究黄油创作理论",
good: "增进鉴赏水平",
bad: "闲适玩家不需要这些"
},
{
name: "暴露性癖",
good: "会引来很多趣味相同的变态",
bad: "四斋蒸鹅心"
},
{
name: "施法",
good: "传统手艺精进了",
bad: "房间门关好了吗"
},
{
name: "刷新作动态",
good: "喜欢的画师发了新图",
bad: "发现游戏跳票"
},
{
name: "回味玩过的作品",
good: "重温感动",
bad: "还是先看看新作"
},
{
name: "出门走走",
good: "宅久了要发霉",
bad: "太陽が眩しすぎる"
},
{
name: "思考人生",
good: "自己的幸福呢?",
bad: "喵喵……喵?"
},
{
name: "撸猫",
good: "啊……好爽",
bad: "家里没有猫的洗洗睡吧"
},
{
name: "抽卡",
good: "单抽出货",
bad: "到井前一发出货"
},
{
name: "拼乐高",
good: "顺利完工",
bad: "发现少了一块零件"
},
{
name: "跳槽",
good: "新工作待遇大幅提升",
bad: "待遇还不如之前的"
},
{
name: "和女神聊天",
good: "今天天气不错",
bad: "我去洗澡了,呵呵"
},
{
name: "写开源库",
good: "今天北斗七星汇聚,裤子造的又快又好",
bad: "写好会发现github上已经有了更好的"
},
{
name: "给测试妹子埋个bug",
good: "下辈子的幸福就靠这个bug了",
bad: "妹子会认为你活和代码一样差"
},
{
name: "写单元测试",
good: "写单元测试将减少出错",
bad: "写单元测试会降低你的开发效率"
},
{
name: "洗澡",
good: "你几天没洗澡了?",
bad: "会把设计方面的灵感洗掉"
},
{
name: "白天上线",
good: "今天白天上线是安全的",
bad: "可能导致灾难性后果"
},
{
name: "重构",
good: "代码质量得到提高",
bad: "你很有可能会陷入泥潭"
},
{
name: "招人",
good: "你面前这位有成为牛人的潜质",
bad: "这人会写程序吗?"
},
{
name: "面试",
good: "面试官今天心情很好",
bad: "面试官不爽,会拿你出气"
},
{
name: "申请加薪",
good: "老板今天心情很好",
bad: "公司正在考虑裁员"
},
{
name: "提交代码",
good: "遇到冲突的几率是最低的",
bad: "会遇到的一大堆冲突"
},
{
name: "代码复审",
good: "发现重要问题的几率大大增加",
bad: "你什么问题都发现不了,白白浪费时间"
},
{
name: "晚上上线",
good: "晚上是程序员精神最好的时候",
bad: "你白天已经筋疲力尽了"
},
{
name: "乘电梯",
good: "正好赶上打卡截止时间",
bad: "电梯超载"
},
{
name: "复读",
good: "有时候,人云亦云也是一种生存方式",
bad: "你的对手是鸽子"
},
{
name: "肝爆",
good: "努力使人进步,肝爆让人快乐",
bad: "醒醒,限时活动没了"
},
{
name: "氪金",
good: "早买早享受,晚买哭着求",
bad: "第二天就 50% off"
},
{
name: "卖弱",
good: "楚楚动人更容易打动群友",
bad: "Boy♂next♂door"
},
{
name: "唱脑力",
good: "唱一次提神醒脑,唱两次精神百倍",
bad: "会与复读机一起对群聊造成毁灭性打击"
},
{
name: "看手元",
good: "从手元中获得一点音游经验",
bad: "会被大佬闪瞎"
},
{
name: "录手元",
good: "音游届的未来新星UP主就是你",
bad: "打完歌才发现忘记开录像"
},
{
name: "挑战魔王曲",
good: "一上来就是一个新纪录",
bad: "有这点时间还不如干点别的"
},
{
name: "咕咕咕",
good: "一时咕一时爽",
bad: "会被抓起来,被群友强迫穿上女装"
},
{
name: "与群友水聊",
good: "扶我起来我还能打字",
bad: "一不小心就被大佬闪瞎"
},
{
name: "迫害大佬",
good: "迫害是大佬进步的阶梯",
bad: "亲爱的,你号没了"
},
{
name: "算命",
good: "算啥都准",
bad: "诸事不宜"
},
{
name: "成为魔法少女",
good: "勇敢的烧酒啊快去拯救世界吧!",
bad: "会掉头"
},
{
name: "沟通克苏鲁",
good: "奇怪的知识增加了",
bad: "&▓▓▓◆▓▓▓¥#▓@■.◆"
},
{
name: "看新番",
good: "你看的这部新番有成为本季度霸权的可能",
bad: "这周更新的是总集篇"
},
{
name: "看旧番",
good: "在宅的道路上又前进了一步",
bad: "被剧情喂屎"
},
{
name: "看里番",
good: "传统手艺精进了",
bad: "房间门关好了吗?"
},
{
name: "看漫画",
good: "正在追的作品十话连发",
bad: "刷到正在追的作品的腰斩停更通知"
},
{
name: "看轻小说",
good: "插画很好舔,孩子很满意",
bad: "买插画送的厕纸有啥好看的"
},
{
name: "看本子",
good: "被精准戳中性癖",
bad: "更新的全是你不喜欢的类型"
},
{
name: "前往女仆咖啡厅",
good: "感受身心上的治愈",
bad: "虚假的女仆只会让你内心更加空虚"
},
{
name: "女装Cosplay",
good: "好评如潮",
bad: "照片传到班级群还被认出来"
},
{
name: "修仙",
good: "能突破到下一个境界",
bad: "会在进阶中遭受心魔侵蚀"
},
{
name: "渡劫",
good: "万事俱备,只待飞升",
bad: "没能扛过去,寿元终"
},
{
name: "在妹子面前吹牛",
good: "改善你矮穷挫的形象",
bad: "会被识破"
},
{
name: "发超过10条的状态",
good: "显得你很高产",
bad: "会被人直接拉黑"
},
{
name: "在B站上传视频",
good: "播放量爆炸",
bad: "没人看"
},
{
name: "搬运视频",
good: "会被硬币砸得很爽",
bad: "不会有人看的"
},
{
name: "上微博",
good: "今天的瓜不能错过",
bad: "被智障发言糊一脸"
},
{
name: "作死",
good: "节目效果一流",
bad: "吾之旧友弔似汝,如今坟头草丈五"
},
{
name: "看老黄历",
good: "反正你已经看了",
bad: "反正你已经看了"
},
{
name: "学习一门新技能",
good: "有会成为大神的资质",
bad: "可能会误入歧途"
},
{
name: "睡懒觉",
good: "避免内存不足",
bad: "早上很早醒来睡不着了"
},
{
name: "睡懒觉",
good: "你今天会更有精神",
bad: "会错过重要的事情"
},
{
name: "上课玩手机",
good: "会发现好玩的事情",
bad: "会被老师教训"
},
{
name: "抄作业",
good: "没有作业抄的学生生活是罪恶的!",
bad: "老师会认真批改,你懂的……"
},
{
name: "学习",
good: "你已经几天(月、年)没学习了?",
bad: "会睡着"
},
{
name: "出门带伞",
good: "今天下雨你信不信",
bad: "好运气都被遮住了"
},
{
name: "走夜路",
good: "偶尔也要一个人静一静",
bad: "有坏人"
},
{
name: "补番",
good: "你会后悔没早点看这部番",
bad: "你会后悔看了这部番"
},
{
name: "玩Minecraft",
good: "建筑灵感爆发",
bad: "启动器都会崩溃"
},
{
name: "上Steam",
good: "愿望单里全是90%off",
bad: "钱包被G胖洗劫一空"
},
{
name: "修图",
good: "原片直出毫无压力",
bad: "Photoshop未响应"
},
{
name: "赶稿",
good: "完美守住deadline",
bad: "终究还是超期了"
},
{
name: "摸鱼",
good: "摸鱼一时爽,一直摸鱼一直爽",
bad: "被老板当场抓获"
},
{
name: "入手新游戏",
good: "你会玩的很开心",
bad: "这游戏明天就99%off"
},
{
name: "出门",
good: "今天会是个好天气",
bad: "中途突降暴雨"
}
];
// src/core/signin.ts
var SigninService = class {
static {
__name(this, "SigninService");
}
ctx;
cfg;
constructor(context, config) {
this.ctx = context;
this.cfg = config;
}
async callSignin(uid, userid, luck) {
const date = /* @__PURE__ */ new Date();
const roll = new Fate();
const exp = await roll.random(this.cfg.signExp[0], this.cfg.signExp[1], luck);
const coin = await roll.random(this.cfg.signCoin[0], this.cfg.signCoin[1], luck);
const userData = await this.ctx.database.get("fate", { id: uid });
if (userData.length === 0) {
let accCount = 1;
let accExp = exp;
this.ctx.database.create("fate", {
id: uid,
name: userid,
time: date,
exp: accExp,
signCount: accCount
});
this.ctx.monetary.gain(uid, coin, this.cfg.currency);
return {
status: 0,
getExp: exp,
allExp: accExp,
getCoin: coin,
signTime: date,
count: accCount
};
}
if (userData[0].time.getDate() === date.getDate()) {
return {
status: 1,
getExp: 0,
allExp: userData[0].exp,
getCoin: 0,
signTime: userData[0].time,
count: userData[0].signCount
};
} else {
let accExp = userData[0].exp + exp;
let accCount = userData[0].signCount + 1;
this.ctx.database.set(
"fate",
{ id: uid },
{
name: userid,
time: date,
exp: accExp,
signCount: accCount
}
);
this.ctx.monetary.gain(uid, coin, this.cfg.currency);
return {
status: 0,
getExp: exp,
allExp: accExp,
getCoin: coin,
signTime: date,
count: accCount
};
}
}
getLevelInfo(exp, info) {
let index = 0;
for (let i = 0; i < info.length; i++) {
if (exp >= info[i].levelExp) {
index++;
} else {
break;
}
}
let nExp;
if (index >= info.length) {
nExp = "???";
} else {
nExp = info[index].levelExp;
}
index--;
return {
levelInfo: info[index],
nextExp: nExp
};
}
getFortuneInfo(luck, info) {
let index = 0;
for (let i = 0; i < info.length; i++) {
if (luck >= info[i].luck) {
index++;
} else {
break;
}
}
index--;
return info[index].desc;
}
getGreeting(hour) {
const greeting = timeGreetings.find(
(timeGreeting) => hour >= timeGreeting.range[0] && hour < timeGreeting.range[1]
);
return greeting ? greeting.message : "你好";
}
};
// src/command/fortune.ts
var import_koishi = require("koishi");
var import_fs2 = __toESM(require("fs"));
var import_path2 = __toESM(require("path"));
// src/utils/external.ts
async function fetchHitokoto() {
const controller = new AbortController();
try {
const response = await fetch("https://v1.hitokoto.cn/?c=a&c&b&k", {
signal: controller.signal
});
const {
hitokoto: hitokotoText,
from: fromText,
from_who: fromWhoText
} = await response.json();
let hitokoto;
if (fromWhoText != null) {
hitokoto = `『${hitokotoText}』<br>—— ${fromWhoText}「${fromText}」`;
} else {
hitokoto = `『${hitokotoText}』<br>——「${fromText}」`;
}
return hitokoto;
} catch (error) {
if (error.name === "AbortError") return "请求已取消";
console.error("获取 hitokoto 时出错:", error);
return "无法获取 hitokoto";
} finally {
controller.abort();
}
}
__name(fetchHitokoto, "fetchHitokoto");
// src/command/fortune.ts
var import_url = require("url");
// src/utils/files.ts
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
async function getFolderImg(folder) {
let imgfilename = await readFilenames(folder);
const filteredArr = imgfilename.filter((filename) => {
return /\.(png|jpg|jpeg|ico|svg)$/i.test(filename);
});
return filteredArr;
}
__name(getFolderImg, "getFolderImg");
async function readFilenames(dirPath) {
let filenames = [];
const files = import_fs.default.readdirSync(dirPath);
files.forEach((filename) => {
const fullPath = import_path.default.join(dirPath, filename);
if (import_fs.default.statSync(fullPath).isDirectory()) {
filenames = filenames.concat(readFilenames(fullPath));
} else {
filenames.push(filename);
}
});
return filenames;
}
__name(readFilenames, "readFilenames");
// src/command/fortune.ts
function registerFortuneCommand(ctx, config, signin, jrys) {
const eventJson = [...defaultEventJson, ...config.event];
const templateHTML = import_fs2.default.readFileSync(
import_path2.default.resolve(__dirname, ctx.state.baseDir, "template.txt"),
"utf-8"
);
ctx.command("jrys", "今日运势").userFields(["id", "name"]).action(async ({ session }) => {
const date = /* @__PURE__ */ new Date();
let name2 = "";
if (session.user.name) {
name2 = `@${session.user.name}`;
}
name2 = name2.length > 13 ? name2.substring(0, 12) + "..." : name2;
const luck = await jrys.getFortune(session.user.id);
const sign = await signin.callSignin(session.user.id, session.author.id, luck);
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
const luckInfo = signin.getFortuneInfo(luck, config.fortuneSet);
const [gooddo1, gooddo2, baddo1, baddo2] = await jrys.getRandomObjects(
eventJson,
session.user.id
);
const hitokoto = await fetchHitokoto();
const greeting = signin.getGreeting(date.getHours());
const levelinfo = signin.getLevelInfo(sign.allExp, config.levelSet);
const percent = typeof levelinfo.nextExp == "string" ? "100.000" : (sign.allExp / levelinfo.nextExp * 100).toFixed(3).toString();
let bgUrl;
if (config.imgUrl.match(/http(s)?:\/\/(.*)/gi)) {
bgUrl = config.imgUrl;
} else {
bgUrl = (0, import_url.pathToFileURL)(
import_path2.default.resolve(
__dirname,
config.imgUrl + import_koishi.Random.pick(await getFolderImg(config.imgUrl))
)
).href;
}
let avatarUrl = session.author.avatar;
if (avatarUrl == void 0) {
avatarUrl = "avatar.png";
}
try {
const content = templateHTML.replace(
"${bodyClass}",
date.getHours() >= 18 || date.getHours() < 6 ? "darkMode" : ""
).replace("${bgUrl}", bgUrl).replace("${avatarUrl}", avatarUrl).replace("${greeting}", greeting).replace("${date}", `${month}/${day}`).replace("${hitokoto}", hitokoto).replace("${name}", name2).replace(
"${signStatus}",
sign.status === 1 ? "今天已经签到过了!" : "签到成功! 🫧+" + sign.getExp + "🪙+" + sign.getCoin
).replace("${levelColor}", levelinfo.levelInfo.levelColor).replace("${levelName}", levelinfo.levelInfo.levelName).replace("${exp}", `${sign.allExp}/${levelinfo.nextExp}`).replace("${expPercent}", percent).replace("${luckValue}", luck.toString()).replace("${luckDescription}", luckInfo).replace(
"${gooddo}",
`${gooddo1.name}——${gooddo1.good}<br>${gooddo2.name}——${gooddo2.good}`
).replace(
"${baddo}",
`${baddo1.name}——${baddo1.bad}<br>${baddo2.name}——${baddo2.bad}`
);
let page;
try {
page = await ctx.puppeteer.browser.newPage();
await page.setViewport({ width: 600, height: 1080 * 2 });
await page.goto(ctx.state.baseURL);
await page.evaluate(() => document.body.innerHTML = "");
await page.setContent(content, {
waitUntil: "networkidle0"
});
await page.waitForSelector("#body", { timeout: 3e4 });
const element = await page.$("#body");
let msg;
if (!element) {
msg = null;
throw new Error("Element not found");
}
const imgBuf = await element.screenshot({
encoding: "binary"
});
msg = import_koishi.h.image(imgBuf, "image/png");
return import_koishi.h.quote(session.event.message.id) + msg;
} finally {
if (page) page.close();
}
} catch (err) {
logger.error(err);
return "服务内部错误,请联系管理员。";
}
});
}
__name(registerFortuneCommand, "registerFortuneCommand");
// src/command/migration.ts
function registerMigrationCommand(ctx) {
ctx.command("jrysmigrate <qqname:string>").userFields(["id", "name"]).action(async ({ session }, qqname) => {
try {
const oldData = await ctx.database.get("jrys", { name: qqname });
if (oldData.length === 0) {
return "用户未找到,请检查用户名是否正确输入";
}
const nowData = await ctx.database.get("fate", { id: session.user.id });
if (nowData.length === 0) {
await ctx.database.create("fate", {
id: session.user.id,
name: session.author.id,
time: oldData[0].time,
exp: oldData[0].exp,
signCount: oldData[0].signCount
});
} else {
await ctx.database.set(
"fate",
{ id: session.user.id },
{
name: session.author.id,
exp: nowData[0].exp + oldData[0].exp,
signCount: nowData[0].signCount + oldData[0].signCount
}
);
}
return `迁移成功!`;
} catch (error) {
logger.error(error);
return "服务内部错误,请联系管理员。";
}
});
}
__name(registerMigrationCommand, "registerMigrationCommand");
// src/command/index.ts
function registerCommands(ctx, config) {
const signin = new SigninService(ctx, config);
const jrys = new Fate();
registerFortuneCommand(ctx, config, signin, jrys);
registerMigrationCommand(ctx);
}
__name(registerCommands, "registerCommands");
// src/database/model.ts
var initDatabase = /* @__PURE__ */ __name((ctx) => {
ctx.model.extend(
"fate",
{
id: "integer",
name: "string",
time: "timestamp",
exp: "unsigned",
signCount: "unsigned"
},
{
primary: "id",
indexes: ["name", "time"]
}
);
}, "initDatabase");
// src/index.ts
var import_path3 = __toESM(require("path"));
// src/command/types.ts
var import_koishi2 = require("koishi");
var Config = import_koishi2.Schema.object({
imgUrl: import_koishi2.Schema.string().role("link").description("随机横图api或者本地路径").required(),
signExp: import_koishi2.Schema.tuple([Number, Number]).description("签到获得经验范围").default([1, 100]),
currency: import_koishi2.Schema.string().description("Monetary货币名称").default("coin"),
signCoin: import_koishi2.Schema.tuple([Number, Number]).description("签到获得货币范围").default([1, 100]),
levelSet: import_koishi2.Schema.array(
import_koishi2.Schema.object({
level: import_koishi2.Schema.number().description("等级"),
levelExp: import_koishi2.Schema.number().description("等级最低经验"),
levelName: import_koishi2.Schema.string().description("等级名称"),
levelColor: import_koishi2.Schema.string().role("color").description("等级颜色")
})
).role("table").default(defaultLevelInfo).description("经验等级设置: 升序排列 | 最低等级经验必须为0"),
fortuneSet: import_koishi2.Schema.array(
import_koishi2.Schema.object({
luck: import_koishi2.Schema.number().description("每级最低运势"),
desc: import_koishi2.Schema.string().description("运势描述")
})
).role("table").default(defaultFortuneInfo).description(
"运势值描述信息: 升序排列 | 运势取值0~100, 最低一级必须为0 | 描述信息最长14个中文字符"
),
event: import_koishi2.Schema.array(
import_koishi2.Schema.object({
name: import_koishi2.Schema.string().description("事件名称"),
good: import_koishi2.Schema.string().description("好的结局"),
bad: import_koishi2.Schema.string().description("坏的结局")
})
).role("table").default([{ name: "网购", good: "买到超值好物", bad: "会被坑" }]).description("自定义黄历事件")
});
// src/index.ts
var inject = {
required: ["database", "puppeteer", "monetary"]
};
var name = "fate";
var logger = new import_koishi3.Logger("[Fate]>> ");
function apply(ctx, config) {
const baseDir = import_path3.default.resolve(__dirname, "./assets");
ctx.state.baseDir = baseDir;
ctx.state.baseURL = new URL(`file://${baseDir}/`).href;
initDatabase(ctx);
registerCommands(ctx, config);
}
__name(apply, "apply");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Config,
apply,
inject,
logger,
name
});