Skip to content

Commit b98472e

Browse files
pratikbuildsTheGreatAxios
authored andcommitted
fix(conversation): read a .ts file sent as a transport stream as text
mediaKindOf let any video/* media type win over the extension. Servers and desktop browsers report a TypeScript file as an MPEG transport stream (video/mp2t, or video/vnd.dlna.mpeg-tts on Windows), since both use .ts, so index.ts read as video and previewed as a broken player. Those two types now defer to the extension, and stay video when the name has no known extension.
1 parent cb5170a commit b98472e

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

‎src/lib/media-kind.test.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ describe("mediaKindOf", () => {
1717
expect(mediaKindOf("clip.pdf", "video/webm")).toBe("video");
1818
});
1919

20+
test("a transport stream media type defers to the extension", () => {
21+
expect(mediaKindOf("index.ts", "video/mp2t")).toBe("text");
22+
expect(mediaKindOf("index.ts", "Video/MP2T; x=1")).toBe("text");
23+
expect(mediaKindOf("index.ts", "video/vnd.dlna.mpeg-tts")).toBe("text");
24+
expect(mediaKindOf("capture", "video/mp2t")).toBe("video");
25+
expect(mediaKindOf("capture.m2ts", "video/mp2t")).toBe("video");
26+
});
27+
2028
test("ignores media type parameters and case", () => {
2129
expect(mediaKindOf("a", "Text/Plain; charset=utf-8")).toBe("text");
2230
});

‎src/lib/media-kind.ts‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,27 @@ const TEXT_MEDIA_TYPES: ReadonlySet<string> = new Set([
7474
"application/yaml",
7575
]);
7676

77+
/**
78+
* MPEG transport stream types. They share `.ts` with TypeScript, and servers
79+
* and desktop browsers report them for a TypeScript file, so the name decides.
80+
*/
81+
const TRANSPORT_STREAM_TYPES: ReadonlySet<string> = new Set([
82+
"video/mp2t",
83+
"video/vnd.dlna.mpeg-tts",
84+
]);
85+
7786
function table(
7887
kind: MediaKind,
7988
extensions: readonly string[],
8089
): readonly (readonly [string, MediaKind])[] {
8190
return extensions.map((extension) => [extension, kind] as const);
8291
}
8392

84-
function kindOfMediaType(mediaType: string): MediaKind | null {
85-
const essence = mediaType.split(";")[0]?.trim().toLowerCase() ?? "";
93+
function essenceOf(mediaType: string): string {
94+
return mediaType.split(";")[0]?.trim().toLowerCase() ?? "";
95+
}
96+
97+
function kindOfMediaType(essence: string): MediaKind | null {
8698
if (essence.startsWith("image/")) return "image";
8799
if (essence.startsWith("video/")) return "video";
88100
if (essence.startsWith("audio/")) return "audio";
@@ -103,9 +115,13 @@ function kindOfName(name: string): MediaKind | null {
103115
/**
104116
* A file's kind from its name and media type. A media type that names a kind
105117
* wins; a blank or generic one (`application/octet-stream`) defers to the
106-
* name's extension, matched case-insensitively. Anything unrecognised is
107-
* `other`.
118+
* name's extension, matched case-insensitively. An MPEG transport stream
119+
* type (`video/mp2t`) also defers to the extension, since a TypeScript file
120+
* shares `.ts` and often arrives with it, and is `video` when the extension
121+
* says nothing. Anything unrecognised is `other`.
108122
*/
109123
export function mediaKindOf(name: string, mediaType: string): MediaKind {
110-
return kindOfMediaType(mediaType) ?? kindOfName(name) ?? "other";
124+
const essence = essenceOf(mediaType);
125+
if (TRANSPORT_STREAM_TYPES.has(essence)) return kindOfName(name) ?? "video";
126+
return kindOfMediaType(essence) ?? kindOfName(name) ?? "other";
111127
}

0 commit comments

Comments
 (0)