fix(library): expose scan activity and failed analysis file details
ci / api / api (push) Successful in 55s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m6s
ci / db / db (push) Successful in 52s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m38s
release / android (APK в релиз) (push) Successful in 3m50s
ci / ts / ts (packages + web) (push) Successful in 3m20s
release / release (версия и заметки) (push) Successful in 5s
release / desktop (Linux и Windows в релиз) (push) Successful in 44m45s
release / prune (старые файлы и прогоны) (push) Successful in 7s

This commit is contained in:
mrleo1nid committed 2026-10-22 15:25:48 +03:00
1 parent 17b6dd2041
commit 0dc0384c78
20 files changed
+1114 -326

No files matched your search

+34 -3
View File
@@ -511,7 +511,7 @@ func (st *Store) Counts(ctx context.Context) (Counts, error) {
err := st.pool.QueryRow(ctx, `
SELECT (SELECT count(*) FROM artists), (SELECT count(*) FROM albums), (SELECT count(*) FROM tracks),
(SELECT count(*) FROM media_files), (SELECT count(*) FROM media_files WHERE missing_since IS NOT NULL),
(SELECT count(*) FROM media_files WHERE scan_error IS NOT NULL)`).
(SELECT count(*) FROM media_files WHERE scan_error IS NOT NULL AND missing_since IS NULL)`).
Scan(&c.Artists, &c.Albums, &c.Tracks, &c.Files, &c.Missing, &c.Errors)
if err != nil {
return Counts{}, fmt.Errorf("library: counts: %w", err)
@@ -531,7 +531,7 @@ type FileError struct {
func (st *Store) FileErrors(ctx context.Context, after string, limit int) ([]FileError, error) {
rows, err := st.pool.Query(ctx, `
SELECT id, source_id, rel_path, scan_error FROM media_files
WHERE scan_error IS NOT NULL AND rel_path > $1 ORDER BY rel_path LIMIT $2`, after, limit)
WHERE scan_error IS NOT NULL AND missing_since IS NULL AND rel_path > $1 ORDER BY rel_path LIMIT $2`, after, limit)
if err != nil {
return nil, fmt.Errorf("library: file errors: %w", err)
}
@@ -624,7 +624,38 @@ func (st *Store) AnalysisCounts(ctx context.Context) (AnalysisCounts, error) {
return c, nil
}
// RetryFailedAnalysis возвращает неудавшиеся задачи анализа в очередь с нуля попыток.
// AnalysisError is a failed analysis job with a known file path, when available.
type AnalysisError struct {
TrackID uuid.UUID
Title string
SourceID *uuid.UUID
SourceName *string
RelPath *string
Error string
}
// AnalysisErrors includes failed jobs even when their file is no longer available.
func (st *Store) AnalysisErrors(ctx context.Context, after uuid.UUID, limit int) ([]AnalysisError, error) {
rows, err := st.pool.Query(ctx, `
SELECT t.id, t.title, f.source_id, s.name, f.rel_path, COALESCE(a.error, '')
FROM analysis_jobs a JOIN tracks t ON t.id = a.track_id
LEFT JOIN LATERAL (
SELECT mf.source_id, mf.rel_path FROM media_files mf WHERE mf.track_id = t.id
ORDER BY (mf.id = t.primary_file_id) DESC NULLS LAST, (mf.missing_since IS NULL) DESC, mf.id
LIMIT 1
) f ON true
LEFT JOIN library_sources s ON s.id = f.source_id
WHERE a.status = 'failed' AND t.id > $1 ORDER BY t.id LIMIT $2`, after, limit)
if err != nil {
return nil, fmt.Errorf("library: analysis errors: %w", err)
}
return pgx.CollectRows(rows, func(r pgx.CollectableRow) (AnalysisError, error) {
var e AnalysisError
return e, r.Scan(&e.TrackID, &e.Title, &e.SourceID, &e.SourceName, &e.RelPath, &e.Error)
})
}
// RetryFailedAnalysis returns failed jobs to the queue with attempts reset.
func (st *Store) RetryFailedAnalysis(ctx context.Context) (int, error) {
tag, err := st.pool.Exec(ctx, `
UPDATE analysis_jobs SET status = 'queued', attempts = 0, error = NULL, updated_at = now()