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:
Geert Rademakes 2025-08-14 11:55:54 +02:00
parent 7557eddeb4
commit 675c1f8d8f
2 changed files with 91 additions and 31 deletions

View File

@ -102,33 +102,21 @@ router.post('/upload', upload.single('file'), async (req, res) => {
if (markForScan) {
try {
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');
// 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
const tempId = `stub-${musicFile._id.toString()}`;
let existingStub = await Song.findOne({ id: tempId });
@ -140,14 +128,25 @@ router.post('/upload', upload.single('file'), async (req, res) => {
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:', 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) {
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' });
}
const { markForScan = false } = req.body;
const results = [];
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();
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
invalidateFolderCache();
} catch (error) {

View File

@ -155,6 +155,11 @@ export const MusicUpload: React.FC<MusicUploadProps> = ({ onUploadComplete }) =>
<VStack spacing={4} align="stretch" w="full">
<Box>
<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 ? (
<Box
p={6}
@ -171,7 +176,10 @@ export const MusicUpload: React.FC<MusicUploadProps> = ({ onUploadComplete }) =>
<FolderBrowser
folders={folders}
selectedFolder={targetFolder}
onFolderSelect={setTargetFolder}
onFolderSelect={(folder) => {
console.log('Folder selected:', folder);
setTargetFolder(folder);
}}
/>
) : (
<Input