Add bun-storage dependency and refactor localStorage implementation

This commit is contained in:
Seth 2025-05-10 23:33:16 -04:00
parent e0516864ed
commit 387785df7a
7 changed files with 59 additions and 56 deletions

View file

@ -6,6 +6,7 @@
"dependencies": {
"@tidal-music/auth": "^1.3.4",
"@types/fluent-ffmpeg": "^2.1.27",
"bun-storage": "^0.2.1",
"dasha": "3",
"ffmpeg-static": "^5.2.0",
"flac-stream-tagger": "^1.0.10",
@ -41,6 +42,8 @@
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"bun-storage": ["bun-storage@0.2.1", "", {}, "sha512-yEgiKZ38eI8v4KO7mQcsRR7suCv+ZVQmM1uETyWc0CRQgJ8vZqyY6AbQCqlLfQ41EBOHiDvHhTxy3EquZomyZg=="],
"bun-types": ["bun-types@1.2.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-tvWMx5vPqbRXgE8WUZI94iS1xAYs8bkqESR9cxBB1Wi+urvfTrF1uzuDgBHFAdO0+d2lmsbG3HmeKMvUyj6pWA=="],
"caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="],

View file

@ -2,7 +2,11 @@ import Auth from "./src/helpers/auth";
import Utils from "./src/helpers/utils";
import { utimes } from "fs/promises";
const utils = new Utils(await Auth());
const auth = await Auth()
const utils = new Utils(auth);
await utils.init()
Bun.serve({
routes: {
@ -53,7 +57,7 @@ Bun.serve({
},
development: true
})
/*
const tracks = await utils.fetchTracks();
let i = 1;
@ -102,3 +106,4 @@ for await (const track of tracks.items) {
}
console.log("Done")
*/

BIN
localStorage.sqlite Normal file

Binary file not shown.

View file

@ -10,6 +10,7 @@
"dependencies": {
"@tidal-music/auth": "^1.3.4",
"@types/fluent-ffmpeg": "^2.1.27",
"bun-storage": "^0.2.1",
"dasha": "3",
"ffmpeg-static": "^5.2.0",
"flac-stream-tagger": "^1.0.10",

View file

@ -1,29 +1,5 @@
const database = Bun.file('localStorage.json');
import { createLocalStorage } from "bun-storage";
if (!await database.exists()) {
await Bun.write(database, JSON.stringify({}));
}
const [localStorage, emitter] = createLocalStorage("./localStorage.sqlite");
let data = {};
data = await database.json() || {};
globalThis.localStorage = {
getItem: (key) => {
return data[key] || null;
},
setItem: (key, value) => {
data[key] = value;
Bun.write(database, JSON.stringify(data));
},
removeItem: (key) => {
delete data[key];
Bun.write(database, JSON.stringify(data));
},
clear: () => {
data = {};
Bun.write(database, JSON.stringify(data));
}
};
export { }
globalThis.localStorage = localStorage;

View file

@ -10,23 +10,55 @@ Ffmpeg.setFfmpegPath(ffmpegPath as string);
export default class {
private _authHeaders: { [key: string]: string }
private _userId: number;
private _userId: string | undefined;
private _userCountry: string;
private _userLocale: string;
constructor(authHeaders: { [key: string]: string }) {
this._authHeaders = authHeaders
this._userId = 0;
this._authHeaders = authHeaders;
this._userCountry = "WW"; // Default to Worldwide
this._userLocale = (process.env.LC_ALL ||
process.env.LANG ||
process.env.LANGUAGE ||
Intl.DateTimeFormat().resolvedOptions().locale ||
"en_US").replaceAll("-", "_").split(".")[0];
}
async fetch(url: string) {
const parsedUrl = new URL(`https://desktop.tidal.com/v1${url}`);
parsedUrl.searchParams.set("countryCode", this._userCountry);
parsedUrl.searchParams.set("locale", this._userLocale);
parsedUrl.searchParams.set("deviceType", "DESKTOP");
const response = await fetch(parsedUrl, {
headers: {
...this._authHeaders,
"x-tidal-token": "mhPVJJEBNRzVjr2p",
},
referrer: "https://desktop.tidal.com/",
})
if (!response.ok) {
throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`)
}
return await response.json() as Object;
}
async init() {
const { token } = await credentialsProvider.getCredentials() as { token: string };
this._userId = JSON.parse(Buffer.from(token, "base64").toString("utf-8")).uid;
}
async fetchTrack(id: number) {
const audio = await fetch(`https://desktop.tidal.com/v1/tracks/${id}/playbackinfo?audioquality=HI_RES_LOSSLESS&playbackmode=STREAM&assetpresentation=FULL`, {
headers: this._authHeaders
})
const creds = await credentialsProvider.getCredentials()
return await audio.json() as {
this._userId = creds.userId
const { countryCode } = await this.fetch("/country") as { countryCode: string }
this._userCountry = countryCode;
}
async fetchTrack(id: number) {
const audio = await this.fetch(`/tracks/${id}/playbackinfo?audioquality=HI_RES_LOSSLESS&playbackmode=STREAM&assetpresentation=FULL`)
return audio as {
trackId: number,
audioPresentation: string,
audioMode: string,
@ -45,11 +77,9 @@ export default class {
}
async fetchTracks() {
const tracks = await fetch(`https://desktop.tidal.com/v1/users/${this._userId}/favorites/tracks?offset=0&limit=10000&order=DATE&orderDirection=DESC&countryCode=US&locale=en_US&deviceType=DESKTOP`, {
headers: this._authHeaders
})
const tracks = await this.fetch(`/users/${this._userId}/favorites/tracks?offset=0&limit=10000&order=DATE&orderDirection=DESC`);
return await tracks.json();
return tracks;
}
async downloadFlac(manifestMimeType: string, manifest: string) {

12
tmp.ts
View file

@ -1,12 +0,0 @@
Bun.serve({
routes: {
"/test.mpd": async () => {
return new Response(Bun.file("tmp/fpwp4o.mpd"), {
headers: {
// cors allow all
"Access-Control-Allow-Origin": "*",
}
})
},
}
})