fix: keep MEDIA tokens with punctuation and log web media failures
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
// Shared helpers for parsing MEDIA tokens from command/stdout text.
|
// Shared helpers for parsing MEDIA tokens from command/stdout text.
|
||||||
|
|
||||||
export const MEDIA_LINE_RE = /\bMEDIA:/i;
|
export const MEDIA_LINE_RE = /\bMEDIA:/i;
|
||||||
export const MEDIA_TOKEN_RE = /\bMEDIA:\s*([^\s]+)/i;
|
// Allow optional wrapping backticks and punctuation after the token; capture the core token.
|
||||||
|
export const MEDIA_TOKEN_RE = /\bMEDIA:\s*`?([^\s`]+)`?/i;
|
||||||
|
|
||||||
export function normalizeMediaSource(src: string) {
|
export function normalizeMediaSource(src: string) {
|
||||||
if (src.startsWith("file://")) return src.replace("file://", "");
|
if (src.startsWith("file://")) return src.replace("file://", "");
|
||||||
|
|||||||
@@ -367,18 +367,47 @@ export async function monitorWebProvider(
|
|||||||
onReplyStart: msg.sendComposing,
|
onReplyStart: msg.sendComposing,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!replyResult || (!replyResult.text && !replyResult.mediaUrl)) return;
|
if (!replyResult || (!replyResult.text && !replyResult.mediaUrl)) {
|
||||||
|
logVerbose(
|
||||||
|
"Skipping auto-reply: no text/media returned from resolver",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (replyResult.mediaUrl) {
|
if (replyResult.mediaUrl) {
|
||||||
logVerbose(
|
logVerbose(
|
||||||
`Web auto-reply media detected: ${replyResult.mediaUrl}`,
|
`Web auto-reply media detected: ${replyResult.mediaUrl}`,
|
||||||
);
|
);
|
||||||
const media = await loadWebMedia(replyResult.mediaUrl);
|
try {
|
||||||
await msg.sendMedia({
|
const media = await loadWebMedia(replyResult.mediaUrl);
|
||||||
image: media.buffer,
|
if (isVerbose()) {
|
||||||
caption: replyResult.text || undefined,
|
logVerbose(
|
||||||
mimetype: media.contentType,
|
`Web auto-reply media size: ${(media.buffer.length / (1024 * 1024)).toFixed(2)}MB`,
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
await msg.sendMedia({
|
||||||
|
image: media.buffer,
|
||||||
|
caption: replyResult.text || undefined,
|
||||||
|
mimetype: media.contentType,
|
||||||
|
});
|
||||||
|
logInfo(
|
||||||
|
`✅ Sent web media reply to ${msg.from} (${(media.buffer.length / (1024 * 1024)).toFixed(2)}MB)`,
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(
|
||||||
|
danger(
|
||||||
|
`Failed sending web media to ${msg.from}: ${String(err)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (replyResult.text) {
|
||||||
|
await msg.reply(replyResult.text);
|
||||||
|
logInfo(
|
||||||
|
`⚠️ Media skipped; sent text-only to ${msg.from}`,
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await msg.reply(replyResult.text ?? "");
|
await msg.reply(replyResult.text ?? "");
|
||||||
}
|
}
|
||||||
@@ -523,6 +552,7 @@ async function downloadInboundMedia(
|
|||||||
async function loadWebMedia(
|
async function loadWebMedia(
|
||||||
mediaUrl: string,
|
mediaUrl: string,
|
||||||
): Promise<{ buffer: Buffer; contentType?: string }> {
|
): Promise<{ buffer: Buffer; contentType?: string }> {
|
||||||
|
const MAX_WEB_BYTES = 16 * 1024 * 1024; // 16MB: web provider can handle larger than Twilio
|
||||||
if (mediaUrl.startsWith("file://")) {
|
if (mediaUrl.startsWith("file://")) {
|
||||||
mediaUrl = mediaUrl.replace("file://", "");
|
mediaUrl = mediaUrl.replace("file://", "");
|
||||||
}
|
}
|
||||||
@@ -532,15 +562,25 @@ async function loadWebMedia(
|
|||||||
throw new Error(`Failed to fetch media: HTTP ${res.status}`);
|
throw new Error(`Failed to fetch media: HTTP ${res.status}`);
|
||||||
}
|
}
|
||||||
const array = Buffer.from(await res.arrayBuffer());
|
const array = Buffer.from(await res.arrayBuffer());
|
||||||
if (array.length > 5 * 1024 * 1024) {
|
if (array.length > MAX_WEB_BYTES) {
|
||||||
throw new Error("Media exceeds 5MB limit");
|
throw new Error(
|
||||||
|
`Media exceeds ${Math.floor(MAX_WEB_BYTES / (1024 * 1024))}MB limit (got ${(
|
||||||
|
array.length /
|
||||||
|
(1024 * 1024)
|
||||||
|
).toFixed(1)}MB)`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return { buffer: array, contentType: res.headers.get("content-type") ?? undefined };
|
return { buffer: array, contentType: res.headers.get("content-type") ?? undefined };
|
||||||
}
|
}
|
||||||
// Local path
|
// Local path
|
||||||
const data = await fs.readFile(mediaUrl);
|
const data = await fs.readFile(mediaUrl);
|
||||||
if (data.length > 5 * 1024 * 1024) {
|
if (data.length > MAX_WEB_BYTES) {
|
||||||
throw new Error("Media exceeds 5MB limit");
|
throw new Error(
|
||||||
|
`Media exceeds ${Math.floor(MAX_WEB_BYTES / (1024 * 1024))}MB limit (got ${(
|
||||||
|
data.length /
|
||||||
|
(1024 * 1024)
|
||||||
|
).toFixed(1)}MB)`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return { buffer: data };
|
return { buffer: data };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user