From 797726b68ed120248cc4c097c709ad070f254028 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sat, 16 May 2026 19:31:02 -0400 Subject: [PATCH] feat(worker): broadcast scan_complete WebSocket message on scan job finish The MessageTypeScanComplete constant existed but was never actually sent by the worker. This meant the frontend had no way to know when a scan finished. - After a JobTypeScan completes, broadcast scan_complete to the job's user via WebSocket ConnectionManager - Includes job_id, files_scanned, new_items, and errors in the payload - Only broadcasts for JobTypeScan (not other job types) when connManager is available and job.UserID is set --- internal/services/worker.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/internal/services/worker.go b/internal/services/worker.go index 050adf0..da7c0d4 100644 --- a/internal/services/worker.go +++ b/internal/services/worker.go @@ -305,6 +305,19 @@ func (w *Worker) processJob(job *Job) { NewItems: newItems, Errors: errors, } + + if job.Type == JobTypeScan && w.connManager != nil && job.UserID != "" { + w.connManager.BroadcastToUser(job.UserID, wsync.BroadcastMessage{ + Type: wsync.MessageTypeScanComplete, + Data: map[string]interface{}{ + "job_id": job.ID, + "files_scanned": filesScanned, + "new_items": newItems, + "errors": errors, + }, + }) + } + w.mu.Unlock() } @@ -888,9 +901,9 @@ func (w *Worker) processDirectoryScanJob(job *Job) (interface{}, error) { // Create temporary scanner instance for this job scanner := NewMediaScanner(db) scanner.job = job - // Find which library owns this directory + // Find which library owns this directory (prefix match for subdirectories) ctx := context.Background() - libRow, err := db.GetLibraryByFolder(ctx, directory) + libRow, err := db.GetLibraryByFolderPathPrefix(ctx, directory) if err != nil { return nil, fmt.Errorf("directory not associated with any library: %s", directory) }