

























@@ -1,5 +1,10 @@
11import { describe, expect, it } from "vitest";
2-import { normalizeWebhookMessage, normalizeWebhookReaction } from "./monitor-normalize.js";
2+import {
3+buildMessagePlaceholder,
4+isBlueBubblesAudioAttachment,
5+normalizeWebhookMessage,
6+normalizeWebhookReaction,
7+} from "./monitor-normalize.js";
3849function createFallbackDmPayload(overrides: Record<string, unknown> = {}) {
510return {
@@ -140,3 +145,62 @@ describe("normalizeWebhookReaction", () => {
140145expect(result?.action).toBe("added");
141146});
142147});
148+149+describe("isBlueBubblesAudioAttachment", () => {
150+it("detects audio by `audio/*` MIME type", () => {
151+expect(isBlueBubblesAudioAttachment({ mimeType: "audio/x-m4a" })).toBe(true);
152+expect(isBlueBubblesAudioAttachment({ mimeType: "audio/mp4" })).toBe(true);
153+});
154+155+it("detects audio by Apple UTI even when MIME is missing", () => {
156+expect(isBlueBubblesAudioAttachment({ uti: "public.audio" })).toBe(true);
157+expect(isBlueBubblesAudioAttachment({ uti: "public.mpeg-4-audio" })).toBe(true);
158+expect(isBlueBubblesAudioAttachment({ uti: "com.apple.m4a-audio" })).toBe(true);
159+expect(isBlueBubblesAudioAttachment({ uti: "com.apple.coreaudio-format" })).toBe(true);
160+});
161+162+it("treats UTI matching as case-insensitive", () => {
163+expect(isBlueBubblesAudioAttachment({ uti: "Public.Audio" })).toBe(true);
164+});
165+166+it("returns false for image / video / unknown attachments", () => {
167+expect(isBlueBubblesAudioAttachment({ mimeType: "image/jpeg" })).toBe(false);
168+expect(isBlueBubblesAudioAttachment({ mimeType: "video/quicktime" })).toBe(false);
169+expect(isBlueBubblesAudioAttachment({ uti: "public.jpeg" })).toBe(false);
170+expect(isBlueBubblesAudioAttachment({})).toBe(false);
171+});
172+});
173+174+describe("buildMessagePlaceholder audio detection", () => {
175+function makeMsg(attachments: Array<{ mimeType?: string; uti?: string }>) {
176+return {
177+text: "",
178+senderId: "+15551234567",
179+senderIdExplicit: false,
180+isGroup: false,
181+ attachments,
182+} as Parameters<typeof buildMessagePlaceholder>[0];
183+}
184+185+it("emits <media:audio> for `audio/*` MIME (existing behavior)", () => {
186+expect(buildMessagePlaceholder(makeMsg([{ mimeType: "audio/x-m4a" }]))).toContain(
187+"<media:audio>",
188+);
189+});
190+191+it("emits <media:audio> for Apple `public.audio` UTI when MIME is missing", () => {
192+expect(buildMessagePlaceholder(makeMsg([{ uti: "public.audio" }]))).toContain("<media:audio>");
193+});
194+195+it("emits <media:audio> for Apple `com.apple.m4a-audio` UTI", () => {
196+expect(buildMessagePlaceholder(makeMsg([{ uti: "com.apple.m4a-audio" }]))).toContain(
197+"<media:audio>",
198+);
199+});
200+201+it("falls back to <media:attachment> for non-audio mixes", () => {
202+expect(
203+buildMessagePlaceholder(makeMsg([{ uti: "public.audio" }, { mimeType: "image/jpeg" }])),
204+).toContain("<media:attachment>");
205+});
206+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。