Experiment to rebuild Diffuse using web applets.
1import { parseBlob, parseFromTokenizer, parseWebStream } from "music-metadata";
2import * as URI from "uri-js";
3import * as HTTP_TOKENIZER from "@tokenizer/http";
4import * as RANGE_TOKENIZER from "@tokenizer/range";
5
6import type { TrackStats, TrackTags } from "@applets/core/types";
7import type { Extraction, Urls } from "./types";
8
9// 🛠️
10
11export async function musicMetadataTags({
12 includeArtwork,
13 mimeType,
14 stream,
15 urls,
16}: {
17 includeArtwork?: boolean;
18 mimeType?: string;
19 stream?: ReadableStream;
20 urls?: Urls;
21}): Promise<Extraction> {
22 const uri = urls ? URI.parse(urls.get) : undefined;
23 const pathParts = uri?.path?.split("/");
24 const filename = pathParts?.[pathParts.length - 1];
25
26 let meta;
27
28 if (urls?.get.startsWith("blob:")) {
29 const blob = await fetch(urls.get).then((r) => r.blob());
30 meta = await parseBlob(blob, { skipCovers: !includeArtwork });
31 } else if (urls) {
32 const httpClient = new HTTP_TOKENIZER.HttpClient(urls.head, { resolveUrl: false });
33 httpClient.resolvedUrl = urls.get;
34 const getHeadInfo = httpClient.getHeadInfo;
35
36 // FUCKAROUND: Not sure of the downsides of this
37 httpClient.getHeadInfo = async () => {
38 const info = await getHeadInfo.call(httpClient);
39 return { ...info, acceptPartialRequests: true };
40 };
41
42 const tokenizer = await RANGE_TOKENIZER.tokenizer(httpClient);
43
44 meta = await parseFromTokenizer(tokenizer, { skipCovers: !includeArtwork });
45 } else if (stream) {
46 meta = await parseWebStream(stream, { mimeType }, { skipCovers: !includeArtwork });
47 } else {
48 throw new Error("Missing args, need either some urls or a stream.");
49 }
50
51 const stats: TrackStats = {
52 duration: meta.format.duration,
53 };
54
55 const tags: TrackTags = {
56 album: meta.common.album,
57 artist: meta.common.artist,
58 disc: { no: meta.common.disk.no || 1, of: meta.common.disk.of ?? undefined },
59 genre: Array.isArray(meta.common.genre) ? meta.common.genre[0] : meta.common.genre,
60 title: meta.common.title || filename || urls?.head || "Unknown",
61 track: { no: meta.common.track.no || 1, of: meta.common.track.of ?? undefined },
62 year: meta.common.year,
63 };
64
65 return {
66 artwork: includeArtwork ? meta.common.picture : undefined,
67 stats,
68 tags,
69 };
70}