fix(upload): resolve folder selection issue and improve 'To Be Scanned' playlist creation - add debug logging, visual selection indicator, simplify playlist creation logic, support batch uploads with markForScan
This commit is contained in:
parent
7557eddeb4
commit
675c1f8d8f
@ -102,33 +102,21 @@ router.post('/upload', upload.single('file'), async (req, res) => {
|
|||||||
if (markForScan) {
|
if (markForScan) {
|
||||||
try {
|
try {
|
||||||
const { Playlist } = await import('../models/Playlist.js');
|
const { Playlist } = await import('../models/Playlist.js');
|
||||||
// Ensure root exists or create simple structure
|
|
||||||
let root = await Playlist.findOne({ name: 'ROOT' });
|
|
||||||
if (!root) {
|
|
||||||
root = new Playlist({ name: 'ROOT', type: 'folder', children: [] });
|
|
||||||
await root.save();
|
|
||||||
}
|
|
||||||
// Find or create the "To Be Scanned" playlist at root level
|
|
||||||
const findNode = (node: any, name: string): any => {
|
|
||||||
if (!node) return null;
|
|
||||||
if (node.type === 'playlist' && node.name === name) return node;
|
|
||||||
if (Array.isArray(node.children)) {
|
|
||||||
for (const child of node.children) {
|
|
||||||
const found = findNode(child, name);
|
|
||||||
if (found) return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
let toScan = findNode(root, 'To Be Scanned');
|
|
||||||
if (!toScan) {
|
|
||||||
toScan = { id: 'to-be-scanned', name: 'To Be Scanned', type: 'playlist', tracks: [] } as any;
|
|
||||||
root.children = [...(root.children || []), toScan];
|
|
||||||
}
|
|
||||||
// Add by songId? We don't have a Song yet; add by MusicFile ObjectId to track later
|
|
||||||
// Instead, we will create a stub Song entry if none exists so XML export can include it
|
|
||||||
const { Song } = await import('../models/Song.js');
|
const { Song } = await import('../models/Song.js');
|
||||||
|
|
||||||
|
// Find or create the "To Be Scanned" playlist
|
||||||
|
let toScanPlaylist = await Playlist.findOne({ name: 'To Be Scanned' });
|
||||||
|
if (!toScanPlaylist) {
|
||||||
|
toScanPlaylist = new Playlist({
|
||||||
|
name: 'To Be Scanned',
|
||||||
|
type: 'playlist',
|
||||||
|
tracks: [],
|
||||||
|
order: 0
|
||||||
|
});
|
||||||
|
await toScanPlaylist.save();
|
||||||
|
console.log('✅ Created "To Be Scanned" playlist');
|
||||||
|
}
|
||||||
|
|
||||||
// Create stub song with temporary id if needed
|
// Create stub song with temporary id if needed
|
||||||
const tempId = `stub-${musicFile._id.toString()}`;
|
const tempId = `stub-${musicFile._id.toString()}`;
|
||||||
let existingStub = await Song.findOne({ id: tempId });
|
let existingStub = await Song.findOne({ id: tempId });
|
||||||
@ -140,14 +128,25 @@ router.post('/upload', upload.single('file'), async (req, res) => {
|
|||||||
album: musicFile.album || '',
|
album: musicFile.album || '',
|
||||||
totalTime: musicFile.duration ? String(Math.round(musicFile.duration / 1000)) : '',
|
totalTime: musicFile.duration ? String(Math.round(musicFile.duration / 1000)) : '',
|
||||||
location: '',
|
location: '',
|
||||||
|
s3File: {
|
||||||
|
musicFileId: musicFile._id,
|
||||||
|
s3Key: musicFile.s3Key,
|
||||||
|
s3Url: musicFile.s3Url,
|
||||||
|
hasS3File: true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await stub.save();
|
await stub.save();
|
||||||
|
console.log('✅ Created stub song:', tempId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add stub song to playlist if not already there
|
||||||
|
if (!toScanPlaylist.tracks.includes(tempId)) {
|
||||||
|
toScanPlaylist.tracks.push(tempId);
|
||||||
|
await toScanPlaylist.save();
|
||||||
|
console.log('✅ Added song to "To Be Scanned" playlist');
|
||||||
}
|
}
|
||||||
// Push stub id into playlist
|
|
||||||
toScan.tracks = Array.from(new Set([...(toScan.tracks || []), tempId]));
|
|
||||||
await root.save();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to mark uploaded file for scanning:', e);
|
console.error('❌ Failed to mark uploaded file for scanning:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +169,7 @@ router.post('/batch-upload', upload.array('files', 10), async (req, res) => {
|
|||||||
return res.status(400).json({ error: 'No files uploaded' });
|
return res.status(400).json({ error: 'No files uploaded' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { markForScan = false } = req.body;
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
for (const file of req.files as Express.Multer.File[]) {
|
for (const file of req.files as Express.Multer.File[]) {
|
||||||
@ -195,6 +195,58 @@ router.post('/batch-upload', upload.array('files', 10), async (req, res) => {
|
|||||||
await musicFile.save();
|
await musicFile.save();
|
||||||
results.push({ success: true, musicFile });
|
results.push({ success: true, musicFile });
|
||||||
|
|
||||||
|
// Optionally add to "To Be Scanned" playlist
|
||||||
|
if (markForScan) {
|
||||||
|
try {
|
||||||
|
const { Playlist } = await import('../models/Playlist.js');
|
||||||
|
const { Song } = await import('../models/Song.js');
|
||||||
|
|
||||||
|
// Find or create the "To Be Scanned" playlist
|
||||||
|
let toScanPlaylist = await Playlist.findOne({ name: 'To Be Scanned' });
|
||||||
|
if (!toScanPlaylist) {
|
||||||
|
toScanPlaylist = new Playlist({
|
||||||
|
name: 'To Be Scanned',
|
||||||
|
type: 'playlist',
|
||||||
|
tracks: [],
|
||||||
|
order: 0
|
||||||
|
});
|
||||||
|
await toScanPlaylist.save();
|
||||||
|
console.log('✅ Created "To Be Scanned" playlist (batch)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create stub song with temporary id if needed
|
||||||
|
const tempId = `stub-${musicFile._id.toString()}`;
|
||||||
|
let existingStub = await Song.findOne({ id: tempId });
|
||||||
|
if (!existingStub) {
|
||||||
|
const stub = new Song({
|
||||||
|
id: tempId,
|
||||||
|
title: musicFile.title || musicFile.originalName,
|
||||||
|
artist: musicFile.artist || '',
|
||||||
|
album: musicFile.album || '',
|
||||||
|
totalTime: musicFile.duration ? String(Math.round(musicFile.duration / 1000)) : '',
|
||||||
|
location: '',
|
||||||
|
s3File: {
|
||||||
|
musicFileId: musicFile._id,
|
||||||
|
s3Key: musicFile.s3Key,
|
||||||
|
s3Url: musicFile.s3Url,
|
||||||
|
hasS3File: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await stub.save();
|
||||||
|
console.log('✅ Created stub song (batch):', tempId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add stub song to playlist if not already there
|
||||||
|
if (!toScanPlaylist.tracks.includes(tempId)) {
|
||||||
|
toScanPlaylist.tracks.push(tempId);
|
||||||
|
await toScanPlaylist.save();
|
||||||
|
console.log('✅ Added song to "To Be Scanned" playlist (batch)');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ Failed to mark uploaded file for scanning (batch):', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Invalidate folder cache since we added a new file
|
// Invalidate folder cache since we added a new file
|
||||||
invalidateFolderCache();
|
invalidateFolderCache();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -155,6 +155,11 @@ export const MusicUpload: React.FC<MusicUploadProps> = ({ onUploadComplete }) =>
|
|||||||
<VStack spacing={4} align="stretch" w="full">
|
<VStack spacing={4} align="stretch" w="full">
|
||||||
<Box>
|
<Box>
|
||||||
<Text color="gray.300" fontSize="sm" mb={3}>Target S3 folder</Text>
|
<Text color="gray.300" fontSize="sm" mb={3}>Target S3 folder</Text>
|
||||||
|
{targetFolder && (
|
||||||
|
<Text color="blue.400" fontSize="sm" mb={2}>
|
||||||
|
Selected: {targetFolder === '' ? '(root)' : targetFolder}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
{isLoadingFolders ? (
|
{isLoadingFolders ? (
|
||||||
<Box
|
<Box
|
||||||
p={6}
|
p={6}
|
||||||
@ -171,7 +176,10 @@ export const MusicUpload: React.FC<MusicUploadProps> = ({ onUploadComplete }) =>
|
|||||||
<FolderBrowser
|
<FolderBrowser
|
||||||
folders={folders}
|
folders={folders}
|
||||||
selectedFolder={targetFolder}
|
selectedFolder={targetFolder}
|
||||||
onFolderSelect={setTargetFolder}
|
onFolderSelect={(folder) => {
|
||||||
|
console.log('Folder selected:', folder);
|
||||||
|
setTargetFolder(folder);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user