Files
minstrel/internal/db/dbq/loudness.sql.go
T
bvandeusenandClaude Opus 5.5 f34423a0e0
release / go (push) Successful in 2m17s
release / govulncheck (push) Successful in 26s
release / web (push) Successful in 2m4s
release / Attach APK to the Release (tag releases only) (push) Canceled after 0s
release / Build + push container image (push) Canceled after 0s
release / Verify release artifacts (tag releases only) (push) Canceled after 0s
release / integration (push) Canceled after 4m39s
release / android (push) Canceled after 2m53s
release / Build signed APK (releases and dev) (push) Canceled after 2m24s
feat: leveled FLAC stream for Sonos/UPnP speakers (M464 #5001)
Speakers fetch their own audio, so the phone cannot level it. A cast
token minted with level=true (and the client's asAlbum, which only the
queue holder knows) now returns GET /api/tracks/{id}/leveled.flac: the
track rendered by ffmpeg at the user's gain (volume=XdB, plus
alimiter at -1 dBFS for a limiter-mode boost), metadata stripped, FLAC
at 16 or 24 bits and at most 48 kHz. The gain is computed server-side
from the user's preference and the stored loudness, carried as
?g=<centi-dB>&lim=0|1 and signed into the token, so an edited URL does
not verify. Unity gains get the plain stream.

Renders are written beside the cache file and renamed in, keyed by the
source's size and mtime, coalesced per file (singleflight, detached
from the requesting speaker so a retry finds the render running),
started at mint time so the fetch finds them ready, and evicted least
recently used past leveled_cache_mb, a new admin setting (migration
0068, Loudness analysis card).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:31:07 -04:00

