karin-plugin-kkk 2.19.0 → 2.20.0

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.
@@ -1,6 +1,6 @@
1
1
  import { n as __esmMin, o as __toESM, r as __export } from "./rolldown-runtime-BMXAG3ag.js";
2
- import { D as init_locale, O as zhCN, _n as init_zod, a as require_lib, at as format, c as Window, cn as require_express, dn as init_source, fn as AxiosError$1, gn as init_esm, hn as Xhshow, i as require_dist, it as formatDistanceToNow, ln as require_protobufjs, mn as axios_default, n as require_jsQR, nt as init_date_fns, o as require_qr_code_styling, ot as differenceInSeconds, pn as init_axios, r as require_heic_convert, rt as fromUnixTime, s as init_lib, t as require_png, un as Chalk, vn as zod_default } from "./vendor-BsdYKPEs.js";
3
- import { n as init_client, r as reactServerRender } from "./template-CHNHRIxO.js";
2
+ import { E as zhCN, T as init_locale, _n as init_zod, a as init_lib, cn as require_express, dn as init_source, et as init_date_fns, fn as AxiosError$1, gn as init_esm, hn as Xhshow, i as require_qr_code_styling, it as differenceInSeconds, ln as require_protobufjs, mn as axios_default, n as require_dist, nt as formatDistanceToNow, o as Window, on as require_png, pn as init_axios, r as require_lib, rt as format, sn as require_jsQR, t as require_heic_convert, tt as fromUnixTime, un as Chalk, vn as zod_default } from "./vendor-CZcAPGm1.js";
3
+ import { n as init_client, r as reactServerRender } from "./template-BMkKJo_s.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,8 @@ 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 { pipeline } from "node:stream/promises";
17
16
  import axios, { AxiosError } from "node-karin/axios";
17
+ import { pipeline } from "node:stream/promises";
18
18
  import { Transform } from "node:stream";
19
19
  import express from "node-karin/express";
20
20
  import template from "node-karin/template";
@@ -2897,7 +2897,7 @@ var init_getdata$3 = __esmMin(() => {
2897
2897
  ...params,
2898
2898
  max_cursor: resp.max_cursor?.toString() ?? "0"
2899
2899
  }),
