import Auth from "./src/helpers/auth"; import Utils from "./src/helpers/utils"; import { utimes } from "fs/promises"; const auth = await Auth() const utils = new Utils(auth); await utils.init() Bun.serve({ routes: { "/api/track/:id": async req => { const trackId = parseInt(req.params.id) const flac = Bun.file(`downloaded/${trackId}.flac`) if (await flac.exists()) { return new Response(flac, { headers: { "Content-Type": "audio/flac", //"Content-Disposition": `attachment; filename="${trackId}.flac"`, "Cache-Control": "public, max-age=31536000", "ETag": trackId.toString(), } }) } const m4a = Bun.file(`downloaded/${trackId}.m4a`) if (await m4a.exists()) { return new Response(m4a, { headers: { "Content-Type": "audio/m4a", //"Content-Disposition": `attachment; filename="${trackId}.m4a"`, "Cache-Control": "public, max-age=31536000", "ETag": trackId.toString(), } }) } const { manifestMimeType, manifest } = await utils.fetchTrack(trackId) const audio = await utils.downloadFlac(manifestMimeType, manifest); if (audio.mimeType === "audio/flac") { audio.buffer = Buffer.from(await utils.tagFlac(trackId, audio.buffer)) await Bun.write(`downloaded/${trackId}.flac`, audio.buffer) } else if (audio.mimeType === "audio/m4a") { await Bun.write(`downloaded/${trackId}.m4a`, audio.buffer) } return new Response(audio.buffer, { headers: { "Content-Type": audio.mimeType, "Cache-Control": "public, max-age=31536000", "ETag": trackId.toString(), } }) }, "/api/@me/tracks": async () => { const tracks = await utils.fetchTracks(); return new Response(Bun.gzipSync(JSON.stringify(tracks)), { headers: { "Content-Type": "application/json", "Content-Encoding": "gzip", } }) } }, development: true, idleTimeout: 255 }) const tracks = await utils.fetchTracks() as { limit: number, offset: number, totalNumberOfItems: number, items: { created: string, item: { id: string title: string duration: number, // in seconds replayGain: number, peak: number, allowStreaming: boolean, streamReady: boolean, payToStream: boolean, adSupportedStreamReady: boolean, djReady: boolean, stemReady: boolean, streamStartDate: string, premiumStreamingOnly: boolean, trackNumber: number, volumeNumber: number, // discNumber version: null, // ? popularity: number, copyright: string, bpm: null, // think this is only provided to DJ users url: string, isrc: string, editable: boolean, explicit: boolean, audioQuality: string, audioModes: "STEREO"[], // todo find other modes mediaMetadata: { tags: "LOSSLESS"[], // todo find other tags }, upload: boolean, // was uploaded by a user artist: { id: number, name: string, handle: null, // ? type: "MAIN", // todo find other types picture: string, }, artists: [ { id: number, name: string, handle: null, type: "MAIN", picture: string, } ], album: { id: number, title: string, cover: string, vibrantColor: string, videoCover: null, }, mixes: { TRACK_MIX: string, }, } }[] }; /* Remove all tracks that are unavailable for (const track of tracks.items) { if (track.item.streamReady) { continue } await utils.fetch("/users/199235629/favorites/tracks/" + track.item.id, { method: "DELETE", }) console.log("Removed from favorites", track.item.id) } */ /* function findDuplicateTracksByName(tracks: typeof tracks.items) { const seen = new Map(); for (const trackObj of tracks) { const title = trackObj.item.title; const normalized = title.trim().toLowerCase(); if (!seen.has(normalized)) { seen.set(normalized, { count: 1, originals: [trackObj] }); } else { const entry = seen.get(normalized)!; entry.count++; entry.originals.push(trackObj); } } // Filter to only include titles with duplicates return Array.from(seen.entries()) .filter(([_, v]) => v.count > 1) .map(([normalizedTitle, data]) => ({ normalizedTitle, count: data.count, duplicates: data.originals, })); } function findDuplicateTracksByISRC(tracks: typeof tracks.items) { const seen = new Map(); for (const trackObj of tracks) { const isrc = trackObj.item.isrc; // Skip if ISRC is missing or empty if (!isrc) continue; if (!seen.has(isrc)) { seen.set(isrc, { count: 1, originals: [trackObj] }); } else { const entry = seen.get(isrc)!; entry.count++; entry.originals.push(trackObj); } } // Only return those with duplicates return Array.from(seen.entries()) .filter(([_, v]) => v.count > 1) .map(([isrc, data]) => ({ name: data.originals[0].item.title, isrc, count: data.count, duplicates: data.originals, })); } */ /* // Usage: const duplicatesByISRC = findDuplicateTracksByISRC(tracks.items); duplicatesByISRC.forEach(({ name, isrc, count, duplicates }) => { console.log(`Name: ${name} ISRC: "${isrc}" - Count: ${count}`); duplicates.forEach((trackObj) => { //console.log(` - Track ID: ${trackObj.item.id}, Created: ${trackObj.created}`); }); }); */ /* // Usage: const duplicates = findDuplicateTracksByName(tracks.items); console.log("Duplicate tracks:"); duplicates.forEach(({ normalizedTitle, count, duplicates }) => { console.log(`Title: "${normalizedTitle}" - Count: ${count}`); duplicates.forEach((trackObj) => { //console.log(` - Track ID: ${trackObj.item.id}, Created: ${trackObj.created}`); }); }); */ let i = 1; for await (const track of tracks.items) { const { id } = track.item const createdAt = new Date(track.created) const trackId = parseInt(id) if (await Bun.file(`downloaded/${trackId}.flac`).exists() || await Bun.file(`downloaded/${trackId}.m4a`).exists() || await Bun.file(`downloaded/${trackId}.unknown`).exists()) { //console.log(`Already downloaded ${trackId}.flac`) i++; continue } const trackData = await utils.fetchTrack(trackId) if (trackData?.status === 404 || trackData === null) { console.error(`track ${trackId} not available`) i++; continue } try { const audio = await utils.downloadFlac(trackData.manifestMimeType, trackData.manifest) const format = audio.mimeType.split("/")[1]; const name = `downloaded/${trackId}.${format}` if (audio.mimeType === "audio/flac") { const taggedAudio = await utils.tagFlac(trackId, audio.buffer) await Bun.write(name, taggedAudio) } else { await Bun.write(name, audio.buffer) } await utimes(name, createdAt, createdAt) //console.log(`Downloaded ${trackId}.flac`) } catch (e) { console.error(`Failed to download ${trackId}.flac`, e) } console.log(`Downloaded track ${i} of ${tracks.items.length}`) i++; } console.log("Done")