Add bun-storage dependency and refactor localStorage implementation
This commit is contained in:
parent
e0516864ed
commit
387785df7a
7 changed files with 59 additions and 56 deletions
3
bun.lock
3
bun.lock
|
@ -6,6 +6,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tidal-music/auth": "^1.3.4",
|
"@tidal-music/auth": "^1.3.4",
|
||||||
"@types/fluent-ffmpeg": "^2.1.27",
|
"@types/fluent-ffmpeg": "^2.1.27",
|
||||||
|
"bun-storage": "^0.2.1",
|
||||||
"dasha": "3",
|
"dasha": "3",
|
||||||
"ffmpeg-static": "^5.2.0",
|
"ffmpeg-static": "^5.2.0",
|
||||||
"flac-stream-tagger": "^1.0.10",
|
"flac-stream-tagger": "^1.0.10",
|
||||||
|
@ -41,6 +42,8 @@
|
||||||
|
|
||||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
"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=="],
|
"bun-types": ["bun-types@1.2.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-tvWMx5vPqbRXgE8WUZI94iS1xAYs8bkqESR9cxBB1Wi+urvfTrF1uzuDgBHFAdO0+d2lmsbG3HmeKMvUyj6pWA=="],
|
||||||
|
|
||||||
"caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="],
|
"caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="],
|
||||||
|
|
9
index.ts
9
index.ts
|
@ -2,7 +2,11 @@ import Auth from "./src/helpers/auth";
|
||||||
import Utils from "./src/helpers/utils";
|
import Utils from "./src/helpers/utils";
|
||||||
import { utimes } from "fs/promises";
|
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({
|
Bun.serve({
|
||||||
routes: {
|
routes: {
|
||||||
|
@ -53,7 +57,7 @@ Bun.serve({
|
||||||
},
|
},
|
||||||
development: true
|
development: true
|
||||||
})
|
})
|
||||||
|
/*
|
||||||
const tracks = await utils.fetchTracks();
|
const tracks = await utils.fetchTracks();
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
|
@ -102,3 +106,4 @@ for await (const track of tracks.items) {
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Done")
|
console.log("Done")
|
||||||
|
*/
|
BIN
localStorage.sqlite
Normal file
BIN
localStorage.sqlite
Normal file
Binary file not shown.
|
@ -10,6 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tidal-music/auth": "^1.3.4",
|
"@tidal-music/auth": "^1.3.4",
|
||||||
"@types/fluent-ffmpeg": "^2.1.27",
|
"@types/fluent-ffmpeg": "^2.1.27",
|
||||||
|
"bun-storage": "^0.2.1",
|
||||||
"dasha": "3",
|
"dasha": "3",
|
||||||
"ffmpeg-static": "^5.2.0",
|
"ffmpeg-static": "^5.2.0",
|
||||||
"flac-stream-tagger": "^1.0.10",
|
"flac-stream-tagger": "^1.0.10",
|
||||||
|
|
|
@ -1,29 +1,5 @@
|
||||||
const database = Bun.file('localStorage.json');
|
import { createLocalStorage } from "bun-storage";
|
||||||
|
|
||||||
if (!await database.exists()) {
|
const [localStorage, emitter] = createLocalStorage("./localStorage.sqlite");
|
||||||
await Bun.write(database, JSON.stringify({}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {};
|
globalThis.localStorage = localStorage;
|
||||||
|
|
||||||
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 { }
|
|
|
@ -10,23 +10,55 @@ Ffmpeg.setFfmpegPath(ffmpegPath as string);
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
private _authHeaders: { [key: string]: string }
|
private _authHeaders: { [key: string]: string }
|
||||||
private _userId: number;
|
private _userId: string | undefined;
|
||||||
|
private _userCountry: string;
|
||||||
|
private _userLocale: string;
|
||||||
|
|
||||||
constructor(authHeaders: { [key: string]: string }) {
|
constructor(authHeaders: { [key: string]: string }) {
|
||||||
this._authHeaders = authHeaders
|
this._authHeaders = authHeaders;
|
||||||
this._userId = 0;
|
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() {
|
async init() {
|
||||||
const { token } = await credentialsProvider.getCredentials() as { token: string };
|
const creds = await credentialsProvider.getCredentials()
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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,
|
trackId: number,
|
||||||
audioPresentation: string,
|
audioPresentation: string,
|
||||||
audioMode: string,
|
audioMode: string,
|
||||||
|
@ -45,11 +77,9 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchTracks() {
|
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`, {
|
const tracks = await this.fetch(`/users/${this._userId}/favorites/tracks?offset=0&limit=10000&order=DATE&orderDirection=DESC`);
|
||||||
headers: this._authHeaders
|
|
||||||
})
|
|
||||||
|
|
||||||
return await tracks.json();
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadFlac(manifestMimeType: string, manifest: string) {
|
async downloadFlac(manifestMimeType: string, manifest: string) {
|
||||||
|
|
12
tmp.ts
12
tmp.ts
|
@ -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": "*",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
Loading…
Add table
Reference in a new issue