Migration 0050 adds candidate_artist_tags + candidate_artist_tag_state: folksonomy tags for artists NOT in the library, which track_tags cannot hold because it's FK'd to tracks(id) and a Discover candidate has no local row. Slice 6 ranks against these; this slice only fills the cache. The reuse the task claimed is real and verified: MusicBrainz's fetchEntityTags(ctx, "artist", mbid, scale) already existed for the #1519 recording→artist fallback, so FetchArtistTags is a thin wrapper. Two subtleties it does NOT inherit: - Weight scale is 1.0, not artistTagWeightFactor (0.6). That discount exists because FetchTrackTags uses artist tags as a *proxy* for a track's; here the artist IS the subject. Applying it would make these weights incomparable with track_tags — exactly the comparison slice 6 depends on. Pinned by a test. - fetchEntityTags reports existing-but-untagged as (empty, nil) so the track path can fall through. There's no next level here, so empty becomes the terminal ErrNotFound; otherwise the enricher would settle a candidate as "enriched" with zero tags. ArtistTagProvider is the split TrackTagProvider's own doc comment anticipated ("e.g. artist-level tags"). Last.fm gains artist.getTopTags, which returns the same toptags envelope, so the response type and normalizer are reused unchanged. Rather than write the merge-and-classify loop twice, extracted it from EnrichTrack into runChain(). The ErrNotFound-vs-transient split is the load-bearing part — those lead to opposite persistence decisions — so it now has direct unit tests it never had while inlined. Bookkeeping is a separate table, not columns, because the "providers had nothing" outcome must be recordable for a candidate with zero tag rows, and there is no per-candidate row to hang columns off ( artist_similarity_unmatched holds many rows per candidate). Absence of a state row means "never processed", so a transient failure writes nothing and stays eligible. Two capacity realities are designed for, not papered over: - The pool is O(library artists x neighbours) and MusicBrainz allows ~1 req/s, so it can never drain in one pass. The eligibility query returns candidates in descending summed-similarity order, so the ones that can actually reach a deck are enriched first. - candidateBatch (50) is smaller than the track batch (200): tracks are finite and drain to completion, candidates are effectively unbounded and would otherwise starve the track arm forever. GC sweeps both tables — the similarity feed churns, and a candidate that joins the library has its tags in track_tags now. Tags swept before state so a mid-sweep crash leaves a valid state, not a re-fetch loop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
688 lines
16 KiB
Go
688 lines
16 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
|
|
package dbq
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"fmt"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
type LidarrQuarantineActionKind string
|
|
|
|
const (
|
|
LidarrQuarantineActionKindResolved LidarrQuarantineActionKind = "resolved"
|
|
LidarrQuarantineActionKindDeletedFile LidarrQuarantineActionKind = "deleted_file"
|
|
LidarrQuarantineActionKindDeletedViaLidarr LidarrQuarantineActionKind = "deleted_via_lidarr"
|
|
)
|
|
|
|
func (e *LidarrQuarantineActionKind) Scan(src interface{}) error {
|
|
switch s := src.(type) {
|
|
case []byte:
|
|
*e = LidarrQuarantineActionKind(s)
|
|
case string:
|
|
*e = LidarrQuarantineActionKind(s)
|
|
default:
|
|
return fmt.Errorf("unsupported scan type for LidarrQuarantineActionKind: %T", src)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type NullLidarrQuarantineActionKind struct {
|
|
LidarrQuarantineActionKind LidarrQuarantineActionKind
|
|
Valid bool // Valid is true if LidarrQuarantineActionKind is not NULL
|
|
}
|
|
|
|
// Scan implements the Scanner interface.
|
|
func (ns *NullLidarrQuarantineActionKind) Scan(value interface{}) error {
|
|
if value == nil {
|
|
ns.LidarrQuarantineActionKind, ns.Valid = "", false
|
|
return nil
|
|
}
|
|
ns.Valid = true
|
|
return ns.LidarrQuarantineActionKind.Scan(value)
|
|
}
|
|
|
|
// Value implements the driver Valuer interface.
|
|
func (ns NullLidarrQuarantineActionKind) Value() (driver.Value, error) {
|
|
if !ns.Valid {
|
|
return nil, nil
|
|
}
|
|
return string(ns.LidarrQuarantineActionKind), nil
|
|
}
|
|
|
|
type LidarrQuarantineReason string
|
|
|
|
const (
|
|
LidarrQuarantineReasonBadRip LidarrQuarantineReason = "bad_rip"
|
|
LidarrQuarantineReasonWrongFile LidarrQuarantineReason = "wrong_file"
|
|
LidarrQuarantineReasonWrongTags LidarrQuarantineReason = "wrong_tags"
|
|
LidarrQuarantineReasonDuplicate LidarrQuarantineReason = "duplicate"
|
|
LidarrQuarantineReasonOther LidarrQuarantineReason = "other"
|
|
)
|
|
|
|
func (e *LidarrQuarantineReason) Scan(src interface{}) error {
|
|
switch s := src.(type) {
|
|
case []byte:
|
|
*e = LidarrQuarantineReason(s)
|
|
case string:
|
|
*e = LidarrQuarantineReason(s)
|
|
default:
|
|
return fmt.Errorf("unsupported scan type for LidarrQuarantineReason: %T", src)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type NullLidarrQuarantineReason struct {
|
|
LidarrQuarantineReason LidarrQuarantineReason
|
|
Valid bool // Valid is true if LidarrQuarantineReason is not NULL
|
|
}
|
|
|
|
// Scan implements the Scanner interface.
|
|
func (ns *NullLidarrQuarantineReason) Scan(value interface{}) error {
|
|
if value == nil {
|
|
ns.LidarrQuarantineReason, ns.Valid = "", false
|
|
return nil
|
|
}
|
|
ns.Valid = true
|
|
return ns.LidarrQuarantineReason.Scan(value)
|
|
}
|
|
|
|
// Value implements the driver Valuer interface.
|
|
func (ns NullLidarrQuarantineReason) Value() (driver.Value, error) {
|
|
if !ns.Valid {
|
|
return nil, nil
|
|
}
|
|
return string(ns.LidarrQuarantineReason), nil
|
|
}
|
|
|
|
type LidarrRequestKind string
|
|
|
|
const (
|
|
LidarrRequestKindArtist LidarrRequestKind = "artist"
|
|
LidarrRequestKindAlbum LidarrRequestKind = "album"
|
|
LidarrRequestKindTrack LidarrRequestKind = "track"
|
|
)
|
|
|
|
func (e *LidarrRequestKind) Scan(src interface{}) error {
|
|
switch s := src.(type) {
|
|
case []byte:
|
|
*e = LidarrRequestKind(s)
|
|
case string:
|
|
*e = LidarrRequestKind(s)
|
|
default:
|
|
return fmt.Errorf("unsupported scan type for LidarrRequestKind: %T", src)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type NullLidarrRequestKind struct {
|
|
LidarrRequestKind LidarrRequestKind
|
|
Valid bool // Valid is true if LidarrRequestKind is not NULL
|
|
}
|
|
|
|
// Scan implements the Scanner interface.
|
|
func (ns *NullLidarrRequestKind) Scan(value interface{}) error {
|
|
if value == nil {
|
|
ns.LidarrRequestKind, ns.Valid = "", false
|
|
return nil
|
|
}
|
|
ns.Valid = true
|
|
return ns.LidarrRequestKind.Scan(value)
|
|
}
|
|
|
|
// Value implements the driver Valuer interface.
|
|
func (ns NullLidarrRequestKind) Value() (driver.Value, error) {
|
|
if !ns.Valid {
|
|
return nil, nil
|
|
}
|
|
return string(ns.LidarrRequestKind), nil
|
|
}
|
|
|
|
type LidarrRequestStatus string
|
|
|
|
const (
|
|
LidarrRequestStatusPending LidarrRequestStatus = "pending"
|
|
LidarrRequestStatusApproved LidarrRequestStatus = "approved"
|
|
LidarrRequestStatusRejected LidarrRequestStatus = "rejected"
|
|
LidarrRequestStatusCompleted LidarrRequestStatus = "completed"
|
|
LidarrRequestStatusFailed LidarrRequestStatus = "failed"
|
|
)
|
|
|
|
func (e *LidarrRequestStatus) Scan(src interface{}) error {
|
|
switch s := src.(type) {
|
|
case []byte:
|
|
*e = LidarrRequestStatus(s)
|
|
case string:
|
|
*e = LidarrRequestStatus(s)
|
|
default:
|
|
return fmt.Errorf("unsupported scan type for LidarrRequestStatus: %T", src)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type NullLidarrRequestStatus struct {
|
|
LidarrRequestStatus LidarrRequestStatus
|
|
Valid bool // Valid is true if LidarrRequestStatus is not NULL
|
|
}
|
|
|
|
// Scan implements the Scanner interface.
|
|
func (ns *NullLidarrRequestStatus) Scan(value interface{}) error {
|
|
if value == nil {
|
|
ns.LidarrRequestStatus, ns.Valid = "", false
|
|
return nil
|
|
}
|
|
ns.Valid = true
|
|
return ns.LidarrRequestStatus.Scan(value)
|
|
}
|
|
|
|
// Value implements the driver Valuer interface.
|
|
func (ns NullLidarrRequestStatus) Value() (driver.Value, error) {
|
|
if !ns.Valid {
|
|
return nil, nil
|
|
}
|
|
return string(ns.LidarrRequestStatus), nil
|
|
}
|
|
|
|
type Album struct {
|
|
ID pgtype.UUID
|
|
Title string
|
|
SortTitle string
|
|
ArtistID pgtype.UUID
|
|
ReleaseDate pgtype.Date
|
|
Mbid *string
|
|
CoverArtPath *string
|
|
CreatedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
CoverArtSource *string
|
|
CoverArtSourcesVersion int32
|
|
}
|
|
|
|
type Artist struct {
|
|
ID pgtype.UUID
|
|
Name string
|
|
SortName string
|
|
Mbid *string
|
|
CreatedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
ArtistThumbPath *string
|
|
ArtistFanartPath *string
|
|
ArtistArtSource *string
|
|
ArtistArtSourcesVersion int32
|
|
}
|
|
|
|
type ArtistSimilarity struct {
|
|
ArtistAID pgtype.UUID
|
|
ArtistBID pgtype.UUID
|
|
Score float64
|
|
Source string
|
|
FetchedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type ArtistSimilarityUnmatched struct {
|
|
SeedArtistID pgtype.UUID
|
|
CandidateMbid string
|
|
CandidateName string
|
|
Score float64
|
|
Source string
|
|
FetchedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type AuditLog struct {
|
|
ID pgtype.UUID
|
|
ActorID pgtype.UUID
|
|
TargetID pgtype.UUID
|
|
Action string
|
|
Metadata []byte
|
|
CreatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type CandidateArtistTagState struct {
|
|
CandidateMbid string
|
|
TagSource string
|
|
TagSourcesVersion int32
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type CandidateArtistTag struct {
|
|
CandidateMbid string
|
|
Tag string
|
|
Weight float64
|
|
}
|
|
|
|
type ContextualLike struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
LikedAt pgtype.Timestamptz
|
|
DeletedAt pgtype.Timestamptz
|
|
SessionVector []byte
|
|
SessionID pgtype.UUID
|
|
}
|
|
|
|
type CoverArtProviderSetting struct {
|
|
ProviderID string
|
|
Enabled bool
|
|
ApiKey *string
|
|
DisplayOrder int32
|
|
CreatedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type CoverArtSourcesMetum struct {
|
|
ID bool
|
|
CurrentVersion int32
|
|
LastRegisteredProvidersHash string
|
|
}
|
|
|
|
type DiagnosticEvent struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
ClientID string
|
|
AppVersion *string
|
|
OsVersion *string
|
|
Kind string
|
|
Payload []byte
|
|
OccurredAt pgtype.Timestamptz
|
|
ReceivedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type GeneralLike struct {
|
|
UserID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
LikedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type GeneralLikesAlbum struct {
|
|
UserID pgtype.UUID
|
|
AlbumID pgtype.UUID
|
|
LikedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type GeneralLikesArtist struct {
|
|
UserID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
LikedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type LibraryChange struct {
|
|
ID int64
|
|
EntityType string
|
|
EntityID string
|
|
Op string
|
|
ChangedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type LidarrConfig struct {
|
|
ID int16
|
|
Enabled bool
|
|
BaseUrl *string
|
|
ApiKey *string
|
|
DefaultQualityProfileID *int32
|
|
DefaultRootFolderPath *string
|
|
CreatedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
DefaultMetadataProfileID *int32
|
|
}
|
|
|
|
type LidarrQuarantine struct {
|
|
UserID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
Reason LidarrQuarantineReason
|
|
Notes *string
|
|
CreatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type LidarrQuarantineAction struct {
|
|
ID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
TrackTitle string
|
|
ArtistName string
|
|
AlbumTitle *string
|
|
Action LidarrQuarantineActionKind
|
|
AdminID pgtype.UUID
|
|
LidarrAlbumMbid *string
|
|
AffectedUsers int32
|
|
CreatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type LidarrRequest struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
Status LidarrRequestStatus
|
|
Kind LidarrRequestKind
|
|
LidarrArtistMbid string
|
|
LidarrAlbumMbid *string
|
|
LidarrTrackMbid *string
|
|
ArtistName string
|
|
AlbumTitle *string
|
|
TrackTitle *string
|
|
QualityProfileID *int32
|
|
RootFolderPath *string
|
|
DecidedAt pgtype.Timestamptz
|
|
DecidedBy pgtype.UUID
|
|
Notes *string
|
|
CompletedAt pgtype.Timestamptz
|
|
MatchedTrackID pgtype.UUID
|
|
MatchedAlbumID pgtype.UUID
|
|
MatchedArtistID pgtype.UUID
|
|
RequestedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
LidarrAddConfirmedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type PasswordReset struct {
|
|
Token string
|
|
UserID pgtype.UUID
|
|
CreatedAt pgtype.Timestamptz
|
|
ExpiresAt pgtype.Timestamptz
|
|
UsedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type PlayEvent struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
SessionID pgtype.UUID
|
|
StartedAt pgtype.Timestamptz
|
|
EndedAt pgtype.Timestamptz
|
|
DurationPlayedMs *int32
|
|
CompletionRatio *float64
|
|
WasSkipped bool
|
|
ClientID *string
|
|
SessionVectorAtPlay []byte
|
|
ScrobbledAt pgtype.Timestamptz
|
|
Source *string
|
|
PickKind *string
|
|
DeviceClass *string
|
|
}
|
|
|
|
type PlaySession struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
StartedAt pgtype.Timestamptz
|
|
EndedAt pgtype.Timestamptz
|
|
LastEventAt pgtype.Timestamptz
|
|
TrackCount int32
|
|
ClientID *string
|
|
}
|
|
|
|
type PlaybackError struct {
|
|
ID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
ClientID string
|
|
Kind string
|
|
Detail *string
|
|
OccurredAt pgtype.Timestamptz
|
|
ResolvedAt pgtype.Timestamptz
|
|
ResolvedBy pgtype.UUID
|
|
Resolution *string
|
|
}
|
|
|
|
type Playlist struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
Name string
|
|
Description string
|
|
IsPublic bool
|
|
CoverPath *string
|
|
TrackCount int32
|
|
DurationSec int32
|
|
CreatedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
Kind string
|
|
SystemVariant *string
|
|
SeedArtistID pgtype.UUID
|
|
}
|
|
|
|
type PlaylistTrack struct {
|
|
PlaylistID pgtype.UUID
|
|
Position int32
|
|
TrackID pgtype.UUID
|
|
Title string
|
|
ArtistName string
|
|
AlbumTitle string
|
|
DurationSec int32
|
|
AddedAt pgtype.Timestamptz
|
|
PickKind *string
|
|
}
|
|
|
|
type RecommendationTuningAudit struct {
|
|
ID int64
|
|
ChangedAt pgtype.Timestamptz
|
|
Scope string
|
|
Action string
|
|
Changes []byte
|
|
}
|
|
|
|
type RecommendationWeightProfile struct {
|
|
Profile string
|
|
BaseWeight float64
|
|
LikeBoost float64
|
|
RecencyWeight float64
|
|
SkipPenalty float64
|
|
JitterMagnitude float64
|
|
ContextWeight float64
|
|
SimilarityWeight float64
|
|
TasteWeight float64
|
|
UpdatedAt pgtype.Timestamptz
|
|
ContextTimeWeight float64
|
|
}
|
|
|
|
type RegistrationSetting struct {
|
|
ID bool
|
|
Mode string
|
|
}
|
|
|
|
type ScanRun struct {
|
|
ID pgtype.UUID
|
|
StartedAt pgtype.Timestamptz
|
|
FinishedAt pgtype.Timestamptz
|
|
Library []byte
|
|
MbidBackfill []byte
|
|
CoverEnrich []byte
|
|
ErrorMessage *string
|
|
ArtistArtEnrich []byte
|
|
}
|
|
|
|
type ScrobbleQueue struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
PlayEventID pgtype.UUID
|
|
Status string
|
|
Attempts int32
|
|
NextAttemptAt pgtype.Timestamptz
|
|
LastError *string
|
|
EnqueuedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type Session struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
TokenHash []byte
|
|
UserAgent string
|
|
CreatedAt pgtype.Timestamptz
|
|
LastSeenAt pgtype.Timestamptz
|
|
}
|
|
|
|
type SkipEvent struct {
|
|
ID pgtype.UUID
|
|
UserID pgtype.UUID
|
|
TrackID pgtype.UUID
|
|
SessionID pgtype.UUID
|
|
SkippedAt pgtype.Timestamptz
|
|
PositionMs int32
|
|
}
|
|
|
|
type SmtpConfig struct {
|
|
ID bool
|
|
Enabled bool
|
|
Host string
|
|
Port int32
|
|
Username string
|
|
Password string
|
|
FromAddress string
|
|
FromName string
|
|
UseTls bool
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type SuggestionSnooze struct {
|
|
UserID pgtype.UUID
|
|
CandidateMbid string
|
|
CandidateName string
|
|
SnoozedUntil pgtype.Timestamptz
|
|
CreatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type SystemPlaylistRotationState struct {
|
|
UserID pgtype.UUID
|
|
PlaylistKind string
|
|
PlayedTrackIds []pgtype.UUID
|
|
RotationStartedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type SystemPlaylistRun struct {
|
|
UserID pgtype.UUID
|
|
LastRunAt pgtype.Timestamptz
|
|
LastRunDate pgtype.Date
|
|
InFlight bool
|
|
LastError *string
|
|
}
|
|
|
|
type TagProviderSetting struct {
|
|
ProviderID string
|
|
Enabled bool
|
|
ApiKey *string
|
|
DisplayOrder int32
|
|
CreatedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type TagSourcesMetum struct {
|
|
ID bool
|
|
CurrentVersion int32
|
|
LastRegisteredProvidersHash string
|
|
}
|
|
|
|
type TasteProfileArtist struct {
|
|
UserID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
Weight float64
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type TasteProfileEra struct {
|
|
UserID pgtype.UUID
|
|
Era string
|
|
Weight float64
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type TasteProfileMood struct {
|
|
UserID pgtype.UUID
|
|
Mood string
|
|
Weight float64
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type TasteProfileTag struct {
|
|
UserID pgtype.UUID
|
|
Tag string
|
|
Weight float64
|
|
UpdatedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type TasteTuning struct {
|
|
Singleton bool
|
|
HalfLifeDays float64
|
|
EngagementHardSkip float64
|
|
EngagementNeutral float64
|
|
EngagementFull float64
|
|
UpdatedAt pgtype.Timestamptz
|
|
EnrichedTagScale float64
|
|
EraScale float64
|
|
MoodScale float64
|
|
}
|
|
|
|
type Track struct {
|
|
ID pgtype.UUID
|
|
Title string
|
|
AlbumID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
TrackNumber *int32
|
|
DiscNumber *int32
|
|
DurationMs int32
|
|
FilePath string
|
|
FileSize int64
|
|
FileFormat string
|
|
Bitrate *int32
|
|
Mbid *string
|
|
Genre *string
|
|
AddedAt pgtype.Timestamptz
|
|
UpdatedAt pgtype.Timestamptz
|
|
TagSource *string
|
|
TagSourcesVersion int32
|
|
}
|
|
|
|
type TrackSimilarity struct {
|
|
TrackAID pgtype.UUID
|
|
TrackBID pgtype.UUID
|
|
Score float64
|
|
Source string
|
|
FetchedAt pgtype.Timestamptz
|
|
}
|
|
|
|
type TrackTag struct {
|
|
TrackID pgtype.UUID
|
|
Tag string
|
|
Weight float64
|
|
}
|
|
|
|
type User struct {
|
|
ID pgtype.UUID
|
|
Username string
|
|
PasswordHash string
|
|
ApiToken string
|
|
IsAdmin bool
|
|
CreatedAt pgtype.Timestamptz
|
|
SubsonicPassword *string
|
|
ListenbrainzToken *string
|
|
ListenbrainzEnabled bool
|
|
DisplayName *string
|
|
AutoApproveRequests bool
|
|
Email *string
|
|
Timezone string
|
|
TimezoneUpdatedAt pgtype.Timestamptz
|
|
DebugModeEnabled bool
|
|
}
|
|
|
|
type UserInvite struct {
|
|
Token string
|
|
InvitedBy pgtype.UUID
|
|
Note *string
|
|
CreatedAt pgtype.Timestamptz
|
|
ExpiresAt pgtype.Timestamptz
|
|
RedeemedAt pgtype.Timestamptz
|
|
RedeemedBy pgtype.UUID
|
|
}
|
|
|
|
type YouMightLikeAlbum struct {
|
|
UserID pgtype.UUID
|
|
AlbumID pgtype.UUID
|
|
Rank int32
|
|
BuiltAt pgtype.Timestamptz
|
|
}
|
|
|
|
type YouMightLikeArtist struct {
|
|
UserID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
Rank int32
|
|
BuiltAt pgtype.Timestamptz
|
|
}
|