use new items list standart

This commit is contained in:
SrGooglo 2025-02-05 02:51:35 +00:00
parent 3990ef45c9
commit 9c9fa4c18b
13 changed files with 295 additions and 177 deletions

View File

@ -12,6 +12,7 @@ const AllowedUpdateFields = [
export default class Release {
static async create(payload) {
console.log(payload)
if (!payload.title) {
throw new OperationError(400, "Release title is required")
}
@ -21,7 +22,7 @@ export default class Release {
}
// ensure list is an array of strings with tracks ids only
playload.list = playload.list.map((item) => {
payload.list = payload.list.map((item) => {
if (typeof item !== "string") {
item = item._id
}

View File

@ -1,66 +1,96 @@
import { Track, TrackLike } from "@db_models"
async function fullfillData(list, { user_id = null }) {
if (!Array.isArray(list)) {
list = [list]
}
const trackIds = list.map((track) => {
return track._id
})
// if user_id is provided, fetch likes
if (user_id) {
const tracksLikes = await TrackLike.find({
user_id: user_id,
track_id: { $in: trackIds },
})
list = list.map(async (track) => {
const trackLike = tracksLikes.find((trackLike) => {
return trackLike.track_id.toString() === track._id.toString()
})
if (trackLike) {
track.liked_at = trackLike.created_at
track.liked = true
}
return track
})
list = await Promise.all(list)
}
// process some metadata
list = list.map(async (track) => {
if (track.metadata) {
if (track.metadata.bitrate && track.metadata.bitrate > 9000) {
track.metadata.lossless = true
}
}
return track
})
list = await Promise.all(list)
return list
}
export default async (track_id, { user_id = null, onlyList = false } = {}) => {
if (!track_id) {
throw new OperationError(400, "Missing track_id")
}
if (!track_id) {
throw new OperationError(400, "Missing track_id")
}
const isMultiple = Array.isArray(track_id) || track_id.includes(",")
const isMultiple = Array.isArray(track_id) || track_id.includes(",")
if (isMultiple) {
const track_ids = Array.isArray(track_id) ? track_id : track_id.split(",")
if (isMultiple) {
const track_ids = Array.isArray(track_id)
? track_id
: track_id.split(",")
const tracks = await Track.find({
_id: { $in: track_ids }
}).lean()
let tracks = await Track.find({
_id: { $in: track_ids },
}).lean()
if (user_id) {
const trackLikes = await TrackLike.find({
user_id: user_id,
track_id: { $in: track_ids }
})
tracks = await fullfillData(tracks, {
user_id,
})
// FIXME: this could be a performance issue when there are a lot of likes
// Array.find may not be a good idea
for (const trackLike of trackLikes) {
const track = tracks.find(track => track._id.toString() === trackLike.track_id.toString())
if (onlyList) {
return tracks
}
if (track) {
track.liked_at = trackLike.created_at
track.liked = true
}
}
}
return {
total_count: await Track.countDocuments({
_id: { $in: track_ids },
}),
list: tracks,
}
}
if (onlyList) {
return tracks
}
let track = await Track.findOne({
_id: track_id,
}).lean()
return {
total_count: await Track.countDocuments({ _id: { $in: track_ids } }),
list: tracks,
}
}
if (!track) {
throw new OperationError(404, "Track not found")
}
const track = await Track.findOne({
_id: track_id
}).lean()
track = await fullfillData(track, {
user_id,
})
if (!track) {
throw new OperationError(404, "Track not found")
}
if (user_id) {
const trackLike = await TrackLike.findOne({
user_id: user_id,
track_id: track_id,
})
if (trackLike) {
track.liked_at = trackLike.created_at
track.liked = true
}
}
return track
}
return track[0]
}

View File

@ -9,7 +9,7 @@ export default async (user_id, track_id, to) => {
throw new OperationError(400, "Missing track_id")
}
const track = await Track.findById(track_id)
const track = await Track.findById(track_id).catch(() => null)
if (!track) {
throw new OperationError(404, "Track not found")

View File

@ -45,8 +45,6 @@ export default async (user_id, track_id, to) => {
}
}
console.log(global.websocket.find)
const targetSocket = await global.websocket.find.socketByUserId(user_id)
if (targetSocket) {

View File

@ -1,23 +1,23 @@
import { MusicRelease, Track } from "@db_models"
export default async (req) => {
const { limit = 10, trim = 0, order = "desc" } = req.query
const { limit = 10, trim = 0, order = "desc" } = req.query
const searchQuery = {}
const searchQuery = {}
const total_length = await MusicRelease.countDocuments(searchQuery)
const total_length = await MusicRelease.countDocuments(searchQuery)
let result = await MusicRelease.find({
...searchQuery,
public: true,
})
.limit(limit)
.skip(trim)
.sort({ created_at: order === "desc" ? -1 : 1 })
let result = await MusicRelease.find({
...searchQuery,
public: true,
})
.limit(limit)
.skip(trim)
.sort({ created_at: order === "desc" ? -1 : 1 })
return {
total_length: total_length,
has_more: total_length > trim + result.length,
items: result,
}
}
return {
total_length: total_length,
has_more: total_length > trim + result.length,
items: result,
}
}

View File

@ -1,16 +1,16 @@
export default {
middlewares: ["withAuthentication"],
fn: async (req) => {
const { keywords, limit = 10, offset = 0 } = req.query
middlewares: ["withAuthentication"],
fn: async (req) => {
const { keywords, limit = 10, offset = 0 } = req.query
const user_id = req.auth.session.user_id
const user_id = req.auth.session.user_id
let total_length = 0
let result = []
let total_length = 0
let result = []
return {
total_length: total_length,
items: result,
}
}
}
return {
total_length: total_length,
items: result,
}
},
}

View File

@ -6,9 +6,8 @@ export default {
const { track_id } = req.params
const { video_source, lrc, sync_audio_at } = req.body
let track = await Track.findOne({
_id: track_id,
})
// check if track exists
let track = await Track.findById(track_id).catch(() => null)
if (!track) {
throw new OperationError(404, "Track not found")
@ -22,13 +21,14 @@ export default {
track_id: track_id,
video_source: video_source,
lrc: lrc,
track: track,
})
// check if trackLyric exists
let trackLyric = await TrackLyric.findOne({
track_id: track_id
}).lean()
})
// if trackLyric exists, update it, else create it
if (!trackLyric) {
trackLyric = new TrackLyric({
track_id: track_id,

View File

@ -1,73 +1,93 @@
import {
TrackLike,
} from "@db_models"
import { TrackLike } from "@db_models"
import TrackClass from "@classes/track"
const HANDLERS = {
track: {
model: TrackLike,
class: TrackClass,
type: "tracks",
idField: "track_id",
},
// release: {
// model: ReleaseLike,
// class: ReleaseClass,
// type: 'releases',
// idField: 'release_id'
// },
// playlist: {
// model: PlaylistLike,
// class: PlaylistClass,
// type: 'playlists',
// idField: 'playlist_id'
// },
}
async function getLikedItemsFromHandler(config, userId, pagination) {
try {
// obtain ids data and total items
const [total, likes] = await Promise.all([
config.model.countDocuments({ user_id: userId }),
config.model
.find({ user_id: userId })
.sort({ created_at: -1 })
.limit(pagination.limit)
.skip(pagination.offset),
])
const likedAtMap = new Map()
const itemIds = []
for (const like of likes) {
const itemId = like[config.idField]
likedAtMap.set(itemId, like.created_at)
itemIds.push(itemId)
}
// fetch track data
let processedItems = await config.class.get(itemIds, {
onlyList: true,
minimalData: true,
})
// mix with likes data
processedItems = processedItems.map((item) => {
item.liked = true
item.liked_at = likedAtMap.get(item._id.toString())
return item
})
return {
items: processedItems,
total_items: total,
}
} catch (error) {
console.error(`Error processing ${config.type}:`, error)
return { items: [], total_items: 0 }
}
}
//
// A endpoint to fetch track & playlists & releases likes
//
export default {
middlewares: ["withAuthentication"],
fn: async (req) => {
const user_id = req.auth.session.user_id
const { limit, offset } = req.query
middlewares: ["withAuthentication"],
fn: async (req) => {
const userId = req.auth.session.user_id
const { limit = 50, offset = 0 } = req.query
const [
totalTrackLikes,
totalReleasesLikes,
totalPlaylistsLikes,
] = await Promise.all([
TrackLike.countDocuments({ user_id }),
0,
0,
])
const activeHandlers = Object.values(HANDLERS)
let [
trackLikes,
releasesLikes,
playlistsLikes
] = await Promise.all([
TrackLike.find({
user_id
})
.limit(limit)
.skip(offset),
[],
[],
])
const results = await Promise.all(
activeHandlers.map((handler) =>
getLikedItemsFromHandler(handler, userId, { limit, offset }),
),
)
let [
Tracks,
Releases,
Playlists,
] = await Promise.all([
TrackClass.get(trackLikes.map(trackLike => trackLike.track_id), {
user_id,
onlyList: true,
}),
[],
[],
])
Tracks = Tracks.sort((a, b) => b.liked_at - a.liked_at)
// Releases = Releases.sort((a, b) => b.liked_at - a.liked_at)
// Playlists = Playlists.sort((a, b) => b.liked_at - a.liked_at)
return {
tracks: {
list: Tracks,
total_items: totalTrackLikes,
},
releases: {
list: Releases,
total_items: totalReleasesLikes,
},
playlists: {
list: Playlists,
total_items: totalPlaylistsLikes,
},
total_length: totalTrackLikes + totalReleasesLikes + totalPlaylistsLikes,
}
}
}
return activeHandlers.reduce((response, handler, index) => {
response[handler.type] = results[index]
return response
}, {})
},
}

View File

@ -16,6 +16,20 @@ export default {
.limit(req.query.limit ?? 20)
.sort({ created_at: -1 })
// filter tracks has different service than comtymusic
activities = activities.map((activity) => {
if (activity.payload.service && activity.payload.service !== "default") {
return null
}
return activity
})
// filter null & undefined tracks
activities = activities.filter((activity) => {
return activity
})
// filter undefined tracks_ids
activities = activities.filter((activity) => {
return activity.payload && activity.payload.track_id

View File

@ -2,33 +2,33 @@ import { MusicRelease, Track } from "@db_models"
import TrackClass from "@classes/track"
export default {
middlewares: ["withOptionalAuthentication"],
fn: async (req) => {
const { release_id } = req.params
const { limit = 50, offset = 0 } = req.query
middlewares: ["withOptionalAuthentication"],
fn: async (req) => {
const { release_id } = req.params
const { limit = 50, offset = 0 } = req.query
let release = await MusicRelease.findOne({
_id: release_id
})
let release = await MusicRelease.findOne({
_id: release_id,
})
if (!release) {
throw new OperationError(404, "Release not found")
}
if (!release) {
throw new OperationError(404, "Release not found")
}
release = release.toObject()
release = release.toObject()
const totalTracks = await Track.countDocuments({
_id: release.list
})
const totalTracks = await Track.countDocuments({
_id: release.list,
})
const tracks = await TrackClass.get(release.list, {
user_id: req.auth?.session?.user_id,
onlyList: true
})
const tracks = await TrackClass.get(release.list, {
user_id: req.auth?.session?.user_id,
onlyList: true,
})
release.listLength = totalTracks
release.list = tracks
release.listLength = totalTracks
release.items = tracks
return release
}
}
return release
},
}

View File

@ -0,0 +1,17 @@
import { TrackOverride } from "@db_models"
export default async (req) => {
const { track_id } = req.params
const { service } = req.query
const trackOverride = await TrackOverride.findOne({
track_id: track_id,
service: service,
})
if (!trackOverride) {
throw new OperationError(404, "Track override not found")
}
return trackOverride.override
}

View File

@ -0,0 +1,36 @@
import { TrackOverride } from "@db_models"
export default {
middlewares: ["withAuthentication", "onlyAdmin"],
fn: async (req) => {
const { track_id } = req.params
const { service, override } = req.body
let trackOverride = await TrackOverride.findOne({
track_id: track_id,
service: service,
}).catch(() => null)
if (!trackOverride) {
trackOverride = new TrackOverride({
track_id: track_id,
service: service,
override: override,
})
await trackOverride.save()
} else {
trackOverride = await TrackOverride.findOneAndUpdate(
{
track_id: track_id,
service: service,
},
{
override: override,
},
)
}
return trackOverride.override
}
}

View File

@ -8,7 +8,9 @@ export default {
let results = []
for await (const item of req.body.list) {
requiredFields(["title", "source"], item)
if (!item.source || !item.title) {
continue
}
const track = await TrackClass.create({
...item,