Files
silo-server/internal/models/media_group.go
22fec4ed2d feat(metadata): add resilient match queue diagnostics (#463)
* feat(metadata): add resilient match queue diagnostics

* fix(metadata): harden match queue lifecycle

---------

Co-authored-by: Quick104 <31828688+Quick104@users.noreply.github.com>
2026-07-24 12:18:49 -04:00

162 lines
4.6 KiB
Go

package models
import (
"encoding/json"
"time"
)
// ScannedMediaGroup is the persisted group-inference snapshot for one logical
// content group inside a library folder.
type ScannedMediaGroup struct {
MediaFolderID int
GroupKeyVersion int
ContentGroupKey string
State string
InferredType string
TypeConfidence string
BaseTitle string
BaseYear int
TmdbID string
ImdbID string
TvdbID string
ObservedFileCount int
SampleFilePath string
SampleObservedRootPath string
EvidenceJSON []byte
OverrideSource string
FirstSeenAt time.Time
LastSeenAt time.Time
}
// MediaGroupOverride stores an operator-provided override for a scanned group.
type MediaGroupOverride struct {
MediaFolderID int
GroupKeyVersion int
ContentGroupKey string
ForcedType string
ForcedTitle string
ForcedYear int
ForcedTmdbID string
ForcedImdbID string
ForcedTvdbID string
Note string
CreatedByUserID *int
UpdatedByUserID *int
CreatedAt time.Time
UpdatedAt time.Time
}
// Scopes for MediaIdentityOverride rows.
const (
IdentityOverrideScopeRoot = "root"
IdentityOverrideScopeFile = "file"
)
// MediaIdentityOverride stores an operator-provided identity forced onto all
// files under a root path (scope "root") or one file (scope "file"). Applied
// per file during group inference, before bucketing, so overridden files form
// their own content group — this is what makes a version split durable across
// rescans. File scope wins over root scope.
type MediaIdentityOverride struct {
ID int64
MediaFolderID int
Scope string // "root" or "file"
RootPath string // scope="root"
FilePath string // scope="file"
ForcedType string
ForcedTitle string
ForcedYear int
ForcedTmdbID string
ForcedImdbID string
ForcedTvdbID string
Note string
CreatedByUserID *int
UpdatedByUserID *int
CreatedAt time.Time
UpdatedAt time.Time
}
// ObservedMediaLocation tracks one physical path-scoped media location.
type ObservedMediaLocation struct {
MediaFolderID int
ObservedRootPath string
LocationType string
SampleFilePath string
ObservedFileCount int
ContentGroupCount int
PrimaryGroupKeyVersion int
PrimaryContentGroupKey string
State string
EvidenceJSON []byte
FirstSeenAt time.Time
LastSeenAt time.Time
}
// MediaGroupLocation links a logical content group to a physical location.
type MediaGroupLocation struct {
MediaFolderID int
GroupKeyVersion int
ContentGroupKey string
ObservedRootPath string
IsPrimary bool
FirstSeenAt time.Time
LastSeenAt time.Time
}
// SeriesRootMatchQueueEntry represents one pending or parked series-root job.
type SeriesRootMatchQueueEntry struct {
MediaFolderID int
ObservedRootPath string
FirstQueuedAt time.Time
AvailableAt time.Time
LastAttemptedAt *time.Time
AttemptCount int
LastError string
State string
FailureKind string
FailureDetail json.RawMessage
DeterministicAttemptCount int
InputFingerprint string
MatcherRevision int
ParkedAt *time.Time
UpdatedAt time.Time
}
// SeriesRootMatchJob is the claimed work payload returned to the matcher.
type SeriesRootMatchJob struct {
MediaFolderID int
ObservedRootPath string
SampleFilePath string
ObservedFileCount int
LeaseToken string
RerunRequested bool
}
// MovieMatchJob is a claimed movie file plus the ownership token required to
// complete, fail, or release that exact claim.
type MovieMatchJob struct {
File *MediaFile
LeaseToken string
RerunRequested bool
}
// MovieMatchQueueEntry represents one pending or parked movie-file job.
type MovieMatchQueueEntry struct {
MediaFileID int
MediaFolderID int
FilePath string
FirstQueuedAt time.Time
AvailableAt time.Time
LastAttemptedAt *time.Time
AttemptCount int
LastError string
State string
FailureKind string
FailureDetail json.RawMessage
DeterministicAttemptCount int
InputFingerprint string
MatcherRevision int
ParkedAt *time.Time
UpdatedAt time.Time
}