mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(feishu): include video upload duration (#98235)
This commit is contained in:
@@ -214,6 +214,8 @@ describe("sendMediaFeishu msg_type routing", () => {
|
||||
});
|
||||
|
||||
it("uses msg_type=media for mp4 video", async () => {
|
||||
runFfprobeMock.mockResolvedValueOnce("4.2\n");
|
||||
|
||||
await sendMediaFeishu({
|
||||
cfg: emptyConfig,
|
||||
to: "user:ou_target",
|
||||
@@ -222,6 +224,17 @@ describe("sendMediaFeishu msg_type routing", () => {
|
||||
});
|
||||
|
||||
expect(callData<{ file_type?: string }>(fileCreateMock).file_type).toBe("mp4");
|
||||
expect(callData<{ duration?: number }>(fileCreateMock).duration).toBe(4200);
|
||||
const ffprobeArgs = mockCallArg<string[]>(runFfprobeMock, 0, 0);
|
||||
expect(ffprobeArgs.slice(0, -1)).toEqual([
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"csv=p=0",
|
||||
]);
|
||||
expect(ffprobeArgs.at(-1)).toMatch(/input\.mp4$/);
|
||||
expect(callData<{ msg_type?: string }>(messageCreateMock).msg_type).toBe("media");
|
||||
});
|
||||
|
||||
@@ -297,6 +310,7 @@ describe("sendMediaFeishu msg_type routing", () => {
|
||||
});
|
||||
|
||||
it("uses msg_type=media for remote mp4 content even when the filename is generic", async () => {
|
||||
runFfprobeMock.mockResolvedValueOnce("6.789\n");
|
||||
loadWebMediaMock.mockResolvedValueOnce({
|
||||
buffer: Buffer.from("remote-video"),
|
||||
fileName: "download",
|
||||
@@ -311,6 +325,9 @@ describe("sendMediaFeishu msg_type routing", () => {
|
||||
});
|
||||
|
||||
expect(callData<{ file_type?: string }>(fileCreateMock).file_type).toBe("mp4");
|
||||
expect(callData<{ duration?: number }>(fileCreateMock).duration).toBe(6789);
|
||||
const ffprobeArgs = mockCallArg<string[]>(runFfprobeMock, 0, 0);
|
||||
expect(ffprobeArgs.at(-1)).toMatch(/input\.mp4$/);
|
||||
expect(callData<{ msg_type?: string }>(messageCreateMock).msg_type).toBe("media");
|
||||
});
|
||||
|
||||
|
||||
@@ -822,12 +822,23 @@ async function prepareFeishuVoiceMedia(params: {
|
||||
}
|
||||
}
|
||||
|
||||
async function probeAudioDurationMs(buffer: Buffer): Promise<number | undefined> {
|
||||
async function probeMediaDurationMs(params: {
|
||||
buffer: Buffer;
|
||||
fileName: string;
|
||||
contentType?: string;
|
||||
}): Promise<number | undefined> {
|
||||
try {
|
||||
return await withTempWorkspace(
|
||||
{ rootDir: resolvePreferredOpenClawTmpDir(), prefix: "feishu-audio-probe-" },
|
||||
{ rootDir: resolvePreferredOpenClawTmpDir(), prefix: "feishu-media-probe-" },
|
||||
async (workspace) => {
|
||||
const inputPath = await workspace.write("input.ogg", buffer);
|
||||
const ext = normalizeLowercaseStringOrEmpty(path.extname(params.fileName));
|
||||
const inferredExt =
|
||||
ext && ext.length <= 12
|
||||
? ext
|
||||
: mediaKindFromMime(params.contentType) === "video"
|
||||
? ".mp4"
|
||||
: ".ogg";
|
||||
const inputPath = await workspace.write(`input${inferredExt}`, params.buffer);
|
||||
const stdout = await runFfprobe(
|
||||
["-v", "error", "-show_entries", "format=duration", "-of", "csv=p=0", inputPath],
|
||||
{ timeoutMs: 5_000 },
|
||||
@@ -840,11 +851,23 @@ async function probeAudioDurationMs(buffer: Buffer): Promise<number | undefined>
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
console.warn("[feishu] failed to probe audio duration; voice bubble will omit it:", err);
|
||||
console.warn("[feishu] failed to probe media duration; upload will omit it:", err);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function maybeProbeUploadDurationMs(params: {
|
||||
buffer: Buffer;
|
||||
fileName: string;
|
||||
contentType?: string;
|
||||
msgType: "file" | "audio" | "media";
|
||||
}): Promise<number | undefined> {
|
||||
if (params.msgType !== "audio" && params.msgType !== "media") {
|
||||
return undefined;
|
||||
}
|
||||
return await probeMediaDurationMs(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload and send media (image or file) from URL, local path, or buffer.
|
||||
* When mediaUrl is a local path, mediaLocalRoots (from core outbound context)
|
||||
@@ -930,7 +953,12 @@ export async function sendMediaFeishu(params: {
|
||||
...(voiceIntentDegradedToFile ? { voiceIntentDegradedToFile: true } : {}),
|
||||
};
|
||||
}
|
||||
const durationMs = routing.msgType === "audio" ? await probeAudioDurationMs(buffer) : undefined;
|
||||
const durationMs = await maybeProbeUploadDurationMs({
|
||||
buffer,
|
||||
fileName: name,
|
||||
contentType,
|
||||
msgType: routing.msgType,
|
||||
});
|
||||
const { fileKey } = await uploadFileFeishu({
|
||||
cfg,
|
||||
file: buffer,
|
||||
|
||||
Reference in New Issue
Block a user