From 5fc3dd42fc243480041d31d06a6402cc4d85373f Mon Sep 17 00:00:00 2001 From: Lachie Underhill Date: Mon, 2 Sep 2024 17:48:43 +1000 Subject: [PATCH] chore: add types to some api and gw calls --- deemix/src/itemgen.ts | 27 +++---------- deemix/src/types/Track.ts | 66 +++++++++++++++++-------------- deezer-js/src/api.ts | 82 ++++++++++++++++++++++++++++++++++++--- deezer-js/src/gw.ts | 21 ++++++++-- 4 files changed, 136 insertions(+), 60 deletions(-) diff --git a/deemix/src/itemgen.ts b/deemix/src/itemgen.ts index 077c8b16..39dfbffd 100644 --- a/deemix/src/itemgen.ts +++ b/deemix/src/itemgen.ts @@ -9,21 +9,14 @@ const { map_user_playlist, map_track, map_album } = require("deezer-js").utils; import { each } from "async"; import { Deezer } from "deezer-js"; import { Album } from "./types/Album"; +import { APIAlbum, APITrack } from "deezer-js/src/api"; export async function generateTrackItem( dz: Deezer, id: string, bitrate: number, - trackAPI?: { - id: any; - title: any; - album: { cover_small: string }; - md5_image: any; - track_token: any; - artist: { name: any }; - explicit_lyrics: any; - }, - albumAPI?: any + trackAPI?: APITrack, + albumAPI?: APIAlbum ) { // Get essential track info if (!trackAPI) { @@ -76,22 +69,12 @@ export async function generateTrackItem( export async function generateAlbumItem( dz: Deezer, - id: string | any[], + id: string, bitrate: number, rootArtist?: { id: any; name: any; picture_small: any } ) { // Get essential album info - let albumAPI: { - id: any; - root_artist: any; - nb_tracks: number; - tracks: { data: string | any[] }; - cover_small: string; - md5_image: any; - title: any; - artist: { name: any }; - explicit_lyrics: any; - }; + let albumAPI: APIAlbum; if (String(id).startsWith("upc")) { const upcs = [id.slice(4).toString()]; upcs.push(parseInt(upcs[0], 10).toString()); // Try UPC without leading zeros as well diff --git a/deemix/src/types/Track.ts b/deemix/src/types/Track.ts index 648e192a..645166e5 100644 --- a/deemix/src/types/Track.ts +++ b/deemix/src/types/Track.ts @@ -1,6 +1,6 @@ import { Deezer, TrackFormats, utils } from "deezer-js"; import { AlbumDoesntExists, NoDataToParse } from "../errors"; -import { FeaturesOption } from "../settings"; +import { FeaturesOption, Settings } from "../settings"; import { andCommaConcat, changeCase, @@ -15,6 +15,7 @@ import { VARIOUS_ARTISTS } from "./index"; import { Lyrics } from "./Lyrics"; import { Picture } from "./Picture"; import { Playlist } from "./Playlist"; +import { APITrack } from "deezer-js/src/api"; const { map_track, map_album } = utils; export const formatsName = { @@ -41,7 +42,7 @@ class Track { filesizes: Record; local: boolean; mainArtist: Artist | null; - artist: { Main: any[] }; + artist: { Main: any[]; Featured?: any[] }; artists: any[]; album: Album | null; trackNumber: string; @@ -54,7 +55,7 @@ class Track { explicit: boolean; ISRC: string; replayGain: string; - playlist: null; + playlist: Playlist | null; position: null; searched: boolean; bitrate: keyof typeof formatsName; @@ -63,7 +64,7 @@ class Track { mainArtistsString: string; featArtistsString: string; fullArtistsString: string; - urls: Record<(typeof formatsName)[keyof typeof formatsName], string>; + urls: Partial>; downloadURL: string; rank: any; artistString: any; @@ -106,7 +107,7 @@ class Track { this.urls = {}; } - parseEssentialData(trackAPI) { + parseEssentialData(trackAPI: APITrack) { this.id = String(trackAPI.id); this.duration = trackAPI.duration; this.trackToken = trackAPI.track_token; @@ -120,51 +121,58 @@ class Track { this.urls = {}; } - async parseData(dz: Deezer, id, trackAPI, albumAPI, playlistAPI) { + async parseData( + dz: Deezer, + id, + existingTrack?: DeezerTrack, + albumAPI, + playlistAPI + ) { if (id) { - let trackAPI_new = await dz.gw.get_track_with_fallback(id); - trackAPI_new = map_track(trackAPI_new); - if (!trackAPI) trackAPI = {}; - trackAPI = { ...trackAPI, ...trackAPI_new }; - } else if (!trackAPI) { + const gwTrack = await dz.gw.get_track_with_fallback(id); + const newTrack = map_track(gwTrack); + + if (!existingTrack) existingTrack = {}; + existingTrack = { ...existingTrack, ...newTrack }; + } else if (!existingTrack) { throw new NoDataToParse(); } - this.parseEssentialData(trackAPI); + this.parseEssentialData(existingTrack); // only public api has bpm - if (!trackAPI.bpm && !this.local) { + if (!existingTrack.bpm && !this.local) { try { - const trackAPI_new = await dz.api.get_track(trackAPI.id); - trackAPI_new.release_date = trackAPI.release_date; - trackAPI = { ...trackAPI, ...trackAPI_new }; + const trackAPI_new = await dz.api.get_track(existingTrack.id); + trackAPI_new.release_date = existingTrack.release_date; + existingTrack = { ...existingTrack, ...trackAPI_new }; } catch { /* empty */ } } if (this.local) { - this.parseLocalTrackData(trackAPI); + this.parseLocalTrackData(existingTrack); } else { - this.parseTrack(trackAPI); + this.parseTrack(existingTrack); // Get Lyrics Data - if (!trackAPI.lyrics && this.lyrics.id !== "0") { + if (!existingTrack.lyrics && this.lyrics.id !== "0") { try { - trackAPI.lyrics = await dz.gw.get_track_lyrics(this.id); + existingTrack.lyrics = await dz.gw.get_track_lyrics(this.id); } catch { this.lyrics.id = "0"; } } if (this.lyrics.id !== "0") { - this.lyrics.parseLyrics(trackAPI.lyrics); + this.lyrics.parseLyrics(existingTrack.lyrics); } // Parse Album Data this.album = new Album( - trackAPI.album.id, - trackAPI.album.title, - trackAPI.album.md5_origin || "" + existingTrack.album.id, + existingTrack.album.title, + existingTrack.album.md5_origin || "" ); // Get album Data @@ -206,8 +214,8 @@ class Track { // Fill missing data if (this.album.date && !this.date) this.date = this.album.date; - if (trackAPI.genres) { - trackAPI.genres.forEach((genre) => { + if (existingTrack.genres) { + existingTrack.genres.forEach((genre) => { if (!this.album.genre.includes(genre)) this.album.genre.push(genre); }); } @@ -221,7 +229,7 @@ class Track { if (!this.artist.Main.length) { this.artist.Main = [this.mainArtist.name]; } - this.position = trackAPI.position; + this.position = existingTrack.position; if (playlistAPI) { this.playlist = new Playlist(playlistAPI); @@ -339,7 +347,7 @@ class Track { } } - async checkAndRenewTrackToken(dz) { + async checkAndRenewTrackToken(dz: Deezer) { const now = new Date(); const expiration = new Date(this.trackTokenExpiration * 1000); if (now > expiration) { @@ -349,7 +357,7 @@ class Track { } } - applySettings(settings) { + applySettings(settings: Settings) { // Check if should save the playlist as a compilation if (settings.tags.savePlaylistAsCompilation && this.playlist) { this.trackNumber = this.position; diff --git a/deezer-js/src/api.ts b/deezer-js/src/api.ts index 04f87f64..b5c05d6d 100644 --- a/deezer-js/src/api.ts +++ b/deezer-js/src/api.ts @@ -28,6 +28,78 @@ export const SearchOrder = { DURATION_DESC: "DURATION_DESC", }; +export interface APIArtist { + id: number; + name: string; + link: string; + share: string; + picture: string; + picture_small: string; + picture_medium: string; + picture_big: string; + picture_xl: string; + nb_album: number; + nb_fan: number; + radio: boolean; + tracklist: string; + role: string; +} + +export interface APIAlbum { + id: string; + title: string; + link: string; + cover: string; + cover_small: string; + cover_medium: string; + cover_big: string; + cover_xl: string; + release_date: string; // Assuming the date is in string format (e.g., "YYYY-MM-DD") +} + +export interface APITrack { + id: number; + readable: boolean; + title: string; + title_short: string; + title_version: string; + unseen: boolean; + isrc: string; + link: string; + share: string; + duration: number; + track_position: number; + disk_number: number; + rank: number; + release_date: string; // Assuming the date is in string format (e.g., "YYYY-MM-DD") + explicit_lyrics: boolean; + explicit_content_lyrics: number; + explicit_content_cover: number; + preview: string; + bpm: number; + gain: number; + available_countries: string[]; // List of countries as strings + alternative?: APITrack; // Assuming alternative is of type Track + contributors: APIContributor[]; // Assuming Contributor is an object + md5_image: string; + track_token: string; + artist: APIArtist; + album: APIAlbum; +} + +export interface APIContributor { + id: number; + name: string; + link: string; + share: string; + picture: string; + picture_small: string; + picture_medium: string; + picture_big: string; + picture_xl: string; + role: string; +} + type APIArgs = Record; export class API { @@ -41,7 +113,7 @@ export class API { this.access_token = null; } - async api_call(method: string, args: APIArgs = {}) { + async api_call(method: string, args: APIArgs = {}): Promise { if (this.access_token) args["access_token"] = this.access_token; let result_json; @@ -127,8 +199,8 @@ export class API { return result_json; } - get_album(album_id) { - return this.api_call(`album/${album_id}`); + get_album(album_id: string): Promise { + return this.api_call(`album/${album_id}`) as Promise; } get_album_by_UPC(upc) { @@ -423,8 +495,8 @@ export class API { return this.api_call("search/user", args); } - get_track(song_id) { - return this.api_call(`track/${song_id}`); + get_track(song_id: string): Promise { + return this.api_call(`track/${song_id}`) as Promise; } get_track_by_ISRC(isrc) { diff --git a/deezer-js/src/gw.ts b/deezer-js/src/gw.ts index 574e8242..f0189ae6 100644 --- a/deezer-js/src/gw.ts +++ b/deezer-js/src/gw.ts @@ -15,6 +15,19 @@ export const PlaylistStatus = { COLLABORATIVE: 2, }; +export interface GWTrack { + SNG_ID: number; + SNG_TITLE: string; + DURATION: number; + MD5_ORIGIN: number; + MEDIA_VERSION: number; + FILESIZE: number; + ALB_TITLE: string; + ALB_PICTURE: string; + ART_ID: number; + ART_NAME: string; +} + export const EMPTY_TRACK_OBJ = { SNG_ID: 0, SNG_TITLE: "", @@ -26,7 +39,7 @@ export const EMPTY_TRACK_OBJ = { ALB_PICTURE: "", ART_ID: 0, ART_NAME: "", -}; +} satisfies GWTrack; export class GW { http_headers: any; @@ -39,7 +52,7 @@ export class GW { this.api_token = null; } - async api_call(method: string, args?: any, params?: any) { + async api_call(method: string, args?: any, params?: any): Promise { if (typeof args === undefined) args = {}; if (typeof params === undefined) params = {}; if (!this.api_token && method !== "deezer.getUserData") @@ -132,7 +145,7 @@ export class GW { return this.api_call("deezer.getChildAccounts"); } - get_track(sng_id) { + get_track(sng_id): Promise { return this.api_call("song.getData", { SNG_ID: sng_id }); } @@ -510,7 +523,7 @@ export class GW { if (user_data.USER.USER_ID === user_id) return this.get_my_favorite_tracks(options); const limit = options.limit || 25; - let data = this.get_user_profile_page(user_id, "loved", { limit }); + let data = await this.get_user_profile_page(user_id, "loved", { limit }); data = data.TAB.loved.data; const result = []; data.forEach((track) => {