Added saved library API

This commit is contained in:
lucast committed 2026-10-05 17:54:29 +02:00
1 parent 36d05ab04f
commit 0526e83a9b
7 files changed
+107 -11

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
import { setResponseStatus } from "h3"
import { User } from "#server/models/user"
import { Album } from "#server/models/album"
import { Track } from "#server/models/track"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "#server/utils/auth"
export default defineAuthenticatedEventHandler(async (event) => {
const authenticatedUser = await requireAuthenticatedUser(event)
const user = await User.findById(authenticatedUser._id).select("savedTracks")
if (!user) {
setResponseStatus(event, 404)
return { message: "User not found" }
}
if (!user.savedTracks.length) return []
const tracks = await Track.find({ _id: { $in: user.savedTracks } }).select("_id album").exec()
const albumByTrack = new Map(tracks.map((track: any) => [track._id.toString(), track.album?.toString()]))
const albumIds: string[] = []
const seen = new Set<string>()
for (const savedTrack of user.savedTracks) {
const albumId = albumByTrack.get(savedTrack.toString())
if (albumId && !seen.has(albumId)) {
seen.add(albumId)
albumIds.push(albumId)
}
}
if (!albumIds.length) return []
const albums = await Album.find({ _id: { $in: albumIds } }).populate("artists").populate("genre").exec()
const albumsById = new Map(albums.map((album: any) => [album._id.toString(), album]))
return albumIds.map((id) => albumsById.get(id)).filter((album) => album != null)
})
+1 -1
View File
@@ -1,4 +1,4 @@
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "../../utils/auth"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "#server/utils/auth"
export default defineAuthenticatedEventHandler(async (event) => {
return await requireAuthenticatedUser(event)
+26
View File
@@ -0,0 +1,26 @@
import { getQuery, setResponseStatus } from "h3"
import { User } from "#server/models/user"
import {
defineAuthenticatedEventHandler,
requireAuthenticatedUser,
} from "#server/utils/auth"
import { parseMongoIds, validationResponse } from "#server/utils/api-validation"
export default defineAuthenticatedEventHandler(async (event) => {
const authenticatedUser = await requireAuthenticatedUser(event)
const parsedIds = parseMongoIds(getQuery(event).ids ?? getQuery(event).id)
if ("error" in parsedIds) return validationResponse(event, parsedIds.error)
const user = await User.findById(authenticatedUser._id)
if (!user) {
setResponseStatus(event, 404)
return { message: "User not found" }
}
user.savedTracks = user.savedTracks.filter(
(savedTrack: { toString(): string }) =>
!parsedIds.value.includes(savedTrack.toString()),
)
await user.save()
return {}
})
+10 -4
View File
@@ -1,15 +1,21 @@
import { User } from "../../models/user"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "../../utils/auth"
import { User } from "#server/models/user"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "#server/utils/auth"
import { setResponseStatus } from "h3"
export default defineAuthenticatedEventHandler(async (event) => {
const authenticatedUser = await requireAuthenticatedUser(event)
const user = await User.findById(authenticatedUser._id).populate("savedTracks")
const user = await User.findById(authenticatedUser._id).populate({
path: "savedTracks",
populate: [
{ path: "artists" },
{ path: "album", populate: { path: "artists" } },
],
})
if (!user) {
setResponseStatus(event, 404)
return { message: "User not found" }
}
return user.savedTracks
return user.savedTracks.filter((track: unknown) => track != null)
})
+4 -4
View File
@@ -1,8 +1,8 @@
import { getQuery, setResponseStatus } from "h3"
import mongoose, { type ObjectId } from "mongoose"
import { User } from "../../models/user"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "../../utils/auth"
import { parseMongoId, validationResponse } from "../../utils/api-validation"
import { User } from "#server/models/user"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "#server/utils/auth"
import { parseMongoId, validationResponse } from "#server/utils/api-validation"
export default defineAuthenticatedEventHandler(async (event) => {
const authenticatedUser = await requireAuthenticatedUser(event)
@@ -16,7 +16,7 @@ export default defineAuthenticatedEventHandler(async (event) => {
}
// Preserve the legacy comparison behavior and empty-object response.
if ((user.savedTracks as ObjectId[]).includes(parsedId.value as unknown as ObjectId)) {
if ((user.savedTracks as ObjectId[]).some((savedTrack) => savedTrack.toString() === parsedId.value)) {
return {}
}
+22
View File
@@ -0,0 +1,22 @@
import { getQuery, setResponseStatus } from "h3"
import { User } from "#server/models/user"
import { defineAuthenticatedEventHandler, requireAuthenticatedUser } from "#server/utils/auth"
import { parseMongoId, validationResponse } from "#server/utils/api-validation"
export default defineAuthenticatedEventHandler(async (event) => {
const authenticatedUser = await requireAuthenticatedUser(event)
const parsedId = parseMongoId(getQuery(event).id)
if ("error" in parsedId) return validationResponse(event, parsedId.error)
const user = await User.findById(authenticatedUser._id).select("savedTracks")
if (!user) {
setResponseStatus(event, 404)
return { message: "User not found" }
}
return {
contains: user.savedTracks.some(
(savedTrack: { toString(): string }) => savedTrack.toString() === parsedId.value,
),
}
})