251 lines
6.8 KiB
JavaScript

import axios from "axios"
import { DateTime } from "luxon"
const TIDAL_CLIENT_ID = process.env.TIDAL_CLIENT_ID
const TIDAL_CLIENT_SECRET = process.env.TIDAL_CLIENT_SECRET
export default class TidalAPI {
static async checkAuthStatus(device_code) {
const data = {
"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({
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) {
return false
}
return response.data
}
static async getAuthUrl() {
let data = {
client_id: TIDAL_CLIENT_ID,
scope: "r_usr+w_usr+w_sub"
}
const response = await axios({
method: "POST",
url: "https://auth.tidal.com/v1/oauth2/device_authorization",
params: data
})
return {
url: "https://" + response.data.verificationUri + "/" + response.data.userCode,
device_code: response.data.deviceCode,
expires_in: response.data.expiresIn
}
}
static async getUserData({
access_token,
user_id,
country
}) {
const url = `https://api.tidal.com/v1/users/${user_id}?countryCode=${country}`
const response = await axios({
method: "GET",
url,
headers: {
"Origin": "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`
}
})
return response.data
}
static async getTrackPlaybackUrl({
track_id,
quality,
access_token,
}) {
let data = {
soundQuality: quality ?? "LOSSLESS",
}
const response = await axios({
method: "GET",
url: `https://api.tidal.com/v1/tracks/${track_id}/streamUrl`,
params: data,
headers: {
"Origin": "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`
}
})
return response.data
}
static async getTrackMetadata({
track_id,
access_token,
country,
}) {
const response = await axios({
method: "GET",
url: `https://api.tidal.com/v1/tracks/${track_id}/?countryCode=${country}`,
headers: {
"Origin": "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`
}
})
return response.data
}
static async getTrackManifest({
track_id,
quality,
access_token,
country,
}) {
const playback = await TidalAPI.getTrackPlaybackUrl({
track_id,
quality,
access_token,
country,
})
const metadata = await TidalAPI.getTrackMetadata({
track_id,
access_token,
country,
})
return {
playback,
metadata
}
}
static async search({
query,
type = "all"
}) {
let url = `https://api.tidal.com/v1/search`
switch (type) {
case "all":
url = `https://api.tidal.com/v1/search`
break
case "playlists":
url = `https://api.tidal.com/v1/search/playlists`
break
case "artists":
url = `https://api.tidal.com/v1/search/artists`
break
case "albums":
url = `https://api.tidal.com/v1/search/albums`
break
case "tracks":
url = `https://api.tidal.com/v1/search/tracks`
break
}
const response = await axios({
method: "GET",
url: url,
params: {
query: query,
countryCode: "AZ"
},
headers: {
"Origin": "http://listen.tidal.com",
"x-tidal-token": TIDAL_CLIENT_ID
}
})
return response.data.tracks.items.map((item) => {
item._id = item.id
const coverUID = item.album.cover.replace(/-/g, "/")
item.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg`
item.artist = item.artists.map(artist => artist.name).join(", ")
item.metadata = {
title: item.title,
artists: item.artists.map(artist => artist.name).join(", "),
artist: item.artists.map(artist => artist.name).join(", "),
album: item.album.title,
duration: item.duration
}
item.service = "tidal"
return item
})
}
static async getFavoriteTracks({
user_id,
country,
access_token,
limit = 100,
offset = 0,
}) {
const url = `https://api.tidal.com/v1/users/${user_id}/favorites/tracks?countryCode=${country}`
const response = await axios({
method: "GET",
url,
headers: {
"Origin": "http://listen.tidal.com",
Authorization: `Bearer ${access_token}`
},
params: {
order: "DATE",
orderDirection: "DESC",
limit: limit,
offset: offset,
}
})
response.data.items = response.data.items.map((item) => {
// get js time
item.item.liked_at = new Date(item.created).getTime()
item.item.service = "tidal"
item.item._id = item.item.id
const coverUID = item.item.album.cover.replace(/-/g, "/")
item.item.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg`
item.item.artist = item.item.artists.map(artist => artist.name).join(", ")
item.item.metadata = {
title: item.item.title,
artists: item.item.artists.map(artist => artist.name).join(", "),
artist: item.item.artists.map(artist => artist.name).join(", "),
album: item.item.album.title,
duration: item.item.duration
}
item.item.liked = true
item.item._computed = true
return item.item
})
return {
total_length: response.data.totalNumberOfItems,
tracks: response.data.items
}
}
}