A music player that connects to your cloud/distributed storage.
at v4 4.6 kB view raw
1import { parseBlob, parseFromTokenizer, parseWebStream } from "music-metadata"; 2import * as URI from "uri-js"; 3import { HttpClient } from "@tokenizer/http"; 4import { tokenizer as rangeTokenizer } from "@tokenizer/range"; 5 6/** 7 * @import { TrackStats, TrackTags } from "@definitions/types.d.ts"; 8 * @import { Extraction, Urls } from "./types.d.ts"; 9 */ 10 11// 🛠️ 12 13/** 14 * @param {{ includeArtwork?: boolean; mimeType?: string; stream?: ReadableStream; urls?: Urls; }} _ 15 * @returns {Promise<Extraction>} 16 */ 17export async function musicMetadataTags({ 18 includeArtwork, 19 mimeType, 20 stream, 21 urls, 22}) { 23 const uri = urls ? URI.parse(urls.get) : undefined; 24 const pathParts = uri?.path?.split("/"); 25 const filename = pathParts?.[pathParts.length - 1]; 26 27 let meta; 28 29 if (urls?.get.startsWith("blob:")) { 30 const blob = await fetch(urls.get).then((r) => r.blob()); 31 meta = await parseBlob(blob, { skipCovers: !includeArtwork }); 32 } else if (urls) { 33 const httpClient = new HttpClient(urls.head, { 34 resolveUrl: false, 35 }); 36 httpClient.resolvedUrl = urls.get; 37 const getHeadInfo = httpClient.getHeadInfo; 38 39 // FUCKAROUND: Not sure of the downsides of this 40 httpClient.getHeadInfo = async () => { 41 const info = await getHeadInfo.call(httpClient); 42 return { ...info, acceptPartialRequests: true }; 43 }; 44 45 /** @type {any} */ 46 const tokenizer = await rangeTokenizer(httpClient); 47 meta = await parseFromTokenizer(tokenizer, { skipCovers: !includeArtwork }); 48 } else if (stream) { 49 meta = await parseWebStream(stream, { mimeType }, { 50 skipCovers: !includeArtwork, 51 }); 52 } else { 53 throw new Error("Missing args, need either some urls or a stream."); 54 } 55 56 /** @type {TrackStats} */ 57 const stats = { 58 albumGain: meta.format.albumGain, 59 bitrate: meta.format.bitrate, 60 bitsPerSample: meta.format.bitsPerSample, 61 codec: meta.format.codec, 62 container: meta.format.container, 63 duration: meta.format.duration, 64 lossless: meta.format.lossless, 65 numberOfChannels: meta.format.numberOfChannels, 66 sampleRate: meta.format.sampleRate, 67 trackGain: meta.format.trackGain, 68 }; 69 70 /** @type {TrackTags} */ 71 const tags = { 72 album: meta.common.album, 73 albumartist: meta.common.albumartist, 74 albumartists: Array.isArray(meta.common.albumartist) 75 ? meta.common.albumartist 76 : (meta.common.albumartist ? [meta.common.albumartist] : undefined), 77 albumartistsort: meta.common.albumartistsort, 78 albumsort: meta.common.albumsort, 79 arranger: meta.common.arranger, 80 artist: meta.common.artist, 81 artists: meta.common.artists ?? 82 (meta.common.artist ? [meta.common.artist] : []), 83 artistsort: meta.common.artistsort, 84 asin: meta.common.asin, 85 averageLevel: meta.common.averageLevel, 86 barcode: meta.common.barcode, 87 bpm: meta.common.bpm, 88 catalognumbers: meta.common.catalognumber, 89 compilation: meta.common.compilation, 90 composers: meta.common.composer, 91 composersort: meta.common.composersort, 92 conductors: meta.common.conductor, 93 date: meta.common.date, 94 disc: { 95 no: meta.common.disk.no || 1, 96 of: meta.common.disk.of ?? undefined, 97 }, 98 djmixers: meta.common.djmixer, 99 engineers: meta.common.engineer, 100 gapless: meta.common.gapless, 101 genres: Array.isArray(meta.common.genre) 102 ? meta.common.genre 103 : meta.common.genre 104 ? [meta.common.genre] 105 : undefined, 106 isrc: meta.common.isrc, 107 labels: meta.common.label, 108 lyricists: meta.common.lyricist, 109 media: meta.common.media, 110 mixers: meta.common.mixer, 111 moods: Array.isArray(meta.common.mood) 112 ? meta.common.mood 113 : meta.common.mood 114 ? [meta.common.mood] 115 : undefined, 116 originaldate: meta.common.originaldate, 117 originalyear: meta.common.originalyear, 118 peakLevel: meta.common.peakLevel, 119 producers: meta.common.producer, 120 publishers: meta.common.publisher, 121 releasecountry: meta.common.releasecountry, 122 releasedate: meta.common.releasedate, 123 releasestatus: meta.common.releasestatus, 124 releasetypes: meta.common.releasetype, 125 remixers: meta.common.remixer, 126 technicians: meta.common.technician, 127 title: meta.common.title || filename || urls?.head || "Unknown", 128 titlesort: meta.common.titlesort, 129 track: { 130 no: meta.common.track.no || 1, 131 of: meta.common.track.of ?? undefined, 132 }, 133 work: meta.common.work, 134 writers: meta.common.writer, 135 year: meta.common.year, 136 }; 137 138 return { 139 artwork: includeArtwork ? meta.common.picture : undefined, 140 stats, 141 tags, 142 }; 143}