Documentation
¶
Index ¶
- Constants
- Variables
- func BookSidecarExists(bookPath string) bool
- func BookSidecarPath(bookPath string) string
- func ChaptersToModels(chapters []ChapterMetadata) []*models.Chapter
- func FileSidecarExists(filePath string) bool
- func FileSidecarPath(filePath string) string
- func WriteBookSidecar(bookPath string, s *BookSidecar) error
- func WriteBookSidecarFromModel(book *models.Book) error
- func WriteFileSidecar(filePath string, s *FileSidecar) error
- func WriteFileSidecarFromModel(file *models.File) error
- func WriteFileSidecarWithChapters(file *models.File, chapters []*models.Chapter) error
- type AuthorMetadata
- type BookSidecar
- type ChapterMetadata
- type FileSidecar
- type IdentifierMetadata
- type NarratorMetadata
- type SeriesMetadata
Constants ¶
const CurrentVersion = 1
CurrentVersion is the current version of the sidecar file format. Increment this when making breaking changes to the schema.
const SidecarSuffix = ".metadata.json"
Variables ¶
var ErrEmptySidecarPath = errors.New("sidecar: path is empty")
ErrEmptySidecarPath is returned by Write* helpers when the caller supplies an empty book or file path. An empty path would otherwise resolve to the current working directory via filepath.Clean("") → ".", which historically caused stray "..metadata.json" files to be written next to whatever process was running (including Go test binaries).
Functions ¶
func BookSidecarExists ¶
BookSidecarExists checks if a book sidecar file exists.
func BookSidecarPath ¶
BookSidecarPath returns the sidecar file path for a book. For directory-based books: {bookdir}/{dirname}.metadata.json. For root-level books: {dir}/{filename_without_ext}.metadata.json. Returns "" when bookPath is empty — an empty bookPath has no meaningful sidecar location and must not be coerced into a CWD-relative path.
func ChaptersToModels ¶
func ChaptersToModels(chapters []ChapterMetadata) []*models.Chapter
ChaptersToModels converts ChapterMetadata slice to model chapters. Note: This creates chapter models without IDs - they should be inserted fresh.
func FileSidecarExists ¶
FileSidecarExists checks if a file sidecar exists.
func FileSidecarPath ¶
FileSidecarPath returns the sidecar file path for a media file. Returns {filepath}.metadata.json, or "" when filePath is empty.
func WriteBookSidecar ¶
func WriteBookSidecar(bookPath string, s *BookSidecar) error
WriteBookSidecar writes a book sidecar file. Note: The caller is responsible for ensuring the parent directory exists. For root-level files with OrganizeFileStructure enabled, the directory should be created before calling this function. Returns ErrEmptySidecarPath if bookPath is empty.
func WriteBookSidecarFromModel ¶
WriteBookSidecarFromModel writes a book sidecar from a Book model.
For root-level books in libraries with OrganizeFileStructure disabled, the scanner writes a synthetic organized-folder path into book.Filepath that never exists on disk. Writing a sidecar to that path would fail, so if book.Filepath doesn't resolve to an existing directory we fall back to anchoring the sidecar next to a file in the book (preferring a main file). The cover always lives next to the file in that case, so co-locating the book sidecar matches how the rest of the system resolves paths.
func WriteFileSidecar ¶
func WriteFileSidecar(filePath string, s *FileSidecar) error
WriteFileSidecar writes a file sidecar. Returns ErrEmptySidecarPath if filePath is empty.
func WriteFileSidecarFromModel ¶
WriteFileSidecarFromModel writes a file sidecar from a File model.
Types ¶
type AuthorMetadata ¶
type AuthorMetadata struct {
Name string `json:"name"`
SortName string `json:"sort_name,omitempty"`
SortOrder int `json:"sort_order,omitempty"`
Role *string `json:"role,omitempty"` // CBZ creator role: writer, penciller, inker, etc.
}
AuthorMetadata represents an author in the sidecar file.
type BookSidecar ¶
type BookSidecar struct {
Version int `json:"version"`
Title string `json:"title,omitempty"`
SortTitle string `json:"sort_title,omitempty"`
Subtitle *string `json:"subtitle,omitempty"`
Description *string `json:"description,omitempty"`
Authors []AuthorMetadata `json:"authors,omitempty"`
Series []SeriesMetadata `json:"series,omitempty"`
Genres []string `json:"genres,omitempty"`
Tags []string `json:"tags,omitempty"`
}
BookSidecar represents the metadata sidecar for a book. This is stored as {bookname}.metadata.json in the book directory.
func BookSidecarFromModel ¶
func BookSidecarFromModel(book *models.Book) *BookSidecar
BookSidecarFromModel creates a BookSidecar from a Book model.
func ReadBookSidecar ¶
func ReadBookSidecar(bookPath string) (*BookSidecar, error)
ReadBookSidecar reads and parses a book sidecar file. Returns nil, nil if the sidecar doesn't exist or bookPath is empty.
func ReadBookSidecarFromModel ¶ added in v0.0.37
ReadBookSidecarFromModel reads the book sidecar for a Book, using the same anchor-resolution logic as WriteBookSidecarFromModel. For root-level books with a synthetic book.Filepath, the sidecar is read from next to a file in the book instead of from the non-existent synthetic directory.
fileHint (may be nil) is consulted when the resolved anchor doesn't exist on disk — typically because book.Files was not loaded and book.Filepath is the synthetic pre-organize path. Pass the current file being scanned so resolution works before the book is reloaded with its files relation.
type ChapterMetadata ¶
type ChapterMetadata struct {
Title string `json:"title"`
StartPage *int `json:"start_page,omitempty"`
StartTimestampMs *int64 `json:"start_timestamp_ms,omitempty"`
Href *string `json:"href,omitempty"`
Children []ChapterMetadata `json:"children,omitempty"`
}
ChapterMetadata represents a chapter in the sidecar file. Position fields are mutually exclusive based on file type: - CBZ uses StartPage (0-indexed). - M4B uses StartTimestampMs. - EPUB uses Href.
func ChaptersFromModels ¶
func ChaptersFromModels(chapters []*models.Chapter) []ChapterMetadata
ChaptersFromModels converts model chapters to ChapterMetadata slice.
type FileSidecar ¶
type FileSidecar struct {
Version int `json:"version"`
Narrators []NarratorMetadata `json:"narrators,omitempty"`
URL *string `json:"url,omitempty"`
Publisher *string `json:"publisher,omitempty"`
ReleaseDate *string `json:"release_date,omitempty"` // ISO 8601 date string (YYYY-MM-DD)
Identifiers []IdentifierMetadata `json:"identifiers,omitempty"`
Name *string `json:"name,omitempty"`
Chapters []ChapterMetadata `json:"chapters,omitempty"`
CoverPage *int `json:"cover_page,omitempty"` // 0-indexed page number for page-based formats (CBZ, PDF)
Language *string `json:"language,omitempty"`
Abridged *bool `json:"abridged,omitempty"`
}
FileSidecar represents the metadata sidecar for a media file. This is stored as {filename}.metadata.json alongside the media file.
func FileSidecarFromModel ¶
func FileSidecarFromModel(file *models.File) *FileSidecar
FileSidecarFromModel creates a FileSidecar from a File model.
func ReadFileSidecar ¶
func ReadFileSidecar(filePath string) (*FileSidecar, error)
ReadFileSidecar reads and parses a file sidecar. Returns nil, nil if the sidecar doesn't exist or filePath is empty.
type IdentifierMetadata ¶
type IdentifierMetadata struct {
Type string `json:"type"` // isbn_10, isbn_13, asin, uuid, goodreads, google, other
Value string `json:"value"`
}
IdentifierMetadata represents an identifier in the sidecar file.
type NarratorMetadata ¶
type NarratorMetadata struct {
Name string `json:"name"`
SortName string `json:"sort_name,omitempty"`
SortOrder int `json:"sort_order,omitempty"`
}
NarratorMetadata represents a narrator in the sidecar file.
type SeriesMetadata ¶
type SeriesMetadata struct {
Name string `json:"name"`
SortName string `json:"sort_name,omitempty"`
Number *float64 `json:"number,omitempty"`
Unit *string `json:"unit,omitempty"` // models.SeriesNumberUnitVolume or models.SeriesNumberUnitChapter; CBZ only
SortOrder int `json:"sort_order,omitempty"`
}
SeriesMetadata represents series information in the sidecar file.