karin-plugin-kkk 2.19.1 → 2.20.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 +31 -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/tools.js +3 -3
- package/lib/apps/update.js +3 -3
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/{main-BZ80CSSD.js → main-C6bm6hYZ.js} +311 -20
- package/lib/core_chunk/{template-BjkVe9U9.js → template-CQ-u6h09.js} +4 -4
- package/lib/core_chunk/template.js +2 -2
- package/lib/core_chunk/{vendor-BsdYKPEs.js → vendor-B3KhGHI_.js} +128588 -130210
- package/lib/index.js +3 -3
- package/lib/root.js +1 -1
- package/lib/web.config.js +3 -3
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [2.20.1](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.20.0...v2.20.1) (2026-02-23)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 🐛 错误修复
|
|
9
|
+
|
|
10
|
+
* 抖音图集解析中,图片类型识别错误 ([3a1d57d](https://github.com/ikenxuan/karin-plugin-kkk/commit/3a1d57d7e7f7c68ed3cdae813d0a83b5bfc4fbb9))
|
|
11
|
+
* 获取封面图空指针错误 ([d8434c7](https://github.com/ikenxuan/karin-plugin-kkk/commit/d8434c746ee11671656bda17ddb754d2aa2a6422))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### ✨ 细节优化
|
|
15
|
+
|
|
16
|
+
* 兼容性提高 ([3ea0cf7](https://github.com/ikenxuan/karin-plugin-kkk/commit/3ea0cf7706bdef6a3d3ef0e121c0991782162728))
|
|
17
|
+
|
|
18
|
+
## [2.20.0](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.19.1...v2.20.0) (2026-02-23)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### ✨ 新功能
|
|
22
|
+
|
|
23
|
+
* **core:** 引用解析支持识别图片中的二维码进行解析 ([82e7878](https://github.com/ikenxuan/karin-plugin-kkk/commit/82e78788a53332b605a5fc5280d824eefc81b0f2))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### 💄 UI 优化
|
|
27
|
+
|
|
28
|
+
* **douyin:** 视频信息的字体优化 ([3d39d6c](https://github.com/ikenxuan/karin-plugin-kkk/commit/3d39d6c86dd7ced63d948e08e8ff3b6c8165bd3e))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### ✨ 细节优化
|
|
32
|
+
|
|
33
|
+
* 提高二维码识别兼容性 ([28ead9d](https://github.com/ikenxuan/karin-plugin-kkk/commit/28ead9da322af913e0defa1ac0f7118f44e9edb1))
|
|
34
|
+
* 细优 ([1f45d0b](https://github.com/ikenxuan/karin-plugin-kkk/commit/1f45d0b81c9dfd906e1be227ddbe799ec26377e4))
|
|
35
|
+
|
|
5
36
|
## [2.19.1](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.19.0...v2.19.1) (2026-02-21)
|
|
6
37
|
|
|
7
38
|
|
package/lib/apps/admin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { C as removeAllFiles, E as task, S as dylogin, T as setdyck, w as setbilick, x as biLogin } from "../core_chunk/main-
|
|
3
|
-
import "../core_chunk/vendor-
|
|
4
|
-
import "../core_chunk/template-
|
|
2
|
+
import { C as removeAllFiles, E as task, S as dylogin, T as setdyck, w as setbilick, x as biLogin } from "../core_chunk/main-C6bm6hYZ.js";
|
|
3
|
+
import "../core_chunk/vendor-B3KhGHI_.js";
|
|
4
|
+
import "../core_chunk/template-CQ-u6h09.js";
|
|
5
5
|
export { biLogin, dylogin, removeAllFiles, setbilick, setdyck, task };
|
package/lib/apps/help.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { b as version, y as help } from "../core_chunk/main-
|
|
3
|
-
import "../core_chunk/vendor-
|
|
4
|
-
import "../core_chunk/template-
|
|
2
|
+
import { b as version, y as help } from "../core_chunk/main-C6bm6hYZ.js";
|
|
3
|
+
import "../core_chunk/vendor-B3KhGHI_.js";
|
|
4
|
+
import "../core_chunk/template-CQ-u6h09.js";
|
|
5
5
|
export { help, version };
|
package/lib/apps/push.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { _ as setdyPush, d as bilibiliPushList, f as changeBotID, g as setbiliPush, h as forcePush, m as douyinPushList, p as douyinPush, u as bilibiliPush, v as testDouyinPush } from "../core_chunk/main-
|
|
3
|
-
import "../core_chunk/vendor-
|
|
4
|
-
import "../core_chunk/template-
|
|
2
|
+
import { _ as setdyPush, d as bilibiliPushList, f as changeBotID, g as setbiliPush, h as forcePush, m as douyinPushList, p as douyinPush, u as bilibiliPush, v as testDouyinPush } from "../core_chunk/main-C6bm6hYZ.js";
|
|
3
|
+
import "../core_chunk/vendor-B3KhGHI_.js";
|
|
4
|
+
import "../core_chunk/template-CQ-u6h09.js";
|
|
5
5
|
export { bilibiliPush, bilibiliPushList, changeBotID, douyinPush, douyinPushList, forcePush, setbiliPush, setdyPush, testDouyinPush };
|
package/lib/apps/qrlogin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { l as qrLogin } from "../core_chunk/main-
|
|
3
|
-
import "../core_chunk/vendor-
|
|
4
|
-
import "../core_chunk/template-
|
|
2
|
+
import { l as qrLogin } from "../core_chunk/main-C6bm6hYZ.js";
|
|
3
|
+
import "../core_chunk/vendor-B3KhGHI_.js";
|
|
4
|
+
import "../core_chunk/template-CQ-u6h09.js";
|
|
5
5
|
export { qrLogin };
|
package/lib/apps/tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { a as douyinAPP, c as xiaohongshuAPP, i as bilibiliAPP, o as kuaishouAPP, s as prefix } from "../core_chunk/main-
|
|
3
|
-
import "../core_chunk/vendor-
|
|
4
|
-
import "../core_chunk/template-
|
|
2
|
+
import { a as douyinAPP, c as xiaohongshuAPP, i as bilibiliAPP, o as kuaishouAPP, s as prefix } from "../core_chunk/main-C6bm6hYZ.js";
|
|
3
|
+
import "../core_chunk/vendor-B3KhGHI_.js";
|
|
4
|
+
import "../core_chunk/template-CQ-u6h09.js";
|
|
5
5
|
export { bilibiliAPP, douyinAPP, kuaishouAPP, prefix, xiaohongshuAPP };
|
package/lib/apps/update.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { n as kkkUpdateCommand, r as update, t as kkkUpdate } from "../core_chunk/main-
|
|
3
|
-
import "../core_chunk/vendor-
|
|
4
|
-
import "../core_chunk/template-
|
|
2
|
+
import { n as kkkUpdateCommand, r as update, t as kkkUpdate } from "../core_chunk/main-C6bm6hYZ.js";
|
|
3
|
+
import "../core_chunk/vendor-B3KhGHI_.js";
|
|
4
|
+
import "../core_chunk/template-CQ-u6h09.js";
|
|
5
5
|
export { kkkUpdate, kkkUpdateCommand, update };
|
package/lib/build-metadata.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
3
|
-
"buildTime": "2026-02-
|
|
4
|
-
"buildTimestamp":
|
|
2
|
+
"version": "2.20.1",
|
|
3
|
+
"buildTime": "2026-02-23T16:01:34.942Z",
|
|
4
|
+
"buildTimestamp": 1771862494942,
|
|
5
5
|
"name": "karin-plugin-kkk",
|
|
6
6
|
"description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
|
|
7
7
|
"homepage": "https://github.com/ikenxuan/karin-plugin-kkk",
|
|
8
|
-
"commitHash": "
|
|
9
|
-
"shortCommitHash": "
|
|
8
|
+
"commitHash": "182d64bef47a9e02ded26f9bc17270cab8993411",
|
|
9
|
+
"shortCommitHash": "182d64be"
|
|
10
10
|
}
|
|
@@ -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 { E as zhCN, T as init_locale, _n as zod_default, a as init_lib, cn as require_protobufjs, dn as AxiosError$1, et as init_date_fns, fn as init_axios, gn as init_zod, hn as init_esm, i as require_qr_code_styling, it as differenceInSeconds, ln as Chalk, mn as Xhshow, n as require_dist, nt as formatDistanceToNow, o as Window, on as require_jsQR, pn as axios_default, r as require_lib, rt as format, sn as require_express, t as require_heic_convert, tt as fromUnixTime, un as init_source } from "./vendor-B3KhGHI_.js";
|
|
3
|
+
import { n as init_client, r as reactServerRender } from "./template-CQ-u6h09.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";
|
|
@@ -13,8 +13,9 @@ import { karinPathBase, karinPathTemp as karinPathTemp$1 } from "node-karin/root
|
|
|
13
13
|
import sqlite3 from "node-karin/sqlite3";
|
|
14
14
|
import YAML from "node-karin/yaml";
|
|
15
15
|
import util from "node:util";
|
|
16
|
-
import {
|
|
16
|
+
import { Transformer } from "@napi-rs/image";
|
|
17
17
|
import axios, { AxiosError } from "node-karin/axios";
|
|
18
|
+
import { pipeline } from "node:stream/promises";
|
|
18
19
|
import { Transform } from "node:stream";
|
|
19
20
|
import express from "node-karin/express";
|
|
20
21
|
import template from "node-karin/template";
|
|
@@ -6386,9 +6387,273 @@ var init_build_metadata = __esmMin(() => {
|
|
|
6386
6387
|
return `${date.getFullYear()}年${String(date.getMonth() + 1).padStart(2, "0")}月${String(date.getDate()).padStart(2, "0")}日 ${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
6387
6388
|
};
|
|
6388
6389
|
});
|
|
6390
|
+
var import_jsQR, QRCodeScanner;
|
|
6391
|
+
var init_QRCodeScanner = __esmMin(() => {
|
|
6392
|
+
import_jsQR = __toESM(require_jsQR(), 1);
|
|
6393
|
+
QRCodeScanner = class {
|
|
6394
|
+
static async scanFromUrl(imageUrl) {
|
|
6395
|
+
try {
|
|
6396
|
+
const response = await axios.get(imageUrl, { responseType: "arraybuffer" });
|
|
6397
|
+
const buffer = Buffer.from(response.data);
|
|
6398
|
+
return this.scanFromBuffer(buffer);
|
|
6399
|
+
} catch (error) {
|
|
6400
|
+
logger.error("识别二维码时发生错误:", error);
|
|
6401
|
+
return null;
|
|
6402
|
+
}
|
|
6403
|
+
}
|
|
6404
|
+
static extractRegion(imageData, x, y, width, height) {
|
|
6405
|
+
const newData = new Uint8ClampedArray(width * height * 4);
|
|
6406
|
+
for (let dy = 0; dy < height; dy++) for (let dx = 0; dx < width; dx++) {
|
|
6407
|
+
const srcX = x + dx;
|
|
6408
|
+
const srcY = y + dy;
|
|
6409
|
+
if (srcX >= imageData.width || srcY >= imageData.height) continue;
|
|
6410
|
+
const srcIndex = (srcY * imageData.width + srcX) * 4;
|
|
6411
|
+
const dstIndex = (dy * width + dx) * 4;
|
|
6412
|
+
newData[dstIndex] = imageData.data[srcIndex];
|
|
6413
|
+
newData[dstIndex + 1] = imageData.data[srcIndex + 1];
|
|
6414
|
+
newData[dstIndex + 2] = imageData.data[srcIndex + 2];
|
|
6415
|
+
newData[dstIndex + 3] = imageData.data[srcIndex + 3];
|
|
6416
|
+
}
|
|
6417
|
+
return {
|
|
6418
|
+
width,
|
|
6419
|
+
height,
|
|
6420
|
+
data: newData
|
|
6421
|
+
};
|
|
6422
|
+
}
|
|
6423
|
+
static enhanceContrast(imageData) {
|
|
6424
|
+
const { width, height, data: data$1 } = imageData;
|
|
6425
|
+
const newData = new Uint8ClampedArray(data$1.length);
|
|
6426
|
+
const histogram = new Array(256).fill(0);
|
|
6427
|
+
for (let i = 0; i < data$1.length; i += 4) {
|
|
6428
|
+
const gray = Math.floor(.299 * data$1[i] + .587 * data$1[i + 1] + .114 * data$1[i + 2]);
|
|
6429
|
+
histogram[gray]++;
|
|
6430
|
+
}
|
|
6431
|
+
const cdf = new Array(256).fill(0);
|
|
6432
|
+
cdf[0] = histogram[0];
|
|
6433
|
+
for (let i = 1; i < 256; i++) cdf[i] = cdf[i - 1] + histogram[i];
|
|
6434
|
+
const totalPixels = width * height;
|
|
6435
|
+
const cdfMin = cdf.find((v) => v > 0) || 0;
|
|
6436
|
+
for (let i = 0; i < data$1.length; i += 4) {
|
|
6437
|
+
const gray = Math.floor(.299 * data$1[i] + .587 * data$1[i + 1] + .114 * data$1[i + 2]);
|
|
6438
|
+
const newGray = Math.floor((cdf[gray] - cdfMin) / (totalPixels - cdfMin) * 255);
|
|
6439
|
+
newData[i] = newGray;
|
|
6440
|
+
newData[i + 1] = newGray;
|
|
6441
|
+
newData[i + 2] = newGray;
|
|
6442
|
+
newData[i + 3] = data$1[i + 3];
|
|
6443
|
+
}
|
|
6444
|
+
return {
|
|
6445
|
+
width,
|
|
6446
|
+
height,
|
|
6447
|
+
data: newData
|
|
6448
|
+
};
|
|
6449
|
+
}
|
|
6450
|
+
static tryRecognizeInRegion(imageData, regionName) {
|
|
6451
|
+
for (const strategy of [
|
|
6452
|
+
{
|
|
6453
|
+
name: "默认",
|
|
6454
|
+
enhance: false,
|
|
6455
|
+
options: void 0
|
|
6456
|
+
},
|
|
6457
|
+
{
|
|
6458
|
+
name: "增强对比度",
|
|
6459
|
+
enhance: true,
|
|
6460
|
+
options: void 0
|
|
6461
|
+
},
|
|
6462
|
+
{
|
|
6463
|
+
name: "attemptBoth",
|
|
6464
|
+
enhance: false,
|
|
6465
|
+
options: { inversionAttempts: "attemptBoth" }
|
|
6466
|
+
},
|
|
6467
|
+
{
|
|
6468
|
+
name: "增强+attemptBoth",
|
|
6469
|
+
enhance: true,
|
|
6470
|
+
options: { inversionAttempts: "attemptBoth" }
|
|
6471
|
+
}
|
|
6472
|
+
]) try {
|
|
6473
|
+
logger.debug(` 尝试策略: ${strategy.name}`);
|
|
6474
|
+
const processedData = strategy.enhance ? this.enhanceContrast(imageData) : imageData;
|
|
6475
|
+
const code = (0, import_jsQR.default)(processedData.data, processedData.width, processedData.height, strategy.options);
|
|
6476
|
+
if (code && code.data) {
|
|
6477
|
+
logger.debug(`✓ 成功识别二维码 [区域: ${regionName}] [策略: ${strategy.name}]`);
|
|
6478
|
+
logger.debug(` 二维码内容: ${code.data}`);
|
|
6479
|
+
return code.data;
|
|
6480
|
+
} else logger.debug(` 策略 ${strategy.name} 未识别到二维码`);
|
|
6481
|
+
} catch (err) {
|
|
6482
|
+
logger.debug(` 策略 ${strategy.name} 执行失败: ${err}`);
|
|
6483
|
+
}
|
|
6484
|
+
logger.debug(` 区域 ${regionName} 识别失败,尝试下一个区域`);
|
|
6485
|
+
return null;
|
|
6486
|
+
}
|
|
6487
|
+
static parseImageBuffer(buffer) {
|
|
6488
|
+
try {
|
|
6489
|
+
const transformer = new Transformer(buffer);
|
|
6490
|
+
const metadata = transformer.metadataSync();
|
|
6491
|
+
const width = metadata.width;
|
|
6492
|
+
const height = metadata.height;
|
|
6493
|
+
const rawPixels = transformer.rawPixelsSync();
|
|
6494
|
+
logger.debug(`图片解析成功: ${width}x${height}, 格式: ${metadata.format}`);
|
|
6495
|
+
logger.debug(`原始像素数据长度: ${rawPixels.length}, 预期长度(RGBA): ${width * height * 4}`);
|
|
6496
|
+
const expectedRGBA = width * height * 4;
|
|
6497
|
+
const expectedRGB = width * height * 3;
|
|
6498
|
+
if (rawPixels.length === expectedRGB) {
|
|
6499
|
+
logger.debug("检测到 RGB 格式,转换为 RGBA");
|
|
6500
|
+
const rgbaData = new Uint8ClampedArray(expectedRGBA);
|
|
6501
|
+
for (let i = 0, j = 0; i < rawPixels.length; i += 3, j += 4) {
|
|
6502
|
+
rgbaData[j] = rawPixels[i];
|
|
6503
|
+
rgbaData[j + 1] = rawPixels[i + 1];
|
|
6504
|
+
rgbaData[j + 2] = rawPixels[i + 2];
|
|
6505
|
+
rgbaData[j + 3] = 255;
|
|
6506
|
+
}
|
|
6507
|
+
return {
|
|
6508
|
+
width,
|
|
6509
|
+
height,
|
|
6510
|
+
data: rgbaData
|
|
6511
|
+
};
|
|
6512
|
+
} else if (rawPixels.length === expectedRGBA) {
|
|
6513
|
+
logger.debug("检测到 RGBA 格式");
|
|
6514
|
+
return {
|
|
6515
|
+
width,
|
|
6516
|
+
height,
|
|
6517
|
+
data: Uint8ClampedArray.from(rawPixels)
|
|
6518
|
+
};
|
|
6519
|
+
} else {
|
|
6520
|
+
logger.warn(`像素数据长度不匹配: ${rawPixels.length}, 预期 RGB: ${expectedRGB}, RGBA: ${expectedRGBA}`);
|
|
6521
|
+
return null;
|
|
6522
|
+
}
|
|
6523
|
+
} catch (err) {
|
|
6524
|
+
logger.warn("图片解析失败:", err);
|
|
6525
|
+
return null;
|
|
6526
|
+
}
|
|
6527
|
+
}
|
|
6528
|
+
static scanFromBuffer(buffer) {
|
|
6529
|
+
try {
|
|
6530
|
+
const imageData = this.parseImageBuffer(buffer);
|
|
6531
|
+
if (!imageData) return null;
|
|
6532
|
+
const { width, height } = imageData;
|
|
6533
|
+
const dataSizeMB = (width * height * 4 / 1024 / 1024).toFixed(2);
|
|
6534
|
+
logger.debug(`图片数据: ${width}x${height}, 内存占用: ${dataSizeMB}MB`);
|
|
6535
|
+
if (width <= 2048 && height <= 2048) {
|
|
6536
|
+
logger.debug("图片尺寸适中,使用全图识别策略");
|
|
6537
|
+
const result = this.tryRecognizeInRegion(imageData, "全图");
|
|
6538
|
+
if (result) return result;
|
|
6539
|
+
}
|
|
6540
|
+
logger.debug(`图片尺寸较大 (${width}x${height}),使用分块扫描策略`);
|
|
6541
|
+
const scanRegions = [];
|
|
6542
|
+
const blockSize = 1024;
|
|
6543
|
+
logger.debug("添加四角扫描区域");
|
|
6544
|
+
scanRegions.push({
|
|
6545
|
+
name: "左上角",
|
|
6546
|
+
x: 0,
|
|
6547
|
+
y: 0,
|
|
6548
|
+
w: Math.min(blockSize, width),
|
|
6549
|
+
h: Math.min(blockSize, height)
|
|
6550
|
+
});
|
|
6551
|
+
if (width > blockSize) scanRegions.push({
|
|
6552
|
+
name: "右上角",
|
|
6553
|
+
x: width - Math.min(blockSize, width),
|
|
6554
|
+
y: 0,
|
|
6555
|
+
w: Math.min(blockSize, width),
|
|
6556
|
+
h: Math.min(blockSize, height)
|
|
6557
|
+
});
|
|
6558
|
+
if (height > blockSize) scanRegions.push({
|
|
6559
|
+
name: "左下角",
|
|
6560
|
+
x: 0,
|
|
6561
|
+
y: height - Math.min(blockSize, height),
|
|
6562
|
+
w: Math.min(blockSize, width),
|
|
6563
|
+
h: Math.min(blockSize, height)
|
|
6564
|
+
});
|
|
6565
|
+
if (width > blockSize && height > blockSize) scanRegions.push({
|
|
6566
|
+
name: "右下角",
|
|
6567
|
+
x: width - Math.min(blockSize, width),
|
|
6568
|
+
y: height - Math.min(blockSize, height),
|
|
6569
|
+
w: Math.min(blockSize, width),
|
|
6570
|
+
h: Math.min(blockSize, height)
|
|
6571
|
+
});
|
|
6572
|
+
if (width > blockSize * 2) {
|
|
6573
|
+
logger.debug("添加顶部/底部中间扫描区域");
|
|
6574
|
+
scanRegions.push({
|
|
6575
|
+
name: "顶部中",
|
|
6576
|
+
x: Math.floor((width - blockSize) / 2),
|
|
6577
|
+
y: 0,
|
|
6578
|
+
w: blockSize,
|
|
6579
|
+
h: Math.min(blockSize, height)
|
|
6580
|
+
});
|
|
6581
|
+
if (height > blockSize) scanRegions.push({
|
|
6582
|
+
name: "底部中",
|
|
6583
|
+
x: Math.floor((width - blockSize) / 2),
|
|
6584
|
+
y: height - blockSize,
|
|
6585
|
+
w: blockSize,
|
|
6586
|
+
h: blockSize
|
|
6587
|
+
});
|
|
6588
|
+
}
|
|
6589
|
+
if (height > blockSize * 2) {
|
|
6590
|
+
logger.debug("添加左右中间扫描区域");
|
|
6591
|
+
const middleY = Math.floor((height - blockSize) / 2);
|
|
6592
|
+
scanRegions.push({
|
|
6593
|
+
name: "左中",
|
|
6594
|
+
x: 0,
|
|
6595
|
+
y: middleY,
|
|
6596
|
+
w: Math.min(blockSize, width),
|
|
6597
|
+
h: blockSize
|
|
6598
|
+
});
|
|
6599
|
+
if (width > blockSize) scanRegions.push({
|
|
6600
|
+
name: "右中",
|
|
6601
|
+
x: width - blockSize,
|
|
6602
|
+
y: middleY,
|
|
6603
|
+
w: blockSize,
|
|
6604
|
+
h: blockSize
|
|
6605
|
+
});
|
|
6606
|
+
}
|
|
6607
|
+
logger.debug("添加滑动窗口扫描区域");
|
|
6608
|
+
const step = Math.floor(blockSize / 2);
|
|
6609
|
+
let slidingWindowCount = 0;
|
|
6610
|
+
for (let y = 0; y < height - blockSize; y += step) {
|
|
6611
|
+
scanRegions.push({
|
|
6612
|
+
name: `滑动窗口-${Math.floor(y / step)}`,
|
|
6613
|
+
x: 0,
|
|
6614
|
+
y,
|
|
6615
|
+
w: Math.min(blockSize, width),
|
|
6616
|
+
h: blockSize
|
|
6617
|
+
});
|
|
6618
|
+
slidingWindowCount++;
|
|
6619
|
+
if (scanRegions.length > 30) {
|
|
6620
|
+
logger.debug(`滑动窗口数量达到上限,停止添加 (已添加 ${slidingWindowCount} 个)`);
|
|
6621
|
+
break;
|
|
6622
|
+
}
|
|
6623
|
+
}
|
|
6624
|
+
logger.debug(`共生成 ${scanRegions.length} 个扫描区域,开始逐个扫描`);
|
|
6625
|
+
for (let i = 0; i < scanRegions.length; i++) {
|
|
6626
|
+
const region = scanRegions[i];
|
|
6627
|
+
logger.debug(`[${i + 1}/${scanRegions.length}] 扫描区域: ${region.name} (位置: ${region.x},${region.y}, 尺寸: ${region.w}x${region.h})`);
|
|
6628
|
+
const regionData = this.extractRegion(imageData, region.x, region.y, region.w, region.h);
|
|
6629
|
+
const result = this.tryRecognizeInRegion(regionData, region.name);
|
|
6630
|
+
if (result) {
|
|
6631
|
+
logger.debug(`二维码识别完成,共扫描了 ${i + 1}/${scanRegions.length} 个区域`);
|
|
6632
|
+
return result;
|
|
6633
|
+
}
|
|
6634
|
+
}
|
|
6635
|
+
logger.warn(`图片中未识别到二维码,已扫描所有 ${scanRegions.length} 个区域`);
|
|
6636
|
+
return null;
|
|
6637
|
+
} catch (error) {
|
|
6638
|
+
logger.error("解析图片时发生错误:", error);
|
|
6639
|
+
return null;
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6642
|
+
static isSupportedPlatform(qrContent) {
|
|
6643
|
+
return [
|
|
6644
|
+
/(https?:\/\/)?(www|v|jx|m|jingxuan)\.(douyin|iesdouyin)\.com/i,
|
|
6645
|
+
/https:\/\/aweme\.snssdk\.com\/aweme\/v1\/play/i,
|
|
6646
|
+
/(bilibili\.com|b23\.tv|t\.bilibili\.com|bili2233\.cn|\bBV[1-9a-zA-Z]{10}\b|\bav\d+\b)/i,
|
|
6647
|
+
/(快手.*快手|v\.kuaishou\.com|kuaishou\.com)/,
|
|
6648
|
+
/(xiaohongshu\.com|xhslink\.com)/
|
|
6649
|
+
].some((pattern) => pattern.test(qrContent));
|
|
6650
|
+
}
|
|
6651
|
+
};
|
|
6652
|
+
});
|
|
6389
6653
|
var Tools, Common;
|
|
6390
6654
|
var init_Common = __esmMin(async () => {
|
|
6391
6655
|
await init_Config();
|
|
6656
|
+
await init_QRCodeScanner();
|
|
6392
6657
|
await init_root();
|
|
6393
6658
|
await init_module();
|
|
6394
6659
|
Tools = class {
|
|
@@ -6405,6 +6670,19 @@ var init_Common = __esmMin(async () => {
|
|
|
6405
6670
|
const reply = await e.bot.getMsg(e.contact, e.replyId);
|
|
6406
6671
|
for (const v of reply.elements) if (v.type === "text") return v.text;
|
|
6407
6672
|
else if (v.type === "json") return v.data;
|
|
6673
|
+
else if (v.type === "image") try {
|
|
6674
|
+
logger.debug("检测到引用消息为图片,尝试识别二维码...");
|
|
6675
|
+
const imageUrl = v.file;
|
|
6676
|
+
if (imageUrl) {
|
|
6677
|
+
const qrContent = await QRCodeScanner.scanFromUrl(imageUrl);
|
|
6678
|
+
if (qrContent && QRCodeScanner.isSupportedPlatform(qrContent)) {
|
|
6679
|
+
logger.debug(`从图片二维码中识别到支持的平台链接: ${qrContent}`);
|
|
6680
|
+
return qrContent;
|
|
6681
|
+
} else if (qrContent) logger.debug(`识别到二维码内容但不是支持的平台: ${qrContent}`);
|
|
6682
|
+
}
|
|
6683
|
+
} catch (error) {
|
|
6684
|
+
logger.error("识别图片二维码时发生错误:", error);
|
|
6685
|
+
}
|
|
6408
6686
|
}
|
|
6409
6687
|
return "";
|
|
6410
6688
|
}
|
|
@@ -8063,6 +8341,7 @@ var utils_exports = __export({
|
|
|
8063
8341
|
Downloader: () => Downloader,
|
|
8064
8342
|
Network: () => Network,
|
|
8065
8343
|
Networks: () => Network,
|
|
8344
|
+
QRCodeScanner: () => QRCodeScanner,
|
|
8066
8345
|
Render: () => Render,
|
|
8067
8346
|
Root: () => Root,
|
|
8068
8347
|
ThrottleStream: () => ThrottleStream,
|
|
@@ -8097,6 +8376,7 @@ var init_utils$1 = __esmMin(async () => {
|
|
|
8097
8376
|
init_Common();
|
|
8098
8377
|
init_FFmpeg();
|
|
8099
8378
|
init_Networks();
|
|
8379
|
+
init_QRCodeScanner();
|
|
8100
8380
|
init_Render();
|
|
8101
8381
|
});
|
|
8102
8382
|
var BilibiliDBBase;
|
|
@@ -12685,15 +12965,16 @@ var init_setup = __esmMin(async () => {
|
|
|
12685
12965
|
});
|
|
12686
12966
|
await init_module();
|
|
12687
12967
|
await init_semver();
|
|
12688
|
-
var requireVersion = "1.14.
|
|
12968
|
+
var requireVersion = "1.14.4";
|
|
12689
12969
|
if (process.env.NODE_ENV !== "development" && isSemverGreater(requireVersion, Root.karinVersion)) {
|
|
12690
12970
|
const msg = `[karin-plugin-kkk] 插件构建时的 karin 版本 (${requireVersion}) 高于当前运行版本 (${Root.karinVersion}),可能会出现兼容性问题!`;
|
|
12691
12971
|
logger.warn(msg);
|
|
12692
12972
|
const notifiedSet = /* @__PURE__ */ new Set();
|
|
12693
12973
|
karin$1.on(BOT_CONNECT, async (bot) => {
|
|
12974
|
+
const botId = bot.selfId;
|
|
12975
|
+
if (botId === "console") return;
|
|
12694
12976
|
await new Promise((resolve$1) => setTimeout(resolve$1, 2e3));
|
|
12695
12977
|
const masters = config.master();
|
|
12696
|
-
const botId = bot.selfId;
|
|
12697
12978
|
logger.info(`[karin-plugin-kkk] 监测到 Bot 连接: ${botId}, 准备发送版本警告`);
|
|
12698
12979
|
let warningImage = null;
|
|
12699
12980
|
try {
|
|
@@ -16992,7 +17273,7 @@ var DouYin = class extends Base {
|
|
|
16992
17273
|
if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
|
|
16993
17274
|
for (const [index, imageItem] of images.entries()) {
|
|
16994
17275
|
imagenum++;
|
|
16995
|
-
if (imageItem.clip_type === 2) {
|
|
17276
|
+
if (imageItem.clip_type === 2 || imageItem.clip_type === void 0) {
|
|
16996
17277
|
image_url = imageItem.url_list[2] || imageItem.url_list[1];
|
|
16997
17278
|
processedImages.push(segment.image(image_url));
|
|
16998
17279
|
if (Config.app.removeCache === false) {
|
|
@@ -17230,7 +17511,7 @@ var DouYin = class extends Base {
|
|
|
17230
17511
|
gender: userProfile.data.user.gender ?? 0,
|
|
17231
17512
|
user_age: userProfile.data.user.user_age ?? 0
|
|
17232
17513
|
} : void 0,
|
|
17233
|
-
image_url: this.is_mp4 ? VideoData.data.aweme_detail.video.animated_cover?.url_list[0] ?? VideoData.data.aweme_detail.video.cover.url_list[0] : VideoData.data.aweme_detail.images[0].url_list[0],
|
|
17514
|
+
image_url: 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],
|
|
17234
17515
|
cover_size: this.is_mp4 ? VideoData.data.aweme_detail.video.cover ? {
|
|
17235
17516
|
width: VideoData.data.aweme_detail.video.cover_original_scale.width,
|
|
17236
17517
|
height: VideoData.data.aweme_detail.video.cover_original_scale.height
|
|
@@ -17982,7 +18263,7 @@ var DouYinpush = class extends Base {
|
|
|
17982
18263
|
if (pushItem.pushType === "favorite") {
|
|
17983
18264
|
const authorUserInfo = "author_user_info" in Detail_Data ? Detail_Data.author_user_info : void 0;
|
|
17984
18265
|
img$2 = await Render("douyin/favorite-list", {
|
|
17985
|
-
image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
|
|
18266
|
+
image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover_original_scale?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
|
|
17986
18267
|
desc: this.desc(Detail_Data, Detail_Data.desc),
|
|
17987
18268
|
dianzan: this.count(Detail_Data.statistics.digg_count),
|
|
17988
18269
|
pinglun: this.count(Detail_Data.statistics.comment_count),
|
|
@@ -18001,7 +18282,7 @@ var DouYinpush = class extends Base {
|
|
|
18001
18282
|
} else if (pushItem.pushType === "recommend") {
|
|
18002
18283
|
const authorUserInfo = "author_user_info" in Detail_Data ? Detail_Data.author_user_info : void 0;
|
|
18003
18284
|
img$2 = await Render("douyin/recommend-list", {
|
|
18004
|
-
image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
|
|
18285
|
+
image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover_original_scale?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
|
|
18005
18286
|
desc: this.desc(Detail_Data, Detail_Data.desc),
|
|
18006
18287
|
dianzan: this.count(Detail_Data.statistics.digg_count),
|
|
18007
18288
|
pinglun: this.count(Detail_Data.statistics.comment_count),
|
|
@@ -18112,7 +18393,7 @@ var DouYinpush = class extends Base {
|
|
|
18112
18393
|
bgmContext = await createLiveImageContext$1(liveimgbgm.filepath);
|
|
18113
18394
|
}
|
|
18114
18395
|
for (const item of images1) {
|
|
18115
|
-
if (item.clip_type === 2) {
|
|
18396
|
+
if (item.clip_type === 2 || item.clip_type === void 0) {
|
|
18116
18397
|
images.push(segment.image(item.url_list[0]));
|
|
18117
18398
|
continue;
|
|
18118
18399
|
}
|
|
@@ -18698,8 +18979,6 @@ var Kuaishou = class extends Base {
|
|
|
18698
18979
|
return true;
|
|
18699
18980
|
}
|
|
18700
18981
|
};
|
|
18701
|
-
var import_jsQR = __toESM(require_jsQR(), 1);
|
|
18702
|
-
var import_png = require_png();
|
|
18703
18982
|
await init_module();
|
|
18704
18983
|
await init_Config();
|
|
18705
18984
|
var safeScreenshot = async (page, screenshotPath) => {
|
|
@@ -19039,12 +19318,11 @@ var waitQrcode = async (page) => {
|
|
|
19039
19318
|
const response = await fetch(originalImage);
|
|
19040
19319
|
imageBuffer = Buffer.from(await response.arrayBuffer());
|
|
19041
19320
|
}
|
|
19042
|
-
const
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
logger.mark("二维码解码成功:", code.data);
|
|
19321
|
+
const qrContent = QRCodeScanner.scanFromBuffer(imageBuffer);
|
|
19322
|
+
if (qrContent) {
|
|
19323
|
+
logger.mark("二维码解码成功:", qrContent);
|
|
19046
19324
|
return {
|
|
19047
|
-
url:
|
|
19325
|
+
url: qrContent,
|
|
19048
19326
|
originalImage
|
|
19049
19327
|
};
|
|
19050
19328
|
}
|
|
@@ -19133,8 +19411,8 @@ var HELP_MENU_CONFIG = [
|
|
|
19133
19411
|
icon: "Link",
|
|
19134
19412
|
roles: ["member", "master"]
|
|
19135
19413
|
}, {
|
|
19136
|
-
title: "「#解析」「#kkk
|
|
19137
|
-
description: "
|
|
19414
|
+
title: "「#解析」「#kkk解析」「#弹幕解析」",
|
|
19415
|
+
description: "在解析功能关闭的情况下,可对引用消息进行解析;弹幕解析仅使用于「抖音」「哔哩哔哩」",
|
|
19138
19416
|
icon: "Sparkles",
|
|
19139
19417
|
roles: ["member", "master"]
|
|
19140
19418
|
}]
|
|
@@ -19942,6 +20220,7 @@ await init_Config();
|
|
|
19942
20220
|
await init_ErrorHandler();
|
|
19943
20221
|
var reg = {
|
|
19944
20222
|
douyin: /(https?:\/\/)?(www|v|jx|m|jingxuan)\.(douyin|iesdouyin)\.com/i,
|
|
20223
|
+
douyinCDN: /https:\/\/aweme\.snssdk\.com\/aweme\/v1\/play/i,
|
|
19945
20224
|
bilibili: /(bilibili\.com|b23\.tv|t\.bilibili\.com|bili2233\.cn|\bBV[1-9a-zA-Z]{10}\b|\bav\d+\b)/i,
|
|
19946
20225
|
kuaishou: /(快手.*快手|v\.kuaishou\.com|kuaishou\.com)/,
|
|
19947
20226
|
xiaohongshu: /(xiaohongshu\.com|xhslink\.com)/
|
|
@@ -19997,7 +20276,19 @@ var handlePrefix = wrapWithErrorHandler(async (e, next) => {
|
|
|
19997
20276
|
const originalMsg = e.msg;
|
|
19998
20277
|
e.msg = await Common.getReplyMessage(e);
|
|
19999
20278
|
if (/^#?弹幕解析/.test(originalMsg)) e.msg = "#弹幕解析 " + e.msg;
|
|
20000
|
-
if (reg.
|
|
20279
|
+
if (reg.douyinCDN.test(e.msg)) {
|
|
20280
|
+
logger.debug("检测到抖音 CDN 下载链接,直接下载视频");
|
|
20281
|
+
const videoIdMatch = e.msg.match(/video_id=([^&]+)/);
|
|
20282
|
+
const videoId = videoIdMatch ? videoIdMatch[1] : Date.now().toString();
|
|
20283
|
+
await downloadVideo(e, {
|
|
20284
|
+
video_url: e.msg,
|
|
20285
|
+
title: {
|
|
20286
|
+
timestampTitle: `tmp_${Date.now()}.mp4`,
|
|
20287
|
+
originTitle: `抖音视频_${videoId}.mp4`
|
|
20288
|
+
}
|
|
20289
|
+
});
|
|
20290
|
+
return true;
|
|
20291
|
+
} else if (reg.douyin.test(e.msg)) return await handleDouyin(e, next);
|
|
20001
20292
|
else if (reg.bilibili.test(e.msg)) return await handleBilibili(e, next);
|
|
20002
20293
|
else if (reg.kuaishou.test(e.msg)) return await handleKuaishou(e, next);
|
|
20003
20294
|
else if (reg.xiaohongshu.test(e.msg)) return await handleXiaohongshu(e, next);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __esmMin, o as __toESM, r as __export } from "./rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as init_lu, $t as Bookmark, A as RiHashtag, At as Plug2, B as RiRefreshLine, Bt as FileText, C as AiFillStar, Ct as Shield, D as RiArrowRightFill, Dt as Radio, E as zhCN, Et as ScanLine, F as RiListCheck2, Ft as Info, G as RiStarFill, Gt as Coins, H as RiSendPlaneFill, Ht as ExternalLink, I as RiLiveLine, It as Heart, J as RiTiktokFill, Jt as CircleEllipsis, K as RiStarLine, Kt as Clock, L as RiLoginCircleFill, Lt as Hash, M as RiHeart3Fill, Mt as Music, N as RiHeart3Line, Nt as MessageCircle, O as RiBellFill, Ot as Quote, P as RiLinkM, Pt as MapPin, Q as LuFullscreen, Qt as Calendar, R as RiMessage3Fill, Rt as Gift, S as AiFillHeart, St as Smartphone, T as init_locale, Tt as Share2, U as RiShareForwardFill, Ut as Crown, V as RiRobot2Fill, Vt as Eye, W as RiSparkling2Fill, Wt as CornerDownLeft, X as RiVideoLine, Xt as CircleAlert, Y as RiUserFollowLine, Yt as CircleCheckBig, Z as init_ri, Zt as ChartColumn, _ as HiOutlineMenuAlt2, _t as UserPlus, an as require_react, at as init_dist, b as FaCommentDots, bt as Terminal, c as rehypeHighlight, ct as button_default, d as MdAccessTime, dt as IoSearch, en as BookOpen, et as init_date_fns, f as init_md, ft as init_io5, g as init_tb, gt as User, h as TbScan, ht as Users, in as require_server_node, j as RiHeart2Line, jt as Play, k as RiGroupLine, kt as QrCode, l as init_react_markdown, lt as HeroUIProvider, m as init_si, mt as Zap, nn as clsx_default, nt as formatDistanceToNow, ot as code_default, p as SiBilibili, pt as init_lucide_react, q as RiThumbUpFill, qt as CircleFadingArrowUp, rn as init_clsx, rt as format, s as init_rehype_highlight, st as chip_default, tn as Bell, u as Markdown, ut as require_jsx_runtime, v as init_hi, vt as TriangleAlert, w as init_ai, wt as ShieldCheck, x as init_fa6, xt as Star, y as FaCodeBranch, yt as ThumbsUp, z as RiQuestionFill, zt as Gamepad2 } from "./vendor-B3KhGHI_.js";
|
|
3
3
|
import { logger as logger$1 } from "node-karin";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
@@ -3634,7 +3634,7 @@ var init_videoInfo$1 = __esmMin(() => {
|
|
|
3634
3634
|
className: "w-full h-full object-cover scale-150 blur-[120px] saturate-[1.8] opacity-50"
|
|
3635
3635
|
}), (0, import_jsx_runtime$22.jsx)("div", { className: "absolute inset-0 bg-black/50" })]
|
|
3636
3636
|
}), (0, import_jsx_runtime$22.jsx)("div", {
|
|
3637
|
-
className: "relative w-full overflow-hidden text-white
|
|
3637
|
+
className: "relative w-full overflow-hidden text-white",
|
|
3638
3638
|
children: (0, import_jsx_runtime$22.jsxs)("div", {
|
|
3639
3639
|
className: "relative z-10",
|
|
3640
3640
|
children: [
|
|
@@ -3692,7 +3692,7 @@ var init_videoInfo$1 = __esmMin(() => {
|
|
|
3692
3692
|
children: [(0, import_jsx_runtime$22.jsxs)("div", {
|
|
3693
3693
|
className: "flex items-center justify-between mb-10",
|
|
3694
3694
|
children: [duration ? (0, import_jsx_runtime$22.jsx)("div", {
|
|
3695
|
-
className: "px-6 py-4 rounded-2xl bg-white/20 backdrop-blur-2xl border border-white/30 shadow-lg text-white text-3xl
|
|
3695
|
+
className: "px-6 py-4 rounded-2xl bg-white/20 backdrop-blur-2xl border border-white/30 shadow-lg text-white text-3xl tracking-wider",
|
|
3696
3696
|
children: duration
|
|
3697
3697
|
}) : (0, import_jsx_runtime$22.jsx)("div", {}), props.data.music && (0, import_jsx_runtime$22.jsxs)("div", {
|
|
3698
3698
|
className: "flex items-center gap-6 p-4 rounded-3xl bg-white/20 backdrop-blur-2xl border border-white/30 shadow-lg overflow-hidden",
|
|
@@ -3734,7 +3734,7 @@ var init_videoInfo$1 = __esmMin(() => {
|
|
|
3734
3734
|
className: "text-white/60",
|
|
3735
3735
|
children: icon
|
|
3736
3736
|
}), (0, import_jsx_runtime$22.jsx)("span", {
|
|
3737
|
-
className: "text-4xl
|
|
3737
|
+
className: "text-4xl text-white/90 tabular-nums whitespace-nowrap",
|
|
3738
3738
|
children: formatNumber$3(value)
|
|
3739
3739
|
})]
|
|
3740
3740
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import "./rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import "./vendor-
|
|
3
|
-
import { r as reactServerRender, t as template_default } from "./template-
|
|
2
|
+
import "./vendor-B3KhGHI_.js";
|
|
3
|
+
import { r as reactServerRender, t as template_default } from "./template-CQ-u6h09.js";
|
|
4
4
|
export { template_default as default, reactServerRender };
|