package database import ( "database/sql" "errors" ) // GetSetting reads a key from the settings table, returning def if unset. func GetSetting(db *sql.DB, key, def string) string { var v string err := db.QueryRow(`SELECT value FROM settings WHERE key = ?`, key).Scan(&v) if err != nil { return def } return v } func SetSetting(db *sql.DB, key, value string) error { _, err := db.Exec(`INSERT INTO settings (key, value, updated_at) VALUES (?, ?, strftime('%Y-%m-%dT%H:%M:%fZ','now')) ON CONFLICT (key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at`, key, value) return err } // --- Scan state --- type ScanState struct { ID string MusicFolderID string Status string StartedAt sql.NullString FinishedAt sql.NullString FilesSeen int FilesTotalEstimate int FilesAdded int FilesUpdated int FilesRemoved int ErrorMessage string LastFullScanAt sql.NullString } const scanStateSelect = `SELECT id, music_folder_id, status, started_at, finished_at, files_seen, files_total_estimate, files_added, files_updated, files_removed, error_message, last_full_scan_at FROM scan_state` func GetScanState(db *sql.DB, folderID string) (*ScanState, error) { var s ScanState err := db.QueryRow(scanStateSelect+` WHERE music_folder_id = ?`, folderID).Scan( &s.ID, &s.MusicFolderID, &s.Status, &s.StartedAt, &s.FinishedAt, &s.FilesSeen, &s.FilesTotalEstimate, &s.FilesAdded, &s.FilesUpdated, &s.FilesRemoved, &s.ErrorMessage, &s.LastFullScanAt) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } if err != nil { return nil, err } return &s, nil } func ListScanStates(db *sql.DB) ([]*ScanState, error) { rows, err := db.Query(scanStateSelect) if err != nil { return nil, err } defer rows.Close() var out []*ScanState for rows.Next() { var s ScanState if err := rows.Scan(&s.ID, &s.MusicFolderID, &s.Status, &s.StartedAt, &s.FinishedAt, &s.FilesSeen, &s.FilesTotalEstimate, &s.FilesAdded, &s.FilesUpdated, &s.FilesRemoved, &s.ErrorMessage, &s.LastFullScanAt); err != nil { return nil, err } out = append(out, &s) } return out, rows.Err() } func StartScan(db *sql.DB, folderID string) error { _, err := db.Exec(`UPDATE scan_state SET status='scanning', started_at=strftime('%Y-%m-%dT%H:%M:%fZ','now'), finished_at=NULL, files_seen=0, files_added=0, files_updated=0, files_removed=0, error_message='' WHERE music_folder_id=?`, folderID) return err } func UpdateScanProgress(db *sql.DB, folderID string, filesSeen, filesAdded, filesUpdated int) error { _, err := db.Exec(`UPDATE scan_state SET files_seen=?, files_added=?, files_updated=? WHERE music_folder_id=?`, filesSeen, filesAdded, filesUpdated, folderID) return err } func FinishScan(db *sql.DB, folderID string, filesRemoved int, errMsg string) error { status := "idle" if errMsg != "" { status = "error" } _, err := db.Exec(`UPDATE scan_state SET status=?, finished_at=strftime('%Y-%m-%dT%H:%M:%fZ','now'), files_removed=?, error_message=?, last_full_scan_at=strftime('%Y-%m-%dT%H:%M:%fZ','now') WHERE music_folder_id=?`, status, filesRemoved, errMsg, folderID) return err }