From 68a482bcb3b2d8ccebcc827dfae58b9b813309ab Mon Sep 17 00:00:00 2001 From: Elijah Date: Mon, 25 May 2026 19:26:52 -0700 Subject: [PATCH] Feature: scan and generate missing thumbnails in background on startup --- backend/workers/thumbnails.go | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/backend/workers/thumbnails.go b/backend/workers/thumbnails.go index e0d65c0..5a23ca3 100644 --- a/backend/workers/thumbnails.go +++ b/backend/workers/thumbnails.go @@ -48,9 +48,64 @@ func InitThumbnailManager(cfg *config.Config, db *database.DB) { DB: db, } Instance.Start(2) // Run 2 concurrent workers + go Instance.ScanMissingThumbnails() }) } +func (m *ThumbnailManager) ScanMissingThumbnails() { + time.Sleep(5 * time.Second) // wait for server to settle + log.Println("Scanning for missing thumbnails...") + rows, err := m.DB.Query("SELECT path, checksum FROM files WHERE checksum IS NOT NULL AND checksum != ''") + if err != nil { + log.Printf("Failed to query files for missing thumbnails: %v\n", err) + return + } + defer rows.Close() + + count := 0 + for rows.Next() { + var path, checksum string + if err := rows.Scan(&path, &checksum); err != nil { + continue + } + + destPath := filepath.Join(m.Config.ThumbnailDir, checksum+".jpg") + if _, err := os.Stat(destPath); err == nil { + continue // Thumbnail already exists + } + + ext := strings.ToLower(filepath.Ext(path)) + var mimeType string + if ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".webp" || ext == ".svg" || ext == ".jpeg" { + mimeType = "image/" + } else if ext == ".mp4" || ext == ".webm" || ext == ".ogg" || ext == ".mov" || ext == ".mkv" || ext == ".avi" { + mimeType = "video/" + } else if ext == ".mp3" || ext == ".flac" || ext == ".wav" || ext == ".m4a" || ext == ".aac" { + mimeType = "audio/" + } else if ext == ".docx" || ext == ".pptx" || ext == ".xlsx" { + mimeType = "application/" + } else { + continue + } + + job := ThumbnailJob{ + FilePath: path, + Checksum: checksum, + MimeType: mimeType, + } + + // Use blocking send so we don't drop jobs, but it throttles the scanner + m.Queue <- job + count++ + } + + if count > 0 { + log.Printf("Enqueued %d missing thumbnails for generation\n", count) + } else { + log.Println("No missing thumbnails found.") + } +} + func (m *ThumbnailManager) Start(workers int) { for i := 0; i < workers; i++ { m.wg.Add(1)