koishi-plugin-best-cave 1.2.0 → 1.3.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/lib/index.d.ts +7 -30
- package/lib/index.js +1045 -427
- package/lib/utils/HashStorage.d.ts +95 -0
- package/lib/utils/ImageHasher.d.ts +81 -0
- package/lib/utils/fileHandler.d.ts +63 -0
- package/lib/utils/idManager.d.ts +69 -0
- package/package.json +8 -2
- package/readme.md +29 -8
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 哈希存储状态信息
|
|
3
|
+
*/
|
|
4
|
+
interface HashStatus {
|
|
5
|
+
/** 最后更新时间戳 */
|
|
6
|
+
lastUpdated: string;
|
|
7
|
+
/** 所有回声洞的哈希值条目 */
|
|
8
|
+
entries: Array<{
|
|
9
|
+
caveId: number;
|
|
10
|
+
hashes: string[];
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 图片哈希值存储管理类
|
|
15
|
+
* 负责管理和维护回声洞图片的哈希值
|
|
16
|
+
*/
|
|
17
|
+
export declare class HashStorage {
|
|
18
|
+
private readonly caveDir;
|
|
19
|
+
private static readonly HASH_FILE;
|
|
20
|
+
private static readonly CAVE_FILE;
|
|
21
|
+
private static readonly BATCH_SIZE;
|
|
22
|
+
private hashes;
|
|
23
|
+
private initialized;
|
|
24
|
+
/**
|
|
25
|
+
* 初始化HashStorage实例
|
|
26
|
+
* @param caveDir 回声洞数据目录路径
|
|
27
|
+
*/
|
|
28
|
+
constructor(caveDir: string);
|
|
29
|
+
private get filePath();
|
|
30
|
+
private get resourceDir();
|
|
31
|
+
private get caveFilePath();
|
|
32
|
+
/**
|
|
33
|
+
* 初始化哈希存储
|
|
34
|
+
* 读取现有哈希数据或重新构建哈希值
|
|
35
|
+
* @throws 初始化失败时抛出错误
|
|
36
|
+
*/
|
|
37
|
+
initialize(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* 获取当前哈希存储状态
|
|
40
|
+
* @returns 包含最后更新时间和所有条目的状态对象
|
|
41
|
+
*/
|
|
42
|
+
getStatus(): Promise<HashStatus>;
|
|
43
|
+
/**
|
|
44
|
+
* 更新指定回声洞的图片哈希值
|
|
45
|
+
* @param caveId 回声洞ID
|
|
46
|
+
* @param imgBuffers 图片buffer数组
|
|
47
|
+
*/
|
|
48
|
+
updateCaveHash(caveId: number, imgBuffers?: Buffer[]): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* 更新所有回声洞的哈希值
|
|
51
|
+
* @param isInitialBuild 是否为初始构建
|
|
52
|
+
*/
|
|
53
|
+
updateAllCaves(isInitialBuild?: boolean): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* 查找重复的图片
|
|
56
|
+
* @param imgBuffers 待查找的图片buffer数组
|
|
57
|
+
* @param threshold 相似度阈值
|
|
58
|
+
* @returns 匹配结果数组,包含索引、回声洞ID和相似度
|
|
59
|
+
*/
|
|
60
|
+
findDuplicates(imgBuffers: Buffer[], threshold: number): Promise<Array<{
|
|
61
|
+
index: number;
|
|
62
|
+
caveId: number;
|
|
63
|
+
similarity: number;
|
|
64
|
+
} | null>>;
|
|
65
|
+
/**
|
|
66
|
+
* 加载回声洞数据
|
|
67
|
+
* @returns 回声洞数据数组
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
private loadCaveData;
|
|
71
|
+
/**
|
|
72
|
+
* 保存哈希数据到文件
|
|
73
|
+
* @private
|
|
74
|
+
*/
|
|
75
|
+
private saveHashes;
|
|
76
|
+
/**
|
|
77
|
+
* 构建初始哈希数据
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
private buildInitialHashes;
|
|
81
|
+
/**
|
|
82
|
+
* 更新缺失的哈希值
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
private updateMissingHashes;
|
|
86
|
+
/**
|
|
87
|
+
* 批量处理数组项
|
|
88
|
+
* @param items 待处理项数组
|
|
89
|
+
* @param processor 处理函数
|
|
90
|
+
* @param batchSize 批处理大小
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
private processBatch;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
/**
|
|
3
|
+
* 图片哈希计算工具类
|
|
4
|
+
* 使用 DCT(离散余弦变换)方法计算图片的感知哈希值,可用于图片相似度比较
|
|
5
|
+
*/
|
|
6
|
+
export declare class ImageHasher {
|
|
7
|
+
/**
|
|
8
|
+
* 计算图片的感知哈希值
|
|
9
|
+
* @param imageBuffer - 图片的二进制数据
|
|
10
|
+
* @returns 返回64位的十六进制哈希字符串
|
|
11
|
+
* @throws 当图片处理失败时可能抛出错误
|
|
12
|
+
*/
|
|
13
|
+
static calculateHash(imageBuffer: Buffer): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* 将二进制字符串转换为十六进制
|
|
16
|
+
* @param binary - 二进制字符串
|
|
17
|
+
* @returns 十六进制字符串
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
private static binaryToHex;
|
|
21
|
+
/**
|
|
22
|
+
* 将十六进制字符串转换为二进制
|
|
23
|
+
* @param hex - 十六进制字符串
|
|
24
|
+
* @returns 二进制字符串
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
private static hexToBinary;
|
|
28
|
+
/**
|
|
29
|
+
* 计算图像的DCT(离散余弦变换)
|
|
30
|
+
* @param data - 图像数据
|
|
31
|
+
* @param size - 图像尺寸
|
|
32
|
+
* @returns DCT变换后的矩阵
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
private static computeDCT;
|
|
36
|
+
/**
|
|
37
|
+
* 获取DCT系数
|
|
38
|
+
* @param index - 索引值
|
|
39
|
+
* @param size - 矩阵大小
|
|
40
|
+
* @returns DCT系数
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
private static getDCTCoefficient;
|
|
44
|
+
/**
|
|
45
|
+
* 计算数组的中位数
|
|
46
|
+
* @param arr - 输入数组
|
|
47
|
+
* @returns 中位数
|
|
48
|
+
* @private
|
|
49
|
+
*/
|
|
50
|
+
private static calculateMedian;
|
|
51
|
+
/**
|
|
52
|
+
* 从DCT矩阵中提取特征值
|
|
53
|
+
* @param matrix - DCT矩阵
|
|
54
|
+
* @param size - 矩阵大小
|
|
55
|
+
* @returns 特征值数组
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
private static extractFeatures;
|
|
59
|
+
/**
|
|
60
|
+
* 计算两个哈希值之间的汉明距离
|
|
61
|
+
* @param hash1 - 第一个哈希值
|
|
62
|
+
* @param hash2 - 第二个哈希值
|
|
63
|
+
* @returns 汉明距离
|
|
64
|
+
* @throws 当两个哈希值长度不等时抛出错误
|
|
65
|
+
*/
|
|
66
|
+
static calculateDistance(hash1: string, hash2: string): number;
|
|
67
|
+
/**
|
|
68
|
+
* 计算两个图片哈希值的相似度
|
|
69
|
+
* @param hash1 - 第一个哈希值
|
|
70
|
+
* @param hash2 - 第二个哈希值
|
|
71
|
+
* @returns 返回0-1之间的相似度值,1表示完全相同,0表示完全不同
|
|
72
|
+
*/
|
|
73
|
+
static calculateSimilarity(hash1: string, hash2: string): number;
|
|
74
|
+
/**
|
|
75
|
+
* 批量比较一个新哈希值与多个已存在哈希值的相似度
|
|
76
|
+
* @param newHash - 新的哈希值
|
|
77
|
+
* @param existingHashes - 已存在的哈希值数组
|
|
78
|
+
* @returns 相似度数组,每个元素对应一个已存在哈希值的相似度
|
|
79
|
+
*/
|
|
80
|
+
static batchCompareSimilarity(newHash: string, existingHashes: string[]): number[];
|
|
81
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export declare class FileHandler {
|
|
2
|
+
private static locks;
|
|
3
|
+
private static readonly RETRY_COUNT;
|
|
4
|
+
private static readonly RETRY_DELAY;
|
|
5
|
+
private static readonly CONCURRENCY_LIMIT;
|
|
6
|
+
/**
|
|
7
|
+
* 并发控制
|
|
8
|
+
* @param operation 要执行的操作
|
|
9
|
+
* @param limit 并发限制
|
|
10
|
+
* @returns 操作结果
|
|
11
|
+
*/
|
|
12
|
+
private static withConcurrencyLimit;
|
|
13
|
+
/**
|
|
14
|
+
* 文件操作包装器
|
|
15
|
+
* @param filePath 文件路径
|
|
16
|
+
* @param operation 要执行的操作
|
|
17
|
+
* @returns 操作结果
|
|
18
|
+
*/
|
|
19
|
+
private static withFileOp;
|
|
20
|
+
/**
|
|
21
|
+
* 事务处理
|
|
22
|
+
* @param operations 要执行的操作数组
|
|
23
|
+
* @returns 操作结果数组
|
|
24
|
+
*/
|
|
25
|
+
static withTransaction<T>(operations: Array<{
|
|
26
|
+
filePath: string;
|
|
27
|
+
operation: () => Promise<T>;
|
|
28
|
+
rollback?: () => Promise<void>;
|
|
29
|
+
}>): Promise<T[]>;
|
|
30
|
+
/**
|
|
31
|
+
* 读取 JSON 数据
|
|
32
|
+
* @param filePath 文件路径
|
|
33
|
+
* @returns JSON 数据
|
|
34
|
+
*/
|
|
35
|
+
static readJsonData<T>(filePath: string): Promise<T[]>;
|
|
36
|
+
/**
|
|
37
|
+
* 写入 JSON 数据
|
|
38
|
+
* @param filePath 文件路径
|
|
39
|
+
* @param data 要写入的数据
|
|
40
|
+
*/
|
|
41
|
+
static writeJsonData<T>(filePath: string, data: T[]): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* 确保目录存在
|
|
44
|
+
* @param dir 目录路径
|
|
45
|
+
*/
|
|
46
|
+
static ensureDirectory(dir: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* 确保 JSON 文件存在
|
|
49
|
+
* @param filePath 文件路径
|
|
50
|
+
*/
|
|
51
|
+
static ensureJsonFile(filePath: string): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* 保存媒体文件
|
|
54
|
+
* @param filePath 文件路径
|
|
55
|
+
* @param data 文件数据
|
|
56
|
+
*/
|
|
57
|
+
static saveMediaFile(filePath: string, data: Buffer | string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* 删除媒体文件
|
|
60
|
+
* @param filePath 文件路径
|
|
61
|
+
*/
|
|
62
|
+
static deleteMediaFile(filePath: string): Promise<void>;
|
|
63
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID管理器类
|
|
3
|
+
* 负责管理回声洞ID的分配、删除和统计信息
|
|
4
|
+
*/
|
|
5
|
+
export declare class IdManager {
|
|
6
|
+
private deletedIds;
|
|
7
|
+
private maxId;
|
|
8
|
+
private initialized;
|
|
9
|
+
private readonly statusFilePath;
|
|
10
|
+
private stats;
|
|
11
|
+
private usedIds;
|
|
12
|
+
/**
|
|
13
|
+
* 初始化ID管理器
|
|
14
|
+
* @param baseDir - 基础目录路径
|
|
15
|
+
*/
|
|
16
|
+
constructor(baseDir: string);
|
|
17
|
+
/**
|
|
18
|
+
* 初始化ID管理系统
|
|
19
|
+
* @param caveFilePath - 正式回声洞数据文件路径
|
|
20
|
+
* @param pendingFilePath - 待处理回声洞数据文件路径
|
|
21
|
+
* @throws 当初始化失败时抛出错误
|
|
22
|
+
*/
|
|
23
|
+
initialize(caveFilePath: string, pendingFilePath: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* 处理ID冲突
|
|
26
|
+
* @param conflicts - ID冲突映射表
|
|
27
|
+
* @param caveFilePath - 正式回声洞数据文件路径
|
|
28
|
+
* @param pendingFilePath - 待处理回声洞数据文件路径
|
|
29
|
+
* @param caveData - 正式回声洞数据
|
|
30
|
+
* @param pendingData - 待处理回声洞数据
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
private handleConflicts;
|
|
34
|
+
/**
|
|
35
|
+
* 获取下一个可用的ID
|
|
36
|
+
* @returns 下一个可用的ID
|
|
37
|
+
* @throws 当ID管理器未初始化时抛出错误
|
|
38
|
+
*/
|
|
39
|
+
getNextId(): number;
|
|
40
|
+
/**
|
|
41
|
+
* 标记ID为已删除状态
|
|
42
|
+
* @param id - 要标记为删除的ID
|
|
43
|
+
* @throws 当ID管理器未初始化时抛出错误
|
|
44
|
+
*/
|
|
45
|
+
markDeleted(id: number): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* 添加贡献统计
|
|
48
|
+
* @param contributorNumber - 贡献者编号
|
|
49
|
+
* @param caveId - 回声洞ID
|
|
50
|
+
*/
|
|
51
|
+
addStat(contributorNumber: string, caveId: number): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* 移除贡献统计
|
|
54
|
+
* @param contributorNumber - 贡献者编号
|
|
55
|
+
* @param caveId - 回声洞ID
|
|
56
|
+
*/
|
|
57
|
+
removeStat(contributorNumber: string, caveId: number): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* 获取所有贡献统计信息
|
|
60
|
+
* @returns 贡献者编号到回声洞ID列表的映射
|
|
61
|
+
*/
|
|
62
|
+
getStats(): Record<string, number[]>;
|
|
63
|
+
/**
|
|
64
|
+
* 保存当前状态到文件
|
|
65
|
+
* @private
|
|
66
|
+
* @throws 当保存失败时抛出错误
|
|
67
|
+
*/
|
|
68
|
+
private saveStatus;
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-best-cave",
|
|
3
3
|
"description": "最好的 cave 插件,可开关的审核系统,可引用添加,支持图文混合内容,可查阅投稿列表,完美复刻你的 .cave 体验!",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.1",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Yis_Rime <yis_rime@outlook.com>"
|
|
7
7
|
],
|
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
],
|
|
26
26
|
"devDependencies": {},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"koishi": "^4.18.3"
|
|
28
|
+
"koishi": "^4.18.3",
|
|
29
|
+
"sharp": "^0.32.6",
|
|
30
|
+
"koishi-plugin-adapter-onebot": "^6.1.3"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"sharp": "^0.32.6",
|
|
34
|
+
"koishi-plugin-adapter-onebot": "^6.1.3"
|
|
29
35
|
}
|
|
30
36
|
}
|
package/readme.md
CHANGED
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
### 核心功能
|
|
10
10
|
|
|
11
11
|
- 支持文字与图片混合保存
|
|
12
|
-
-
|
|
13
|
-
-
|
|
12
|
+
- 智能处理各类图片与视频链接
|
|
13
|
+
- 内容智能排序,保持原始布局
|
|
14
14
|
- 完整的权限管理系统
|
|
15
15
|
- 可选的内容审核流程
|
|
16
16
|
- 群组调用冷却机制
|
|
17
|
+
- 重复内容智能检测
|
|
18
|
+
- 黑白名单系统
|
|
19
|
+
- 分页显示支持
|
|
17
20
|
|
|
18
21
|
### 指令
|
|
19
22
|
|
|
@@ -23,19 +26,37 @@
|
|
|
23
26
|
| `cave -a <内容>` | 添加新回声洞(支持文字、图片与视频) | 所有人 |
|
|
24
27
|
| `cave -g <编号>` | 查看指定回声洞 | 所有人 |
|
|
25
28
|
| `cave -r <编号>` | 删除指定回声洞 | 内容贡献者/管理员 |
|
|
29
|
+
| `cave -l [页码/用户ID]` | 查看投稿统计 | 所有人(仅自己)/管理员(全部) |
|
|
26
30
|
|
|
27
31
|
#### 管理指令
|
|
28
32
|
|
|
29
33
|
| 指令 | 说明 | 权限 |
|
|
30
34
|
|------|------|------|
|
|
31
|
-
| `cave -l [用户ID]` | 查看投稿统计 | 管理员 |
|
|
32
35
|
| `cave -p <编号/all>` | 通过待审核内容 | 管理员 |
|
|
33
36
|
| `cave -d <编号/all>` | 拒绝待审核内容 | 管理员 |
|
|
34
37
|
|
|
38
|
+
### 配置项
|
|
39
|
+
|
|
40
|
+
| 配置项 | 类型 | 默认值 | 说明 |
|
|
41
|
+
|--------|------|--------|------|
|
|
42
|
+
| manager | string[] | [] | 管理员用户ID列表 |
|
|
43
|
+
| number | number | 60 | 冷却时间(秒) |
|
|
44
|
+
| enableAudit | boolean | false | 是否启用审核 |
|
|
45
|
+
| imageMaxSize | number | 4 | 图片大小限制(MB) |
|
|
46
|
+
| duplicateThreshold | number | 0.8 | 图片查重阈值(0-1) |
|
|
47
|
+
| allowVideo | boolean | true | 是否允许视频 |
|
|
48
|
+
| videoMaxSize | number | 16 | 视频大小限制(MB) |
|
|
49
|
+
| enablePagination | boolean | false | 是否启用分页 |
|
|
50
|
+
| itemsPerPage | number | 10 | 每页显示条数 |
|
|
51
|
+
| blacklist | string[] | [] | 黑名单用户/群组ID |
|
|
52
|
+
| whitelist | string[] | [] | 白名单用户/群组ID |
|
|
53
|
+
|
|
35
54
|
### 注意事项
|
|
36
55
|
|
|
37
|
-
1.
|
|
38
|
-
2.
|
|
39
|
-
3.
|
|
40
|
-
4.
|
|
41
|
-
5.
|
|
56
|
+
1. 图片和视频会自动保存到本地,请确保存储空间充足
|
|
57
|
+
2. 管理员不受群组冷却时间限制
|
|
58
|
+
3. 开启审核模式后,白名单内的用户可直接投稿
|
|
59
|
+
4. 引用消息添加时会保留原消息的格式与布局
|
|
60
|
+
5. 支持自动检测重复图片内容,可通过阈值调整严格程度
|
|
61
|
+
6. 黑名单中的用户无法使用任何功能
|
|
62
|
+
7. 支持按页码查看投稿统计,提升大量数据的浏览体验
|