include some missing methods

This commit is contained in:
SrGooglo 2023-10-10 13:39:57 +00:00
parent b7d057958b
commit b2c8ad9f95

View File

@ -3,269 +3,431 @@ import axios from "axios"
const TIDAL_CLIENT_ID = process.env.TIDAL_CLIENT_ID const TIDAL_CLIENT_ID = process.env.TIDAL_CLIENT_ID
const TIDAL_CLIENT_SECRET = process.env.TIDAL_CLIENT_SECRET const TIDAL_CLIENT_SECRET = process.env.TIDAL_CLIENT_SECRET
export default class TidalAPI { function tranformTrackData(data = {}) {
static async checkAuthStatus(device_code) { // TODO: Support Track remixes & versions
const data = { data._id = data.id
"client_id": TIDAL_CLIENT_ID,
"device_code": device_code,
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"scope": "r_usr+w_usr+w_sub"
}
const response = await axios({ const coverUID = data.album.cover.replace(/-/g, "/")
method: "POST",
url: "https://auth.tidal.com/v1/oauth2/token",
params: data,
auth: {
username: TIDAL_CLIENT_ID,
password: TIDAL_CLIENT_SECRET
}
}).catch((err) => {
return false
})
if (!response) { data.cover = `https://resources.tidal.com/images/${coverUID}/1080x1080.jpg`
return false
}
return response.data data.artist = data.artists.map(artist => artist.name).join(", ")
}
static async getAuthUrl() { data.metadata = {
let data = { title: data.title,
client_id: TIDAL_CLIENT_ID, artists: data.artists.map(artist => artist.name).join(", "),
scope: "r_usr+w_usr+w_sub" artist: data.artists.map(artist => artist.name).join(", "),
} album: data.album.title,
duration: data.duration,
}
const response = await axios({ data.service = "tidal"
method: "POST",
url: "https://auth.tidal.com/v1/oauth2/device_authorization",
params: data
})
return { return data
url: "https://" + response.data.verificationUri + "/" + response.data.userCode, }
device_code: response.data.deviceCode,
expires_in: response.data.expiresIn export default class TidalAPI {
} static API_V1 = "https://api.tidal.com/v1"
} static API_V2 = "https://api.tidal.com/v2"
static async getUserData({ static API_USERS = "https://api.tidal.com/v1/users"
access_token,
user_id, static async checkAuthStatus(device_code) {
country const data = {
}) { client_id: TIDAL_CLIENT_ID,
const url = `https://api.tidal.com/v1/users/${user_id}?countryCode=${country}` device_code: device_code,
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
const response = await axios({ scope: "r_usr+w_usr+w_sub",
method: "GET", }
url,
headers: { const response = await axios({
"Origin": "http://listen.tidal.com", method: "POST",
Authorization: `Bearer ${access_token}` url: "https://auth.tidal.com/v1/oauth2/token",
} params: data,
}) auth: {
username: TIDAL_CLIENT_ID,
return response.data password: TIDAL_CLIENT_SECRET,
} },
}).catch(err => {
static async getTrackPlaybackUrl({ return false
track_id, })
quality,
access_token, if (!response) {
country, return false
}) { }
let params = {
countryCode: country ?? "US", return response.data
audioquality: quality ?? "LOSSLESS", }
playbackmode: "STREAM",
assetpresentation: "FULL", static async getAuthUrl() {
} let data = {
client_id: TIDAL_CLIENT_ID,
let response = await axios({ scope: "r_usr+w_usr+w_sub",
method: "GET", }
url: `https://api.tidal.com/v1/tracks/${track_id}/playbackinfopostpaywall`,
params: params, const response = await axios({
headers: { method: "POST",
Origin: "http://listen.tidal.com", url: "https://auth.tidal.com/v1/oauth2/device_authorization",
Authorization: `Bearer ${access_token}` params: data,
} })
})
return {
let decodedManifest = JSON.parse(global.b64Decode(response.data.manifest)) url: "https://" + response.data.verificationUri + "/" + response.data.userCode,
device_code: response.data.deviceCode,
decodedManifest.url = decodedManifest.urls[0] expires_in: response.data.expiresIn,
}
return { }
metadata: {
trackId: track_id, static async getUserData({ access_token, user_id, country }) {
audioMode: response.data.audioMode, const url = `https://api.tidal.com/v1/users/${user_id}?countryCode=${country}`
audioQuality: response.data.audioQuality,
bitDepth: response.data.bitDepth, const response = await axios({
bitRate: response.data.bitRate, method: "GET",
mimeType: response.data.manifestMimeType url,
}, headers: {
...decodedManifest Origin: "http://listen.tidal.com",
} Authorization: `Bearer ${access_token}`,
} },
static async getTrackMetadata({ })
track_id,
access_token, return response.data
country, }
}) {
const response = await axios({ static async getTrackPlaybackUrl({ track_id, quality, access_token, country }) {
method: "GET", let params = {
url: `https://api.tidal.com/v1/tracks/${track_id}`, countryCode: country ?? "US",
params: { audioquality: quality ?? "LOSSLESS",
"countryCode": country playbackmode: "STREAM",
}, assetpresentation: "FULL",
headers: { }
"Origin": "http://listen.tidal.com",
Authorization: `Bearer ${access_token}` let response = await axios({
} method: "GET",
}) url: `https://api.tidal.com/v1/tracks/${track_id}/playbackinfopostpaywall`,
params: params,
return response.data headers: {
} Origin: "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`,
static async getTrackManifest({ },
track_id, })
quality,
access_token, let decodedManifest = JSON.parse(global.b64Decode(response.data.manifest))
country,
}) { decodedManifest.url = decodedManifest.urls[0]
const playback = await TidalAPI.getTrackPlaybackUrl({
track_id, return {
quality, metadata: {
access_token, trackId: track_id,
country, audioMode: response.data.audioMode,
}) audioQuality: response.data.audioQuality,
bitDepth: response.data.bitDepth,
const metadata = await TidalAPI.getTrackMetadata({ bitRate: response.data.bitRate,
track_id, mimeType: response.data.manifestMimeType,
access_token, },
country, ...decodedManifest,
}) }
}
return { static async getTrackMetadata({ track_id, access_token, country }) {
playback, const response = await axios({
metadata method: "GET",
} url: `https://api.tidal.com/v1/tracks/${track_id}`,
} params: {
countryCode: country,
static async search({ },
query, headers: {
type = "all" Origin: "http://listen.tidal.com",
}) { Authorization: `Bearer ${access_token}`,
let url = `https://api.tidal.com/v1/search` },
})
switch (type) {
case "all": return response.data
url = `https://api.tidal.com/v1/search` }
break
case "playlists": static async getTrackManifest({ track_id, quality, access_token, country }) {
url = `https://api.tidal.com/v1/search/playlists` const playback = await TidalAPI.getTrackPlaybackUrl({
break track_id,
case "artists": quality,
url = `https://api.tidal.com/v1/search/artists` access_token,
break country,
case "albums": })
url = `https://api.tidal.com/v1/search/albums`
break const metadata = await TidalAPI.getTrackMetadata({
case "tracks": track_id,
url = `https://api.tidal.com/v1/search/tracks` access_token,
break country,
} })
const response = await axios({ return {
method: "GET", playback,
url: url, metadata,
params: { }
query: query, }
countryCode: "AZ"
}, static async search({ query, type = "all" }) {
headers: { let url = `https://api.tidal.com/v1/search`
"Origin": "http://listen.tidal.com",
"x-tidal-token": TIDAL_CLIENT_ID switch (type) {
} case "all":
}) url = `https://api.tidal.com/v1/search`
break
return response.data.tracks.items.map((item) => { case "playlists":
item._id = item.id url = `https://api.tidal.com/v1/search/playlists`
break
const coverUID = item.album.cover.replace(/-/g, "/") case "artists":
url = `https://api.tidal.com/v1/search/artists`
item.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg` break
case "albums":
item.artist = item.artists.map(artist => artist.name).join(", ") url = `https://api.tidal.com/v1/search/albums`
break
item.metadata = { case "tracks":
title: item.title, url = `https://api.tidal.com/v1/search/tracks`
artists: item.artists.map(artist => artist.name).join(", "), break
artist: item.artists.map(artist => artist.name).join(", "), }
album: item.album.title,
duration: item.duration const response = await axios({
} method: "GET",
url: url,
item.service = "tidal" params: {
query: query,
return item countryCode: "AZ",
}) },
} headers: {
static async getFavoriteTracks({ Origin: "http://listen.tidal.com",
user_id, "x-tidal-token": TIDAL_CLIENT_ID,
country, },
access_token, })
limit = 100,
offset = 0, return response.data.tracks.items.map(item => {
}) { item = tranformTrackData(item)
const url = `https://api.tidal.com/v1/users/${user_id}/favorites/tracks?countryCode=${country}`
return item
const response = await axios({ })
method: "GET", }
url,
headers: { /**
"Origin": "http://listen.tidal.com", * Retrieves favorite tracks for a user.
Authorization: `Bearer ${access_token}` *
}, * @param {Object} options - The options for retrieving favorite tracks.
params: { * @param {number} options.user_id - The user ID.
order: "DATE", * @param {string} options.country - The country code.
orderDirection: "DESC", * @param {string} options.access_token - The access token.
limit: limit, * @param {number} [options.limit=100] - The maximum number of tracks to retrieve.
offset: offset, * @param {number} [options.offset=0] - The offset for pagination.
} * @return {Object} The response object containing the total length and tracks.
}) */
static async getFavoriteTracks({
response.data.items = response.data.items.map((item) => { user_id,
// get js time access_token,
item.item.liked_at = new Date(item.created).getTime() country,
item.item.service = "tidal" limit = 100,
offset = 0,
item.item._id = item.item.id order = "DATE",
orderDirection = "DESC",
const coverUID = item.item.album.cover.replace(/-/g, "/") }) {
const response = await axios({
item.item.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg` url: `${TidalAPI.API_USERS}/${user_id}/favorites/tracks`,
method: "GET",
item.item.artist = item.item.artists.map(artist => artist.name).join(", ") headers: {
Origin: "http://listen.tidal.com",
item.item.metadata = { Authorization: `Bearer ${access_token}`,
title: item.item.title, },
artists: item.item.artists.map(artist => artist.name).join(", "), params: {
artist: item.item.artists.map(artist => artist.name).join(", "), countryCode: country,
album: item.item.album.title, order,
duration: item.item.duration orderDirection,
} limit,
offset,
item.item.liked = true },
item.item._computed = true })
return item.item response.data.items = response.data.items.map(item => {
}) item.item = tranformTrackData(item.item)
return { item.item.liked_at = new Date(item.created).getTime()
total_length: response.data.totalNumberOfItems, item.item.liked = true
tracks: response.data.items item.item._computed = true
}
} return item.item
})
return {
total_length: response.data.totalNumberOfItems,
tracks: response.data.items,
}
}
/**
* Retrieves self favorite playlists based on specified parameters.
*
* @param {Object} options - The options object.
* @param {string} options.country - The country code.
* @param {string} options.access_token - The access token for authentication.
* @param {number} [options.limit=100] - The maximum number of playlists to retrieve.
* @param {number} [options.offset=0] - The offset for pagination.
* @param {string} [options.order="DATE"] - The field to order the playlists by.
* @param {string} [options.orderDirection="DESC"] - The direction to order the playlists in.
* @return {Object} - An object containing the total length and items of the playlists.
*/
static async getFavoritePlaylists({
country,
access_token,
limit = 100,
offset = 0,
order = "DATE",
orderDirection = "DESC",
}) {
const params = {
folderId: "root",
deviceType: "BROWSER",
countryCode: country,
offset,
limit,
order,
orderDirection,
}
let response = await axios({
url: `${TidalAPI.API_V2}/my-collection/playlists/folders`,
method: "GET",
headers: {
Origin: "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`,
Server: "envoy",
},
params: params,
})
response.data.items = response.data.items.map(item => {
item.data._id = item.data.uuid
item.data.addedAt = item.addedAt
item.data.created_at = item.addedAt
item.data.service = "tidal"
const coverUID = item.data.squareImage.replace(/-/g, "/")
item.data.cover = `https://resources.tidal.com/images/${coverUID}/1080x1080.jpg`
return item.data
})
return {
total_length: response.data.totalNumberOfItems,
items: response.data.items,
}
}
/**
* Retrieves playlist items based on the provided parameters.
*
* @param {Object} options - The options for retrieving playlist items.
* @param {string} options.uuid - The UUID of the playlist.
* @param {number} options.limit - The maximum number of items to retrieve.
* @param {number} options.offset - The offset of items to start retrieving from.
* @param {string} options.country - The country code for retrieving items.
* @param {string} options.access_token - The access token for authentication.
* @return {Object} An object containing the total length and items of the playlist.
*/
static async getPlaylistItems({
uuid,
limit,
offset,
country,
access_token,
}) {
const params = {
limit,
offset,
countryCode: country,
}
let response = await axios({
url: `${TidalAPI.API_V1}/playlists/${uuid}/items`,
method: "GET",
headers: {
Origin: "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`,
Server: "envoy",
},
params: params,
})
response.data.items = response.data.items.map((item) => {
item = tranformTrackData(item.item)
return item
})
return {
total_length: response.data.totalNumberOfItems,
list: response.data.items,
}
}
/**
* Retrieves playlist data from the Tidal API.
*
* @param {Object} options - The options for retrieving the playlist data.
* @param {string} options.uuid - The UUID of the playlist.
* @param {string} options.access_token - The access token for authentication.
* @param {string} options.country - The country code for the playlist data.
* @param {boolean} [options.resolve_items=false] - Whether to resolve the playlist items.
* @param {number} [options.limit] - The maximum number of items to retrieve.
* @param {number} [options.offset] - The offset for pagination.
* @return {Object} The playlist data retrieved from the Tidal API.
*/
static async getPlaylistData({
uuid,
access_token,
country,
resolve_items = false,
limit,
offset,
}) {
const params = {
countryCode: country,
}
let response = await axios({
url: `${TidalAPI.API_V1}/playlists/${uuid}`,
method: "GET",
headers: {
Origin: "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`,
Server: "envoy",
},
params: params,
})
const coverUID = response.data.squareImage.replace(/-/g, "/")
response.data.cover = `https://resources.tidal.com/images/${coverUID}/1080x1080.jpg`
response.data.service = "tidal"
if (resolve_items) {
response.data.list = await TidalAPI.getPlaylistItems({
uuid,
limit,
offset,
access_token,
country,
})
response.data.total_length = response.data.list.total_length
response.data.list = response.data.list.list
}
return response.data
}
static async toggleTrackLike(track_id) {
}
static async togglePlaylistLike(playlist_id) {
}
} }