@napuketto/kernel 0.1.1 → 0.2.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/dist/index.cjs +93 -18
- package/dist/index.d.cts +54 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +54 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +93 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -708,17 +708,17 @@ function videoToCanonical(video) {
|
|
|
708
708
|
type: "video",
|
|
709
709
|
path: ""
|
|
710
710
|
};
|
|
711
|
-
const
|
|
712
|
-
const url = video.videoUrl;
|
|
713
|
-
if (url === void 0) return {
|
|
711
|
+
const base = {
|
|
714
712
|
type: "video",
|
|
715
|
-
path
|
|
716
|
-
};
|
|
717
|
-
return {
|
|
718
|
-
type: "video",
|
|
719
|
-
path,
|
|
720
|
-
url
|
|
713
|
+
path: video.filePath ?? video.videoUrl ?? ""
|
|
721
714
|
};
|
|
715
|
+
if (video.videoUrl !== void 0) base.url = video.videoUrl;
|
|
716
|
+
const thumb = video.thumbPath?.get(0);
|
|
717
|
+
if (thumb !== void 0 && thumb !== "") base.thumbPath = thumb;
|
|
718
|
+
if (video.thumbWidth !== void 0 && video.thumbWidth > 0) base.width = video.thumbWidth;
|
|
719
|
+
if (video.thumbHeight !== void 0 && video.thumbHeight > 0) base.height = video.thumbHeight;
|
|
720
|
+
if (video.fileTime !== void 0 && video.fileTime > 0) base.durationSec = video.fileTime;
|
|
721
|
+
return base;
|
|
722
722
|
}
|
|
723
723
|
/** FILE 元素 → canonical file。 */
|
|
724
724
|
function fileToCanonical(file) {
|
|
@@ -824,7 +824,7 @@ function toSendElements(elements) {
|
|
|
824
824
|
}
|
|
825
825
|
});
|
|
826
826
|
break;
|
|
827
|
-
case "video":
|
|
827
|
+
case "video": throw kernelError("视频发送需经 MsgApi 预处理(prepareVideoElement)", "INVALID_PARAM");
|
|
828
828
|
case "file":
|
|
829
829
|
case "forward":
|
|
830
830
|
case "json":
|
|
@@ -1231,6 +1231,27 @@ const PTT_WAVE_AMPLITUDES = [
|
|
|
1231
1231
|
15,
|
|
1232
1232
|
17
|
|
1233
1233
|
];
|
|
1234
|
+
/**
|
|
1235
|
+
* VIDEO 元素发送契约值(2026-10-17 收向实测字段 + 发送实测调通)。
|
|
1236
|
+
*
|
|
1237
|
+
* 依据:历史视频消息 `getLatestDbMsgs` 的 videoElement 实测快照(fileFormat /
|
|
1238
|
+
* busiType / subBusiType / storeID / original / videoFrom / sourceVideoCodecFormat
|
|
1239
|
+
* 均为实测出现的取值)。2026-10-17 18:12 自建宿主实测调通:`sendMsg` 成功
|
|
1240
|
+
* (sendStatus 2/3,群内可播放);关键坑是**缩略图目标路径必须用视频 md5**
|
|
1241
|
+
* (见 prepareVideoElement 注释),与字段取值无关。
|
|
1242
|
+
*/
|
|
1243
|
+
const VIDEO_FILE_FORMAT = 0;
|
|
1244
|
+
const VIDEO_BUSI_TYPE = 0;
|
|
1245
|
+
const VIDEO_SUB_BUSI_TYPE = 0;
|
|
1246
|
+
const VIDEO_STORE_ID = 1;
|
|
1247
|
+
const VIDEO_ORIGINAL = true;
|
|
1248
|
+
const VIDEO_FROM = 0;
|
|
1249
|
+
const VIDEO_SOURCE_CODEC_FORMAT = 0;
|
|
1250
|
+
/** 视频缩略图在 thumbPath Map 中的 key(收向实测 Map<0, path>)。 */
|
|
1251
|
+
const VIDEO_THUMB_KEY = 0;
|
|
1252
|
+
/** getRichMediaFilePathForGuild 的 downloadType:1 = 原文件,2 = 缩略图。 */
|
|
1253
|
+
const RICH_MEDIA_DOWNLOAD_TYPE_ORIGIN = 1;
|
|
1254
|
+
const RICH_MEDIA_DOWNLOAD_TYPE_THUMB = 2;
|
|
1234
1255
|
/** downloadRichMedia 契约值(2026-09-08 B1 实测:downloadType=2 可用 / thumbSize=0)。 */
|
|
1235
1256
|
const DOWNLOAD_TYPE_COMMON = 2;
|
|
1236
1257
|
const THUMB_SIZE_NONE = 0;
|
|
@@ -1244,20 +1265,20 @@ function sleep$1(ms) {
|
|
|
1244
1265
|
});
|
|
1245
1266
|
}
|
|
1246
1267
|
/** 读文件 stat(富媒体发送预处理;文件不存在抛 INVALID_PARAM)。 */
|
|
1247
|
-
async function statFile(path) {
|
|
1268
|
+
async function statFile(path, label = "图片") {
|
|
1248
1269
|
try {
|
|
1249
1270
|
return await stat(path);
|
|
1250
1271
|
} catch {
|
|
1251
|
-
throw kernelError(
|
|
1272
|
+
throw kernelError(`${label}文件不存在: ${path}`, "INVALID_PARAM");
|
|
1252
1273
|
}
|
|
1253
1274
|
}
|
|
1254
1275
|
/** 计算文件 md5(十六进制小写)。 */
|
|
1255
|
-
async function hashFile(path) {
|
|
1276
|
+
async function hashFile(path, label = "图片") {
|
|
1256
1277
|
try {
|
|
1257
1278
|
const buf = await readFile(path);
|
|
1258
1279
|
return createHash("md5").update(buf).digest("hex");
|
|
1259
1280
|
} catch {
|
|
1260
|
-
throw kernelError(
|
|
1281
|
+
throw kernelError(`${label}文件读取失败: ${path}`, "INVALID_PARAM");
|
|
1261
1282
|
}
|
|
1262
1283
|
}
|
|
1263
1284
|
/**
|
|
@@ -1349,6 +1370,9 @@ var MsgApi = class {
|
|
|
1349
1370
|
case "voice":
|
|
1350
1371
|
out.push(await this.preparePttElement(el.path));
|
|
1351
1372
|
break;
|
|
1373
|
+
case "video":
|
|
1374
|
+
out.push(await this.prepareVideoElement(el));
|
|
1375
|
+
break;
|
|
1352
1376
|
default: out.push(...toSendElements([el]));
|
|
1353
1377
|
}
|
|
1354
1378
|
return out;
|
|
@@ -1420,10 +1444,61 @@ var MsgApi = class {
|
|
|
1420
1444
|
};
|
|
1421
1445
|
}
|
|
1422
1446
|
/**
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1447
|
+
* VIDEO 元素预处理:md5 → 目标路径 → copyFile → 完整 videoElement。
|
|
1448
|
+
*
|
|
1449
|
+
* 字段依据:2026-10-17 收向实测(历史视频消息 videoElement 全字段快照)+
|
|
1450
|
+
* 发送实测(2026-10-17 18:12 自建宿主发送成功,群内可播放):
|
|
1451
|
+
* 1. `thumbPath` 必须是真实 `Map<number, string>`(收向实测 `Map<0, path>`)——
|
|
1452
|
+
* 经 JSON/IPC 传参会退化成 `{}`,wrapper 转换失败;
|
|
1453
|
+
* 2. **缩略图目标路径用视频 md5**(`Video/<YYYY-MM>/Thumb/<videoMd5>_0.png`):
|
|
1454
|
+
* 真实消息实测 videoMd5=`3d27…`、thumbMd5=`46da…`,落盘文件名却是
|
|
1455
|
+
* `3d27…_0.png`;此前按 thumbMd5 放置 → native 传输按视频 md5 找不到缩略图
|
|
1456
|
+
* → `rich media transfer failed`(20+ 组字段变体都无效的真正原因);
|
|
1457
|
+
* 3. `thumbMd5` 是缩略图**内容**的 md5,与文件名无关;`fileTime` 为秒。
|
|
1458
|
+
*/
|
|
1459
|
+
async prepareVideoElement(el) {
|
|
1460
|
+
const file = await statFile(el.path, "视频");
|
|
1461
|
+
const md5 = await hashFile(el.path, "视频");
|
|
1462
|
+
const fileName = basename(el.path);
|
|
1463
|
+
const videoElement = {
|
|
1464
|
+
fileName,
|
|
1465
|
+
filePath: await this.placeMediaFile(el.path, ElementType.VIDEO, md5, fileName, RICH_MEDIA_DOWNLOAD_TYPE_ORIGIN),
|
|
1466
|
+
fileSize: String(file.size),
|
|
1467
|
+
videoMd5: md5,
|
|
1468
|
+
fileTime: el.durationSec ?? 0,
|
|
1469
|
+
fileFormat: VIDEO_FILE_FORMAT,
|
|
1470
|
+
busiType: VIDEO_BUSI_TYPE,
|
|
1471
|
+
subBusiType: VIDEO_SUB_BUSI_TYPE,
|
|
1472
|
+
fileUuid: "",
|
|
1473
|
+
fileSubId: "",
|
|
1474
|
+
storeID: VIDEO_STORE_ID,
|
|
1475
|
+
original: VIDEO_ORIGINAL,
|
|
1476
|
+
videoFrom: VIDEO_FROM,
|
|
1477
|
+
sourceVideoCodecFormat: VIDEO_SOURCE_CODEC_FORMAT
|
|
1478
|
+
};
|
|
1479
|
+
if (el.thumbPath !== void 0 && el.thumbPath !== "") {
|
|
1480
|
+
const thumbSize = await statFile(el.thumbPath, "视频缩略图");
|
|
1481
|
+
const thumbMd5 = await hashFile(el.thumbPath, "视频缩略图");
|
|
1482
|
+
const thumbRelPath = await this.placeMediaFile(el.thumbPath, ElementType.VIDEO, md5, `${md5}${extname(el.thumbPath)}`, RICH_MEDIA_DOWNLOAD_TYPE_THUMB);
|
|
1483
|
+
videoElement.thumbMd5 = thumbMd5;
|
|
1484
|
+
videoElement.thumbSize = thumbSize.size;
|
|
1485
|
+
videoElement.thumbWidth = el.width ?? 0;
|
|
1486
|
+
videoElement.thumbHeight = el.height ?? 0;
|
|
1487
|
+
videoElement.thumbPath = /* @__PURE__ */ new Map([[VIDEO_THUMB_KEY, thumbRelPath]]);
|
|
1488
|
+
}
|
|
1489
|
+
return {
|
|
1490
|
+
elementType: ElementType.VIDEO,
|
|
1491
|
+
elementId: "",
|
|
1492
|
+
videoElement
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* 富媒体文件放置(PIC/PTT/VIDEO 共用):md5 + 文件名 → QQ 内部目标路径
|
|
1497
|
+
* (getRichMediaFilePathForGuild)→ util.copyFile 放置 → 返回目标路径。
|
|
1498
|
+
*
|
|
1499
|
+
* `downloadType`:1 = 原文件(Ori),2 = 缩略图(Thumb,视频缩略图必须)。
|
|
1425
1500
|
*/
|
|
1426
|
-
async placeMediaFile(path, elementType, md5, fileName) {
|
|
1501
|
+
async placeMediaFile(path, elementType, md5, fileName, downloadType = RICH_MEDIA_DOWNLOAD_TYPE_ORIGIN) {
|
|
1427
1502
|
const service = this.service;
|
|
1428
1503
|
const util = this.util;
|
|
1429
1504
|
const relPath = service.getRichMediaFilePathForGuild({
|
|
@@ -1433,7 +1508,7 @@ var MsgApi = class {
|
|
|
1433
1508
|
elementSubType: 0,
|
|
1434
1509
|
thumbSize: 0,
|
|
1435
1510
|
needCreate: true,
|
|
1436
|
-
downloadType
|
|
1511
|
+
downloadType,
|
|
1437
1512
|
file_uuid: ""
|
|
1438
1513
|
});
|
|
1439
1514
|
if (util !== null) {
|