karin-plugin-kkk 2.22.0 → 2.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/lib/apps/admin.js +3 -3
- package/lib/apps/help.js +3 -3
- package/lib/apps/push.js +3 -3
- package/lib/apps/qrlogin.js +3 -3
- package/lib/apps/statistics.js +5 -0
- package/lib/apps/tools.js +3 -3
- package/lib/apps/update.js +3 -3
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/{main-DgimuYt0.js → main-BdZy8WYB.js} +494 -28
- package/lib/core_chunk/{template-B9tgdrVz.js → template-CnW8M_F0.js} +3974 -2935
- package/lib/core_chunk/template.d.mts +60 -1
- package/lib/core_chunk/template.js +2 -2
- package/lib/core_chunk/{vendor-BcMLByns.js → vendor-DxfKHvj-.js} +34116 -7991
- package/lib/index.js +3 -3
- package/lib/karin-plugin-kkk.css +262 -23
- package/lib/root.js +1 -1
- package/lib/web.config.js +3 -3
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __esmMin, o as __toESM, r as __export } from "./rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as init_client, r as reactServerRender } from "./template-
|
|
2
|
+
import { A as init_locale, An as init_zod, Cn as Chalk, Dn as axios_default, En as init_axios, On as Xhshow, Sn as require_protobufjs, Tn as AxiosError$1, _n as require_png, a as Window, bn as require_heic_decode, dt as init_date_fns, ft as fromUnixTime, ht as differenceInSeconds, i as init_lib, j as zhCN, jn as zod_default, kn as init_dist, mt as format, n as require_lib, pt as formatDistanceToNow, r as require_qr_code_styling, t as require_dist, vn as require_jsQR, wn as init_source, xn as require_express, yn as require_jpeg_js } from "./vendor-DxfKHvj-.js";
|
|
3
|
+
import { n as init_client, r as reactServerRender } from "./template-CnW8M_F0.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import karin$1, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, checkPort, common, components, config, copyConfigSync, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, filesByExt, getBot, hooks, karin, karinPathHtml, karinPathTemp, logger, logs, mkdirSync, range, render, requireFileSync, restart, segment, updatePkg, watch } from "node-karin";
|
|
6
6
|
import fs from "node:fs";
|
|
@@ -6621,7 +6621,7 @@ var init_QRCodeScanner = __esmMin(() => {
|
|
|
6621
6621
|
}
|
|
6622
6622
|
static async parseHEIC(buffer) {
|
|
6623
6623
|
try {
|
|
6624
|
-
const decoded = await (0, import_heic_decode$1.default)({ buffer });
|
|
6624
|
+
const decoded = await (0, import_heic_decode$1.default)({ buffer: buffer.buffer });
|
|
6625
6625
|
logger.debug(`HEIC 解析成功: ${decoded.width}x${decoded.height}`);
|
|
6626
6626
|
return {
|
|
6627
6627
|
width: decoded.width,
|
|
@@ -9885,9 +9885,323 @@ var init_douyin = __esmMin(async () => {
|
|
|
9885
9885
|
}
|
|
9886
9886
|
};
|
|
9887
9887
|
});
|
|
9888
|
+
var MigrationManager;
|
|
9889
|
+
var init_migration = __esmMin(() => {
|
|
9890
|
+
MigrationManager = class {
|
|
9891
|
+
dbPath;
|
|
9892
|
+
constructor(dbPath) {
|
|
9893
|
+
this.dbPath = dbPath;
|
|
9894
|
+
}
|
|
9895
|
+
runQuery(db$1, sql, params = []) {
|
|
9896
|
+
return new Promise((resolve$1, reject) => {
|
|
9897
|
+
db$1.run(sql, params, function(err) {
|
|
9898
|
+
if (err) reject(err);
|
|
9899
|
+
else resolve$1({
|
|
9900
|
+
lastID: this.lastID,
|
|
9901
|
+
changes: this.changes
|
|
9902
|
+
});
|
|
9903
|
+
});
|
|
9904
|
+
});
|
|
9905
|
+
}
|
|
9906
|
+
getQuery(db$1, sql, params = []) {
|
|
9907
|
+
return new Promise((resolve$1, reject) => {
|
|
9908
|
+
db$1.get(sql, params, (err, row) => {
|
|
9909
|
+
if (err) reject(err);
|
|
9910
|
+
else resolve$1(row);
|
|
9911
|
+
});
|
|
9912
|
+
});
|
|
9913
|
+
}
|
|
9914
|
+
allQuery(db$1, sql, params = []) {
|
|
9915
|
+
return new Promise((resolve$1, reject) => {
|
|
9916
|
+
db$1.all(sql, params, (err, rows) => {
|
|
9917
|
+
if (err) reject(err);
|
|
9918
|
+
else resolve$1(rows);
|
|
9919
|
+
});
|
|
9920
|
+
});
|
|
9921
|
+
}
|
|
9922
|
+
async initMigrationTable(db$1) {
|
|
9923
|
+
await this.runQuery(db$1, `\n CREATE TABLE IF NOT EXISTS _migrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n version INTEGER NOT NULL UNIQUE,\n name TEXT NOT NULL,\n executedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `);
|
|
9924
|
+
}
|
|
9925
|
+
async getExecutedMigrations(db$1) {
|
|
9926
|
+
try {
|
|
9927
|
+
return await this.allQuery(db$1, "SELECT * FROM _migrations ORDER BY version");
|
|
9928
|
+
} catch {
|
|
9929
|
+
return [];
|
|
9930
|
+
}
|
|
9931
|
+
}
|
|
9932
|
+
async recordMigration(db$1, migration) {
|
|
9933
|
+
await this.runQuery(db$1, "INSERT INTO _migrations (version, name, executedAt) VALUES (?, ?, ?)", [
|
|
9934
|
+
migration.version,
|
|
9935
|
+
migration.name,
|
|
9936
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
9937
|
+
]);
|
|
9938
|
+
}
|
|
9939
|
+
async executeMigration(db$1, migration) {
|
|
9940
|
+
logger.info(`[Migration] 执行迁移 v${migration.version}: ${migration.name}`);
|
|
9941
|
+
try {
|
|
9942
|
+
await this.runQuery(db$1, "BEGIN TRANSACTION");
|
|
9943
|
+
for (const sql of migration.up) await this.runQuery(db$1, sql);
|
|
9944
|
+
await this.recordMigration(db$1, migration);
|
|
9945
|
+
await this.runQuery(db$1, "COMMIT");
|
|
9946
|
+
logger.info(`[Migration] ✓ 迁移 v${migration.version} 执行成功`);
|
|
9947
|
+
} catch (error) {
|
|
9948
|
+
await this.runQuery(db$1, "ROLLBACK");
|
|
9949
|
+
logger.error(`[Migration] ✗ 迁移 v${migration.version} 执行失败:`, error);
|
|
9950
|
+
throw error;
|
|
9951
|
+
}
|
|
9952
|
+
}
|
|
9953
|
+
async runMigrations(db$1, migrations) {
|
|
9954
|
+
await this.initMigrationTable(db$1);
|
|
9955
|
+
const executedMigrations = await this.getExecutedMigrations(db$1);
|
|
9956
|
+
const executedVersions = new Set(executedMigrations.map((m) => m.version));
|
|
9957
|
+
const versions = migrations.map((m) => m.version);
|
|
9958
|
+
const uniqueVersions = new Set(versions);
|
|
9959
|
+
if (versions.length !== uniqueVersions.size) throw new Error("[Migration] 迁移版本号必须唯一");
|
|
9960
|
+
const pendingMigrations = [...migrations].sort((a, b) => a.version - b.version).filter((m) => !executedVersions.has(m.version));
|
|
9961
|
+
if (pendingMigrations.length === 0) {
|
|
9962
|
+
logger.debug("[Migration] 数据库已是最新版本,无需迁移");
|
|
9963
|
+
return;
|
|
9964
|
+
}
|
|
9965
|
+
logger.info(`[Migration] 发现 ${pendingMigrations.length} 个待执行的迁移`);
|
|
9966
|
+
for (const migration of pendingMigrations) await this.executeMigration(db$1, migration);
|
|
9967
|
+
logger.info("[Migration] 所有迁移执行完成");
|
|
9968
|
+
}
|
|
9969
|
+
async getCurrentVersion(db$1) {
|
|
9970
|
+
try {
|
|
9971
|
+
await this.initMigrationTable(db$1);
|
|
9972
|
+
return (await this.getQuery(db$1, "SELECT MAX(version) as version FROM _migrations"))?.version || 0;
|
|
9973
|
+
} catch {
|
|
9974
|
+
return 0;
|
|
9975
|
+
}
|
|
9976
|
+
}
|
|
9977
|
+
async rollbackTo(db$1, targetVersion, migrations) {
|
|
9978
|
+
const currentVersion = await this.getCurrentVersion(db$1);
|
|
9979
|
+
if (targetVersion >= currentVersion) {
|
|
9980
|
+
logger.warn("[Migration] 目标版本不低于当前版本,无需回滚");
|
|
9981
|
+
return;
|
|
9982
|
+
}
|
|
9983
|
+
const migrationsToRollback = migrations.filter((m) => m.version > targetVersion && m.version <= currentVersion).sort((a, b) => b.version - a.version);
|
|
9984
|
+
logger.info(`[Migration] 开始回滚到版本 ${targetVersion}`);
|
|
9985
|
+
for (const migration of migrationsToRollback) {
|
|
9986
|
+
if (!migration.down || migration.down.length === 0) throw new Error(`[Migration] 迁移 v${migration.version} 没有提供回滚脚本`);
|
|
9987
|
+
logger.info(`[Migration] 回滚迁移 v${migration.version}: ${migration.name}`);
|
|
9988
|
+
try {
|
|
9989
|
+
await this.runQuery(db$1, "BEGIN TRANSACTION");
|
|
9990
|
+
for (const sql of migration.down) await this.runQuery(db$1, sql);
|
|
9991
|
+
await this.runQuery(db$1, "DELETE FROM _migrations WHERE version = ?", [migration.version]);
|
|
9992
|
+
await this.runQuery(db$1, "COMMIT");
|
|
9993
|
+
logger.info(`[Migration] ✓ 迁移 v${migration.version} 回滚成功`);
|
|
9994
|
+
} catch (error) {
|
|
9995
|
+
await this.runQuery(db$1, "ROLLBACK");
|
|
9996
|
+
logger.error(`[Migration] ✗ 迁移 v${migration.version} 回滚失败:`, error);
|
|
9997
|
+
throw error;
|
|
9998
|
+
}
|
|
9999
|
+
}
|
|
10000
|
+
logger.info("[Migration] 回滚完成");
|
|
10001
|
+
}
|
|
10002
|
+
};
|
|
10003
|
+
});
|
|
10004
|
+
var StatisticsDBBase;
|
|
10005
|
+
var init_statistics = __esmMin(async () => {
|
|
10006
|
+
await init_utils$1();
|
|
10007
|
+
await init_migration();
|
|
10008
|
+
StatisticsDBBase = class {
|
|
10009
|
+
db;
|
|
10010
|
+
dbPath;
|
|
10011
|
+
migrationManager;
|
|
10012
|
+
constructor() {
|
|
10013
|
+
this.dbPath = path.join(`${karinPathBase}/${Root.pluginName}/data`, "statistics.db");
|
|
10014
|
+
this.migrationManager = new MigrationManager(this.dbPath);
|
|
10015
|
+
}
|
|
10016
|
+
async init() {
|
|
10017
|
+
try {
|
|
10018
|
+
logger.debug(logger.green("--------------------------[StatisticsDB] 开始初始化数据库--------------------------"));
|
|
10019
|
+
logger.debug("[StatisticsDB] 正在连接数据库...");
|
|
10020
|
+
await (await import("node:fs/promises")).mkdir(path.dirname(this.dbPath), { recursive: true });
|
|
10021
|
+
this.db = new sqlite3.Database(this.dbPath);
|
|
10022
|
+
await this.createTables();
|
|
10023
|
+
logger.debug("[StatisticsDB] 数据库模型同步成功");
|
|
10024
|
+
await this.initGlobalStatistics();
|
|
10025
|
+
await this.syncHistoryFromStats();
|
|
10026
|
+
logger.debug(logger.green("--------------------------[StatisticsDB] 初始化数据库完成--------------------------"));
|
|
10027
|
+
} catch (error) {
|
|
10028
|
+
logger.error("[StatisticsDB] 数据库初始化失败:", error);
|
|
10029
|
+
throw error;
|
|
10030
|
+
}
|
|
10031
|
+
return this;
|
|
10032
|
+
}
|
|
10033
|
+
async createTables() {
|
|
10034
|
+
for (const query of [
|
|
10035
|
+
`CREATE TABLE IF NOT EXISTS ParseStatistics (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n groupId TEXT NOT NULL,\n userId TEXT NOT NULL,\n platform TEXT NOT NULL,\n parseCount INTEGER DEFAULT 0,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n UNIQUE(groupId, userId, platform)\n )`,
|
|
10036
|
+
`CREATE TABLE IF NOT EXISTS ParseHistory (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n date TEXT NOT NULL UNIQUE,\n totalParses INTEGER DEFAULT 0,\n douyin INTEGER DEFAULT 0,\n bilibili INTEGER DEFAULT 0,\n kuaishou INTEGER DEFAULT 0,\n xiaohongshu INTEGER DEFAULT 0,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
|
|
10037
|
+
`CREATE TABLE IF NOT EXISTS GlobalStatistics (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`
|
|
10038
|
+
]) await this.runQuery(query);
|
|
10039
|
+
}
|
|
10040
|
+
async initGlobalStatistics() {
|
|
10041
|
+
for (const key of ["totalGroups", "totalParses"]) if (!await this.getQuery("SELECT * FROM GlobalStatistics WHERE key = ?", [key])) await this.runQuery("INSERT INTO GlobalStatistics (key, value, updatedAt) VALUES (?, ?, ?)", [
|
|
10042
|
+
key,
|
|
10043
|
+
"0",
|
|
10044
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
10045
|
+
]);
|
|
10046
|
+
}
|
|
10047
|
+
runQuery(sql, params = []) {
|
|
10048
|
+
return new Promise((resolve$1, reject) => {
|
|
10049
|
+
this.db.run(sql, params, function(err) {
|
|
10050
|
+
if (err) reject(err);
|
|
10051
|
+
else resolve$1({
|
|
10052
|
+
lastID: this.lastID,
|
|
10053
|
+
changes: this.changes
|
|
10054
|
+
});
|
|
10055
|
+
});
|
|
10056
|
+
});
|
|
10057
|
+
}
|
|
10058
|
+
getQuery(sql, params = []) {
|
|
10059
|
+
return new Promise((resolve$1, reject) => {
|
|
10060
|
+
this.db.get(sql, params, (err, row) => {
|
|
10061
|
+
if (err) reject(err);
|
|
10062
|
+
else resolve$1(row);
|
|
10063
|
+
});
|
|
10064
|
+
});
|
|
10065
|
+
}
|
|
10066
|
+
allQuery(sql, params = []) {
|
|
10067
|
+
return new Promise((resolve$1, reject) => {
|
|
10068
|
+
this.db.all(sql, params, (err, rows) => {
|
|
10069
|
+
if (err) reject(err);
|
|
10070
|
+
else resolve$1(rows);
|
|
10071
|
+
});
|
|
10072
|
+
});
|
|
10073
|
+
}
|
|
10074
|
+
async recordParse(groupId, userId, platform$1) {
|
|
10075
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10076
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
10077
|
+
if (await this.getQuery("SELECT * FROM ParseStatistics WHERE groupId = ? AND userId = ? AND platform = ?", [
|
|
10078
|
+
groupId,
|
|
10079
|
+
userId,
|
|
10080
|
+
platform$1
|
|
10081
|
+
])) await this.runQuery("UPDATE ParseStatistics SET parseCount = parseCount + 1, updatedAt = ? WHERE groupId = ? AND userId = ? AND platform = ?", [
|
|
10082
|
+
now,
|
|
10083
|
+
groupId,
|
|
10084
|
+
userId,
|
|
10085
|
+
platform$1
|
|
10086
|
+
]);
|
|
10087
|
+
else {
|
|
10088
|
+
await this.runQuery("INSERT INTO ParseStatistics (groupId, userId, platform, parseCount, createdAt, updatedAt) VALUES (?, ?, ?, 1, ?, ?)", [
|
|
10089
|
+
groupId,
|
|
10090
|
+
userId,
|
|
10091
|
+
platform$1,
|
|
10092
|
+
now,
|
|
10093
|
+
now
|
|
10094
|
+
]);
|
|
10095
|
+
const groupExists = await this.getQuery("SELECT COUNT(DISTINCT groupId) as count FROM ParseStatistics WHERE groupId = ?", [groupId]);
|
|
10096
|
+
if (groupExists && groupExists.count === 1) await this.incrementTotalGroups();
|
|
10097
|
+
}
|
|
10098
|
+
await this.incrementTotalParses();
|
|
10099
|
+
await this.updateDailyHistory(today, platform$1);
|
|
10100
|
+
}
|
|
10101
|
+
async updateDailyHistory(date, platform$1) {
|
|
10102
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10103
|
+
try {
|
|
10104
|
+
if (await this.getQuery("SELECT * FROM ParseHistory WHERE date = ?", [date])) await this.runQuery(`UPDATE ParseHistory SET totalParses = totalParses + 1, ${platform$1} = ${platform$1} + 1 WHERE date = ?`, [date]);
|
|
10105
|
+
else await this.runQuery("INSERT INTO ParseHistory (date, totalParses, douyin, bilibili, kuaishou, xiaohongshu, createdAt) VALUES (?, 1, ?, ?, ?, ?, ?)", [
|
|
10106
|
+
date,
|
|
10107
|
+
platform$1 === "douyin" ? 1 : 0,
|
|
10108
|
+
platform$1 === "bilibili" ? 1 : 0,
|
|
10109
|
+
platform$1 === "kuaishou" ? 1 : 0,
|
|
10110
|
+
platform$1 === "xiaohongshu" ? 1 : 0,
|
|
10111
|
+
now
|
|
10112
|
+
]);
|
|
10113
|
+
} catch (error) {
|
|
10114
|
+
logger.error("[StatisticsDB] 更新每日历史记录失败:", error);
|
|
10115
|
+
}
|
|
10116
|
+
}
|
|
10117
|
+
async getRecentHistory(days = 30) {
|
|
10118
|
+
return await this.allQuery("SELECT * FROM ParseHistory ORDER BY date DESC LIMIT ?", [days]);
|
|
10119
|
+
}
|
|
10120
|
+
async syncHistoryFromStats() {
|
|
10121
|
+
try {
|
|
10122
|
+
const historyCount = await this.getQuery("SELECT COUNT(*) as count FROM ParseHistory");
|
|
10123
|
+
if (historyCount && historyCount.count > 0) return;
|
|
10124
|
+
const allStats = await this.getAllStatistics();
|
|
10125
|
+
const dateMap = /* @__PURE__ */ new Map();
|
|
10126
|
+
for (const stat of allStats) {
|
|
10127
|
+
const date = stat.createdAt.split("T")[0];
|
|
10128
|
+
if (!dateMap.has(date)) dateMap.set(date, {
|
|
10129
|
+
douyin: 0,
|
|
10130
|
+
bilibili: 0,
|
|
10131
|
+
kuaishou: 0,
|
|
10132
|
+
xiaohongshu: 0
|
|
10133
|
+
});
|
|
10134
|
+
const dateData = dateMap.get(date);
|
|
10135
|
+
dateData[stat.platform] += stat.parseCount;
|
|
10136
|
+
}
|
|
10137
|
+
for (const [date, platforms] of dateMap.entries()) {
|
|
10138
|
+
const totalParses = platforms.douyin + platforms.bilibili + platforms.kuaishou + platforms.xiaohongshu;
|
|
10139
|
+
await this.runQuery("INSERT OR IGNORE INTO ParseHistory (date, totalParses, douyin, bilibili, kuaishou, xiaohongshu, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?)", [
|
|
10140
|
+
date,
|
|
10141
|
+
totalParses,
|
|
10142
|
+
platforms.douyin,
|
|
10143
|
+
platforms.bilibili,
|
|
10144
|
+
platforms.kuaishou,
|
|
10145
|
+
platforms.xiaohongshu,
|
|
10146
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
10147
|
+
]);
|
|
10148
|
+
}
|
|
10149
|
+
logger.info(`[StatisticsDB] 已同步 ${dateMap.size} 天的历史数据`);
|
|
10150
|
+
} catch (error) {
|
|
10151
|
+
logger.error("[StatisticsDB] 同步历史数据失败:", error);
|
|
10152
|
+
}
|
|
10153
|
+
}
|
|
10154
|
+
async getGroupStatistics(groupId) {
|
|
10155
|
+
return await this.allQuery("SELECT * FROM ParseStatistics WHERE groupId = ? ORDER BY platform, userId", [groupId]);
|
|
10156
|
+
}
|
|
10157
|
+
async getGroupUniqueUsers(groupId) {
|
|
10158
|
+
return (await this.getQuery("SELECT COUNT(DISTINCT userId) as count FROM ParseStatistics WHERE groupId = ?", [groupId]))?.count || 0;
|
|
10159
|
+
}
|
|
10160
|
+
async getTotalUniqueUsers() {
|
|
10161
|
+
return (await this.getQuery("SELECT COUNT(DISTINCT userId) as count FROM ParseStatistics"))?.count || 0;
|
|
10162
|
+
}
|
|
10163
|
+
async getAllStatistics() {
|
|
10164
|
+
return await this.allQuery("SELECT * FROM ParseStatistics ORDER BY groupId, platform");
|
|
10165
|
+
}
|
|
10166
|
+
async getPlatformTotalParses(platform$1) {
|
|
10167
|
+
return (await this.getQuery("SELECT SUM(parseCount) as total FROM ParseStatistics WHERE platform = ?", [platform$1]))?.total || 0;
|
|
10168
|
+
}
|
|
10169
|
+
async getTotalGroups() {
|
|
10170
|
+
return (await this.getQuery("SELECT COUNT(DISTINCT groupId) as count FROM ParseStatistics"))?.count || 0;
|
|
10171
|
+
}
|
|
10172
|
+
async getTotalParses() {
|
|
10173
|
+
const result = await this.getQuery("SELECT value FROM GlobalStatistics WHERE key = ?", ["totalParses"]);
|
|
10174
|
+
return parseInt(result?.value || "0", 10);
|
|
10175
|
+
}
|
|
10176
|
+
async incrementTotalGroups() {
|
|
10177
|
+
const totalGroups = await this.getTotalGroups();
|
|
10178
|
+
await this.runQuery("UPDATE GlobalStatistics SET value = ?, updatedAt = ? WHERE key = ?", [
|
|
10179
|
+
totalGroups.toString(),
|
|
10180
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
10181
|
+
"totalGroups"
|
|
10182
|
+
]);
|
|
10183
|
+
}
|
|
10184
|
+
async incrementTotalParses() {
|
|
10185
|
+
await this.runQuery("UPDATE GlobalStatistics SET value = value + 1, updatedAt = ? WHERE key = ?", [(/* @__PURE__ */ new Date()).toISOString(), "totalParses"]);
|
|
10186
|
+
}
|
|
10187
|
+
async getGlobalSummary() {
|
|
10188
|
+
return {
|
|
10189
|
+
totalGroups: await this.getTotalGroups(),
|
|
10190
|
+
totalParses: await this.getTotalParses(),
|
|
10191
|
+
platformStats: {
|
|
10192
|
+
douyin: await this.getPlatformTotalParses("douyin"),
|
|
10193
|
+
bilibili: await this.getPlatformTotalParses("bilibili"),
|
|
10194
|
+
kuaishou: await this.getPlatformTotalParses("kuaishou"),
|
|
10195
|
+
xiaohongshu: await this.getPlatformTotalParses("xiaohongshu")
|
|
10196
|
+
}
|
|
10197
|
+
};
|
|
10198
|
+
}
|
|
10199
|
+
};
|
|
10200
|
+
});
|
|
9888
10201
|
var db_exports = __export({
|
|
9889
10202
|
BilibiliDBBase: () => BilibiliDBBase,
|
|
9890
10203
|
DouyinDBBase: () => DouyinDBBase,
|
|
10204
|
+
StatisticsDBBase: () => StatisticsDBBase,
|
|
9891
10205
|
bilibiliDB: () => bilibiliDBInstance,
|
|
9892
10206
|
bilibiliDBInstance: () => bilibiliDBInstance,
|
|
9893
10207
|
cleanOldDynamicCache: () => cleanOldDynamicCache,
|
|
@@ -9895,18 +10209,25 @@ var db_exports = __export({
|
|
|
9895
10209
|
douyinDBInstance: () => douyinDBInstance,
|
|
9896
10210
|
getBilibiliDB: () => getBilibiliDB,
|
|
9897
10211
|
getDouyinDB: () => getDouyinDB,
|
|
9898
|
-
|
|
10212
|
+
getStatisticsDB: () => getStatisticsDB,
|
|
10213
|
+
initAllDatabases: () => initAllDatabases$1,
|
|
10214
|
+
statisticsDB: () => statisticsDBInstance,
|
|
10215
|
+
statisticsDBInstance: () => statisticsDBInstance
|
|
9899
10216
|
}, 1);
|
|
9900
|
-
var douyinDB, douyinInitializing, bilibiliDB, bilibiliInitializing, getDouyinDB, getBilibiliDB, initAllDatabases$1, douyinDBInstance, bilibiliDBInstance, cleanOldDynamicCache;
|
|
10217
|
+
var douyinDB, douyinInitializing, bilibiliDB, bilibiliInitializing, statisticsDB, statisticsInitializing, getDouyinDB, getBilibiliDB, getStatisticsDB, initAllDatabases$1, douyinDBInstance, bilibiliDBInstance, statisticsDBInstance, cleanOldDynamicCache;
|
|
9901
10218
|
var init_db = __esmMin(async () => {
|
|
9902
10219
|
await init_bilibili();
|
|
9903
10220
|
await init_douyin();
|
|
10221
|
+
await init_statistics();
|
|
9904
10222
|
init_bilibili();
|
|
9905
10223
|
init_douyin();
|
|
10224
|
+
init_statistics();
|
|
9906
10225
|
douyinDB = null;
|
|
9907
10226
|
douyinInitializing = false;
|
|
9908
10227
|
bilibiliDB = null;
|
|
9909
10228
|
bilibiliInitializing = false;
|
|
10229
|
+
statisticsDB = null;
|
|
10230
|
+
statisticsInitializing = false;
|
|
9910
10231
|
getDouyinDB = async () => {
|
|
9911
10232
|
if (douyinDB) return douyinDB;
|
|
9912
10233
|
if (douyinInitializing) {
|
|
@@ -9935,15 +10256,35 @@ var init_db = __esmMin(async () => {
|
|
|
9935
10256
|
bilibiliInitializing = false;
|
|
9936
10257
|
}
|
|
9937
10258
|
};
|
|
10259
|
+
getStatisticsDB = async () => {
|
|
10260
|
+
if (statisticsDB) return statisticsDB;
|
|
10261
|
+
if (statisticsInitializing) {
|
|
10262
|
+
await new Promise((resolve$1) => setTimeout(resolve$1, 100));
|
|
10263
|
+
return statisticsDB;
|
|
10264
|
+
}
|
|
10265
|
+
statisticsInitializing = true;
|
|
10266
|
+
try {
|
|
10267
|
+
statisticsDB = await new StatisticsDBBase().init();
|
|
10268
|
+
return statisticsDB;
|
|
10269
|
+
} finally {
|
|
10270
|
+
statisticsInitializing = false;
|
|
10271
|
+
}
|
|
10272
|
+
};
|
|
9938
10273
|
initAllDatabases$1 = async () => {
|
|
9939
|
-
const [douyin$2, bilibili$2] = await Promise.all([
|
|
10274
|
+
const [douyin$2, bilibili$2, statistics] = await Promise.all([
|
|
10275
|
+
getDouyinDB(),
|
|
10276
|
+
getBilibiliDB(),
|
|
10277
|
+
getStatisticsDB()
|
|
10278
|
+
]);
|
|
9940
10279
|
return {
|
|
9941
10280
|
douyinDB: douyin$2,
|
|
9942
|
-
bilibiliDB: bilibili$2
|
|
10281
|
+
bilibiliDB: bilibili$2,
|
|
10282
|
+
statisticsDB: statistics
|
|
9943
10283
|
};
|
|
9944
10284
|
};
|
|
9945
10285
|
douyinDBInstance = await getDouyinDB();
|
|
9946
10286
|
bilibiliDBInstance = await getBilibiliDB();
|
|
10287
|
+
statisticsDBInstance = await getStatisticsDB();
|
|
9947
10288
|
cleanOldDynamicCache = async (platform$1, days = 7) => {
|
|
9948
10289
|
if (platform$1 === "douyin") return await (await getDouyinDB()).cleanOldAwemeCache(days);
|
|
9949
10290
|
else return await (await getBilibiliDB()).cleanOldDynamicCache(days);
|
|
@@ -17441,6 +17782,7 @@ var Bilibilipush = class extends Base {
|
|
|
17441
17782
|
const imgArray = [];
|
|
17442
17783
|
const title = data$1[dynamicId].Dynamic_Data.modules.module_dynamic.major?.opus?.title || "bilibili_dynamic";
|
|
17443
17784
|
const images = data$1[dynamicId].Dynamic_Data.modules.module_dynamic.major && data$1[dynamicId].Dynamic_Data.modules.module_dynamic?.major?.draw?.items || data$1[dynamicId].Dynamic_Data.modules.module_dynamic?.major?.opus.pics;
|
|
17785
|
+
if (images.length === 0) break;
|
|
17444
17786
|
for (const [index, img2] of images.entries()) {
|
|
17445
17787
|
const imageUrl = await processImageUrl(img2.src ?? img2.url, title, index);
|
|
17446
17788
|
imgArray.push(segment.image(imageUrl));
|
|
@@ -18241,7 +18583,7 @@ var DouYin = class extends Base {
|
|
|
18241
18583
|
gender: userProfile.data.user.gender ?? 0,
|
|
18242
18584
|
user_age: userProfile.data.user.user_age ?? 0
|
|
18243
18585
|
} : void 0,
|
|
18244
|
-
image_url: isArticle ? VideoData.data.aweme_detail.video.origin_cover.url_list[0] : this.is_mp4 ? VideoData.data.aweme_detail.video.animated_cover?.url_list[0] ?? VideoData.data.aweme_detail.video.cover_original_scale?.url_list[0] ?? VideoData.data.aweme_detail.video.cover.url_list[0] : VideoData.data.aweme_detail.images[0].url_list[0],
|
|
18586
|
+
image_url: isArticle ? VideoData.data.aweme_detail.video.origin_cover.url_list[0] : this.is_mp4 ? VideoData.data.aweme_detail.video.animated_cover?.url_list[0] ?? VideoData.data.aweme_detail.video.dynamic_cover?.url_list[0] ?? VideoData.data.aweme_detail.video.cover_original_scale?.url_list[0] ?? VideoData.data.aweme_detail.video.cover.url_list[0] : VideoData.data.aweme_detail.images[0].url_list[0],
|
|
18245
18587
|
cover_size: isArticle ? VideoData.data.aweme_detail.video.origin_cover ? {
|
|
18246
18588
|
width: VideoData.data.aweme_detail.video.origin_cover.width,
|
|
18247
18589
|
height: VideoData.data.aweme_detail.video.origin_cover.height
|
|
@@ -20138,7 +20480,7 @@ var waitQrcode = async (page) => {
|
|
|
20138
20480
|
const response = await fetch(originalImage);
|
|
20139
20481
|
imageBuffer = Buffer.from(await response.arrayBuffer());
|
|
20140
20482
|
}
|
|
20141
|
-
const qrContent = QRCodeScanner.scanFromBuffer(imageBuffer);
|
|
20483
|
+
const qrContent = await QRCodeScanner.scanFromBuffer(imageBuffer);
|
|
20142
20484
|
if (qrContent) {
|
|
20143
20485
|
logger.mark("二维码解码成功:", qrContent);
|
|
20144
20486
|
return {
|
|
@@ -20209,24 +20551,39 @@ await init_Config();
|
|
|
20209
20551
|
var HELP_MENU_CONFIG = [
|
|
20210
20552
|
{
|
|
20211
20553
|
title: "常用功能",
|
|
20212
|
-
items: [
|
|
20213
|
-
|
|
20214
|
-
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
|
|
20218
|
-
|
|
20219
|
-
|
|
20220
|
-
|
|
20221
|
-
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20229
|
-
|
|
20554
|
+
items: [
|
|
20555
|
+
{
|
|
20556
|
+
title: "自动识别分享链接进行解析",
|
|
20557
|
+
description: (() => {
|
|
20558
|
+
const platforms = [];
|
|
20559
|
+
if (Config.douyin?.switch) platforms.push("抖音");
|
|
20560
|
+
if (Config.bilibili?.switch) platforms.push("哔哩哔哩");
|
|
20561
|
+
if (Config.kuaishou?.switch) platforms.push("快手");
|
|
20562
|
+
if (Config.xiaohongshu?.switch) platforms.push("小红书");
|
|
20563
|
+
return platforms.length > 0 ? `支持「${platforms.join("」「")}」` : "暂无可用平台";
|
|
20564
|
+
})(),
|
|
20565
|
+
icon: "Link",
|
|
20566
|
+
roles: ["member", "master"]
|
|
20567
|
+
},
|
|
20568
|
+
{
|
|
20569
|
+
title: "「#解析」「#kkk解析」「#弹幕解析」",
|
|
20570
|
+
description: "在解析功能关闭的情况下,可对引用消息进行解析;弹幕解析仅使用于「抖音」「哔哩哔哩」",
|
|
20571
|
+
icon: "Sparkles",
|
|
20572
|
+
roles: ["member", "master"]
|
|
20573
|
+
},
|
|
20574
|
+
{
|
|
20575
|
+
title: "#kkk解析统计",
|
|
20576
|
+
description: "查看当前群组的解析统计数据,包括各平台解析次数、使用用户数等",
|
|
20577
|
+
icon: "BarChart",
|
|
20578
|
+
roles: ["member", "master"]
|
|
20579
|
+
},
|
|
20580
|
+
{
|
|
20581
|
+
title: "#kkk全局解析统计",
|
|
20582
|
+
description: "查看全局解析统计数据,包括所有群组的解析情况、趋势分析和群组排行",
|
|
20583
|
+
icon: "TrendingUp",
|
|
20584
|
+
roles: ["master"]
|
|
20585
|
+
}
|
|
20586
|
+
]
|
|
20230
20587
|
},
|
|
20231
20588
|
{
|
|
20232
20589
|
title: "推送相关",
|
|
@@ -20664,6 +21021,86 @@ const qrLogin = karin$1.command(/^#?(kkk)?登录$/i, async (e) => {
|
|
|
20664
21021
|
perm: "master",
|
|
20665
21022
|
name: "kkk-APP扫码登录"
|
|
20666
21023
|
});
|
|
21024
|
+
await init_module();
|
|
21025
|
+
await init_db();
|
|
21026
|
+
const groupStatistics = karin$1.command(/^#?kkk解析统计$/, async (e) => {
|
|
21027
|
+
try {
|
|
21028
|
+
const groupId = e.isGroup ? e.contact?.peer || "" : "";
|
|
21029
|
+
if (!groupId) {
|
|
21030
|
+
await e.reply("此命令仅支持在群聊中使用");
|
|
21031
|
+
return true;
|
|
21032
|
+
}
|
|
21033
|
+
let groupName = "";
|
|
21034
|
+
let groupMemberCount;
|
|
21035
|
+
let groupAvatar;
|
|
21036
|
+
try {
|
|
21037
|
+
const groupInfo = await e.bot.getGroupInfo(groupId);
|
|
21038
|
+
groupName = groupInfo?.groupName || "";
|
|
21039
|
+
groupMemberCount = groupInfo?.memberCount;
|
|
21040
|
+
groupAvatar = groupInfo?.avatar;
|
|
21041
|
+
} catch (error) {
|
|
21042
|
+
logger.debug("[统计] 获取群组信息失败:", error);
|
|
21043
|
+
}
|
|
21044
|
+
const statisticsDB$1 = await getStatisticsDB();
|
|
21045
|
+
const groupStats = await statisticsDB$1.getGroupStatistics(groupId);
|
|
21046
|
+
const groupUniqueUsers = await statisticsDB$1.getGroupUniqueUsers(groupId);
|
|
21047
|
+
const globalSummary = await statisticsDB$1.getGlobalSummary();
|
|
21048
|
+
const groupTotalParses = groupStats.reduce((sum, stat) => sum + stat.parseCount, 0);
|
|
21049
|
+
const platformData = {
|
|
21050
|
+
douyin: groupStats.filter((s) => s.platform === "douyin").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21051
|
+
bilibili: groupStats.filter((s) => s.platform === "bilibili").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21052
|
+
kuaishou: groupStats.filter((s) => s.platform === "kuaishou").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21053
|
+
xiaohongshu: groupStats.filter((s) => s.platform === "xiaohongshu").reduce((sum, s) => sum + s.parseCount, 0)
|
|
21054
|
+
};
|
|
21055
|
+
const img$2 = await Render("statistics/group", {
|
|
21056
|
+
groupId,
|
|
21057
|
+
groupName,
|
|
21058
|
+
groupMemberCount,
|
|
21059
|
+
groupAvatar,
|
|
21060
|
+
groupTotalParses,
|
|
21061
|
+
groupUniqueUsers,
|
|
21062
|
+
platformData,
|
|
21063
|
+
globalTotalGroups: globalSummary.totalGroups,
|
|
21064
|
+
globalTotalParses: globalSummary.totalParses
|
|
21065
|
+
});
|
|
21066
|
+
await e.reply(img$2);
|
|
21067
|
+
return true;
|
|
21068
|
+
} catch (error) {
|
|
21069
|
+
await e.reply(`获取解析统计失败:${error}`);
|
|
21070
|
+
return true;
|
|
21071
|
+
}
|
|
21072
|
+
}, { name: "kkk-解析统计" });
|
|
21073
|
+
const globalStatistics = karin$1.command(/^#?kkk全局解析统计$/, async (e) => {
|
|
21074
|
+
try {
|
|
21075
|
+
const statisticsDB$1 = await getStatisticsDB();
|
|
21076
|
+
const allStats = await statisticsDB$1.getAllStatistics();
|
|
21077
|
+
const historyData = await statisticsDB$1.getRecentHistory(30);
|
|
21078
|
+
const groupIds = [...new Set(allStats.map((s) => s.groupId))];
|
|
21079
|
+
const groupInfoMap = /* @__PURE__ */ new Map();
|
|
21080
|
+
for (const groupId of groupIds) try {
|
|
21081
|
+
const groupInfo = await e.bot.getGroupInfo(groupId);
|
|
21082
|
+
groupInfoMap.set(groupId, {
|
|
21083
|
+
groupName: groupInfo?.groupName,
|
|
21084
|
+
groupAvatar: groupInfo?.avatar
|
|
21085
|
+
});
|
|
21086
|
+
} catch (error) {
|
|
21087
|
+
logger.debug(`[统计] 获取群组 ${groupId} 信息失败:`, error);
|
|
21088
|
+
}
|
|
21089
|
+
const img$2 = await Render("statistics/global", {
|
|
21090
|
+
allStats,
|
|
21091
|
+
historyData: historyData.reverse(),
|
|
21092
|
+
groupInfoMap: Object.fromEntries(groupInfoMap)
|
|
21093
|
+
});
|
|
21094
|
+
await e.reply(img$2);
|
|
21095
|
+
return true;
|
|
21096
|
+
} catch (error) {
|
|
21097
|
+
await e.reply(`获取全局解析统计失败:${error}`);
|
|
21098
|
+
return true;
|
|
21099
|
+
}
|
|
21100
|
+
}, {
|
|
21101
|
+
name: "kkk-全局解析统计",
|
|
21102
|
+
perm: "master"
|
|
21103
|
+
});
|
|
20667
21104
|
const getXiaohongshuID = async (url, log = true) => {
|
|
20668
21105
|
const longLink = (await axios.get(url, { headers: { "User-Agent": "Apifox/1.0.0 (https://apifox.com)" } }))?.request?.res?.responseUrl ?? url;
|
|
20669
21106
|
const normalizedLink = (() => {
|
|
@@ -21055,6 +21492,7 @@ var processXiaohongshuEmojis = (text, emojiData) => {
|
|
|
21055
21492
|
}).join("");
|
|
21056
21493
|
};
|
|
21057
21494
|
await init_module();
|
|
21495
|
+
await init_db();
|
|
21058
21496
|
await init_Config();
|
|
21059
21497
|
await init_ErrorHandler();
|
|
21060
21498
|
var reg = {
|
|
@@ -21074,6 +21512,13 @@ var handleDouyin = wrapWithErrorHandler(async (e) => {
|
|
|
21074
21512
|
}
|
|
21075
21513
|
const iddata = await getDouyinID(e, String(urlMatch[0]));
|
|
21076
21514
|
await new DouYin(e, iddata, { forceBurnDanmaku }).DouyinHandler(iddata);
|
|
21515
|
+
const groupId = e.isGroup ? e.contact?.peer || "" : "";
|
|
21516
|
+
const userId = e.userId || "";
|
|
21517
|
+
if (groupId && userId) try {
|
|
21518
|
+
await (await getStatisticsDB()).recordParse(groupId, userId, "douyin");
|
|
21519
|
+
} catch (error) {
|
|
21520
|
+
logger.debug("[统计] 记录抖音解析统计失败:", error);
|
|
21521
|
+
}
|
|
21077
21522
|
return true;
|
|
21078
21523
|
}, { businessName: "抖音视频解析" });
|
|
21079
21524
|
var handleBilibili = wrapWithErrorHandler(async (e) => {
|
|
@@ -21093,6 +21538,13 @@ var handleBilibili = wrapWithErrorHandler(async (e) => {
|
|
|
21093
21538
|
}
|
|
21094
21539
|
const iddata = await getBilibiliID(url);
|
|
21095
21540
|
await new Bilibili(e, iddata, { forceBurnDanmaku }).BilibiliHandler(iddata);
|
|
21541
|
+
const groupId = e.isGroup ? e.contact?.peer || "" : "";
|
|
21542
|
+
const userId = e.userId || "";
|
|
21543
|
+
if (groupId && userId) try {
|
|
21544
|
+
await (await getStatisticsDB()).recordParse(groupId, userId, "bilibili");
|
|
21545
|
+
} catch (error) {
|
|
21546
|
+
logger.debug("[统计] 记录B站解析统计失败:", error);
|
|
21547
|
+
}
|
|
21096
21548
|
return true;
|
|
21097
21549
|
}, { businessName: "B站视频解析" });
|
|
21098
21550
|
var handleKuaishou = wrapWithErrorHandler(async (e) => {
|
|
@@ -21100,6 +21552,13 @@ var handleKuaishou = wrapWithErrorHandler(async (e) => {
|
|
|
21100
21552
|
const iddata = await getKuaishouID(String(kuaishouUrl));
|
|
21101
21553
|
const WorkData = await fetchKuaishouData(iddata.type, iddata);
|
|
21102
21554
|
await new Kuaishou(e, iddata).KuaishouHandler(WorkData);
|
|
21555
|
+
const groupId = e.isGroup ? e.contact?.peer || "" : "";
|
|
21556
|
+
const userId = e.userId || "";
|
|
21557
|
+
if (groupId && userId) try {
|
|
21558
|
+
await (await getStatisticsDB()).recordParse(groupId, userId, "kuaishou");
|
|
21559
|
+
} catch (error) {
|
|
21560
|
+
logger.debug("[统计] 记录快手解析统计失败:", error);
|
|
21561
|
+
}
|
|
21103
21562
|
}, { businessName: "快手视频解析" });
|
|
21104
21563
|
var handleXiaohongshu = wrapWithErrorHandler(async (e) => {
|
|
21105
21564
|
const url = e.msg.replaceAll("\\", "").match(/https?:\/\/[^\s"'<>]+/)?.[0];
|
|
@@ -21109,6 +21568,13 @@ var handleXiaohongshu = wrapWithErrorHandler(async (e) => {
|
|
|
21109
21568
|
}
|
|
21110
21569
|
const iddata = await getXiaohongshuID(url);
|
|
21111
21570
|
await new Xiaohongshu(e, iddata).XiaohongshuHandler(iddata);
|
|
21571
|
+
const groupId = e.isGroup ? e.contact?.peer || "" : "";
|
|
21572
|
+
const userId = e.userId || "";
|
|
21573
|
+
if (groupId && userId) try {
|
|
21574
|
+
await (await getStatisticsDB()).recordParse(groupId, userId, "xiaohongshu");
|
|
21575
|
+
} catch (error) {
|
|
21576
|
+
logger.debug("[统计] 记录小红书解析统计失败:", error);
|
|
21577
|
+
}
|
|
21112
21578
|
return true;
|
|
21113
21579
|
}, { businessName: "小红书视频解析" });
|
|
21114
21580
|
var handlePrefix = wrapWithErrorHandler(async (e, next) => {
|
|
@@ -21353,4 +21819,4 @@ const update = karin$1.task("kkk-更新检测", "*/5 * * * *", Handler, {
|
|
|
21353
21819
|
name: "kkk-更新检测",
|
|
21354
21820
|
log: false
|
|
21355
21821
|
});
|
|
21356
|
-
export {
|
|
21822
|
+
export { init_root as A, biLogin as C, webConfig as D, task as E, web_config_default as O, version as S, removeOldFiles as T, forcePush as _, douyinAPP as a, testDouyinPush as b, xiaohongshuAPP as c, qrLogin as d, bilibiliPush as f, douyinPushList as g, douyinPush as h, bilibiliAPP as i, Root as k, globalStatistics as l, changeBotID as m, kkkUpdateCommand as n, kuaishouAPP as o, bilibiliPushList as p, update as r, prefix as s, kkkUpdate as t, groupStatistics as u, setbiliPush as v, dylogin as w, help as x, setdyPush as y };
|