@momuhoka/koishi-plugin-jrrp
Version:
自用今日人品插件,AI生成仅供参考:主要负责协助AI大人完成功能完善和BUG修复
432 lines (430 loc) • 17.5 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Config: () => Config,
apply: () => apply,
name: () => name,
using: () => using
});
module.exports = __toCommonJS(src_exports);
var import_koishi = require("koishi");
var name = "jrrp";
var using = ["database"];
var Config = import_koishi.Schema.object({
resetHour: import_koishi.Schema.number().min(0).max(23).default(0).description("每天重置人品的时间(0~23点)"),
utcOffsetMinutes: import_koishi.Schema.number().default(480).description("时区偏移(分钟),如北京时间为 480"),
salt: import_koishi.Schema.string().default("koishi-jrrp").description("盐值,用于随机种子生成,防止可预测"),
nameMode: import_koishi.Schema.union(["username", "at"]).default("username").description("人品输出中的{name}字段显示方式(username 或 at)"),
style: import_koishi.Schema.string().default("今天 {name} 的人品是:{score}/100 {comment}").description("主输出样式模板"),
enableActivities: import_koishi.Schema.boolean().default(true).description("是否显示宜/忌"),
enableLuckyNumber: import_koishi.Schema.boolean().default(true).description("是否显示幸运数字"),
enableLuckyColor: import_koishi.Schema.boolean().default(true).description("是否显示幸运颜色"),
enableYiyan: import_koishi.Schema.boolean().default(true).description("是否使用一言作为额外内容"),
scoreMode: import_koishi.Schema.union(["normal", "fathead"]).default("normal").description("分数模式:normal 正常分布,fathead 偏积极"),
activitiesCustom: import_koishi.Schema.array(String).role("table").description("自定义活动列表(优先于默认)"),
commentsCustom: import_koishi.Schema.array(import_koishi.Schema.object({
min: import_koishi.Schema.number().required(),
max: import_koishi.Schema.number().required(),
text: import_koishi.Schema.string().required()
})).role("table").description("自定义分数评论"),
customYiyanApi: import_koishi.Schema.object({
url: import_koishi.Schema.string().required().description("自定义一言API接口地址"),
data: import_koishi.Schema.string().required().description("自定义一言API请求数据(如有需要)")
}).description("自定义一言API接口地址(填写后启用)").default({ url: "", data: "" }),
fatheadConfig: import_koishi.Schema.object({
totalMin: import_koishi.Schema.number().default(0).description("总分区间最小值"),
totalMax: import_koishi.Schema.number().default(100).description("总分区间最大值"),
fatMin: import_koishi.Schema.number().default(60).description("胖头区间左端点"),
fatMax: import_koishi.Schema.number().default(90).description("胖头区间右端点"),
fatRatio: import_koishi.Schema.number().default(0.7).description("胖头区间概率")
}).description("胖头分布设置(仅胖头模式有效)").default({ totalMin: 0, totalMax: 100, fatMin: 60, fatMax: 90, fatRatio: 0.7 })
});
var defaultActivities = [
"整理房间",
"喝杯水",
"散步",
"早睡",
"尝试新菜",
"备份文件",
"阅读",
"运动",
"联系朋友",
"听音乐",
"写随笔",
"晒太阳",
"打扫卫生",
"学习新知识",
"计划明天",
"关注健康",
"理性消费",
"放松休息",
"逛超市",
"做家务",
"尝试新游戏",
"看电影",
"写感谢信",
"微笑",
"冥想",
"做饭",
"收拾桌面",
"整理资料",
"浏览新闻",
"做理财规划",
"尝试新穿搭",
"拍照",
"逛公园",
"看动漫",
"做手工",
"写日记",
"逛论坛",
"尝试新APP",
"关注天气",
"清理手机",
"学习外语",
"练习书法",
"画画",
"做运动计划",
"尝试新发型",
"逛书店",
"做健康检查",
"尝试新饮品",
"关注时事",
"做心理调节",
"整理邮箱",
"清理垃圾文件",
"尝试新兴趣",
"做自我总结",
"关注安全",
"尝试新路线",
"做预算",
"关注环保",
"做公益",
"关注家人",
"逛商场",
"尝试新餐厅",
"做健康饮食计划",
"关注宠物健康",
"尝试新运动",
"做时间管理",
"关注交通安全",
"尝试新技能",
"做自我提升",
"关注心理健康",
"逛博物馆",
"做志愿服务",
"尝试新乐器",
"关注网络安全",
"做职业规划",
"尝试新社交活动",
"关注社区动态",
"做兴趣小组活动",
"尝试新学习方法",
"关注节能减排",
"做家庭聚会",
"尝试新娱乐方式",
"关注公共卫生",
"做自我反思",
"尝试新工作方式",
"关注社会新闻",
"做团队协作",
"尝试新阅读材料",
"关注个人隐私",
"做年度计划"
];
var defaultComments = [
{ min: 0, max: 9, text: ["今天有点挑战,但保持笑容会更好~", "低开高走,别灰心!", "小心运势,积极面对!"] },
{ min: 10, max: 29, text: ["可能会遇到小波折,但你能应付~", "有点小坎坷,勇敢一点!", "坚持下去会有转机~"] },
{ min: 30, max: 49, text: ["平平淡淡也有好风景~", "今天很普通,享受平静吧", "平稳度过,别忘微笑"] },
{ min: 50, max: 69, text: ["小吉,小确幸就在身边~", "运势不错,可以尝试新事物", "有点小幸运,抓住机会"] },
{ min: 70, max: 84, text: ["吉,适合开展计划~", "今天很顺利,行动力满满", "适合做重要决定"] },
{ min: 85, max: 94, text: ["大吉,今天特别顺利~", "好运连连,事事顺心", "心想事成的一天"] },
{ min: 95, max: 100, text: ["欧皇降临,好运爆棚!", "极致好运,快去抽卡!", "幸运爆表,万事如意"] }
];
function fnv1a32(str) {
let h = 2166136261 >>> 0;
for (let i = 0; i < str.length; i++) {
h ^= str.charCodeAt(i);
h = Math.imul(h, 16777619) >>> 0;
}
return h >>> 0;
}
__name(fnv1a32, "fnv1a32");
function mulberry32(seed) {
let t = seed >>> 0;
return function() {
t += 1831565813;
let r = Math.imul(t ^ t >>> 15, 1 | t);
r ^= r + Math.imul(r ^ r >>> 7, 61 | r);
return ((r ^ r >>> 14) >>> 0) / 4294967296;
};
}
__name(mulberry32, "mulberry32");
function fatheadScore(rng) {
return Math.floor(Math.pow(rng(), 1 / 5) * 40 + 60);
}
__name(fatheadScore, "fatheadScore");
function fatheadScoreCustom(rng, totalMin = 0, totalMax = 100, fatMin = 60, fatMax = 90, fatRatio = 0.7) {
const r = rng();
if (r < fatRatio) {
return Math.floor(rng() * (fatMax - fatMin + 1) + fatMin);
} else {
const otherRanges = [];
if (fatMin > totalMin) otherRanges.push([totalMin, fatMin - 1]);
if (fatMax < totalMax) otherRanges.push([fatMax + 1, totalMax]);
if (otherRanges.length === 0) return fatMin;
const pick = otherRanges[Math.floor(rng() * otherRanges.length)];
return Math.floor(rng() * (pick[1] - pick[0] + 1) + pick[0]);
}
}
__name(fatheadScoreCustom, "fatheadScoreCustom");
function currentDateKey(resetHour, offsetMin, now = /* @__PURE__ */ new Date()) {
const utc = now.getTime() + now.getTimezoneOffset() * 6e4;
const local = utc + offsetMin * 6e4;
const d = new Date(local);
const hour = d.getUTCHours();
if (hour < resetHour) d.setUTCDate(d.getUTCDate() - 1);
return `${d.getUTCFullYear()}-${(d.getUTCMonth() + 1).toString().padStart(2, "0")}-${d.getUTCDate().toString().padStart(2, "0")}`;
}
__name(currentDateKey, "currentDateKey");
function pickComment(ctx, score, custom) {
const rules = custom && custom.length ? custom : defaultComments;
for (const r of rules) {
if (score >= r.min && score <= r.max) {
if (Array.isArray(r.text)) {
const idx = Math.floor(Math.random() * r.text.length);
return r.text[idx];
} else {
return r.text;
}
}
}
return "";
}
__name(pickComment, "pickComment");
async function pickYiYan(ctx, config) {
const url = config?.customYiyanApi?.url ? config.customYiyanApi.url : "https://v1.hitokoto.cn/";
const data = config?.customYiyanApi?.data;
try {
const res = await ctx.http.get(url);
if (data) {
if (res[data]) return `『${res[data]}』`;
} else {
if (typeof res === "string") return `『${res}』`;
if (res?.hitokoto) return `『${res.hitokoto}』`;
if (res?.data) return `『${res.data}』`;
if (res?.data?.hitokoto) return `『${res.data.hitokoto}』`;
}
} catch (e) {
ctx.logger("jrrp").warn("获取一言失败:\n", e);
}
return "";
}
__name(pickYiYan, "pickYiYan");
function sampleMany(rng, list, n) {
const a = list.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(rng() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a.slice(0, Math.min(n, a.length));
}
__name(sampleMany, "sampleMany");
function formatStyle(style, data) {
return style.replace(/\{(\w+)\}/g, (_, k) => String(data[k] ?? ""));
}
__name(formatStyle, "formatStyle");
function apply(ctx, config) {
ctx.on("ready", async () => {
ctx.model.extend("jrrp", {
userId: "string",
date: "string",
score: "integer",
comment: "string",
good: "string",
bad: "string",
luckyNumber: "integer",
luckyColor: "string",
yiyan: "string"
}, { primary: ["userId", "date"] });
});
const activities = (config.activitiesCustom?.length ? config.activitiesCustom : defaultActivities).slice();
ctx.command("jrrp", "查看今日人品").alias("rp").alias("今日人品").alias("人品").option("detail", "-d, --detail 显示详细签运").action(async ({ session, options }) => {
if (!session) return "(无法获取会话信息)";
const dateKey = currentDateKey(config.resetHour, config.utcOffsetMinutes);
const id = session.userId;
let nameField;
if (config.nameMode === "at") {
if (session.platform === "qq" || session.platform === "onebot") {
nameField = import_koishi.segment.at(id).toString();
} else {
nameField = `<at id=${id}/>`;
}
} else {
ctx.logger("jrrp").warn("@用户失败,使用用户昵称代替");
nameField = session.username;
}
const record = await ctx.database.get("jrrp", { userId: id, date: dateKey });
if (record.length > 0) {
const head = formatStyle(config.style, { name: nameField, id, date: dateKey, score: record[0].score, comment: record[0].comment });
let tail = "";
if (options?.detail || config.enableActivities || config.enableLuckyNumber || config.enableLuckyColor || config.enableYiyan) {
let good = [];
let bad = [];
if (config.enableActivities && record[0].good && record[0].bad) {
good = record[0].good ? record[0].good.split(",") : [];
bad = record[0].bad ? record[0].bad.split(",") : [];
tail += `
宜:${good.join("、") || "暂无"}
忌:${bad.join("、") || "暂无"}`;
}
if (config.enableLuckyNumber && record[0].luckyNumber) {
tail += `
幸运数字:${record[0].luckyNumber}`;
}
if (config.enableLuckyColor && record[0].luckyColor) {
tail += `
幸运颜色:${record[0].luckyColor}`;
}
if (config.enableYiyan && record[0].yiyan) {
tail += `
签语:${record[0].yiyan}`;
}
}
return `${head}${tail}`;
} else {
const seedBase = `${id}|${dateKey}|${config.salt}`;
const seed = fnv1a32(seedBase);
const rng = mulberry32(seed);
let score;
if (config.scoreMode === "fathead") {
const fat = config.fatheadConfig ?? {};
score = fatheadScoreCustom(
rng,
fat.totalMin ?? 0,
fat.totalMax ?? 100,
fat.fatMin ?? 60,
fat.fatMax ?? 90,
fat.fatRatio ?? 0.7
);
} else {
score = Math.floor(rng() * 101);
}
const comment = pickComment(ctx, score, config.commentsCustom);
await ctx.database.create("jrrp", { userId: id, date: dateKey, score, comment });
const head = formatStyle(config.style, { name: nameField, id, date: dateKey, score, comment });
let tail = "";
let good = [];
let bad = [];
good = sampleMany(rng, activities, 2);
bad = sampleMany(rng, activities.filter((a) => !good.includes(a)), 2);
await ctx.database.set("jrrp", { userId: id, date: dateKey }, { good: good.join(","), bad: bad.join(",") });
tail += options?.detail || config.enableActivities ? `
宜:${good.join("、") || "暂无"}
忌:${bad.join("、") || "暂无"}` : "";
const luckyNumber = 1 + Math.floor(rng() * 9);
await ctx.database.set("jrrp", { userId: id, date: dateKey }, { luckyNumber });
tail += options?.detail || config.enableLuckyNumber ? `
幸运数字:${luckyNumber}` : "";
const colors = [
"红(热情、好运)",
"橙(活力、温暖)",
"黄(智慧、财富)",
"绿(健康、平安)",
"青(清新、成长)",
"蓝(冷静、信任)",
"紫(高贵、神秘)",
"黑(稳重、力量)",
"白(纯洁、希望)",
"灰(低调、沉稳)",
"金(富贵、成功)",
"银(高雅、创新)",
"粉(温柔、浪漫)",
"棕(踏实、可靠)",
"青绿(生机、和谐)",
"湖蓝(宁静、治愈)",
"米色(温和、包容)",
"藏青(睿智、深邃)",
"珊瑚(活泼、幸福)",
"酒红(成熟、魅力)"
];
const luckyColor = colors[Math.floor(rng() * colors.length)];
await ctx.database.set("jrrp", { userId: id, date: dateKey }, { luckyColor });
tail += options?.detail || config.enableLuckyColor ? `
幸运颜色:${luckyColor}` : "";
const yiyan = await pickYiYan(ctx, config);
await ctx.database.set("jrrp", { userId: id, date: dateKey }, { yiyan });
tail += options?.detail || config.enableYiyan ? `
签语:${yiyan ? yiyan : "暂无"}` : "";
return `${head}${tail}`;
}
});
ctx.command("jrrp.del [uid] [date]", "删除指定用户与日期的人品记录(管理)", { hidden: true }).userFields(["authority"]).check(async ({ session }) => {
if (!session) return "(无法获取会话信息)";
const user = await ctx.database.getUser(session.platform, session.userId, ["authority"]);
if (!user || user.authority < 3) return "你没有权限执行此命令。";
}).action(async ({ session }, uid, date) => {
const userId = uid || session.userId;
const dateKey = date || currentDateKey(config.resetHour, config.utcOffsetMinutes);
await ctx.database.remove("jrrp", { userId, date: dateKey });
return `已删除 ${userId} @ ${dateKey} 的人品记录`;
});
ctx.command("jrrp.rebuild", "重构数据库表(管理)", { hidden: true }).check(async ({ session }) => {
if (!session) return "(无法获取会话信息)";
const user = await ctx.database.getUser(session.platform, session.userId, ["authority"]);
if (!user || user.authority < 3) return "你没有权限执行此命令。";
}).action(async () => {
await ctx.database.drop("jrrp");
ctx.logger.warn(`已删除数据库表:jrrp`);
ctx.model.extend("jrrp", {
userId: "string",
date: "string",
score: "integer",
comment: "string",
good: "string",
bad: "string",
luckyNumber: "integer",
luckyColor: "string",
yiyan: "string"
}, { primary: ["userId", "date"] });
return `已重构数据库表:jrrp`;
});
ctx.command("jrrp.sim [uid] [date]", "按指定用户与日期模拟 JRRP(管理)").userFields(["authority"]).check(async ({ session }) => {
if (!session) return "(无法获取会话信息)";
const user = await ctx.database.getUser(session.platform, session.userId, ["authority"]);
if (!user || user.authority < 3) return "你没有权限执行此命令。";
}).option("platform", "-p <platform:string>").action(async ({ session }, uid, date) => {
const userId = uid || session.userId;
const dateKey = date || currentDateKey(config.resetHour, config.utcOffsetMinutes);
const seedBase = `${userId}|${dateKey}|${config.salt}`;
const seed = fnv1a32(seedBase);
const rng = mulberry32(seed);
const score = config.scoreMode === "fathead" ? fatheadScore(rng) : Math.floor(rng() * 101);
return `模拟 ${userId} @ ${dateKey} 的人品为 ${score}/100`;
});
}
__name(apply, "apply");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Config,
apply,
name,
using
});