diff --git a/apps/server/src/database/queries/album.ts b/apps/server/src/database/queries/album.ts index 2b6debf..89aecdd 100644 --- a/apps/server/src/database/queries/album.ts +++ b/apps/server/src/database/queries/album.ts @@ -1,8 +1,24 @@ +import { storeTrackAlbumArtist } from "../../spotify/dbTools"; import { AlbumModel, InfosModel } from "../Models"; import { User } from "../schemas/user"; +import { getAlbums as fetchAlbums } from "../../spotify/dbTools"; -export const getAlbums = (albumsId: string[]) => - AlbumModel.find({ id: { $in: albumsId } }); +export const getAlbums = async (userID: string, albumIds: string[]) => { + const albums = await AlbumModel.find({ id: { $in: albumIds } }); + + const validFetchedAlbums = albums.filter(album => album.name && album.name.trim() !== ''); + const foundAlbumIds = validFetchedAlbums.map(album => album.id); + const missingAlbumIds = albumIds.filter(id => !foundAlbumIds.includes(id)); + + if (missingAlbumIds.length > 0) { + const fetchedAlbums = await fetchAlbums(userID, missingAlbumIds); + await storeTrackAlbumArtist({ albums: fetchedAlbums }); + + return [...albums, ...fetchedAlbums]; + } + + return albums; +}; export const searchAlbum = (str: string) => AlbumModel.find({ name: { $regex: new RegExp(str, "i") } }); diff --git a/apps/server/src/database/queries/artist.ts b/apps/server/src/database/queries/artist.ts index 43a9baa..077b614 100644 --- a/apps/server/src/database/queries/artist.ts +++ b/apps/server/src/database/queries/artist.ts @@ -1,10 +1,26 @@ +import { storeTrackAlbumArtist } from "../../spotify/dbTools"; import { Timesplit } from "../../tools/types"; import { ArtistModel, InfosModel } from "../Models"; import { User } from "../schemas/user"; import { getGroupByDateProjection, getGroupingByTimeSplit } from "./statsTools"; +import { getArtists as fetchArtists } from "../../spotify/dbTools"; -export const getArtists = (artistIds: string[]) => - ArtistModel.find({ id: { $in: artistIds } }); +export const getArtists = async (userID: string, artistIds: string[]) => { + const artists = await ArtistModel.find({ id: { $in: artistIds } }); + + const validFetchedArtists = artists.filter(artist => artist.name && artist.name.trim() !== ''); + const foundArtistIds = validFetchedArtists.map(artist => artist.id); + const missingArtistIds = artistIds.filter(id => !foundArtistIds.includes(id)); + + if (missingArtistIds.length > 0) { + const fetchedArtists = await fetchArtists(userID, missingArtistIds); + await storeTrackAlbumArtist({ artists: fetchedArtists }); + + return [...artists, ...fetchedArtists]; + } + + return artists; +}; export const searchArtist = (str: string) => ArtistModel.find({ name: { $regex: new RegExp(str, "i") } }); diff --git a/apps/server/src/database/queries/tools.ts b/apps/server/src/database/queries/tools.ts index 5fece9c..2206fab 100644 --- a/apps/server/src/database/queries/tools.ts +++ b/apps/server/src/database/queries/tools.ts @@ -34,15 +34,22 @@ export const getTracksWithoutAlbum = () => ]); export const getAlbumsWithoutArtist = () => - AlbumModel.aggregate([ + AlbumModel.aggregate([ + { $unwind: '$artists' }, { $lookup: { - from: "artists", - as: "full_artist", - localField: "album", - foreignField: "id", - }, + from: 'artists', + localField: 'artists', + foreignField: 'id', + as: 'artistDetails' + } }, - { $unwind: "$full_artist" }, - { $match: { full_artist: null } }, - ]); + { $match: { artistDetails: { $eq: [] } } }, + { + $group: { + _id: '$id', + album: { $first: '$$ROOT' } + } + }, + { $replaceRoot: { newRoot: '$album' } } +]); diff --git a/apps/server/src/database/queries/track.ts b/apps/server/src/database/queries/track.ts index fb671d4..53e1d82 100644 --- a/apps/server/src/database/queries/track.ts +++ b/apps/server/src/database/queries/track.ts @@ -2,9 +2,24 @@ import { InfosModel, TrackModel } from "../Models"; import { User } from "../schemas/user"; import { Timesplit } from "../../tools/types"; import { getGroupByDateProjection, getGroupingByTimeSplit } from "./statsTools"; +import { getTracks as fetchTracks, storeTrackAlbumArtist } from "../../spotify/dbTools"; -export const getTracks = (tracksId: string[]) => - TrackModel.find({ id: { $in: tracksId } }); +export const getTracks = async (userID: string, tracksId: string[]) => { + const tracks = await TrackModel.find({ id: { $in: tracksId } }); + + const validFetchedTracks = tracks.filter(track => track.name && track.name.trim() !== ''); + const foundTrackIds = validFetchedTracks.map(track => track.id); + const missingTrackIds = tracksId.filter(id => !foundTrackIds.includes(id)); + + if (missingTrackIds.length > 0) { + const fetchedTracks = await fetchTracks(userID, missingTrackIds); + await storeTrackAlbumArtist({ tracks: fetchedTracks }); + + return [...tracks, ...fetchedTracks]; + } + + return tracks; +}; export const searchTrack = (str: string) => TrackModel.find({ name: { $regex: new RegExp(str, "i") } }).populate( diff --git a/apps/server/src/database/queries/user.ts b/apps/server/src/database/queries/user.ts index 233503c..5b2aa02 100644 --- a/apps/server/src/database/queries/user.ts +++ b/apps/server/src/database/queries/user.ts @@ -241,10 +241,17 @@ export const getSongs = async ( ], }, }); + if (!fullUser) { return []; } - return fullUser.tracks; + + // Filter out invalid tracks + const validTracks = fullUser.tracks.filter((track: any) => { + return track.track.full_album !== null && track.track.full_artist.length > 0; + }); + + return validTracks; }; export const getUserCount = () => UserModel.countDocuments(); diff --git a/apps/server/src/migrations/1708973485301-add_metadata_to_infos.ts b/apps/server/src/migrations/1708973485301-add_metadata_to_infos.ts index 8320cda..e594484 100644 --- a/apps/server/src/migrations/1708973485301-add_metadata_to_infos.ts +++ b/apps/server/src/migrations/1708973485301-add_metadata_to_infos.ts @@ -10,7 +10,7 @@ export async function up() { for await (const user of UserModel.find()) { for await (const info of InfosModel.find({ owner: user._id })) { - const [track] = await getTracks([info.id]); + const [track] = await getTracks(user._id.toString(), [info.id]); if (!track) { continue; } diff --git a/apps/server/src/routes/album.ts b/apps/server/src/routes/album.ts index 1a5e2de..3187732 100644 --- a/apps/server/src/routes/album.ts +++ b/apps/server/src/routes/album.ts @@ -22,8 +22,9 @@ router.get( isLoggedOrGuest, async (req, res) => { try { + const { user } = req as LoggedRequest; const { ids } = req.params as TypedPayload; - const albums = await getAlbums(ids.split(",")); + const albums = await getAlbums(user._id.toString(), ids.split(",")); if (!albums || albums.length === 0) { return res.status(404).end(); } @@ -47,14 +48,14 @@ router.get( try { const { user } = req as LoggedRequest; const { id } = req.params as TypedPayload; - const [album] = await getAlbums([id]); + const [album] = await getAlbums(user._id.toString(), [id]); if (!album) { return res.status(404).end(); } const promises = [ getFirstAndLastListenedAlbum(user, id), getAlbumSongs(user, id), - getArtists(album.artists), + getArtists(user._id.toString(), album.artists), // getTotalListeningOfAlbum(user, id), ]; const [firstLast, tracks, artists] = await Promise.all(promises); @@ -79,7 +80,7 @@ router.get( try { const { user } = req as LoggedRequest; const { id } = req.params as TypedPayload; - const [album] = await getAlbums([id]); + const [album] = await getAlbums(user._id.toString(), [id]); if (!album) { return res.status(404).end(); } diff --git a/apps/server/src/routes/artist.ts b/apps/server/src/routes/artist.ts index 287e9d8..f8b0d65 100644 --- a/apps/server/src/routes/artist.ts +++ b/apps/server/src/routes/artist.ts @@ -32,8 +32,9 @@ router.get( isLoggedOrGuest, async (req, res) => { try { + const { user } = req as LoggedRequest; const { ids } = req.params as TypedPayload; - const artists = await getArtists(ids.split(",")); + const artists = await getArtists(user._id.toString(), ids.split(",")); if (!artists || artists.length === 0) { return res.status(404).end(); } @@ -58,7 +59,7 @@ router.get( const { user } = req as LoggedRequest; const { id } = req.params as TypedPayload; - const [artist] = await getArtists([id]); + const [artist] = await getArtists(user._id.toString(), [id]); if (!artist) { return res.status(404).end(); } @@ -108,7 +109,7 @@ router.get( const { id } = req.params as TypedPayload; try { - const [artist] = await getArtists([id]); + const [artist] = await getArtists(user._id.toString(), [id]); if (!artist) { return res.status(404).end(); } diff --git a/apps/server/src/routes/track.ts b/apps/server/src/routes/track.ts index 54c75ba..f28f134 100644 --- a/apps/server/src/routes/track.ts +++ b/apps/server/src/routes/track.ts @@ -27,8 +27,9 @@ router.get( isLoggedOrGuest, async (req, res) => { try { + const { user } = req as LoggedRequest; const { ids } = req.params as TypedPayload; - const tracks = await getTracks(ids.split(",")); + const tracks = await getTracks(user._id.toString(), ids.split(",")); if (!tracks || tracks.length === 0) { return res.status(404).end(); } @@ -52,15 +53,15 @@ router.get( try { const { user } = req as LoggedRequest; const { id } = req.params as TypedPayload; - const [track] = await getTracks([id]); + const [track] = await getTracks(user._id.toString(), [id]); const [trackArtist] = track?.artists ?? []; if (!track || !trackArtist) { return res.status(404).end(); } const promises = [ - getAlbums([track.album]), + getAlbums(user._id.toString(), [track.album]), getTrackListenedCount(user, id), - getArtists([trackArtist]), + getArtists(user._id.toString(), [trackArtist]), getTrackFirstAndLastListened(user, track.id), bestPeriodOfTrack(user, track.id), getTrackRecentHistory(user, track.id), @@ -97,7 +98,7 @@ router.get( const { id } = req.params as TypedPayload; try { - const [track] = await getTracks([id]); + const [track] = await getTracks(user._id.toString(), [id]); if (!track) { return res.status(404).end(); }