- Remove end-of-job cleanup phases from S3 sync and song matching jobs - Update Song documents immediately after each successful match in both Phase 1 and Phase 2 - Ensure hasS3File flag is set to true immediately for each matched song - Enable play buttons to appear instantly as songs are processed - Make system perfectly resilient to interruptions - no orphaned files - Allow seamless resume capability for long-running sync jobs - Provide real-time availability of matched songs without waiting for job completion - Maintain system consistency regardless of when sync gets interrupted
81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
import express from 'express';
|
|
import { Playlist } from '../models/Playlist.js';
|
|
import { Request, Response } from 'express';
|
|
|
|
const router = express.Router();
|
|
|
|
// Get all playlists
|
|
router.get('/', async (req: Request, res: Response) => {
|
|
try {
|
|
const playlists = await Playlist.find({});
|
|
res.json(playlists);
|
|
} catch (error) {
|
|
console.error('Error fetching playlists:', error);
|
|
res.status(500).json({ message: 'Error fetching playlists', error });
|
|
}
|
|
});
|
|
|
|
// Get playlist structure only (without track data) for faster loading
|
|
router.get('/structure', async (req: Request, res: Response) => {
|
|
try {
|
|
const playlists = await Playlist.find({});
|
|
|
|
// Keep track counts but remove full track data to reduce payload size
|
|
const structureOnly = playlists.map(playlist => {
|
|
const cleanPlaylist = playlist.toObject() as any;
|
|
|
|
// Replace tracks array with track count for the main playlist
|
|
if (cleanPlaylist.tracks) {
|
|
cleanPlaylist.trackCount = cleanPlaylist.tracks.length;
|
|
delete cleanPlaylist.tracks;
|
|
} else {
|
|
cleanPlaylist.trackCount = 0;
|
|
}
|
|
|
|
// Recursively process children
|
|
const cleanChildren = (children: any[]): any[] => {
|
|
return children.map(child => {
|
|
const cleanChild = { ...child } as any;
|
|
|
|
// Replace tracks array with track count
|
|
if (cleanChild.tracks) {
|
|
cleanChild.trackCount = cleanChild.tracks.length;
|
|
delete cleanChild.tracks;
|
|
} else {
|
|
cleanChild.trackCount = 0;
|
|
}
|
|
|
|
if (cleanChild.children && cleanChild.children.length > 0) {
|
|
cleanChild.children = cleanChildren(cleanChild.children);
|
|
}
|
|
return cleanChild;
|
|
});
|
|
};
|
|
|
|
if (cleanPlaylist.children && cleanPlaylist.children.length > 0) {
|
|
cleanPlaylist.children = cleanChildren(cleanPlaylist.children);
|
|
}
|
|
|
|
return cleanPlaylist;
|
|
});
|
|
|
|
res.json(structureOnly);
|
|
} catch (error) {
|
|
console.error('Error fetching playlist structure:', error);
|
|
res.status(500).json({ message: 'Error fetching playlist structure', error });
|
|
}
|
|
});
|
|
|
|
// Save playlists in batch (replacing all existing ones)
|
|
router.post('/batch', async (req, res) => {
|
|
try {
|
|
await Playlist.deleteMany({}); // Clear existing playlists
|
|
const playlists = await Playlist.create(req.body);
|
|
res.json(playlists);
|
|
} catch (error) {
|
|
console.error('Error saving playlists:', error);
|
|
res.status(500).json({ error: 'Failed to save playlists' });
|
|
}
|
|
});
|
|
|
|
export const playlistsRouter = router;
|