503 lines
14 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: loudness.sql
package dbq
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const deleteAlbumLoudness = `-- name: DeleteAlbumLoudness :exec
DELETE FROM album_loudness WHERE album_id = ANY($1::uuid[])
`
func (q *Queries) DeleteAlbumLoudness(ctx context.Context, albumIds []pgtype.UUID) error {
_, err := q.db.Exec(ctx, deleteAlbumLoudness, albumIds)
return err
}
const deleteTrackLoudness = `-- name: DeleteTrackLoudness :exec
DELETE FROM track_loudness WHERE track_id = $1
`
// The scan saw new bytes at this path. The stored measurement describes the old
// ones, so it goes, and the backfill measures the file again.
func (q *Queries) DeleteTrackLoudness(ctx context.Context, trackID pgtype.UUID) error {
_, err := q.db.Exec(ctx, deleteTrackLoudness, trackID)
return err
}
const getAlbumLoudness = `-- name: GetAlbumLoudness :one
SELECT integrated_lufs, true_peak_dbtp FROM album_loudness WHERE album_id = $1
`
type GetAlbumLoudnessRow struct {
IntegratedLufs *float32
TruePeakDbtp *float32
}
// The stored album values, read before a recompute so a sync change is
// logged only when they actually move.
func (q *Queries) GetAlbumLoudness(ctx context.Context, albumID pgtype.UUID) (GetAlbumLoudnessRow, error) {
row := q.db.QueryRow(ctx, getAlbumLoudness, albumID)
var i GetAlbumLoudnessRow
err := row.Scan(&i.IntegratedLufs, &i.TruePeakDbtp)
return i, err
}
const getAlbumLoudnessByIDs = `-- name: GetAlbumLoudnessByIDs :many
SELECT album_id, integrated_lufs, true_peak_dbtp
FROM album_loudness
WHERE album_id = ANY($1::uuid[])
`
type GetAlbumLoudnessByIDsRow struct {
AlbumID pgtype.UUID
IntegratedLufs *float32
TruePeakDbtp *float32
}
func (q *Queries) GetAlbumLoudnessByIDs(ctx context.Context, ids []pgtype.UUID) ([]GetAlbumLoudnessByIDsRow, error) {
rows, err := q.db.Query(ctx, getAlbumLoudnessByIDs, ids)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetAlbumLoudnessByIDsRow
for rows.Next() {
var i GetAlbumLoudnessByIDsRow
if err := rows.Scan(&i.AlbumID, &i.IntegratedLufs, &i.TruePeakDbtp); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getLoudnessCoverage = `-- name: GetLoudnessCoverage :one
SELECT count(*)::bigint AS total,
count(*) FILTER (
WHERE l.analysis_version >= $1
AND l.integrated_lufs IS NOT NULL
)::bigint AS measured,
count(*) FILTER (
WHERE l.analysis_version >= $1
AND l.integrated_lufs IS NULL AND NOT l.unreadable
)::bigint AS silent,
count(*) FILTER (
WHERE l.analysis_version >= $1
AND l.unreadable
)::bigint AS unreadable,
count(*) FILTER (
WHERE l.track_id IS NULL OR l.analysis_version < $1
)::bigint AS pending
FROM tracks t
LEFT JOIN track_loudness l ON l.track_id = t.id
WHERE t.missing_since IS NULL
`
type GetLoudnessCoverageRow struct {
Total int64
Measured int64
Silent int64
Unreadable int64
Pending int64
}
// The admin gauge. measured + silent + unreadable + pending = total. Missing
// tracks are excluded, or the gauge could never reach the end.
func (q *Queries) GetLoudnessCoverage(ctx context.Context, currentVersion int16) (GetLoudnessCoverageRow, error) {
row := q.db.QueryRow(ctx, getLoudnessCoverage, currentVersion)
var i GetLoudnessCoverageRow
err := row.Scan(
&i.Total,
&i.Measured,
&i.Silent,
&i.Unreadable,
&i.Pending,
)
return i, err
}
const getLoudnessSettings = `-- name: GetLoudnessSettings :one
SELECT id, enabled, backfill_concurrency, updated_at, leveled_cache_mb FROM loudness_settings WHERE id = true
`
func (q *Queries) GetLoudnessSettings(ctx context.Context) (LoudnessSetting, error) {
row := q.db.QueryRow(ctx, getLoudnessSettings)
var i LoudnessSetting
err := row.Scan(
&i.ID,
&i.Enabled,
&i.BackfillConcurrency,
&i.UpdatedAt,
&i.LeveledCacheMb,
)
return i, err
}
const getReplayGainByTrackIDs = `-- name: GetReplayGainByTrackIDs :many
SELECT t.id,
tl.integrated_lufs AS track_lufs,
tl.true_peak_dbtp AS track_peak_dbtp,
al.integrated_lufs AS album_lufs,
al.true_peak_dbtp AS album_peak_dbtp
FROM tracks t
LEFT JOIN track_loudness tl ON tl.track_id = t.id
LEFT JOIN album_loudness al ON al.album_id = t.album_id
WHERE t.id = ANY($1::uuid[])
`
type GetReplayGainByTrackIDsRow struct {
ID pgtype.UUID
TrackLufs *float32
TrackPeakDbtp *float32
AlbumLufs *float32
AlbumPeakDbtp *float32
}
// Track and album loudness for a set of tracks, for every surface that hands
// gains to a client (#4997). A measurement from an older analysis version is
// still delivered: it is a better gain than none until the backfill redoes it.
func (q *Queries) GetReplayGainByTrackIDs(ctx context.Context, ids []pgtype.UUID) ([]GetReplayGainByTrackIDsRow, error) {
rows, err := q.db.Query(ctx, getReplayGainByTrackIDs, ids)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetReplayGainByTrackIDsRow
for rows.Next() {
var i GetReplayGainByTrackIDsRow
if err := rows.Scan(
&i.ID,
&i.TrackLufs,
&i.TrackPeakDbtp,
&i.AlbumLufs,
&i.AlbumPeakDbtp,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listAlbumLoudnessInputs = `-- name: ListAlbumLoudnessInputs :many
SELECT t.id,
(l.track_id IS NOT NULL)::boolean AS settled,
l.true_peak_dbtp,
l.block_hist_start,
l.block_hist
FROM tracks t
LEFT JOIN track_loudness l
ON l.track_id = t.id AND l.analysis_version >= $1
WHERE t.album_id = $2
AND t.missing_since IS NULL
`
type ListAlbumLoudnessInputsParams struct {
CurrentVersion int16
AlbumID pgtype.UUID
}
type ListAlbumLoudnessInputsRow struct {
ID pgtype.UUID
Settled bool
TruePeakDbtp *float32
BlockHistStart *int16
BlockHist []int32
}
// Every present track on one album with its current measurement, if any.
// settled is false for a track not yet measured at the current version.
func (q *Queries) ListAlbumLoudnessInputs(ctx context.Context, arg ListAlbumLoudnessInputsParams) ([]ListAlbumLoudnessInputsRow, error) {
rows, err := q.db.Query(ctx, listAlbumLoudnessInputs, arg.CurrentVersion, arg.AlbumID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListAlbumLoudnessInputsRow
for rows.Next() {
var i ListAlbumLoudnessInputsRow
if err := rows.Scan(
&i.ID,
&i.Settled,
&i.TruePeakDbtp,
&i.BlockHistStart,
&i.BlockHist,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listAlbumsNeedingLoudness = `-- name: ListAlbumsNeedingLoudness :many
WITH present AS (
SELECT t.album_id,
md5(string_agg(
t.id::text || ':' || coalesce(
l.analysis_version::text || '@' || l.analyzed_at::text, '-'),
',' ORDER BY t.id)) AS digest
FROM tracks t
LEFT JOIN track_loudness l
ON l.track_id = t.id AND l.analysis_version >= $3::smallint
WHERE t.missing_since IS NULL
GROUP BY t.album_id
)
SELECT c.album_id, c.digest::text AS digest
FROM present c
LEFT JOIN album_loudness a ON a.album_id = c.album_id
WHERE (a.album_id IS NULL OR a.inputs_digest <> c.digest)
-- Casts: sqlc cannot infer a parameter's type through a CTE alias.
AND c.album_id > $1::uuid
ORDER BY c.album_id
LIMIT $2::integer
`
type ListAlbumsNeedingLoudnessParams struct {
AfterID pgtype.UUID
BatchLimit int32
CurrentVersion int16
}
type ListAlbumsNeedingLoudnessRow struct {
AlbumID pgtype.UUID
Digest string
}
// The album pass's work queue (#4996): albums whose present tracks or their
// measurements have changed since album loudness was last computed, or that
// never had it. The digest is over every present track's id and the
// measurement it holds at the current version ('-' for none), so a track
// joining, leaving or being re-measured changes it. Keyset-paged on album id
// so a pass ends even if storing one album keeps failing.
func (q *Queries) ListAlbumsNeedingLoudness(ctx context.Context, arg ListAlbumsNeedingLoudnessParams) ([]ListAlbumsNeedingLoudnessRow, error) {
rows, err := q.db.Query(ctx, listAlbumsNeedingLoudness, arg.AfterID, arg.BatchLimit, arg.CurrentVersion)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListAlbumsNeedingLoudnessRow
for rows.Next() {
var i ListAlbumsNeedingLoudnessRow
if err := rows.Scan(&i.AlbumID, &i.Digest); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listOrphanAlbumLoudness = `-- name: ListOrphanAlbumLoudness :many
SELECT a.album_id
FROM album_loudness a
WHERE NOT EXISTS (
SELECT 1 FROM tracks t WHERE t.album_id = a.album_id AND t.missing_since IS NULL
)
`
// Album rows whose album has no present track left (every file missing). The
// album row itself survives a missing file, so its loudness would otherwise
// stay behind describing tracks that are gone; it is recomputed if they return.
func (q *Queries) ListOrphanAlbumLoudness(ctx context.Context) ([]pgtype.UUID, error) {
rows, err := q.db.Query(ctx, listOrphanAlbumLoudness)
if err != nil {
return nil, err
}
defer rows.Close()
var items []pgtype.UUID
for rows.Next() {
var album_id pgtype.UUID
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listTracksNeedingLoudness = `-- name: ListTracksNeedingLoudness :many
SELECT t.id, t.file_path, t.duration_ms
FROM tracks t
LEFT JOIN track_loudness l ON l.track_id = t.id
WHERE t.missing_since IS NULL
AND (l.track_id IS NULL OR l.analysis_version < $1)
AND t.id > $2
ORDER BY t.id
LIMIT $3
`
type ListTracksNeedingLoudnessParams struct {
CurrentVersion int16
AfterID pgtype.UUID
BatchLimit int32
}
type ListTracksNeedingLoudnessRow struct {
ID pgtype.UUID
FilePath string
DurationMs int32
}
// The backfill's work queue: tracks with no measurement, or one taken by an
// older method. Keyset-paged on id so a pass visits each track at most once;
// an inconclusive attempt writes no row, and without the cursor a file that
// keeps timing out would be listed again straight away. Missing tracks are
// skipped: there is no file to read.
func (q *Queries) ListTracksNeedingLoudness(ctx context.Context, arg ListTracksNeedingLoudnessParams) ([]ListTracksNeedingLoudnessRow, error) {
rows, err := q.db.Query(ctx, listTracksNeedingLoudness, arg.CurrentVersion, arg.AfterID, arg.BatchLimit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListTracksNeedingLoudnessRow
for rows.Next() {
var i ListTracksNeedingLoudnessRow
if err := rows.Scan(&i.ID, &i.FilePath, &i.DurationMs); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateLoudnessSettings = `-- name: UpdateLoudnessSettings :one
UPDATE loudness_settings
SET enabled = $1,
backfill_concurrency = $2,
leveled_cache_mb = $3,
updated_at = now()
WHERE id = true
RETURNING id, enabled, backfill_concurrency, updated_at, leveled_cache_mb
`
type UpdateLoudnessSettingsParams struct {
Enabled bool
BackfillConcurrency int32
LeveledCacheMb int32
}
// Whole-row write from the admin card; the migrations' CHECKs are the backstop
// behind the service's own validation.
func (q *Queries) UpdateLoudnessSettings(ctx context.Context, arg UpdateLoudnessSettingsParams) (LoudnessSetting, error) {
row := q.db.QueryRow(ctx, updateLoudnessSettings, arg.Enabled, arg.BackfillConcurrency, arg.LeveledCacheMb)
var i LoudnessSetting
err := row.Scan(
&i.ID,
&i.Enabled,
&i.BackfillConcurrency,
&i.UpdatedAt,
&i.LeveledCacheMb,
)
return i, err
}
const upsertAlbumLoudness = `-- name: UpsertAlbumLoudness :exec
INSERT INTO album_loudness (
album_id, integrated_lufs, true_peak_dbtp, tracks_total, tracks_settled, inputs_digest
) VALUES (
$1, $2, $3,
$4, $5, $6
)
ON CONFLICT (album_id) DO UPDATE SET
integrated_lufs = EXCLUDED.integrated_lufs,
true_peak_dbtp = EXCLUDED.true_peak_dbtp,
tracks_total = EXCLUDED.tracks_total,
tracks_settled = EXCLUDED.tracks_settled,
inputs_digest = EXCLUDED.inputs_digest,
computed_at = now()
`
type UpsertAlbumLoudnessParams struct {
AlbumID pgtype.UUID
IntegratedLufs *float32
TruePeakDbtp *float32
TracksTotal int32
TracksSettled int32
InputsDigest string
}
func (q *Queries) UpsertAlbumLoudness(ctx context.Context, arg UpsertAlbumLoudnessParams) error {
_, err := q.db.Exec(ctx, upsertAlbumLoudness,
arg.AlbumID,
arg.IntegratedLufs,
arg.TruePeakDbtp,
arg.TracksTotal,
arg.TracksSettled,
arg.InputsDigest,
)
return err
}
const upsertTrackLoudness = `-- name: UpsertTrackLoudness :exec
INSERT INTO track_loudness (
track_id, integrated_lufs, true_peak_dbtp, loudness_range_lu,
block_hist_start, block_hist, unreadable, analysis_version
) VALUES (
$1, $2, $3,
$4, $5, $6,
$7, $8
)
ON CONFLICT (track_id) DO UPDATE SET
integrated_lufs = EXCLUDED.integrated_lufs,
true_peak_dbtp = EXCLUDED.true_peak_dbtp,
loudness_range_lu = EXCLUDED.loudness_range_lu,
block_hist_start = EXCLUDED.block_hist_start,
block_hist = EXCLUDED.block_hist,
unreadable = EXCLUDED.unreadable,
analysis_version = EXCLUDED.analysis_version,
analyzed_at = now()
`
type UpsertTrackLoudnessParams struct {
TrackID pgtype.UUID
IntegratedLufs *float32
TruePeakDbtp *float32
LoudnessRangeLu *float32
BlockHistStart *int16
BlockHist []int32
Unreadable bool
AnalysisVersion int16
}
// Written when the backfill measures a track (#4995). Replaces the row
// wholesale: a measurement of the old bytes has no standing once the file has
// changed.
func (q *Queries) UpsertTrackLoudness(ctx context.Context, arg UpsertTrackLoudnessParams) error {
_, err := q.db.Exec(ctx, upsertTrackLoudness,
arg.TrackID,
arg.IntegratedLufs,
arg.TruePeakDbtp,
arg.LoudnessRangeLu,
arg.BlockHistStart,
arg.BlockHist,
arg.Unreadable,
arg.AnalysisVersion,
)
return err
}