dba1deaad1
Bridges closed play_events to the scrobble_queue: loads the event, applies the Qualifies() threshold, checks user LB config (enabled + token), and inserts via ON CONFLICT DO NOTHING for idempotency. Best-effort — callers (playevents.Writer hooks, Task 8) will log and swallow errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
50 lines
1.4 KiB
Go
50 lines
1.4 KiB
Go
package scrobble
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
|
)
|
|
|
|
// MaybeEnqueue inserts a scrobble_queue row for the given play_event if:
|
|
// 1. The user has listenbrainz_enabled = true with a non-empty token.
|
|
// 2. The play_event passes Qualifies().
|
|
//
|
|
// Idempotent via UNIQUE(play_event_id) — re-runs are no-ops.
|
|
//
|
|
// Best-effort: callers (the playevents.Writer hooks) should log returned
|
|
// errors but not propagate them, since scrobble delivery is enrichment
|
|
// and must not block the canonical play history.
|
|
func MaybeEnqueue(ctx context.Context, q *dbq.Queries, playEventID pgtype.UUID) error {
|
|
pe, err := q.GetPlayEventByID(ctx, playEventID)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
// Only closed events qualify (DurationPlayedMs/CompletionRatio populated).
|
|
if pe.DurationPlayedMs == nil || pe.CompletionRatio == nil {
|
|
return nil
|
|
}
|
|
if !Qualifies(int(*pe.DurationPlayedMs), *pe.CompletionRatio) {
|
|
return nil
|
|
}
|
|
cfg, err := q.GetListenBrainzConfig(ctx, pe.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !cfg.ListenbrainzEnabled || cfg.ListenbrainzToken == nil || *cfg.ListenbrainzToken == "" {
|
|
return nil
|
|
}
|
|
_, err = q.EnqueueScrobble(ctx, dbq.EnqueueScrobbleParams{
|
|
UserID: pe.UserID,
|
|
PlayEventID: pe.ID,
|
|
})
|
|
return err
|
|
}
|