diff --git a/packages/app/src/pages/music/components/explore/index.jsx b/packages/app/src/pages/music/components/explore/index.jsx
index 8e3cdaef..56a62e51 100755
--- a/packages/app/src/pages/music/components/explore/index.jsx
+++ b/packages/app/src/pages/music/components/explore/index.jsx
@@ -9,7 +9,6 @@ import { Icons, createIconRender } from "components/Icons"
import { WithPlayerContext } from "contexts/WithPlayerContext"
import FeedModel from "models/feed"
-import PlaylistModel from "models/playlists"
import MusicModel from "models/music"
import SyncModel from "models/sync"
@@ -19,32 +18,13 @@ import PlaylistItem from "components/Music/PlaylistItem"
import "./index.less"
const MusicNavbar = (props) => {
- const [loading, setLoading] = React.useState(true)
- const [hasTidal, setHasTidal] = React.useState(false)
-
- React.useEffect(() => {
- SyncModel.hasServiceLinked("tidal")
- .catch(() => {
- setHasTidal(false)
- setLoading(false)
- })
- .then((value) => {
- setHasTidal(value.active)
- setLoading(false)
- })
- }, [])
-
- if (loading) {
- return null
- }
-
return
props.setSearchResults(false)}
diff --git a/packages/app/src/pages/music/components/favorites/index.jsx b/packages/app/src/pages/music/components/favorites/index.jsx
index e89e8ce0..73eb6e0f 100644
--- a/packages/app/src/pages/music/components/favorites/index.jsx
+++ b/packages/app/src/pages/music/components/favorites/index.jsx
@@ -3,10 +3,12 @@ import * as antd from "antd"
import PlaylistView from "components/Music/PlaylistView"
-import MusicModel from "comty.js/models/music"
+import MusicModel from "models/music"
export default () => {
- const [L_Favorites, R_Favorites, E_Favorites] = app.cores.api.useRequest(MusicModel.getFavorites)
+ const [L_Favorites, R_Favorites, E_Favorites] = app.cores.api.useRequest(MusicModel.getFavorites, {
+ useTidal: app.cores.sync.getActiveLinkedServices().tidal
+ })
if (E_Favorites) {
return {
- element._id = element.id
-
- const coverUID = element.album.cover.replace(/-/g, "/")
-
- element.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg`
-
- element.artist = element.artists.map(artist => artist.name).join(", ")
-
- element.metadata = {
- title: element.title,
- artists: element.artists.map(artist => artist.name).join(", "),
- artist: element.artists.map(artist => artist.name).join(", "),
- album: element.album.title,
- duration: element.duration
- }
-
- element.service = "tidal"
-
- results.tracks.push(element)
- })
+ results.tracks = [...results.tracks, ...tidalResult]
}
return res.json(results)
diff --git a/packages/music_server/src/controllers/tracks/routes/get/liked.js b/packages/music_server/src/controllers/tracks/routes/get/liked.js
index c851d195..d834f1a9 100644
--- a/packages/music_server/src/controllers/tracks/routes/get/liked.js
+++ b/packages/music_server/src/controllers/tracks/routes/get/liked.js
@@ -6,17 +6,17 @@ export default async (req, res) => {
return new AuthorizationError(req, res)
}
- let likedIds = await TrackLike.find({
+ let likedTracks = await TrackLike.find({
user_id: req.session.user_id,
})
.sort({ created_at: -1 })
- likedIds = likedIds.map((item) => {
+ const likedTracksIds = likedTracks.map((item) => {
return item.track_id
})
let tracks = await Track.find({
- _id: [...likedIds],
+ _id: likedTracksIds,
//public: true,
})
.catch((err) => {
@@ -26,14 +26,20 @@ export default async (req, res) => {
tracks = tracks.map((item) => {
item = item.toObject()
+ const likeIndex = likedTracksIds.indexOf(item._id.toString())
+
+ if (likeIndex !== -1) {
+ item.liked_at = new Date(likedTracks[likeIndex].created_at).getTime()
+ }
+
item.liked = true
return item
})
tracks.sort((a, b) => {
- const indexA = likedIds.indexOf(a._id.toString())
- const indexB = likedIds.indexOf(b._id.toString())
+ const indexA = likedTracksIds.indexOf(a._id.toString())
+ const indexB = likedTracksIds.indexOf(b._id.toString())
return indexA - indexB
})
diff --git a/packages/sync_server/src/controllers/main/routes/get/active_services.js b/packages/sync_server/src/controllers/main/routes/get/active_services.js
new file mode 100644
index 00000000..786001d9
--- /dev/null
+++ b/packages/sync_server/src/controllers/main/routes/get/active_services.js
@@ -0,0 +1,15 @@
+import SecureSyncEntry from "@shared-classes/SecureSyncEntry"
+import { AuthorizationError } from "@shared-classes/Errors"
+
+export default async (req, res) => {
+ if (!req.session) {
+ return new AuthorizationError(req, res)
+ }
+
+ const tidal_access = await SecureSyncEntry.has(req.session.user_id.toString(), "tidal_access_token")
+
+ return res.json({
+ spotify: null,
+ tidal: tidal_access,
+ })
+}
\ No newline at end of file
diff --git a/packages/sync_server/src/controllers/services/routes/get/tidal/favorites/tracks.js b/packages/sync_server/src/controllers/services/routes/get/tidal/favorites/tracks.js
new file mode 100644
index 00000000..2f43b1e5
--- /dev/null
+++ b/packages/sync_server/src/controllers/services/routes/get/tidal/favorites/tracks.js
@@ -0,0 +1,32 @@
+import SecureSyncEntry from "@shared-classes/SecureSyncEntry"
+import { AuthorizationError, InternalServerError, NotFoundError } from "@shared-classes/Errors"
+
+import TidalAPI from "@shared-classes/TidalAPI"
+
+export default async (req, res) => {
+ if (!req.session) {
+ return new AuthorizationError(req, res)
+ }
+
+ try {
+ const access_token = await SecureSyncEntry.get(req.session.user_id.toString(), "tidal_access_token")
+
+ if (!access_token) {
+ return new AuthorizationError(req, res, "Its needed to link your TIDAL account to perform this action.")
+ }
+
+ let user_data = await SecureSyncEntry.get(req.session.user_id.toString(), "tidal_user")
+
+ user_data = JSON.parse(user_data)
+
+ const response = await TidalAPI.getFavoriteTracks({
+ user_id: user_data.id,
+ country: user_data.countryCode,
+ access_token: access_token,
+ })
+
+ return res.json(response)
+ } catch (error) {
+ return new InternalServerError(req, res, error)
+ }
+}
\ No newline at end of file
diff --git a/shared/classes/TidalAPI/index.js b/shared/classes/TidalAPI/index.js
index de0249a4..34e93480 100644
--- a/shared/classes/TidalAPI/index.js
+++ b/shared/classes/TidalAPI/index.js
@@ -1,4 +1,5 @@
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
@@ -169,6 +170,73 @@ export default class TidalAPI {
}
})
- return response.data
+ 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,
+ }) {
+ 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"
+ }
+ })
+
+ return 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
+ })
}
}
\ No newline at end of file