75 lines
1.9 KiB
JavaScript
75 lines
1.9 KiB
JavaScript
import mongoose from 'mongoose';
|
|
import Track from '../models/Track.js';
|
|
|
|
export const searchController = {
|
|
async search(req, res, next) {
|
|
try {
|
|
const query = (req.query.q || '').trim();
|
|
|
|
if (!query) {
|
|
return res.json({
|
|
success: true,
|
|
data: { tracks: [], artists: [], albums: [] },
|
|
});
|
|
}
|
|
|
|
const regex = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
|
|
|
|
const tracks = await Track.find({
|
|
$or: [
|
|
{ title: regex },
|
|
{ artist: regex },
|
|
{ album: regex },
|
|
],
|
|
})
|
|
.select('-__v')
|
|
.sort({ createdAt: -1 })
|
|
.limit(50)
|
|
.lean();
|
|
|
|
const artistMap = new Map();
|
|
tracks.forEach(t => {
|
|
if (!artistMap.has(t.artist)) {
|
|
artistMap.set(t.artist, {
|
|
_id: new mongoose.Types.ObjectId(),
|
|
name: t.artist,
|
|
imageUrl: t.coverUrl || '',
|
|
trackCount: 0,
|
|
});
|
|
}
|
|
const entry = artistMap.get(t.artist);
|
|
entry.trackCount++;
|
|
if (t.coverUrl && !entry.imageUrl) {
|
|
entry.imageUrl = t.coverUrl;
|
|
}
|
|
});
|
|
const artists = [...artistMap.values()];
|
|
|
|
const albumMap = new Map();
|
|
tracks.forEach(t => {
|
|
if (!albumMap.has(t.album)) {
|
|
albumMap.set(t.album, {
|
|
_id: new mongoose.Types.ObjectId(),
|
|
title: t.album,
|
|
artist: t.artist,
|
|
coverUrl: t.coverUrl || '',
|
|
trackCount: 0,
|
|
});
|
|
}
|
|
const entry = albumMap.get(t.album);
|
|
entry.trackCount++;
|
|
if (t.coverUrl && !entry.coverUrl) {
|
|
entry.coverUrl = t.coverUrl;
|
|
}
|
|
});
|
|
const albums = [...albumMap.values()];
|
|
|
|
const data = { tracks, artists, albums };
|
|
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return next(error);
|
|
}
|
|
},
|
|
};
|