audio streaming app plyr.fm
38
fork

Configure Feed

Select the types of activity you want to include in your feed.

make album uploads concurrent with per-track toast messages (#1238)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

authored by

nate nowack
Claude Opus 4.6
and committed by
GitHub
f594b67a ed9b9876

+16 -13
+9 -8
frontend/src/lib/components/AlbumUploadForm.svelte
··· 36 36 ); 37 37 38 38 let completedCount = $derived(tracks.filter((t) => t.status === 'completed').length); 39 - let currentUploadIndex = $derived(tracks.findIndex((t) => t.status === 'uploading' || t.status === 'processing')); 39 + let activeUploadCount = $derived(tracks.filter((t) => t.status === 'uploading' || t.status === 'processing').length); 40 40 let hasUnresolvedFeatures = $derived(tracks.some((t) => t.hasUnresolvedFeaturesInput)); 41 41 42 42 let canSubmit = $derived( ··· 238 238 let completed = 0; 239 239 let failed = 0; 240 240 241 - for (let i = 0; i < tracks.length; i++) { 242 - const track = tracks[i]; 241 + const promises = tracks.map((track, i) => { 243 242 tracks[i] = { ...tracks[i], status: 'uploading' }; 244 243 245 - await new Promise<void>((resolve) => { 244 + return new Promise<void>((resolve) => { 246 245 let resolved = false; 247 246 const safeResolve = () => { 248 247 if (!resolved) { ··· 264 263 track.title, 265 264 albumTitle.trim(), 266 265 [...track.featuredArtists], 267 - i === 0 ? coverArtFile : null, 266 + coverArtFile, 268 267 [...track.tags], 269 268 track.supportGated, 270 269 track.autoTag, ··· 289 288 safeResolve(); 290 289 }, 291 290 }, 291 + track.title, 292 292 ); 293 293 }); 294 - } 294 + }); 295 + await Promise.allSettled(promises); 295 296 296 297 // refresh albums so we can find the slug for the "view album" link 297 298 await onAlbumsReload(); ··· 404 405 405 406 {#if uploading} 406 407 <div class="upload-progress"> 407 - {#if currentUploadIndex >= 0} 408 + {#if activeUploadCount > 0} 408 409 <p class="progress-text"> 409 - uploading track {currentUploadIndex + 1} of {tracks.length}... 410 + {completedCount} of {tracks.length} completed, {activeUploadCount} uploading... 410 411 </p> 411 412 {:else} 412 413 <p class="progress-text">
+6 -4
frontend/src/lib/uploader.svelte.ts
··· 73 73 autoTag: boolean, 74 74 description: string, 75 75 onSuccess?: () => void, 76 - callbacks?: UploadProgressCallback 76 + callbacks?: UploadProgressCallback, 77 + label?: string 77 78 ): void { 78 79 const taskId = crypto.randomUUID(); 79 80 const fileSizeMB = file.size / 1024 / 1024; 80 81 const isMobile = isMobileDevice(); 82 + const displayName = label ?? title; 81 83 82 84 // warn about large files on mobile 83 85 if (isMobile && fileSizeMB > MOBILE_LARGE_FILE_THRESHOLD_MB) { ··· 85 87 } 86 88 87 89 const uploadMessage = fileSizeMB > 10 88 - ? 'uploading track... (large file, this may take a moment)' 89 - : 'uploading track...'; 90 + ? `uploading "${displayName}"... (large file)` 91 + : `uploading "${displayName}"...`; 90 92 // 0 means infinite/persist until dismissed 91 93 const toastId = toast.info(uploadMessage, 0); 92 94 ··· 185 187 this.activeUploads.delete(taskId); 186 188 187 189 const trackId = update.track_id; 188 - toast.success('track uploaded successfully!', 5000, trackId ? { 190 + toast.success(`"${displayName}" uploaded`, 5000, trackId ? { 189 191 label: 'view track', 190 192 href: `/track/${trackId}` 191 193 } : undefined);
+1 -1
loq.toml
··· 247 247 248 248 [[rules]] 249 249 path = "frontend/src/lib/components/AlbumUploadForm.svelte" 250 - max_lines = 742 250 + max_lines = 743 251 251 252 252 [[rules]] 253 253 path = "frontend/src/lib/components/TrackEntryCard.svelte"