Refactor authentication and utility functions for improved handling of audio formats and API responses
This commit is contained in:
parent
d055deec29
commit
5325bbc34a
3 changed files with 27 additions and 23 deletions
17
index.ts
17
index.ts
|
@ -9,7 +9,7 @@ Bun.serve({
|
|||
"/api/track/:id": async req => {
|
||||
const trackId = parseInt(req.params.id)
|
||||
|
||||
/*const file = Bun.file(`downloaded/${trackId}.flac`)
|
||||
const file = Bun.file(`downloaded/${trackId}.flac`)
|
||||
|
||||
if (await file.exists()) {
|
||||
return new Response(await file.arrayBuffer(), {
|
||||
|
@ -20,7 +20,7 @@ Bun.serve({
|
|||
"ETag": trackId.toString(),
|
||||
}
|
||||
})
|
||||
}*/
|
||||
}
|
||||
|
||||
const { manifestMimeType, manifest } = await utils.fetchTrack(trackId)
|
||||
|
||||
|
@ -50,9 +50,7 @@ Bun.serve({
|
|||
},
|
||||
development: true
|
||||
})
|
||||
|
||||
/*
|
||||
|
||||
const tracks = await utils.fetchTracks();
|
||||
|
||||
for await (const track of tracks.items) {
|
||||
|
@ -67,15 +65,18 @@ for await (const track of tracks.items) {
|
|||
}
|
||||
|
||||
const trackData = await utils.fetchTrack(parseInt(id))
|
||||
|
||||
if (trackData?.status === 404 || trackData === null) {
|
||||
console.error(`track ${trackId} not available`)
|
||||
continue
|
||||
}
|
||||
try {
|
||||
const audio = await utils.tagFlac(trackId, await utils.downloadFlac(trackData.manifestMimeType, trackData.manifest))
|
||||
|
||||
await Bun.write(`downloaded/${trackId}.flac`, audio)
|
||||
await utimes(`downloaded/${trackId}.flac`, createdAt, createdAt)
|
||||
//await Bun.write(`downloaded/${trackId}.flac`, audio)
|
||||
//await utimes(`downloaded/${trackId}.flac`, createdAt, createdAt)
|
||||
//console.log(`Downloaded ${trackId}.flac`)
|
||||
} catch (e) {
|
||||
console.error(`Failed to download ${trackId}.flac`)
|
||||
console.error(`Failed to download ${trackId}.flac`, e)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
import "./localStorage";
|
||||
|
||||
import { init, initializeDeviceLogin, finalizeDeviceLogin, credentialsProvider } from "@tidal-music/auth";
|
||||
import { init, initializeLogin, finalizeLogin, credentialsProvider } from "@tidal-music/auth";
|
||||
|
||||
const clientId = "zU4XHVVkc2tDPo4t";
|
||||
const clientSecret = "VJKhDFqJPqvsPVNBV6ukXTJmwlvbttP7wlMlrc72se4=";
|
||||
const clientId = "mhPVJJEBNRzVjr2p";
|
||||
|
||||
export default async () => {
|
||||
await init({
|
||||
clientId,
|
||||
clientSecret,
|
||||
credentialsStorageKey: "tidal-credentials",
|
||||
scopes: ["r_usr", "w_usr", "w_sub"],
|
||||
scopes: ["r_usr", "w_usr"],
|
||||
})
|
||||
|
||||
const credentials = await credentialsProvider.getCredentials();
|
||||
|
||||
if (typeof credentials.userId !== "string" || (credentials.expires || 0) < Date.now()) {
|
||||
|
||||
const response = await initializeDeviceLogin();
|
||||
const response = await initializeLogin({
|
||||
redirectUri: "https://desktop.tidal.com/login/auth"
|
||||
});
|
||||
|
||||
console.log(`Please open https://${response.verificationUriComplete} to login.`)
|
||||
console.log(`Please open ${response} to login.`)
|
||||
|
||||
await finalizeDeviceLogin();
|
||||
await finalizeLogin(new URL(prompt("Enter the URL you were redirected to: ") || "").search)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -14,9 +14,9 @@ export default class {
|
|||
this.authHeaders = authHeaders
|
||||
}
|
||||
|
||||
async convertAacToFlac(buffer: ArrayBuffer) {
|
||||
async convertAacToFlac(buffer: Buffer<ArrayBuffer> | ArrayBuffer) {
|
||||
const inputStream = new PassThrough();
|
||||
inputStream.end(Buffer.from(buffer));
|
||||
inputStream.end(Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer));
|
||||
|
||||
const outputChunks: Buffer[] = [];
|
||||
|
||||
|
@ -52,10 +52,12 @@ export default class {
|
|||
}
|
||||
|
||||
async fetchTrack(id: number) {
|
||||
const audio = await fetch(`https://api.tidal.com/v1/tracks/${id}/playbackinfopostpaywall/v4?audioquality=HI_RES_LOSSLESS&playbackmode=STREAM&assetpresentation=FULL`, {
|
||||
const audio = await fetch(`https://desktop.tidal.com/v1/tracks/${id}/playbackinfo?audioquality=HI_RES_LOSSLESS&playbackmode=STREAM&assetpresentation=FULL`, {
|
||||
headers: this.authHeaders
|
||||
})
|
||||
|
||||
console.log(await audio.text())
|
||||
|
||||
return await audio.json() as {
|
||||
trackId: number,
|
||||
audioPresentation: string,
|
||||
|
@ -70,6 +72,7 @@ export default class {
|
|||
trackPeakAmplitude: number,
|
||||
bitDepth: number,
|
||||
sampleRate: number,
|
||||
status?: number,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,6 @@ export default class {
|
|||
}
|
||||
|
||||
async downloadFlac(manifestMimeType: string, manifest: string) {
|
||||
const id = Bun.nanoseconds().toString(36);
|
||||
if (manifestMimeType === "application/dash+xml") {
|
||||
const mpd = new DashMPD();
|
||||
mpd.parse(Buffer.from(manifest, "base64").toString("utf-8"))
|
||||
|
@ -124,11 +126,11 @@ export default class {
|
|||
return { buffer: new ArrayBuffer(0), mimeType: "" } // TODO: Handle other mime types
|
||||
}
|
||||
|
||||
async tagFlac(id: number, audioBuffer: { buffer: ArrayBuffer, mimeType: string }) {
|
||||
async tagFlac(id: number, audioBuffer: { buffer: Buffer<ArrayBuffer> | ArrayBuffer, mimeType: string }) {
|
||||
const fileId = Bun.nanoseconds().toString(36);
|
||||
|
||||
if (audioBuffer.mimeType === "audio/mp4") {
|
||||
audioBuffer.buffer = await this.convertAacToFlac(audioBuffer.buffer) as ArrayBuffer;
|
||||
audioBuffer.buffer = await this.convertAacToFlac(audioBuffer.buffer);
|
||||
}
|
||||
|
||||
const trackReq = await fetch(`https://api.tidal.com/v1/tracks/${id}/?countryCode=US`, {
|
||||
|
@ -156,6 +158,7 @@ export default class {
|
|||
title: string,
|
||||
cover: string,
|
||||
},
|
||||
status?: string,
|
||||
};
|
||||
|
||||
const alubmReq = await fetch(`https://api.tidal.com/v1/albums/${track.album.id}/?countryCode=US`, {
|
||||
|
@ -175,7 +178,7 @@ export default class {
|
|||
],
|
||||
}
|
||||
|
||||
return FlacStreamTagger.fromBuffer(Buffer.from(audioBuffer.buffer), {
|
||||
return FlacStreamTagger.fromBuffer(Buffer.from(Buffer.isBuffer(audioBuffer.buffer) ? audioBuffer.buffer : Buffer.from(audioBuffer.buffer)), {
|
||||
tagMap: {
|
||||
title: track.title,
|
||||
trackNumber: track.trackNumber.toString(),
|
||||
|
|
Loading…
Add table
Reference in a new issue