mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-12 10:35:41 -04:00
106 lines
4.3 KiB
JavaScript
106 lines
4.3 KiB
JavaScript
import { Router } from 'express';
|
|
import { Playlist } from '../models/Playlist.js';
|
|
import { PlaylistChannel } from '../models/PlaylistChannel.js';
|
|
import { Channel } from '../models/Channel.js';
|
|
import { SourceChannel } from '../models/SourceChannel.js';
|
|
import { toUiChannel } from '../sources/translate.js';
|
|
export const playlistsRouter = Router();
|
|
// Channel count comes from SourceChannel for (Default) source playlists, else the legacy join table.
|
|
async function channelCountFor(doc) {
|
|
if (doc.source)
|
|
return SourceChannel.countDocuments({ source: doc.source });
|
|
return PlaylistChannel.countDocuments({ playlistId: doc.id });
|
|
}
|
|
playlistsRouter.get('/', async (_req, res, next) => {
|
|
try {
|
|
const docs = await Playlist.find({}, { _id: 0 }).lean();
|
|
const [legacyCounts, sourceCounts] = await Promise.all([
|
|
PlaylistChannel.aggregate([
|
|
{ $group: { _id: '$playlistId', count: { $sum: 1 } } },
|
|
]),
|
|
SourceChannel.aggregate([
|
|
{ $group: { _id: '$source', count: { $sum: 1 } } },
|
|
]),
|
|
]);
|
|
const legacyById = new Map(legacyCounts.map((c) => [c._id, c.count]));
|
|
const sourceBySource = new Map(sourceCounts.map((c) => [c._id, c.count]));
|
|
res.json(docs.map((d) => ({
|
|
...d,
|
|
channels: d.source ? sourceBySource.get(d.source) ?? 0 : legacyById.get(d.id) ?? 0,
|
|
})));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
playlistsRouter.get('/:id', async (req, res, next) => {
|
|
try {
|
|
const doc = await Playlist.findOne({ id: req.params.id }, { _id: 0 }).lean();
|
|
if (!doc)
|
|
return res.status(404).json({ error: 'not_found' });
|
|
res.json({ ...doc, channels: await channelCountFor(doc) });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// List channels in a playlist. (Default) source playlists project the canonical SourceChannel docs
|
|
// through the translation layer (UI shape, nulls for unmapped fields); legacy playlists use the join.
|
|
playlistsRouter.get('/:id/channels', async (req, res, next) => {
|
|
try {
|
|
const playlist = await Playlist.findOne({ id: req.params.id }).lean();
|
|
if (!playlist)
|
|
return res.status(404).json({ error: 'not_found' });
|
|
if (playlist.source) {
|
|
const docs = await SourceChannel.find({ source: playlist.source })
|
|
.sort({ groupKey: 1, name: 1 })
|
|
.lean();
|
|
return res.json(docs.map((d, order) => ({ ...toUiChannel(d), order })));
|
|
}
|
|
const memberships = await PlaylistChannel.find({ playlistId: req.params.id }, { _id: 0 })
|
|
.sort({ order: 1 })
|
|
.lean();
|
|
const channelIds = memberships.map((m) => m.channelId);
|
|
const channels = await Channel.find({ id: { $in: channelIds } }, { _id: 0 }).lean();
|
|
const byId = new Map(channels.map((c) => [c.id, c]));
|
|
res.json(memberships
|
|
.map((m) => {
|
|
const ch = byId.get(m.channelId);
|
|
return ch ? { ...ch, order: m.order } : null;
|
|
})
|
|
.filter(Boolean));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// Add a channel to a (legacy) playlist (idempotent on the unique pair).
|
|
playlistsRouter.post('/:id/channels', async (req, res, next) => {
|
|
try {
|
|
const { channelId, order } = req.body ?? {};
|
|
if (typeof channelId !== 'string' || typeof order !== 'number') {
|
|
return res.status(400).json({ error: 'channelId (string) and order (number) required' });
|
|
}
|
|
const doc = await PlaylistChannel.findOneAndUpdate({ playlistId: req.params.id, channelId }, { $set: { order } }, { upsert: true, new: true, projection: { _id: 0 } }).lean();
|
|
res.status(201).json(doc);
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// Remove a channel from a (legacy) playlist.
|
|
playlistsRouter.delete('/:id/channels/:channelId', async (req, res, next) => {
|
|
try {
|
|
const result = await PlaylistChannel.deleteOne({
|
|
playlistId: req.params.id,
|
|
channelId: req.params.channelId,
|
|
});
|
|
if (result.deletedCount === 0)
|
|
return res.status(404).json({ error: 'not_found' });
|
|
res.status(204).end();
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
//# sourceMappingURL=playlists.js.map
|