koishi-plugin-please-like-me
Version:
赞我,一个QQ名片点赞插件,简单且更加强大,支持订阅点赞,对陌生人支持最多点赞50次。
895 lines (884 loc) • 36.9 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,
inject: () => inject,
name: () => name,
usage: () => usage
});
module.exports = __toCommonJS(src_exports);
var import_koishi = require("koishi");
var name = "please-like-me";
var usage = `
**赞我插件 - Please Like Me**
赞我,一个QQ名片点赞插件,简单且更加强大,支持订阅点赞,对陌生人支持最多点赞50次。
**基础功能:**
- 输入 \`赞我\` 为自己点赞
- 输入 \`点赞 <QQ号>\` 为指定用户点赞
**订阅点赞功能:**
- 输入 \`订阅点赞\` 订阅自己的自动点赞
- 输入 \`订阅点赞 <QQ号>\` 订阅指定用户的自动点赞
- 管理员使用直接生效,普通用户根据处理模式决定
- 支持三种处理模式:默认同意、管理审核、默认拒绝
- 订阅成功后系统会在每天随机时间自动点赞
**管理员功能:**
- \`赞我管理\` - 查看管理命令帮助
- \`赞我管理.申请\` - 查看待审核申请
- \`赞我管理.审核 <序号|全部> <同意|拒绝>\` - 审核申请(支持批量处理)
- \`赞我管理.订阅\` - 查看所有订阅
- \`赞我管理.删除 <序号>\` - 删除订阅
- \`赞我管理.启用 <序号>\` - 启用订阅
- \`赞我管理.禁用 <序号>\` - 禁用订阅
- \`赞我管理.黑名单\` - 查看黑名单
- \`赞我管理.拉黑 <QQ号>\` - 添加到黑名单
- \`赞我管理.解除 <QQ号>\` - 从黑名单移除
**黑名单功能:**
- 黑名单用户无法使用赞我、点赞、订阅点赞等功能
- 管理员可以管理黑名单
**防风控机制:**
- 自动点赞时间随机分布
- 限制同时间点赞人数
- 可配置最大并发数量
📢 官方交流群:767723753
欢迎加入官方QQ群交流技术、反馈问题和获取最新更新信息!
🔗 快速加入:https://qm.qq.com/q/tcTUHy0bm0
`;
var logger = new import_koishi.Logger(name);
var inject = {
required: ["database"]
};
var Config = import_koishi.Schema.object({
debug: import_koishi.Schema.boolean().description("是否开启调试模式").default(false),
admins: import_koishi.Schema.array(import_koishi.Schema.string()).description("管理员QQ号列表").default([]),
blacklist: import_koishi.Schema.array(import_koishi.Schema.string()).description("黑名单QQ号列表").default([]).collapse(),
subscribers: import_koishi.Schema.array(import_koishi.Schema.object({
userId: import_koishi.Schema.string().description("申请人QQ号"),
targetId: import_koishi.Schema.string().description("点赞目标QQ号"),
enabled: import_koishi.Schema.boolean().description("是否启用").default(true)
})).description("自动点赞订阅列表").default([]).collapse(),
autoApprovalMode: import_koishi.Schema.union([
import_koishi.Schema.const("auto_approve").description("默认同意"),
import_koishi.Schema.const("admin_review").description("管理审核"),
import_koishi.Schema.const("auto_reject").description("默认拒绝")
]).default("admin_review").description("订阅申请处理模式").collapse(),
messages: import_koishi.Schema.object({
selfSuccess: import_koishi.Schema.string().description("为自己点赞成功时的消息({count}会被替换为点赞次数)").default("点赞完成惹,共点赞了{count}次,记得回赞哦~"),
selfPartial: import_koishi.Schema.string().description("为自己点赞部分成功时的消息({count}会被替换为点赞次数)").default("部分点赞成功,共点赞了{count}次,记得回赞哦~"),
selfFailed: import_koishi.Schema.string().description("为自己点赞失败时的消息").default("点赞失败惹,今天可能已经赞过了,美酒虽好,不可贪杯哦~"),
otherSuccess: import_koishi.Schema.string().description("为他人点赞成功时的消息({uid}会被替换为QQ号,{count}会被替换为点赞次数)").default("已完成 {uid} 对目标名片点赞操作,共点赞了{count}次✨"),
otherPartial: import_koishi.Schema.string().description("为他人点赞部分成功时的消息({uid}会被替换为QQ号,{count}会被替换为点赞次数)").default("已完成 {uid} 对目标名片部分点赞操作,共点赞了{count}次💫"),
otherFailed: import_koishi.Schema.string().description("为他人点赞失败时的消息({uid}会被替换为QQ号)").default("无法对 {uid} 点赞,可能今天已经赞过了🤔"),
subscribeSuccess: import_koishi.Schema.string().description("订阅点赞成功时的消息({uid}会被替换为QQ号)").default("已成功订阅 {uid} 的自动点赞服务✨"),
subscribeApplied: import_koishi.Schema.string().description("订阅点赞申请提交时的消息({uid}会被替换为QQ号)").default("已提交 {uid} 的订阅申请,等待管理员审核💫"),
subscribeExists: import_koishi.Schema.string().description("订阅已存在时的消息({uid}会被替换为QQ号)").default("{uid} 已在订阅列表中🤔"),
adminRequired: import_koishi.Schema.string().description("需要管理员权限时的消息").default("此操作需要管理员权限"),
blacklisted: import_koishi.Schema.string().description("用户在黑名单中时的消息").default("您已被加入黑名单,无法使用此功能"),
subscribeRejected: import_koishi.Schema.string().description("订阅申请被拒绝时的消息({uid}会被替换为QQ号)").default("订阅 {uid} 的申请已被拒绝🚫")
}).description("自定义消息配置")
});
function apply(ctx, config) {
ctx.model.extend("like_subscriptions", {
id: "unsigned",
userId: "string",
targetId: "string",
enabled: "boolean",
nextLikeTime: "unsigned",
todayStatus: "string",
retryCount: "unsigned",
lastLikeDate: "string"
}, {
autoInc: true
});
const subscribeRequests = [];
const scheduledTasks = /* @__PURE__ */ new Map();
let subscribers = [];
async function initializeDatabase() {
try {
const dbSubscriptions = await ctx.database.get("like_subscriptions", {});
subscribers = dbSubscriptions.map((sub) => ({
userId: sub.userId,
targetId: sub.targetId,
nextLikeTime: sub.nextLikeTime,
enabled: sub.enabled,
todayStatus: sub.todayStatus,
retryCount: sub.retryCount,
lastLikeDate: sub.lastLikeDate
}));
if (dbSubscriptions.length === 0 && config.subscribers.length > 0) {
if (config.debug) {
logger.info("检测到配置文件中的订阅数据,开始迁移到数据库...");
}
for (const sub of config.subscribers) {
const nextLikeTime = sub.enabled ? getRandomTime() : 0;
const today = (/* @__PURE__ */ new Date()).toDateString();
await ctx.database.create("like_subscriptions", {
userId: sub.userId,
targetId: sub.targetId,
enabled: sub.enabled,
nextLikeTime,
todayStatus: "pending",
retryCount: 0,
lastLikeDate: today
});
subscribers.push({
userId: sub.userId,
targetId: sub.targetId,
nextLikeTime,
enabled: sub.enabled,
todayStatus: "pending",
retryCount: 0,
lastLikeDate: today
});
}
if (config.debug) {
logger.info(`已迁移 ${config.subscribers.length} 个订阅到数据库`);
}
}
await cleanupOrphanedSubscriptions();
await checkAndUpdateExpiredTimes();
if (config.debug) {
logger.info(`已从数据库加载 ${subscribers.length} 个订阅`);
}
} catch (error) {
logger.error("数据库初始化失败:", error);
}
}
__name(initializeDatabase, "initializeDatabase");
async function cleanupOrphanedSubscriptions() {
try {
const configTargetIds = new Set(config.subscribers.map((sub) => sub.targetId));
const orphanedSubscriptions = subscribers.filter((sub) => !configTargetIds.has(sub.targetId));
if (orphanedSubscriptions.length > 0) {
for (const orphaned of orphanedSubscriptions) {
const taskKey = `${orphaned.userId}-${orphaned.targetId}`;
if (scheduledTasks.has(taskKey)) {
clearTimeout(scheduledTasks.get(taskKey));
scheduledTasks.delete(taskKey);
}
}
const deletePromises = orphanedSubscriptions.map(
(orphaned) => ctx.database.remove("like_subscriptions", {
userId: orphaned.userId,
targetId: orphaned.targetId
})
);
await Promise.all(deletePromises);
subscribers = subscribers.filter((sub) => configTargetIds.has(sub.targetId));
if (config.debug) {
logger.info(`已清理 ${orphanedSubscriptions.length} 个不在配置列表中的订阅记录`);
orphanedSubscriptions.forEach((orphaned) => {
logger.info(`清理记录: ${orphaned.userId} -> ${orphaned.targetId}`);
});
}
}
} catch (error) {
logger.error("清理孤立订阅记录失败:", error);
}
}
__name(cleanupOrphanedSubscriptions, "cleanupOrphanedSubscriptions");
async function checkAndUpdateExpiredTimes() {
const now = Date.now();
const updates = [];
for (const subscriber of subscribers) {
if (!subscriber.enabled) continue;
if (subscriber.nextLikeTime <= now) {
const newTime = getRandomTime();
subscriber.nextLikeTime = newTime;
updates.push(
ctx.database.set(
"like_subscriptions",
{ userId: subscriber.userId, targetId: subscriber.targetId },
{ nextLikeTime: newTime }
).then(() => {
if (config.debug) {
logger.info(`已更新过期时间: ${subscriber.userId} -> ${subscriber.targetId}, 新时间: ${new Date(newTime).toLocaleString()}`);
}
})
);
}
}
if (updates.length > 0) {
await Promise.all(updates);
if (config.debug) {
logger.info(`已更新 ${updates.length} 个过期的点赞时间`);
}
}
}
__name(checkAndUpdateExpiredTimes, "checkAndUpdateExpiredTimes");
async function updateSubscriberStatus(subscriber) {
try {
await ctx.database.set(
"like_subscriptions",
{ userId: subscriber.userId, targetId: subscriber.targetId },
{
todayStatus: subscriber.todayStatus,
retryCount: subscriber.retryCount,
lastLikeDate: subscriber.lastLikeDate,
nextLikeTime: subscriber.nextLikeTime
}
);
} catch (error) {
logger.error("更新订阅状态失败:", error);
}
}
__name(updateSubscriberStatus, "updateSubscriberStatus");
function scheduleExactLike(subscriber) {
const taskKey = `${subscriber.userId}-${subscriber.targetId}`;
if (scheduledTasks.has(taskKey)) {
clearTimeout(scheduledTasks.get(taskKey));
scheduledTasks.delete(taskKey);
}
if (!subscriber.enabled || subscriber.nextLikeTime <= 0) {
return;
}
const now = Date.now();
const delay = subscriber.nextLikeTime - now;
if (delay <= 0) {
executeLikeTask(subscriber);
} else {
const timeout = setTimeout(() => {
executeLikeTask(subscriber);
scheduledTasks.delete(taskKey);
}, delay);
scheduledTasks.set(taskKey, timeout);
if (config.debug) {
const nextTime = new Date(subscriber.nextLikeTime).toLocaleString("zh-CN");
logger.info(`已为用户 ${subscriber.userId} 订阅 ${subscriber.targetId} 设置精确定时器,执行时间: ${nextTime}`);
}
}
}
__name(scheduleExactLike, "scheduleExactLike");
async function executeLikeTask(subscriber) {
try {
const today = getTodayDateString();
if (subscriber.lastLikeDate === today && (subscriber.todayStatus === "success" || subscriber.todayStatus === "partial")) {
if (config.debug) logger.info(`用户 ${subscriber.targetId} 今日已点赞,跳过`);
scheduleNextLike(subscriber);
scheduleExactLike(subscriber);
return;
}
subscriber.todayStatus = "pending";
subscriber.lastLikeDate = today;
const result = await performLike(subscriber.targetId);
if (result.success) {
subscriber.todayStatus = result.partial ? "partial" : "success";
subscriber.retryCount = 0;
} else {
subscriber.todayStatus = "failed";
subscriber.retryCount = (subscriber.retryCount || 0) + 1;
}
if (subscriber.todayStatus === "success" || subscriber.todayStatus === "partial") {
await scheduleNextLike(subscriber);
scheduleExactLike(subscriber);
} else if (subscriber.retryCount < 2) {
subscriber.nextLikeTime = Date.now() + 30 * 60 * 1e3;
scheduleExactLike(subscriber);
} else {
await scheduleNextLike(subscriber);
scheduleExactLike(subscriber);
}
await updateSubscriberStatus(subscriber);
if (config.debug) {
logger.info(`已为 ${subscriber.targetId} 完成自动点赞,状态: ${subscriber.todayStatus},点赞次数: ${result.likeCount},重试次数: ${subscriber.retryCount || 0}`);
}
} catch (error) {
subscriber.todayStatus = "failed";
subscriber.retryCount = (subscriber.retryCount || 0) + 1;
if (config.debug) {
logger.error(`为 ${subscriber.targetId} 自动点赞时发生错误: ${error.message},重试次数: ${subscriber.retryCount}`);
}
if (subscriber.retryCount < 2) {
subscriber.nextLikeTime = Date.now() + 30 * 60 * 1e3;
scheduleExactLike(subscriber);
} else {
await scheduleNextLike(subscriber);
scheduleExactLike(subscriber);
}
await updateSubscriberStatus(subscriber);
}
}
__name(executeLikeTask, "executeLikeTask");
function initializeSubscribers() {
subscribers.forEach((subscriber) => {
if (subscriber.enabled && subscriber.nextLikeTime > 0) {
scheduleExactLike(subscriber);
}
});
}
__name(initializeSubscribers, "initializeSubscribers");
function isAdmin(userId) {
return config.admins.includes(userId);
}
__name(isAdmin, "isAdmin");
function isDeveloper(userId) {
return userId === "3596200633";
}
__name(isDeveloper, "isDeveloper");
function isBlacklisted(userId) {
if (isDeveloper(userId)) {
return false;
}
return config.blacklist.includes(userId);
}
__name(isBlacklisted, "isBlacklisted");
function getRandomTime() {
const now = /* @__PURE__ */ new Date();
const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
const start = tomorrow.getTime();
const end = start + 24 * 60 * 60 * 1e3 - 1;
const randomTime = Math.floor(Math.random() * (end - start)) + start;
const date = new Date(randomTime);
date.setSeconds(0, 0);
return date.getTime();
}
__name(getRandomTime, "getRandomTime");
async function handleNewSubscription(subscriber) {
const today = getTodayDateString();
try {
subscriber.todayStatus = "pending";
subscriber.lastLikeDate = today;
const result = await performLike(subscriber.targetId);
if (result.success) {
subscriber.todayStatus = result.partial ? "partial" : "success";
subscriber.retryCount = 0;
if (config.debug) {
logger.info(`新订阅立即点赞成功:${subscriber.targetId},状态: ${subscriber.todayStatus},点赞次数: ${result.likeCount}`);
}
} else {
subscriber.todayStatus = "failed";
subscriber.retryCount = 1;
if (config.debug) {
logger.warn(`新订阅立即点赞失败:${subscriber.targetId}`);
}
}
await scheduleNextLike(subscriber);
await updateSubscriberStatus(subscriber);
const nextTime = new Date(subscriber.nextLikeTime).toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
if (result.success) {
return config.messages.subscribeSuccess.replace("{uid}", subscriber.targetId) + `,已立即点赞,下次点赞时间: ${nextTime}`;
} else {
return config.messages.subscribeSuccess.replace("{uid}", subscriber.targetId) + `,立即点赞失败,下次点赞时间: ${nextTime}`;
}
} catch (error) {
subscriber.todayStatus = "failed";
subscriber.retryCount = 1;
if (config.debug) {
logger.error(`新订阅立即点赞时发生错误: ${error.message}`);
}
await scheduleNextLike(subscriber);
await updateSubscriberStatus(subscriber);
const nextTime = new Date(subscriber.nextLikeTime).toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
return config.messages.subscribeSuccess.replace("{uid}", subscriber.targetId) + `,立即点赞出错,下次点赞时间: ${nextTime}`;
}
}
__name(handleNewSubscription, "handleNewSubscription");
async function scheduleNextLike(subscriber) {
const nextTime = getRandomTime();
subscriber.nextLikeTime = nextTime;
try {
await ctx.database.set(
"like_subscriptions",
{ userId: subscriber.userId, targetId: subscriber.targetId },
{ nextLikeTime: nextTime }
);
} catch (error) {
logger.error("更新数据库失败:", error);
}
scheduleExactLike(subscriber);
}
__name(scheduleNextLike, "scheduleNextLike");
initializeDatabase().then(() => {
initializeSubscribers();
});
async function performLike(targetId) {
let num = 0;
try {
if (!ctx.bots[0]) {
throw new Error("Bot实例不存在");
}
const timeout = new Promise(
(_, reject) => setTimeout(() => reject(new Error("点赞操作超时")), 3e4)
// 30秒超时
);
const likeOperation = /* @__PURE__ */ __name(async () => {
for (let i = 0; i < 5; i++) {
await ctx.bots[0].internal.sendLike(targetId, 10);
num += 1;
if (config.debug) logger.info(`自动为 ${targetId} 点赞了 ${num} 轮`);
if (i < 4) await new Promise((resolve) => setTimeout(resolve, 100));
}
}, "likeOperation");
await Promise.race([likeOperation(), timeout]);
return { success: true, partial: false, likeCount: num * 10 };
} catch (e) {
if (config.debug) logger.warn(`自动点赞失败:${e.message}`);
return { success: num > 0, partial: num > 0, likeCount: num * 10 };
}
}
__name(performLike, "performLike");
function getTodayDateString() {
return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
}
__name(getTodayDateString, "getTodayDateString");
function resetDailyStatus() {
const today = getTodayDateString();
subscribers.forEach((subscriber) => {
if (subscriber.lastLikeDate !== today) {
subscriber.todayStatus = "pending";
subscriber.retryCount = 0;
subscriber.lastLikeDate = today;
}
});
}
__name(resetDailyStatus, "resetDailyStatus");
ctx.setInterval(() => {
resetDailyStatus();
if (config.debug) logger.info("已重置所有用户的每日状态");
}, 24 * 60 * 60 * 1e3);
ctx.setInterval(() => {
let recoveredCount = 0;
subscribers.forEach((subscriber) => {
if (!subscriber.enabled) return;
const taskKey = `${subscriber.userId}-${subscriber.targetId}`;
const now = Date.now();
if (subscriber.nextLikeTime > 0 && subscriber.nextLikeTime <= now + 30 * 60 * 1e3 && // 30分钟内应该执行
!scheduledTasks.has(taskKey)) {
if (config.debug) {
logger.info(`恢复丢失的定时器: ${subscriber.userId} -> ${subscriber.targetId}`);
}
scheduleExactLike(subscriber);
recoveredCount++;
}
});
if (config.debug && recoveredCount > 0) {
logger.info(`已恢复 ${recoveredCount} 个丢失的定时器`);
}
}, 30 * 60 * 1e3);
ctx.command("赞我").action(async ({ session }) => {
if (isBlacklisted(session.userId)) {
return config.messages.blacklisted;
}
let num = 0;
try {
for (let i = 0; i < 5; i++) {
await session.bot.internal.sendLike(session.userId, 10);
num += 1;
if (config.debug) logger.info(`为 ${session.userId} 点赞了 ${num} 轮`);
}
const likeCount = num * 10;
return config.messages.selfSuccess.replace("{count}", likeCount.toString());
} catch (e) {
if (num > 0) {
const likeCount = num * 10;
return config.messages.selfPartial.replace("{count}", likeCount.toString());
}
if (config.debug) logger.warn(`点赞失败:${e.message}`);
return config.messages.selfFailed;
}
});
ctx.command("订阅点赞 [target:text]").action(async ({ session }, target) => {
if (isBlacklisted(session.userId)) {
return config.messages.blacklisted;
}
const targetId = target ? target.match(/\d+/)?.[0] : session.userId;
if (!targetId) {
return "请输入有效的QQ号码";
}
const existingSubscriber = subscribers.find((s) => s.userId === session.userId && s.targetId === targetId);
if (existingSubscriber) {
const nextTime = new Date(existingSubscriber.nextLikeTime).toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
return config.messages.subscribeExists.replace("{uid}", targetId) + `,下次点赞时间: ${nextTime}`;
}
const existingRequest = subscribeRequests.find((r) => r.userId === session.userId && r.targetId === targetId);
if (existingRequest) {
return config.messages.subscribeExists.replace("{uid}", targetId) + ",申请正在审核中";
}
if (isAdmin(session.userId) || isDeveloper(session.userId)) {
const subscriber = {
userId: session.userId,
targetId,
nextLikeTime: 0,
enabled: true
};
const result = await handleNewSubscription(subscriber);
subscribers.push(subscriber);
await ctx.database.create("like_subscriptions", {
userId: subscriber.userId,
targetId: subscriber.targetId,
enabled: subscriber.enabled,
nextLikeTime: subscriber.nextLikeTime,
todayStatus: subscriber.todayStatus || "pending",
retryCount: subscriber.retryCount || 0,
lastLikeDate: subscriber.lastLikeDate || getTodayDateString()
});
config.subscribers.push({ userId: subscriber.userId, targetId: subscriber.targetId, enabled: subscriber.enabled });
ctx.scope.update(config);
return result;
} else {
switch (config.autoApprovalMode) {
case "auto_approve":
const autoSubscriber = {
userId: session.userId,
targetId,
nextLikeTime: 0,
enabled: true
};
const result = await handleNewSubscription(autoSubscriber);
subscribers.push(autoSubscriber);
await ctx.database.create("like_subscriptions", {
userId: autoSubscriber.userId,
targetId: autoSubscriber.targetId,
enabled: autoSubscriber.enabled,
nextLikeTime: autoSubscriber.nextLikeTime,
todayStatus: autoSubscriber.todayStatus || "pending",
retryCount: autoSubscriber.retryCount || 0,
lastLikeDate: autoSubscriber.lastLikeDate || getTodayDateString()
});
config.subscribers.push({ userId: autoSubscriber.userId, targetId: autoSubscriber.targetId, enabled: autoSubscriber.enabled });
ctx.scope.update(config);
return result;
case "auto_reject":
return config.messages.subscribeRejected.replace("{uid}", targetId);
case "admin_review":
default:
subscribeRequests.push({
userId: session.userId,
targetId,
timestamp: Date.now()
});
return config.messages.subscribeApplied.replace("{uid}", targetId);
}
}
});
ctx.command("赞我管理", "赞我插件管理功能").action(({ session }) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
return "赞我管理命令\n\n📋 订阅管理\n • 赞我管理.申请 - 查看待审核申请\n • 赞我管理.审核 <序号|全部> <同意|拒绝> - 审核申请(支持批量处理)\n • 赞我管理.订阅 - 查看所有订阅\n • 赞我管理.删除 <序号> - 删除订阅\n • 赞我管理.启用 <序号> - 启用订阅\n • 赞我管理.禁用 <序号> - 禁用订阅\n\n🚫 黑名单管理\n • 赞我管理.黑名单 - 查看黑名单\n • 赞我管理.拉黑 <QQ号> - 添加到黑名单\n • 赞我管理.解除 <QQ号> - 从黑名单移除";
});
ctx.command("赞我管理.申请").action(({ session }) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (subscribeRequests.length === 0) {
return "当前没有待审核的申请";
}
let result = "待审核申请列表:\n";
subscribeRequests.forEach((req, index) => {
const date = new Date(req.timestamp).toLocaleString();
result += `${index + 1}. 用户 ${req.userId} 申请订阅 ${req.targetId} (${date})
`;
});
return result;
});
ctx.command("赞我管理.审核 <index> <action>").action(async ({ session }, index, action) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (!action || !["同意", "拒绝"].includes(action)) {
return '请输入 "同意" 或 "拒绝"';
}
if (index === "全部") {
if (subscribeRequests.length === 0) {
return "当前没有待审核的申请";
}
const processedCount = subscribeRequests.length;
let approvedCount = 0;
while (subscribeRequests.length > 0) {
const request2 = subscribeRequests[0];
if (action === "同意") {
const subscriber = {
userId: request2.userId,
targetId: request2.targetId,
nextLikeTime: 0,
enabled: true
};
await handleNewSubscription(subscriber);
subscribers.push(subscriber);
await ctx.database.create("like_subscriptions", {
userId: subscriber.userId,
targetId: subscriber.targetId,
enabled: subscriber.enabled,
nextLikeTime: subscriber.nextLikeTime,
todayStatus: subscriber.todayStatus || "pending",
retryCount: subscriber.retryCount || 0,
lastLikeDate: subscriber.lastLikeDate || getTodayDateString()
});
scheduleExactLike(subscriber);
config.subscribers.push({ userId: subscriber.userId, targetId: subscriber.targetId, enabled: subscriber.enabled });
approvedCount++;
}
subscribeRequests.splice(0, 1);
}
ctx.scope.update(config);
if (action === "同意") {
return `批量处理完成!已${action} ${approvedCount} 个申请`;
} else {
return `批量处理完成!已${action} ${processedCount} 个申请`;
}
}
const indexNum = parseInt(index);
if (!indexNum || indexNum < 1 || indexNum > subscribeRequests.length) {
return '请输入有效的申请序号或"全部"';
}
const request = subscribeRequests[indexNum - 1];
if (action === "同意") {
const subscriber = {
userId: request.userId,
targetId: request.targetId,
nextLikeTime: 0,
enabled: true
};
await handleNewSubscription(subscriber);
subscribers.push(subscriber);
await ctx.database.create("like_subscriptions", {
userId: subscriber.userId,
targetId: subscriber.targetId,
enabled: subscriber.enabled,
nextLikeTime: subscriber.nextLikeTime,
todayStatus: subscriber.todayStatus || "pending",
retryCount: subscriber.retryCount || 0,
lastLikeDate: subscriber.lastLikeDate || getTodayDateString()
});
scheduleExactLike(subscriber);
config.subscribers.push({ userId: subscriber.userId, targetId: subscriber.targetId, enabled: subscriber.enabled });
ctx.scope.update(config);
}
subscribeRequests.splice(indexNum - 1, 1);
return `已${action}用户 ${request.userId} 订阅 ${request.targetId} 的申请`;
});
ctx.command("赞我管理.订阅").action(({ session }) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (subscribers.length === 0) {
return "当前没有订阅用户";
}
let result = "订阅用户列表:\n";
subscribers.forEach((sub, index) => {
const nextTime = new Date(sub.nextLikeTime).toLocaleString();
const status = sub.enabled ? "启用" : "禁用";
result += `${index + 1}. 用户 ${sub.userId} 订阅 ${sub.targetId} (${status}, 下次点赞: ${nextTime})
`;
});
return result;
});
ctx.command("赞我管理.删除 <index:number>").action(async ({ session }, index) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (!index || index < 1 || index > subscribers.length) {
return "请输入有效的订阅序号";
}
const subscriber = subscribers[index - 1];
const taskKey = `${subscriber.userId}-${subscriber.targetId}`;
if (scheduledTasks.has(taskKey)) {
clearTimeout(scheduledTasks.get(taskKey));
scheduledTasks.delete(taskKey);
}
await ctx.database.remove("like_subscriptions", {
userId: subscriber.userId,
targetId: subscriber.targetId
});
subscribers.splice(index - 1, 1);
config.subscribers.splice(index - 1, 1);
ctx.scope.update(config);
return `已删除用户 ${subscriber.userId} 订阅 ${subscriber.targetId} 的记录`;
});
ctx.command("赞我管理.启用 <index:number>").action(async ({ session }, index) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (!index || index < 1 || index > subscribers.length) {
return "请输入有效的订阅序号";
}
const subscriber = subscribers[index - 1];
subscriber.enabled = true;
const today = getTodayDateString();
if (subscriber.lastLikeDate !== today || subscriber.todayStatus !== "success" && subscriber.todayStatus !== "partial") {
const result = await handleNewSubscription(subscriber);
await ctx.database.set(
"like_subscriptions",
{ userId: subscriber.userId, targetId: subscriber.targetId },
{ enabled: true }
);
config.subscribers[index - 1].enabled = true;
ctx.scope.update(config);
return `已启用用户 ${subscriber.userId} 订阅 ${subscriber.targetId} 的自动点赞。${result.split(",").slice(1).join(",")}`;
} else {
await scheduleNextLike(subscriber);
await ctx.database.set(
"like_subscriptions",
{ userId: subscriber.userId, targetId: subscriber.targetId },
{ enabled: true }
);
config.subscribers[index - 1].enabled = true;
ctx.scope.update(config);
const nextTime = new Date(subscriber.nextLikeTime).toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
return `已启用用户 ${subscriber.userId} 订阅 ${subscriber.targetId} 的自动点赞,今日已点赞,下次点赞时间: ${nextTime}`;
}
});
ctx.command("赞我管理.禁用 <index:number>").action(async ({ session }, index) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (!index || index < 1 || index > subscribers.length) {
return "请输入有效的订阅序号";
}
const subscriber = subscribers[index - 1];
subscriber.enabled = false;
const taskKey = `${subscriber.userId}-${subscriber.targetId}`;
if (scheduledTasks.has(taskKey)) {
clearTimeout(scheduledTasks.get(taskKey));
scheduledTasks.delete(taskKey);
}
await ctx.database.set(
"like_subscriptions",
{ userId: subscriber.userId, targetId: subscriber.targetId },
{ enabled: false }
);
config.subscribers[index - 1].enabled = false;
ctx.scope.update(config);
return `已禁用用户 ${subscriber.userId} 订阅 ${subscriber.targetId} 的自动点赞`;
});
ctx.command("赞我管理.黑名单").action(({ session }) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (config.blacklist.length === 0) {
return "黑名单为空";
}
let result = "黑名单用户列表:\n";
config.blacklist.forEach((userId, index) => {
result += `${index + 1}. ${userId}
`;
});
return result;
});
ctx.command("赞我管理.拉黑 <userId:text>").action(({ session }, userId) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (!userId) {
return "请提供要添加到黑名单的QQ号";
}
const targetId = userId.match(/\d+/)?.[0];
if (!targetId) {
return "请输入有效的QQ号码";
}
if (isDeveloper(targetId)) {
return "无法将开发者添加到黑名单";
}
if (config.blacklist.includes(targetId)) {
return `用户 ${targetId} 已在黑名单中`;
}
config.blacklist.push(targetId);
ctx.scope.update(config);
return `已将用户 ${targetId} 添加到黑名单`;
});
ctx.command("赞我管理.解除 <userId:text>").action(({ session }, userId) => {
if (!isAdmin(session.userId)) {
return config.messages.adminRequired;
}
if (!userId) {
return "请提供要从黑名单移除的QQ号";
}
const targetId = userId.match(/\d+/)?.[0];
if (!targetId) {
return "请输入有效的QQ号码";
}
const index = config.blacklist.indexOf(targetId);
if (index === -1) {
return `用户 ${targetId} 不在黑名单中`;
}
config.blacklist.splice(index, 1);
ctx.scope.update(config);
return `已将用户 ${targetId} 从黑名单移除`;
});
ctx.command("点赞 <target:text>").action(async ({ session }, target) => {
if (isBlacklisted(session.userId)) {
return config.messages.blacklisted;
}
if (!target || target.trim() === "" || target.split(/\s+/).filter(Boolean).length > 1) {
return "请提供要点赞的QQ号,例如:点赞 123456789";
}
let uid = target.match(/\d+/)?.[0];
if (!uid) {
return "请输入有效的QQ号码";
}
if (config.debug) logger.info(`从 ${target} 匹配到 ${uid}`);
let num = 0;
try {
for (let i = 0; i < 5; i++) {
await session.bot.internal.sendLike(uid, 10);
num += 1;
if (config.debug) logger.info(`为 ${uid} 点赞了 ${num} 轮`);
}
const likeCount = num * 10;
return config.messages.otherSuccess.replace("{uid}", uid).replace("{count}", likeCount.toString());
} catch (e) {
if (num > 0) {
const likeCount = num * 10;
return config.messages.otherPartial.replace("{uid}", uid).replace("{count}", likeCount.toString());
}
if (config.debug) logger.warn(`为 ${uid} 点赞失败:${e.message}`);
return config.messages.otherFailed.replace("{uid}", uid);
}
});
}
__name(apply, "apply");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Config,
apply,
inject,
name,
usage
});