2900
- hasMore: (resp) => resp.has_more === 1,
2900
+ hasMore: (resp) => resp.has_more === true,
2901
2901
  formatFinalResponse: (resp, list) => ({
2902
2902
  ...resp,
2903
2903
  aweme_list: list
@@ -5767,7 +5767,7 @@ var init_src = __esmMin(() => {
5767
5767
  init_server();
5768
5768
  init_types$1();
5769
5769
  init_api_spec();
5770
- getVersion = () => "6.0.0-beta.0";
5770
+ getVersion = () => "6.0.0-beta.2";
5771
5771
  VERSION = getVersion();
5772
5772
  Object.defineProperty(CreateAmagiApp, "version", {
5773
5773
  value: VERSION,
@@ -5819,6 +5819,121 @@ var init_root = __esmMin(() => {
5819
5819
  karinVersion: process.env.KARIN_VERSION
5820
5820
  };
5821
5821
  });
5822
+ var amagiClient_exports = __export({
5823
+ AmagiBase: () => AmagiBase,
5824
+ AmagiError: () => AmagiError,
5825
+ bilibiliFetcher: () => bilibiliFetcher,
5826
+ douyinFetcher: () => douyinFetcher,
5827
+ kuaishouFetcher: () => kuaishouFetcher,
5828
+ reloadAmagiConfig: () => reloadAmagiConfig,
5829
+ xiaohongshuFetcher: () => xiaohongshuFetcher
5830
+ }, 1);
5831
+ var AmagiError, AmagiBase, amagiClientInstance, amagiClient, reloadAmagiConfig, bilibiliFetcher, douyinFetcher, kuaishouFetcher, xiaohongshuFetcher;
5832
+ var init_amagiClient = __esmMin(() => {
5833
+ init_src();
5834
+ init_Config();
5835
+ AmagiError = class extends Error {
5836
+ code;
5837
+ data;
5838
+ rawError;
5839
+ constructor(code, message, data$1, rawError) {
5840
+ super(message);
5841
+ this.name = "AmagiError";
5842
+ this.code = code;
5843
+ this.data = data$1;
5844
+ this.rawError = rawError;
5845
+ }
5846
+ };
5847
+ AmagiBase = class {
5848
+ amagi;
5849
+ constructor() {
5850
+ const client = this.createAmagiClient();
5851
+ this.amagi = this.wrapAmagiClient(client);
5852
+ }
5853
+ createAmagiClient = () => Client({
5854
+ cookies: {
5855
+ douyin: Config.cookies.douyin,
5856
+ bilibili: Config.cookies.bilibili,
5857
+ kuaishou: Config.cookies.kuaishou,
5858
+ xiaohongshu: Config.cookies.xiaohongshu
5859
+ },
5860
+ request: {
5861
+ timeout: Config.request.timeout,
5862
+ headers: { "User-Agent": Config.request["User-Agent"] },
5863
+ proxy: Config.request.proxy?.switch ? Config.request.proxy : false
5864
+ }
5865
+ });
5866
+ reloadConfig() {
5867
+ logger.debug("[AmagiClient] 检测到配置变化,正在重载...");
5868
+ const oldCookies = {
5869
+ douyin: Config.cookies.douyin?.substring(0, 20) + "...",
5870
+ bilibili: Config.cookies.bilibili?.substring(0, 20) + "...",
5871
+ kuaishou: Config.cookies.kuaishou?.substring(0, 20) + "...",
5872
+ xiaohongshu: Config.cookies.xiaohongshu?.substring(0, 20) + "..."
5873
+ };
5874
+ const client = this.createAmagiClient();
5875
+ this.amagi = this.wrapAmagiClient(client);
5876
+ const newCookies = {
5877
+ douyin: Config.cookies.douyin?.substring(0, 20) + "...",
5878
+ bilibili: Config.cookies.bilibili?.substring(0, 20) + "...",
5879
+ kuaishou: Config.cookies.kuaishou?.substring(0, 20) + "...",
5880
+ xiaohongshu: Config.cookies.xiaohongshu?.substring(0, 20) + "..."
5881
+ };
5882
+ logger.debug("[AmagiClient] 配置重载完成");
5883
+ logger.debug(`[AmagiClient] Cookie 变化对比:\n${util.inspect({
5884
+ "旧配置": oldCookies,
5885
+ "新配置": newCookies
5886
+ }, {
5887
+ colors: true,
5888
+ depth: 2
5889
+ })}`);
5890
+ }
5891
+ wrapAmagiClient = (client) => {
5892
+ const createProxy = (target) => new Proxy(target, { get(obj, prop) {
5893
+ const value = obj[prop];
5894
+ if (value && typeof value === "object" && !Array.isArray(value)) return createProxy(value);
5895
+ if (typeof value === "function") return async (...args) => {
5896
+ const result = await value.apply(obj, args);
5897
+ const isResultType = (val) => {
5898
+ if (!val || typeof val !== "object") return false;
5899
+ if (!("success" in val) || typeof val.success !== "boolean") return false;
5900
+ if (!("code" in val) || !("message" in val)) return false;
5901
+ return true;
5902
+ };
5903
+ if (isResultType(result)) {
5904
+ if (result.success === true) return result;
5905
+ const errMessage = result.message || result.error?.amagiMessage || "请求失败";
5906
+ const errorDetails = util.inspect({
5907
+ code: result.code,
5908
+ data: result.data,
5909
+ message: errMessage,
5910
+ error: result.error
5911
+ }, {
5912
+ depth: 10,
5913
+ colors: true,
5914
+ compact: false,
5915
+ breakLength: 120,
5916
+ showHidden: true
5917
+ });
5918
+ throw new AmagiError(result.code, errorDetails, result.data, result.error);
5919
+ }
5920
+ return result;
5921
+ };
5922
+ return value;
5923
+ } });
5924
+ return createProxy(client);
5925
+ };
5926
+ };
5927
+ amagiClientInstance = new AmagiBase();
5928
+ amagiClient = amagiClientInstance.amagi;
5929
+ reloadAmagiConfig = () => {
5930
+ amagiClientInstance.reloadConfig();
5931
+ };
5932
+ bilibiliFetcher = amagiClient.bilibili.fetcher;
5933
+ douyinFetcher = amagiClient.douyin.fetcher;
5934
+ kuaishouFetcher = amagiClient.kuaishou.fetcher;
5935
+ xiaohongshuFetcher = amagiClient.xiaohongshu.fetcher;
5936
+ });
5822
5937
  var Cfg, configInstance, getConfigInstance, Config;
5823
5938
  var init_Config = __esmMin(() => {
5824
5939
  init_root();
@@ -5839,7 +5954,17 @@ var init_Config = __esmMin(() => {
5839
5954
  if (differences) fs.writeFileSync(`${this.dirCfgPath}/${file}`, result.toString({ lineWidth: -1 }));
5840
5955
  }
5841
5956
  setTimeout(() => {
5842
- filesByExt(this.dirCfgPath, ".yaml", "abs").forEach((file) => watch(file, (_old, _now) => {}));
5957
+ filesByExt(this.dirCfgPath, ".yaml", "abs").forEach((file) => watch(file, (_old, _now) => {
5958
+ const fileName = path.basename(file, ".yaml");
5959
+ if (fileName === "cookies" || fileName === "request") {
5960
+ logger.debug(`[Config] 检测到 ${fileName} 配置变化,正在重载 Amagi Client...`);
5961
+ Promise.resolve().then(() => (init_amagiClient(), amagiClient_exports)).then(({ reloadAmagiConfig: reloadAmagiConfig$1 }) => {
5962
+ reloadAmagiConfig$1();
5963
+ }).catch((error) => {
5964
+ logger.error(`[Config] 重载 Amagi Client 失败: ${error}`);
5965
+ });
5966
+ }
5967
+ }));
5843
5968
  }, 2e3);
5844
5969
  return this;
5845
5970
  }
@@ -6022,82 +6147,6 @@ var init_Config = __esmMin(() => {
6022
6147
  Config = new Proxy({}, { get(target, prop) {
6023
6148
  return getConfigInstance()[prop];
6024
6149
  } });
6025
- }), AmagiError, AmagiBase, amagiClient, bilibiliFetcher, douyinFetcher, kuaishouFetcher;
6026
- var init_amagiClient = __esmMin(() => {
6027
- init_src();
6028
- init_Config();
6029
- AmagiError = class extends Error {
6030
- code;
6031
- data;
6032
- rawError;
6033
- constructor(code, message, data$1, rawError) {
6034
- super(message);
6035
- this.name = "AmagiError";
6036
- this.code = code;
6037
- this.data = data$1;
6038
- this.rawError = rawError;
6039
- }
6040
- };
6041
- AmagiBase = class {
6042
- amagi;
6043
- constructor() {
6044
- const client = this.createAmagiClient();
6045
- this.amagi = this.wrapAmagiClient(client);
6046
- }
6047
- createAmagiClient = () => Client({
6048
- cookies: {
6049
- douyin: Config.cookies.douyin,
6050
- bilibili: Config.cookies.bilibili,
6051
- kuaishou: Config.cookies.kuaishou,
6052
- xiaohongshu: Config.cookies.xiaohongshu
6053
- },
6054
- request: {
6055
- timeout: Config.request.timeout,
6056
- headers: { "User-Agent": Config.request["User-Agent"] },
6057
- proxy: Config.request.proxy?.switch ? Config.request.proxy : false
6058
- }
6059
- });
6060
- wrapAmagiClient = (client) => {
6061
- const createProxy = (target) => new Proxy(target, { get(obj, prop) {
6062
- const value = obj[prop];
6063
- if (value && typeof value === "object" && !Array.isArray(value)) return createProxy(value);
6064
- if (typeof value === "function") return async (...args) => {
6065
- const result = await value.apply(obj, args);
6066
- const isResultType = (val) => {
6067
- if (!val || typeof val !== "object") return false;
6068
- if (!("success" in val) || typeof val.success !== "boolean") return false;
6069
- if (!("code" in val) || !("message" in val)) return false;
6070
- return true;
6071
- };
6072
- if (isResultType(result)) {
6073
- if (result.success === true) return result;
6074
- const errMessage = result.message || result.error?.amagiMessage || "请求失败";
6075
- const errorDetails = util.inspect({
6076
- code: result.code,
6077
- data: result.data,
6078
- message: errMessage,
6079
- error: result.error
6080
- }, {
6081
- depth: 10,
6082
- colors: true,
6083
- compact: false,
6084
- breakLength: 120,
6085
- showHidden: true
6086
- });
6087
- throw new AmagiError(result.code, errorDetails, result.data, result.error);
6088
- }
6089
- return result;
6090
- };
6091
- return value;
6092
- } });
6093
- return createProxy(client);
6094
- };
6095
- };
6096
- amagiClient = new AmagiBase().amagi;
6097
- bilibiliFetcher = amagiClient.bilibili.fetcher;
6098
- douyinFetcher = amagiClient.douyin.fetcher;
6099
- kuaishouFetcher = amagiClient.kuaishou.fetcher;
6100
- amagiClient.xiaohongshu.fetcher;
6101
6150
  });
6102
6151
  var Base, statBotId$1, Count, uploadFile, downloadVideo, downloadFile, processFilename;
6103
6152
  var init_Base = __esmMin(() => {
@@ -6337,9 +6386,235 @@ var init_build_metadata = __esmMin(() => {
6337
6386
  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")}`;
6338
6387
  };
6339
6388
  });
6389
+ var import_jsQR$1, import_png$1, QRCodeScanner;
6390
+ var init_QRCodeScanner = __esmMin(() => {
6391
+ import_jsQR$1 = __toESM(require_jsQR(), 1);
6392
+ import_png$1 = require_png();
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 await 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$1.default)(processedData.data, processedData.width, processedData.height, strategy.options);
6476
+ if (code && code.data) {
6477
+ logger.mark(`✓ 成功识别二维码 [区域: ${regionName}] [策略: ${strategy.name}]`);
6478
+ logger.mark(` 二维码内容: ${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 async scanFromBuffer(buffer) {
6488
+ try {
6489
+ let imageData;
6490
+ try {
6491
+ const png = import_png$1.PNG.sync.read(buffer);
6492
+ imageData = {
6493
+ width: png.width,
6494
+ height: png.height,
6495
+ data: Uint8ClampedArray.from(png.data)
6496
+ };
6497
+ logger.mark(`图片解析成功: ${png.width}x${png.height}, 数据大小: ${(png.data.length / 1024 / 1024).toFixed(2)}MB`);
6498
+ } catch (err) {
6499
+ logger.warn("图片格式不支持,目前仅支持 PNG 格式的二维码识别", err);
6500
+ return null;
6501
+ }
6502
+ const { width, height } = imageData;
6503
+ if (width <= 2048 && height <= 2048) {
6504
+ logger.debug("图片尺寸适中,使用全图识别策略");
6505
+ const result = this.tryRecognizeInRegion(imageData, "全图");
6506
+ if (result) return result;
6507
+ }
6508
+ logger.mark(`图片尺寸较大 (${width}x${height}),使用分块扫描策略`);
6509
+ const scanRegions = [];
6510
+ const blockSize = 1024;
6511
+ logger.debug("添加顶部扫描区域");
6512
+ scanRegions.push({
6513
+ name: "顶部左",
6514
+ x: 0,
6515
+ y: 0,
6516
+ w: Math.min(blockSize, width),
6517
+ h: Math.min(blockSize, height)
6518
+ });
6519
+ if (width > blockSize) scanRegions.push({
6520
+ name: "顶部右",
6521
+ x: width - blockSize,
6522
+ y: 0,
6523
+ w: blockSize,
6524
+ h: Math.min(blockSize, height)
6525
+ });
6526
+ if (width > blockSize * 2) scanRegions.push({
6527
+ name: "顶部中",
6528
+ x: Math.floor((width - blockSize) / 2),
6529
+ y: 0,
6530
+ w: blockSize,
6531
+ h: Math.min(blockSize, height)
6532
+ });
6533
+ if (height > blockSize) {
6534
+ logger.debug("添加底部扫描区域");
6535
+ scanRegions.push({
6536
+ name: "底部左",
6537
+ x: 0,
6538
+ y: height - blockSize,
6539
+ w: Math.min(blockSize, width),
6540
+ h: blockSize
6541
+ });
6542
+ if (width > blockSize) scanRegions.push({
6543
+ name: "底部右",
6544
+ x: width - blockSize,
6545
+ y: height - blockSize,
6546
+ w: blockSize,
6547
+ h: blockSize
6548
+ });
6549
+ }
6550
+ if (height > blockSize * 2) {
6551
+ logger.debug("添加中部扫描区域");
6552
+ const middleY = Math.floor((height - blockSize) / 2);
6553
+ scanRegions.push({
6554
+ name: "中部左",
6555
+ x: 0,
6556
+ y: middleY,
6557
+ w: Math.min(blockSize, width),
6558
+ h: blockSize
6559
+ });
6560
+ if (width > blockSize) scanRegions.push({
6561
+ name: "中部右",
6562
+ x: width - blockSize,
6563
+ y: middleY,
6564
+ w: blockSize,
6565
+ h: blockSize
6566
+ });
6567
+ }
6568
+ logger.debug("添加滑动窗口扫描区域");
6569
+ const step = Math.floor(blockSize / 2);
6570
+ let slidingWindowCount = 0;
6571
+ for (let y = 0; y < height - blockSize; y += step) {
6572
+ scanRegions.push({
6573
+ name: `滑动窗口-${Math.floor(y / step)}`,
6574
+ x: 0,
6575
+ y,
6576
+ w: Math.min(blockSize, width),
6577
+ h: blockSize
6578
+ });
6579
+ slidingWindowCount++;
6580
+ if (scanRegions.length > 30) {
6581
+ logger.debug(`滑动窗口数量达到上限,停止添加 (已添加 ${slidingWindowCount} 个)`);
6582
+ break;
6583
+ }
6584
+ }
6585
+ logger.mark(`共生成 ${scanRegions.length} 个扫描区域,开始逐个扫描`);
6586
+ for (let i = 0; i < scanRegions.length; i++) {
6587
+ const region = scanRegions[i];
6588
+ logger.debug(`[${i + 1}/${scanRegions.length}] 扫描区域: ${region.name} (位置: ${region.x},${region.y}, 尺寸: ${region.w}x${region.h})`);
6589
+ const regionData = this.extractRegion(imageData, region.x, region.y, region.w, region.h);
6590
+ const result = this.tryRecognizeInRegion(regionData, region.name);
6591
+ if (result) {
6592
+ logger.mark(`二维码识别完成,共扫描了 ${i + 1}/${scanRegions.length} 个区域`);
6593
+ return result;
6594
+ }
6595
+ }
6596
+ logger.warn(`图片中未识别到二维码,已扫描所有 ${scanRegions.length} 个区域`);
6597
+ return null;
6598
+ } catch (error) {
6599
+ logger.error("解析图片时发生错误:", error);
6600
+ return null;
6601
+ }
6602
+ }
6603
+ static isSupportedPlatform(qrContent) {
6604
+ return [
6605
+ /(https?:\/\/)?(www|v|jx|m|jingxuan)\.(douyin|iesdouyin)\.com/i,
6606
+ /https:\/\/aweme\.snssdk\.com\/aweme\/v1\/play/i,
6607
+ /(bilibili\.com|b23\.tv|t\.bilibili\.com|bili2233\.cn|\bBV[1-9a-zA-Z]{10}\b|\bav\d+\b)/i,
6608
+ /(快手.*快手|v\.kuaishou\.com|kuaishou\.com)/,
6609
+ /(xiaohongshu\.com|xhslink\.com)/
6610
+ ].some((pattern) => pattern.test(qrContent));
6611
+ }
6612
+ };
6613
+ });
6340
6614
  var Tools, Common;
6341
6615
  var init_Common = __esmMin(async () => {
6342
6616
  await init_Config();
6617
+ await init_QRCodeScanner();
6343
6618
  await init_root();
6344
6619
  await init_module();
6345
6620
  Tools = class {
@@ -6356,6 +6631,19 @@ var init_Common = __esmMin(async () => {
6356
6631
  const reply = await e.bot.getMsg(e.contact, e.replyId);
6357
6632
  for (const v of reply.elements) if (v.type === "text") return v.text;
6358
6633
  else if (v.type === "json") return v.data;
6634
+ else if (v.type === "image") try {
6635
+ logger.debug("检测到引用消息为图片,尝试识别二维码...");
6636
+ const imageUrl = v.file;
6637
+ if (imageUrl) {
6638
+ const qrContent = await QRCodeScanner.scanFromUrl(imageUrl);
6639
+ if (qrContent && QRCodeScanner.isSupportedPlatform(qrContent)) {
6640
+ logger.debug(`从图片二维码中识别到支持的平台链接: ${qrContent}`);
6641
+ return qrContent;
6642
+ } else if (qrContent) logger.debug(`识别到二维码内容但不是支持的平台: ${qrContent}`);
6643
+ }
6644
+ } catch (error) {
6645
+ logger.error("识别图片二维码时发生错误:", error);
6646
+ }
6359
6647
  }
6360
6648
  return "";
6361
6649
  }
@@ -8014,6 +8302,7 @@ var utils_exports = __export({
8014
8302
  Downloader: () => Downloader,
8015
8303
  Network: () => Network,
8016
8304
  Networks: () => Network,
8305
+ QRCodeScanner: () => QRCodeScanner,
8017
8306
  Render: () => Render,
8018
8307
  Root: () => Root,
8019
8308
  ThrottleStream: () => ThrottleStream,
@@ -8048,6 +8337,7 @@ var init_utils$1 = __esmMin(async () => {
8048
8337
  init_Common();
8049
8338
  init_FFmpeg();
8050
8339
  init_Networks();
8340
+ init_QRCodeScanner();
8051
8341
  init_Render();
8052
8342
  });
8053
8343
  var BilibiliDBBase;
@@ -8083,7 +8373,7 @@ var init_bilibili = __esmMin(async () => {
8083
8373
  async createTables() {
8084
8374
  for (const query of [
8085
8375
  `CREATE TABLE IF NOT EXISTS Bots (\n id TEXT PRIMARY KEY,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
8086
- `CREATE TABLE IF NOT EXISTS Groups (\n id TEXT PRIMARY KEY,\n botId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (botId) REFERENCES Bots(id)\n )`,
8376
+ `CREATE TABLE IF NOT EXISTS Groups (\n id TEXT NOT NULL,\n botId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, botId),\n FOREIGN KEY (botId) REFERENCES Bots(id)\n )`,
8087
8377
  `CREATE TABLE IF NOT EXISTS BilibiliUsers (\n host_mid INTEGER PRIMARY KEY,\n remark TEXT,\n filterMode TEXT DEFAULT 'blacklist',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
8088
8378
  `CREATE TABLE IF NOT EXISTS GroupUserSubscriptions (\n groupId TEXT,\n host_mid INTEGER,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (groupId, host_mid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n FOREIGN KEY (host_mid) REFERENCES BilibiliUsers(host_mid)\n )`,
8089
8379
  `CREATE TABLE IF NOT EXISTS DynamicCaches (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n dynamic_id TEXT NOT NULL,\n host_mid INTEGER NOT NULL,\n groupId TEXT NOT NULL,\n dynamic_type TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (host_mid) REFERENCES BilibiliUsers(host_mid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n UNIQUE(dynamic_id, host_mid, groupId)\n )`,
@@ -8602,7 +8892,7 @@ var init_douyin = __esmMin(async () => {
8602
8892
  async createTables() {
8603
8893
  for (const query of [
8604
8894
  `CREATE TABLE IF NOT EXISTS Bots (\n id TEXT PRIMARY KEY,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
8605
- `CREATE TABLE IF NOT EXISTS Groups (\n id TEXT PRIMARY KEY,\n botId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (botId) REFERENCES Bots(id)\n )`,
8895
+ `CREATE TABLE IF NOT EXISTS Groups (\n id TEXT NOT NULL,\n botId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, botId),\n FOREIGN KEY (botId) REFERENCES Bots(id)\n )`,
8606
8896
  `CREATE TABLE IF NOT EXISTS DouyinUsers (\n sec_uid TEXT PRIMARY KEY,\n short_id TEXT,\n remark TEXT,\n living INTEGER DEFAULT 0,\n filterMode TEXT DEFAULT 'blacklist',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
8607
8897
  `CREATE TABLE IF NOT EXISTS GroupUserSubscriptions (\n groupId TEXT,\n sec_uid TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (groupId, sec_uid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid)\n )`,
8608
8898
  `CREATE TABLE IF NOT EXISTS AwemeCaches (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n aweme_id TEXT NOT NULL,\n sec_uid TEXT NOT NULL,\n groupId TEXT NOT NULL,\n pushType TEXT DEFAULT 'post',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n UNIQUE(aweme_id, sec_uid, groupId, pushType)\n )`,
@@ -13782,7 +14072,7 @@ const webConfig = defineConfig({
13782
14072
  children: [components.accordion.createItem("cfg:cookies", {
13783
14073
  title: "Cookies 相关",
13784
14074
  className: "ml-4 mr-4",
13785
- subtitle: "建议配置,否则大部分功能无法使用,此部分修改后需重启方可生效!",
14075
+ subtitle: "建议配置,否则大部分功能无法使用",
13786
14076
  children: [
13787
14077
  components.input.string("douyin", {
13788
14078
  label: "抖音",
@@ -13796,7 +14086,7 @@ const webConfig = defineConfig({
13796
14086
  components.input.string("bilibili", {
13797
14087
  label: "B站",
13798
14088
  type: "text",
13799
- description: "请输入你的B站Cookies,不输入则无法使用B站相关功能噢",
14089
+ description: "请输入你的B站Cookies,不输入部分功能将受限噢",
13800
14090
  defaultValue: all.cookies.bilibili,
13801
14091
  placeholder: "",
13802
14092
  rules: void 0,
@@ -14447,16 +14737,26 @@ const webConfig = defineConfig({
14447
14737
  cleanFlattenedFields(mergeCfg);
14448
14738
  let success = false;
14449
14739
  let isChange = false;
14740
+ let needReloadAmagi = false;
14450
14741
  for (const key of Object.keys(mergeCfg)) {
14451
14742
  const configValue = mergeCfg[key];
14452
14743
  if (configValue && typeof configValue === "object" && Object.keys(configValue).length > 0) {
14453
14744
  isChange = deepEqual(configValue, oldAllCfg[key]);
14454
14745
  if (isChange) {
14455
- if (await Config.ModifyPro(key, configValue)) success = true;
14746
+ if (await Config.ModifyPro(key, configValue)) {
14747
+ success = true;
14748
+ if (key === "cookies" || key === "request") needReloadAmagi = true;
14749
+ }
14456
14750
  }
14457
14751
  }
14458
14752
  }
14459
14753
  await Config.syncConfigToDatabase();
14754
+ if (needReloadAmagi) try {
14755
+ const { reloadAmagiConfig: reloadAmagiConfig$1 } = await Promise.resolve().then(() => (init_amagiClient(), amagiClient_exports));
14756
+ reloadAmagiConfig$1();
14757
+ } catch (error) {
14758
+ logger.error(`[WebConfig] 重载 Amagi Client 失败: ${error}`);
14759
+ }
14460
14760
  return {
14461
14761
  mergeCfg,
14462
14762
  formatCfg,
@@ -16788,7 +17088,7 @@ const douyinComments = async (data$1, emojidata) => {
16788
17088
  const replyCommentsList = [];
16789
17089
  if (replyComment.data.comments && replyComment.data.comments.length > 0) for (const reply of replyComment.data.comments) {
16790
17090
  const replyItem = reply;
16791
- const replyUserintextlongid = replyItem.text_extra && replyItem.text_extra[0] && replyItem.text_extra[0].sec_uid ? replyItem.text_extra.map((extra) => extra.sec_uid) : null;
17091
+ const replyUserintextlongid = replyItem.text_extra && replyItem.text_extra[0] && replyItem.text_extra[0].sec_uid ? replyItem.text_extra.filter((extra) => extra.sec_uid).map((extra) => extra.sec_uid) : null;
16792
17092
  const processedReplyText = await processAtUsers$1(replyItem.text, replyUserintextlongid);
16793
17093
  const replyImageUrl = replyItem.image_list?.[0]?.origin_url?.url_list?.[0];
16794
17094
  const replyStickerUrl = replyItem.sticker?.animate_url?.url_list?.[0];
@@ -17171,7 +17471,7 @@ var DouYin = class extends Base {
17171
17471
  gender: userProfile.data.user.gender ?? 0,
17172
17472
  user_age: userProfile.data.user.user_age ?? 0
17173
17473
  } : void 0,
17174
- 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],
17474
+ 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.images[0].url_list[0],
17175
17475
  cover_size: this.is_mp4 ? VideoData.data.aweme_detail.video.cover ? {
17176
17476
  width: VideoData.data.aweme_detail.video.cover_original_scale.width,
17177
17477
  height: VideoData.data.aweme_detail.video.cover_original_scale.height
@@ -17923,7 +18223,7 @@ var DouYinpush = class extends Base {
17923
18223
  if (pushItem.pushType === "favorite") {
17924
18224
  const authorUserInfo = "author_user_info" in Detail_Data ? Detail_Data.author_user_info : void 0;
17925
18225
  img$2 = await Render("douyin/favorite-list", {
17926
- 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],
18226
+ image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover_original_scale.url_list[0] : Detail_Data.images[0].url_list[0],
17927
18227
  desc: this.desc(Detail_Data, Detail_Data.desc),
17928
18228
  dianzan: this.count(Detail_Data.statistics.digg_count),
17929
18229
  pinglun: this.count(Detail_Data.statistics.comment_count),
@@ -17942,7 +18242,7 @@ var DouYinpush = class extends Base {
17942
18242
  } else if (pushItem.pushType === "recommend") {
17943
18243
  const authorUserInfo = "author_user_info" in Detail_Data ? Detail_Data.author_user_info : void 0;
17944
18244
  img$2 = await Render("douyin/recommend-list", {
17945
- 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],
18245
+ image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover_original_scale.url_list[0] : Detail_Data.images[0].url_list[0],
17946
18246
  desc: this.desc(Detail_Data, Detail_Data.desc),
17947
18247
  dianzan: this.count(Detail_Data.statistics.digg_count),
17948
18248
  pinglun: this.count(Detail_Data.statistics.comment_count),
@@ -18355,12 +18655,7 @@ var DouYinpush = class extends Base {
18355
18655
  }
18356
18656
  } else {
18357
18657
  existingItem.group_id.push(`${groupId}:${botId}`);
18358
- if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = [
18359
- "post",
18360
- "live",
18361
- "favorite",
18362
- "recommend"
18363
- ];
18658
+ if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = ["post", "live"];
18364
18659
  if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, UserInfoData.data.user.nickname);
18365
18660
  await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
18366
18661
  if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
@@ -18373,12 +18668,7 @@ var DouYinpush = class extends Base {
18373
18668
  group_id: [`${groupId}:${botId}`],
18374
18669
  remark: UserInfoData.data.user.nickname,
18375
18670
  short_id: user_shortid,
18376
- pushTypes: [
18377
- "post",
18378
- "live",
18379
- "favorite",
18380
- "recommend"
18381
- ]
18671
+ pushTypes: ["post", "live"]
18382
18672
  });
18383
18673
  if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, UserInfoData.data.user.nickname);
18384
18674
  await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
@@ -19084,8 +19374,8 @@ var HELP_MENU_CONFIG = [
19084
19374
  icon: "Link",
19085
19375
  roles: ["member", "master"]
19086
19376
  }, {
19087
- title: "「#解析」「#kkk解析」",
19088
- description: "在解析功能关闭的情况下,可对引用消息进行解析",
19377
+ title: "「#解析」「#kkk解析」「#弹幕解析」",
19378
+ description: "在解析功能关闭的情况下,可对引用消息进行解析;弹幕解析仅使用于「抖音」「哔哩哔哩」",
19089
19379
  icon: "Sparkles",
19090
19380
  roles: ["member", "master"]
19091
19381
  }]
@@ -19893,6 +20183,7 @@ await init_Config();
19893
20183
  await init_ErrorHandler();
19894
20184
  var reg = {
19895
20185
  douyin: /(https?:\/\/)?(www|v|jx|m|jingxuan)\.(douyin|iesdouyin)\.com/i,
20186
+ douyinCDN: /https:\/\/aweme\.snssdk\.com\/aweme\/v1\/play/i,
19896
20187
  bilibili: /(bilibili\.com|b23\.tv|t\.bilibili\.com|bili2233\.cn|\bBV[1-9a-zA-Z]{10}\b|\bav\d+\b)/i,
19897
20188
  kuaishou: /(快手.*快手|v\.kuaishou\.com|kuaishou\.com)/,
19898
20189
  xiaohongshu: /(xiaohongshu\.com|xhslink\.com)/
@@ -19948,7 +20239,19 @@ var handlePrefix = wrapWithErrorHandler(async (e, next) => {
19948
20239
  const originalMsg = e.msg;
19949
20240
  e.msg = await Common.getReplyMessage(e);
19950
20241
  if (/^#?弹幕解析/.test(originalMsg)) e.msg = "#弹幕解析 " + e.msg;
19951
- if (reg.douyin.test(e.msg)) return await handleDouyin(e, next);
20242
+ if (reg.douyinCDN.test(e.msg)) {
20243
+ logger.debug("检测到抖音 CDN 下载链接,直接下载视频");
20244
+ const videoIdMatch = e.msg.match(/video_id=([^&]+)/);
20245
+ const videoId = videoIdMatch ? videoIdMatch[1] : Date.now().toString();
20246
+ await downloadVideo(e, {
20247
+ video_url: e.msg,
20248
+ title: {
20249
+ timestampTitle: `tmp_${Date.now()}.mp4`,
20250
+ originTitle: `抖音视频_${videoId}.mp4`
20251
+ }
20252
+ });
20253
+ return true;
20254
+ } else if (reg.douyin.test(e.msg)) return await handleDouyin(e, next);
19952
20255
  else if (reg.bilibili.test(e.msg)) return await handleBilibili(e, next);
19953
20256
  else if (reg.kuaishou.test(e.msg)) return await handleKuaishou(e, next);
19954
20257
  else if (reg.xiaohongshu.test(e.msg)) return await handleXiaohongshu(e, next);