104 lines
3.3 KiB
TypeScript
104 lines
3.3 KiB
TypeScript
import Auth from "./src/helpers/auth";
|
|
import Utils from "./src/helpers/utils";
|
|
import { utimes } from "fs/promises";
|
|
|
|
const utils = new Utils(await Auth());
|
|
|
|
Bun.serve({
|
|
routes: {
|
|
"/api/track/:id": async req => {
|
|
const trackId = parseInt(req.params.id)
|
|
|
|
const file = Bun.file(`downloaded/${trackId}.flac`)
|
|
|
|
if (await file.exists()) {
|
|
return new Response(await file.arrayBuffer(), {
|
|
headers: {
|
|
"Content-Type": "audio/flac",
|
|
"Content-Disposition": `attachment; filename="${trackId}.flac"`,
|
|
"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)
|
|
|
|
return new Response(audio.buffer, {
|
|
headers: {
|
|
"Content-Type": audio.mimeType,
|
|
//"Content-Disposition": `attachment; filename="${trackId}.flac"`,
|
|
"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
|
|
})
|
|
|
|
const tracks = await utils.fetchTracks();
|
|
|
|
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)
|
|
}
|
|
|
|
// Downloaded track 1 of 10, etc
|
|
|
|
console.log(`Downloaded track ${i} of ${tracks.items.length}`)
|
|
i++;
|
|
}
|
|
|
|
console.log("Done")
|