Experiment to rebuild Diffuse using web applets.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: artwork extraction via metadata processor

+31 -9
+24 -9
src/pages/processor/metadata-fetcher/_applet.astro
··· 1 1 <script> 2 - import { parseFromTokenizer, parseWebStream } from "music-metadata"; 2 + import { type IPicture, parseFromTokenizer, parseWebStream } from "music-metadata"; 3 3 import { contentType } from "@std/media-types"; 4 4 import * as URI from "uri-js"; 5 5 import * as HTTP_TOKENIZER from "@tokenizer/http"; ··· 13 13 //////////////////////////////////////////// 14 14 const context = register(); 15 15 16 - type Extraction = { stats: TrackStats; tags: TrackTags }; 16 + type Extraction = { artwork?: IPicture[]; stats: TrackStats; tags: TrackTags }; 17 17 type Urls = { get: string; head: string }; 18 18 19 19 //////////////////////////////////////////// ··· 21 21 //////////////////////////////////////////// 22 22 context.setActionHandler("extract", extract); 23 23 24 - async function extract(args: { mimeType?: string; stream?: ReadableStream; urls?: Urls }) { 24 + async function extract(args: { 25 + includeArtwork?: boolean; 26 + mimeType?: string; 27 + stream?: ReadableStream; 28 + urls?: Urls; 29 + }) { 25 30 // Construct records 26 31 // TODO: Use other metadata lib as fallback: https://github.com/buzz/mediainfo.js 27 - const { stats, tags } = await musicMetadataTags(args, false).catch(() => ({ 32 + const { stats, tags } = await musicMetadataTags(args).catch(() => ({ 28 33 stats: undefined, 29 34 tags: undefined, 30 35 })); ··· 33 38 return { stats, tags }; 34 39 } 35 40 41 + //////////////////////////////////////////// 36 42 // 🛠️ 37 - async function musicMetadataTags( 38 - { mimeType, stream, urls }: { mimeType?: string; stream?: ReadableStream; urls?: Urls }, 39 - covers: boolean = false, 40 - ): Promise<Extraction> { 43 + //////////////////////////////////////////// 44 + async function musicMetadataTags({ 45 + includeArtwork, 46 + mimeType, 47 + stream, 48 + urls, 49 + }: { 50 + includeArtwork?: boolean; 51 + mimeType?: string; 52 + stream?: ReadableStream; 53 + urls?: Urls; 54 + }): Promise<Extraction> { 41 55 const uri = urls ? URI.parse(urls.get) : undefined; 42 56 const pathParts = uri?.path?.split("/"); 43 57 const filename = pathParts?.[pathParts.length - 1]; ··· 59 73 60 74 const tokenizer = await RANGE_TOKENIZER.tokenizer(httpClient); 61 75 62 - meta = await parseFromTokenizer(tokenizer, { skipCovers: covers }); 76 + meta = await parseFromTokenizer(tokenizer, { skipCovers: !includeArtwork }); 63 77 } else if (stream) { 64 78 meta = await parseWebStream(stream, { mimeType }); 65 79 } else { ··· 81 95 }; 82 96 83 97 return { 98 + artwork: includeArtwork ? meta.common.picture : undefined, 84 99 stats, 85 100 tags, 86 101 };
+7
src/pages/processor/metadata-fetcher/_manifest.json
··· 9 9 "params_schema": { 10 10 "type": "object", 11 11 "properties": { 12 + "includeArtwork": { 13 + "type": "boolean", 14 + "description": "Include artwork in the output." 15 + }, 16 + "mimeType": { 17 + "type": "string" 18 + }, 12 19 "stream": { 13 20 "type": "object" 14 21 },