fix(replies): normalize media path variants for dedupe

Co-authored-by: Ho Lim <subhoya@gmail.com>
This commit is contained in:
Peter Steinberger
2026-02-22 19:33:10 +01:00
parent 0342bed289
commit 95d7b0bbe1
3 changed files with 39 additions and 3 deletions

View File

@@ -58,4 +58,20 @@ describe("filterMessagingToolMediaDuplicates", () => {
});
expect(result).toBe(payloads);
});
it("dedupes equivalent file and local path variants", () => {
const result = filterMessagingToolMediaDuplicates({
payloads: [{ text: "hello", mediaUrl: "/tmp/photo.jpg" }],
sentMediaUrls: ["file:///tmp/photo.jpg"],
});
expect(result).toEqual([{ text: "hello", mediaUrl: undefined, mediaUrls: undefined }]);
});
it("dedupes encoded file:// paths against local paths", () => {
const result = filterMessagingToolMediaDuplicates({
payloads: [{ text: "hello", mediaUrl: "/tmp/photo one.jpg" }],
sentMediaUrls: ["file:///tmp/photo%20one.jpg"],
});
expect(result).toEqual([{ text: "hello", mediaUrl: undefined, mediaUrls: undefined }]);
});
});

View File

@@ -100,16 +100,35 @@ export function filterMessagingToolMediaDuplicates(params: {
payloads: ReplyPayload[];
sentMediaUrls: string[];
}): ReplyPayload[] {
const normalizeMediaForDedupe = (value: string): string => {
const trimmed = value.trim();
if (!trimmed) {
return "";
}
if (!trimmed.toLowerCase().startsWith("file://")) {
return trimmed;
}
try {
const parsed = new URL(trimmed);
if (parsed.protocol === "file:") {
return decodeURIComponent(parsed.pathname || "");
}
} catch {
// Keep fallback below for non-URL-like inputs.
}
return trimmed.replace(/^file:\/\//i, "");
};
const { payloads, sentMediaUrls } = params;
if (sentMediaUrls.length === 0) {
return payloads;
}
const sentSet = new Set(sentMediaUrls);
const sentSet = new Set(sentMediaUrls.map(normalizeMediaForDedupe).filter(Boolean));
return payloads.map((payload) => {
const mediaUrl = payload.mediaUrl;
const mediaUrls = payload.mediaUrls;
const stripSingle = mediaUrl && sentSet.has(mediaUrl);
const filteredUrls = mediaUrls?.filter((u) => !sentSet.has(u));
const stripSingle = mediaUrl && sentSet.has(normalizeMediaForDedupe(mediaUrl));
const filteredUrls = mediaUrls?.filter((u) => !sentSet.has(normalizeMediaForDedupe(u)));
if (!stripSingle && (!mediaUrls || filteredUrls?.length === mediaUrls.length)) {
return payload; // No change
}