Documentation
¶
Index ¶
- Variables
- type GenreFinder
- type ImprintFinder
- type Monitor
- type PersonFinder
- type PublisherFinder
- type RelationshipUpdates
- type ScanCache
- func (c *ScanCache) GenreCount() int
- func (c *ScanCache) GetKnownFile(path string) *models.File
- func (c *ScanCache) GetOrCreateGenre(ctx context.Context, name string, libraryID int, svc GenreFinder) (*models.Genre, error)
- func (c *ScanCache) GetOrCreateImprint(ctx context.Context, name string, libraryID int, svc ImprintFinder) (*models.Imprint, error)
- func (c *ScanCache) GetOrCreatePerson(ctx context.Context, name string, libraryID int, svc PersonFinder) (*models.Person, error)
- func (c *ScanCache) GetOrCreatePublisher(ctx context.Context, name string, libraryID int, svc PublisherFinder) (*models.Publisher, error)
- func (c *ScanCache) GetOrCreateSeries(ctx context.Context, name string, libraryID int, nameSource string, ...) (*models.Series, error)
- func (c *ScanCache) GetOrCreateTag(ctx context.Context, name string, libraryID int, svc TagFinder) (*models.Tag, error)
- func (c *ScanCache) ImprintCount() int
- func (c *ScanCache) LoadKnownFiles(files []*models.File)
- func (c *ScanCache) LockBook(bookID int) func()
- func (c *ScanCache) LockBookPath(path string, libraryID int) func()
- func (c *ScanCache) PersonCount() int
- func (c *ScanCache) PublisherCount() int
- func (c *ScanCache) SeriesCount() int
- func (c *ScanCache) TagCount() int
- type ScanOptions
- type ScanResult
- type SeriesFinder
- type TagFinder
- type Worker
- func (w *Worker) ProcessScanJob(ctx context.Context, job *models.Job, jobLog *joblogs.JobLogger) error
- func (w *Worker) RefreshMonitorWatches()
- func (w *Worker) Scan(ctx context.Context, opts books.ScanOptions) (*books.ScanResult, error)
- func (w *Worker) Shutdown()
- func (w *Worker) Start()
- func (w *Worker) UpdateBookRelationships(ctx context.Context, bookID int, updates RelationshipUpdates) error
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidScanOptions = errors.New("exactly one of FilePath, FileID, or BookID must be set")
ErrInvalidScanOptions is returned when ScanOptions validation fails.
Functions ¶
This section is empty.
Types ¶
type GenreFinder ¶ added in v0.0.11
type GenreFinder interface {
FindOrCreateGenre(ctx context.Context, name string, libraryID int) (*models.Genre, error)
}
GenreFinder is an interface for finding or creating genres.
type ImprintFinder ¶ added in v0.0.11
type ImprintFinder interface {
FindOrCreateImprint(ctx context.Context, name string, libraryID int) (*models.Imprint, error)
}
ImprintFinder is an interface for finding or creating imprints.
type Monitor ¶ added in v0.0.20
type Monitor struct {
// contains filtered or unexported fields
}
Monitor watches library paths for filesystem changes and triggers targeted rescans using a debounce pattern inspired by Jellyfin's FileRefresher.
func (*Monitor) IgnorePath ¶ added in v0.0.20
IgnorePath temporarily suppresses filesystem events for the given path. Used by the scanner to prevent its own writes (covers, sidecars, file moves) from triggering redundant rescans. The path is ignored for 2× the debounce delay.
func (*Monitor) RefreshWatches ¶ added in v0.0.20
func (m *Monitor) RefreshWatches()
RefreshWatches signals the monitor to reload library paths and update watches. Call this after libraries are created, updated, or deleted.
type PersonFinder ¶ added in v0.0.11
type PersonFinder interface {
FindOrCreatePerson(ctx context.Context, name string, libraryID int) (*models.Person, error)
}
PersonFinder is an interface for finding or creating persons.
type PublisherFinder ¶ added in v0.0.11
type PublisherFinder interface {
FindOrCreatePublisher(ctx context.Context, name string, libraryID int) (*models.Publisher, error)
}
PublisherFinder is an interface for finding or creating publishers.
type RelationshipUpdates ¶ added in v0.0.11
type RelationshipUpdates struct {
Authors []*models.Author
Narrators []*models.Narrator
BookGenres []*models.BookGenre
BookTags []*models.BookTag
BookSeries []*models.BookSeries
// Delete flags indicate which relationships should be cleared before inserting new ones
DeleteAuthors bool
DeleteNarrators bool
DeleteGenres bool
DeleteTags bool
DeleteSeries bool
// FileID is required when DeleteNarrators is true (narrators are per-file)
FileID int
}
RelationshipUpdates holds all relationship data to be updated for a book. This enables bulk inserts for better scan performance. When used in parallel processing, callers should use ScanCache.LockBook to prevent race conditions.
type ScanCache ¶ added in v0.0.11
type ScanCache struct {
// contains filtered or unexported fields
}
ScanCache provides thread-safe caching for entity lookups during parallel file processing. It uses sync.Map for cache storage and per-key mutexes to prevent duplicate concurrent DB calls.
func NewScanCache ¶ added in v0.0.11
func NewScanCache() *ScanCache
NewScanCache creates a new ScanCache.
func (*ScanCache) GenreCount ¶ added in v0.0.11
GenreCount returns the number of unique genres in the cache.
func (*ScanCache) GetKnownFile ¶ added in v0.0.18
GetKnownFile returns a known file by path, or nil if not found.
func (*ScanCache) GetOrCreateGenre ¶ added in v0.0.11
func (c *ScanCache) GetOrCreateGenre(ctx context.Context, name string, libraryID int, svc GenreFinder) (*models.Genre, error)
GetOrCreateGenre retrieves a genre from the cache or calls the service to find/create one. It uses per-key locking to prevent duplicate concurrent DB calls for the same genre.
func (*ScanCache) GetOrCreateImprint ¶ added in v0.0.11
func (c *ScanCache) GetOrCreateImprint(ctx context.Context, name string, libraryID int, svc ImprintFinder) (*models.Imprint, error)
GetOrCreateImprint retrieves an imprint from the cache or calls the service to find/create one. It uses per-key locking to prevent duplicate concurrent DB calls for the same imprint.
func (*ScanCache) GetOrCreatePerson ¶ added in v0.0.11
func (c *ScanCache) GetOrCreatePerson(ctx context.Context, name string, libraryID int, svc PersonFinder) (*models.Person, error)
GetOrCreatePerson retrieves a person from the cache or calls the service to find/create one. It uses per-key locking to prevent duplicate concurrent DB calls for the same person.
func (*ScanCache) GetOrCreatePublisher ¶ added in v0.0.11
func (c *ScanCache) GetOrCreatePublisher(ctx context.Context, name string, libraryID int, svc PublisherFinder) (*models.Publisher, error)
GetOrCreatePublisher retrieves a publisher from the cache or calls the service to find/create one. It uses per-key locking to prevent duplicate concurrent DB calls for the same publisher.
func (*ScanCache) GetOrCreateSeries ¶ added in v0.0.11
func (c *ScanCache) GetOrCreateSeries(ctx context.Context, name string, libraryID int, nameSource string, svc SeriesFinder) (*models.Series, error)
GetOrCreateSeries retrieves a series from the cache or calls the service to find/create one. It uses per-key locking to prevent duplicate concurrent DB calls for the same series.
func (*ScanCache) GetOrCreateTag ¶ added in v0.0.11
func (c *ScanCache) GetOrCreateTag(ctx context.Context, name string, libraryID int, svc TagFinder) (*models.Tag, error)
GetOrCreateTag retrieves a tag from the cache or calls the service to find/create one. It uses per-key locking to prevent duplicate concurrent DB calls for the same tag.
func (*ScanCache) ImprintCount ¶ added in v0.0.11
ImprintCount returns the number of unique imprints in the cache.
func (*ScanCache) LoadKnownFiles ¶ added in v0.0.18
LoadKnownFiles populates the known files cache from a list of existing files.
func (*ScanCache) LockBook ¶ added in v0.0.11
LockBook acquires a lock for the given book ID to prevent concurrent relationship updates. Multiple files belonging to the same book may be processed in parallel, so we need to serialize their relationship updates (authors, series, genres, tags) to avoid race conditions. Returns an unlock function that must be called when done.
func (*ScanCache) LockBookPath ¶ added in v0.0.11
LockBookPath acquires a lock for the given book path to prevent concurrent book creation. Multiple files in the same directory would have the same book path, so we need to serialize their book creation to avoid unique constraint violations. Returns an unlock function that must be called when done.
func (*ScanCache) PersonCount ¶ added in v0.0.11
PersonCount returns the number of unique persons in the cache.
func (*ScanCache) PublisherCount ¶ added in v0.0.11
PublisherCount returns the number of unique publishers in the cache.
func (*ScanCache) SeriesCount ¶ added in v0.0.11
SeriesCount returns the number of unique series in the cache.
type ScanOptions ¶
type ScanOptions struct {
// Entry points (mutually exclusive - exactly one must be set)
FilePath string // Batch scan: discover/create by path
FileID int // Single file resync: file already in DB
BookID int // Book resync: scan all files in book
// Context (required for FilePath mode)
LibraryID int
// Behavior
ForceRefresh bool // Bypass priority checks, overwrite all metadata
// Logging (optional, for batch scan job context)
JobLog *joblogs.JobLogger
}
ScanOptions configures a scan operation.
Entry points are mutually exclusive - exactly one of FilePath, FileID, or BookID must be set:
- FilePath: Batch scan mode - discover or create file/book records by path. Requires LibraryID to be set.
- FileID: Single file resync - file already exists in DB. If the file no longer exists on disk, it will be deleted from the database.
- BookID: Book resync - scan all files belonging to the book. If the book has no files, it will be deleted.
type ScanResult ¶
type ScanResult struct {
// For single file scans
File *models.File // The scanned/updated file (nil if deleted)
Book *models.Book // The parent book (nil if deleted)
FileCreated bool // True if file was newly created (FilePath mode only)
FileDeleted bool // True if file was deleted (no longer on disk)
BookDeleted bool // True if book was also deleted (was last file)
// For book scans (multiple files)
Files []*ScanResult // Results for each file in the book (BookID mode only)
}
ScanResult contains the results of a scan operation.
For single file scans (FilePath or FileID mode), the File and Book fields contain the scanned/updated records. FileCreated indicates whether a new file record was created (only possible in FilePath mode). FileDeleted and BookDeleted indicate whether records were removed because the file no longer exists on disk.
For book scans (BookID mode), the Files slice contains the results for each individual file in the book. The top-level Book field contains the updated book record (unless BookDeleted is true).
type SeriesFinder ¶ added in v0.0.11
type SeriesFinder interface {
FindOrCreateSeries(ctx context.Context, name string, libraryID int, nameSource string) (*models.Series, error)
}
SeriesFinder is an interface for finding or creating series.
type TagFinder ¶ added in v0.0.11
type TagFinder interface {
FindOrCreateTag(ctx context.Context, name string, libraryID int) (*models.Tag, error)
}
TagFinder is an interface for finding or creating tags.
type Worker ¶
type Worker struct {
// contains filtered or unexported fields
}
func (*Worker) ProcessScanJob ¶
func (*Worker) RefreshMonitorWatches ¶ added in v0.0.20
func (w *Worker) RefreshMonitorWatches()
RefreshMonitorWatches signals the filesystem monitor to reload library paths. Safe to call even if the monitor is disabled (no-op).
func (*Worker) Scan ¶
func (w *Worker) Scan(ctx context.Context, opts books.ScanOptions) (*books.ScanResult, error)
Scan implements the books.Scanner interface. It converts books.ScanOptions to worker.ScanOptions, calls the internal scanInternal method, and converts the result back to books.ScanResult.
func (*Worker) UpdateBookRelationships ¶ added in v0.0.11
func (w *Worker) UpdateBookRelationships(ctx context.Context, bookID int, updates RelationshipUpdates) error
UpdateBookRelationships updates all book relationships using the books service methods. It first deletes existing relationships (if flagged) then bulk inserts new ones. This method should be called with appropriate locking when used in parallel processing.