M464 loudness leveling (steps 4–8), APK distribution and security baseline adoptions #136
@@ -552,6 +552,7 @@ SELECT a.id AS album_id,
|
|||||||
SELECT file_path
|
SELECT file_path
|
||||||
FROM tracks
|
FROM tracks
|
||||||
WHERE album_id = a.id
|
WHERE album_id = a.id
|
||||||
|
AND missing_since IS NULL
|
||||||
ORDER BY disc_number NULLS LAST, track_number NULLS LAST, id
|
ORDER BY disc_number NULLS LAST, track_number NULLS LAST, id
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
) t ON true
|
) t ON true
|
||||||
@@ -569,7 +570,9 @@ type ListAlbumsMissingMbidWithTrackRow struct {
|
|||||||
|
|
||||||
// One-shot MBID backfill: returns each album where mbid IS NULL alongside
|
// One-shot MBID backfill: returns each album where mbid IS NULL alongside
|
||||||
// one of its tracks' file_path so the worker can re-read tags. LIMIT
|
// one of its tracks' file_path so the worker can re-read tags. LIMIT
|
||||||
// supplied by caller for batching/progress purposes.
|
// supplied by caller for batching/progress purposes. The track read is
|
||||||
|
// one still on disk; an album with none left is skipped until a scan
|
||||||
|
// finds its files again (#5139).
|
||||||
func (q *Queries) ListAlbumsMissingMbidWithTrack(ctx context.Context, limit int32) ([]ListAlbumsMissingMbidWithTrackRow, error) {
|
func (q *Queries) ListAlbumsMissingMbidWithTrack(ctx context.Context, limit int32) ([]ListAlbumsMissingMbidWithTrackRow, error) {
|
||||||
rows, err := q.db.Query(ctx, listAlbumsMissingMbidWithTrack, limit)
|
rows, err := q.db.Query(ctx, listAlbumsMissingMbidWithTrack, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -668,6 +668,7 @@ const listTracksMissingMbidWithPath = `-- name: ListTracksMissingMbidWithPath :m
|
|||||||
SELECT id, file_path
|
SELECT id, file_path
|
||||||
FROM tracks
|
FROM tracks
|
||||||
WHERE mbid IS NULL
|
WHERE mbid IS NULL
|
||||||
|
AND missing_since IS NULL
|
||||||
ORDER BY id
|
ORDER BY id
|
||||||
LIMIT $1
|
LIMIT $1
|
||||||
`
|
`
|
||||||
@@ -679,6 +680,8 @@ type ListTracksMissingMbidWithPathRow struct {
|
|||||||
|
|
||||||
// Track recording-MBID backfill: tracks with NULL mbid that still have
|
// Track recording-MBID backfill: tracks with NULL mbid that still have
|
||||||
// a file to re-read. $1 caps the batch (mirrors the album backfill).
|
// a file to re-read. $1 caps the batch (mirrors the album backfill).
|
||||||
|
// Missing tracks are skipped: there is no file, and opening it anyway
|
||||||
|
// logged a warning per track on every scan (#5139).
|
||||||
func (q *Queries) ListTracksMissingMbidWithPath(ctx context.Context, limit int32) ([]ListTracksMissingMbidWithPathRow, error) {
|
func (q *Queries) ListTracksMissingMbidWithPath(ctx context.Context, limit int32) ([]ListTracksMissingMbidWithPathRow, error) {
|
||||||
rows, err := q.db.Query(ctx, listTracksMissingMbidWithPath, limit)
|
rows, err := q.db.Query(ctx, listTracksMissingMbidWithPath, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -145,7 +145,9 @@ UPDATE albums
|
|||||||
-- name: ListAlbumsMissingMbidWithTrack :many
|
-- name: ListAlbumsMissingMbidWithTrack :many
|
||||||
-- One-shot MBID backfill: returns each album where mbid IS NULL alongside
|
-- One-shot MBID backfill: returns each album where mbid IS NULL alongside
|
||||||
-- one of its tracks' file_path so the worker can re-read tags. LIMIT
|
-- one of its tracks' file_path so the worker can re-read tags. LIMIT
|
||||||
-- supplied by caller for batching/progress purposes.
|
-- supplied by caller for batching/progress purposes. The track read is
|
||||||
|
-- one still on disk; an album with none left is skipped until a scan
|
||||||
|
-- finds its files again (#5139).
|
||||||
SELECT a.id AS album_id,
|
SELECT a.id AS album_id,
|
||||||
a.artist_id AS artist_id,
|
a.artist_id AS artist_id,
|
||||||
a.title AS title,
|
a.title AS title,
|
||||||
@@ -155,6 +157,7 @@ SELECT a.id AS album_id,
|
|||||||
SELECT file_path
|
SELECT file_path
|
||||||
FROM tracks
|
FROM tracks
|
||||||
WHERE album_id = a.id
|
WHERE album_id = a.id
|
||||||
|
AND missing_since IS NULL
|
||||||
ORDER BY disc_number NULLS LAST, track_number NULLS LAST, id
|
ORDER BY disc_number NULLS LAST, track_number NULLS LAST, id
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
) t ON true
|
) t ON true
|
||||||
|
|||||||
@@ -26,9 +26,12 @@ RETURNING *;
|
|||||||
-- name: ListTracksMissingMbidWithPath :many
|
-- name: ListTracksMissingMbidWithPath :many
|
||||||
-- Track recording-MBID backfill: tracks with NULL mbid that still have
|
-- Track recording-MBID backfill: tracks with NULL mbid that still have
|
||||||
-- a file to re-read. $1 caps the batch (mirrors the album backfill).
|
-- a file to re-read. $1 caps the batch (mirrors the album backfill).
|
||||||
|
-- Missing tracks are skipped: there is no file, and opening it anyway
|
||||||
|
-- logged a warning per track on every scan (#5139).
|
||||||
SELECT id, file_path
|
SELECT id, file_path
|
||||||
FROM tracks
|
FROM tracks
|
||||||
WHERE mbid IS NULL
|
WHERE mbid IS NULL
|
||||||
|
AND missing_since IS NULL
|
||||||
ORDER BY id
|
ORDER BY id
|
||||||
LIMIT $1;
|
LIMIT $1;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package library
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The MBID backfills read tags from files, so a track whose file is gone has
|
||||||
|
// nothing to give them. Before #5139 they opened it anyway, and every scan
|
||||||
|
// logged an "open failed" warning per missing track.
|
||||||
|
func TestMBIDBackfill_SkipsMissingTracks_Integration(t *testing.T) {
|
||||||
|
pool := newPool(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
q := dbq.New(pool)
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
// The album's first track is missing; its second is on disk, untagged.
|
||||||
|
gone, album, artist := seedTrack(t, pool, filepath.Join(dir, "gone.mp3"))
|
||||||
|
present := filepath.Join(dir, "present.mp3")
|
||||||
|
if err := os.WriteFile(present, []byte("not really audio"), 0o600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
two := int32(2)
|
||||||
|
if _, err := q.UpsertTrack(ctx, dbq.UpsertTrackParams{
|
||||||
|
Title: "Present", AlbumID: album.ID, ArtistID: artist.ID, TrackNumber: &two,
|
||||||
|
DurationMs: 1000, FilePath: present, FileSize: 100, FileFormat: "mp3",
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("track: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := pool.Exec(ctx, "UPDATE tracks SET missing_since = now() WHERE id = $1", gone.ID); err != nil {
|
||||||
|
t.Fatalf("mark missing: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks, err := q.ListTracksMissingMbidWithPath(ctx, 100)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(tracks) != 1 || tracks[0].FilePath != present {
|
||||||
|
t.Errorf("track backfill lists %+v, want only %s", tracks, present)
|
||||||
|
}
|
||||||
|
albums, err := q.ListAlbumsMissingMbidWithTrack(ctx, 100)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(albums) != 1 || albums[0].TrackFilePath != present {
|
||||||
|
t.Errorf("album backfill reads %+v, want the album via %s", albums, present)
|
||||||
|
}
|
||||||
|
|
||||||
|
// With every track gone, the album has no file to read and is skipped.
|
||||||
|
if _, err := pool.Exec(ctx, "UPDATE tracks SET missing_since = now() WHERE album_id = $1", album.ID); err != nil {
|
||||||
|
t.Fatalf("mark missing: %v", err)
|
||||||
|
}
|
||||||
|
var logs bytes.Buffer
|
||||||
|
logger := slog.New(slog.NewTextHandler(&logs, nil))
|
||||||
|
if res, err := BackfillTrackMBIDs(ctx, pool, logger, -1, nil); err != nil || res.Processed != 0 {
|
||||||
|
t.Errorf("track backfill processed %d (err %v), want 0", res.Processed, err)
|
||||||
|
}
|
||||||
|
if res, err := BackfillMBIDs(ctx, pool, logger, -1, nil); err != nil || res.Processed != 0 {
|
||||||
|
t.Errorf("album backfill processed %d (err %v), want 0", res.Processed, err)
|
||||||
|
}
|
||||||
|
if strings.Contains(logs.String(), "open failed") {
|
||||||
|
t.Errorf("a backfill opened a missing file:\n%s", logs.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user