Documentation
¶
Index ¶
- func ApplyPreset(preset string, scalarStrategy string, arrayStrategy string) (string, string, error)
- func NFOToMovie(nfo *Movie) (*models.Movie, []string)
- func ParseArrayStrategy(strategy string) bool
- func ResolveNFOFilename(movie *models.Movie, nfoFilenameTemplate string, groupActress bool, ...) string
- type Actor
- type AudioStream
- type Config
- type DataSource
- type Fanart
- type FileInfo
- type Generator
- func (g *Generator) Generate(movie *models.Movie, outputPath string, partSuffix string, ...) error
- func (g *Generator) GenerateFromScraperResult(result *models.ScraperResult, outputPath string) error
- func (g *Generator) MovieToNFO(movie *models.Movie, videoFilePath string) *Movie
- func (g *Generator) ScraperResultToNFO(result *models.ScraperResult) *Movie
- func (g *Generator) WriteNFO(nfo *Movie, path string) error
- type MergeResult
- type MergeStats
- type MergeStrategy
- type Movie
- type ParseResult
- type Rating
- type Ratings
- type StreamDetails
- type SubtitleStream
- type Thumb
- type UniqueID
- type VideoStream
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyPreset ¶
func ApplyPreset(preset string, scalarStrategy string, arrayStrategy string) (string, string, error)
ApplyPreset applies a preset configuration to scalar and array strategy strings. Presets:
- "conservative": preserve-existing + merge (strictest preservation)
- "gap-fill": fill-missing-only + merge (safe gap filling)
- "aggressive": prefer-scraper + replace (trust scrapers completely)
Returns the resolved scalar and array strategy strings, or an error if preset is invalid. If preset is empty, returns the original strategy strings unchanged.
func NFOToMovie ¶
NFOToMovie converts an NFO Movie struct to a models.Movie
func ParseArrayStrategy ¶
ParseArrayStrategy converts array strategy string to boolean Valid values: "merge", "replace" (case-insensitive) Returns true (merge) as default
func ResolveNFOFilename ¶
func ResolveNFOFilename(movie *models.Movie, nfoFilenameTemplate string, groupActress bool, perFile bool, isMultiPart bool, partSuffix string) string
ResolveNFOFilename computes the NFO filename for a movie using the same logic as Generate, without writing the file. This ensures that history/revert code tracks the exact path the generator will use.
Types ¶
type Actor ¶
type Actor struct {
Name string `xml:"name"`
AltName string `xml:"altname,omitempty"` // Alternative/romanized name
Role string `xml:"role,omitempty"`
Order int `xml:"order,omitempty"`
Thumb string `xml:"thumb,omitempty"`
}
Actor represents an actress/actor in the movie
type AudioStream ¶
type AudioStream struct {
Codec string `xml:"codec,omitempty"`
Language string `xml:"language,omitempty"`
Channels int `xml:"channels,omitempty"`
}
AudioStream represents audio stream information
type Config ¶
type Config struct {
// Actress name formatting
ActorFirstNameOrder bool // true = FirstName LastName, false = LastName FirstName
ActorJapaneseNames bool // Use Japanese names if available
UnknownActress string // Placeholder for unknown actresses (default: "Unknown")
// File naming
NFOFilenameTemplate string // Template for NFO filename (default: "<ID>.nfo")
PerFile bool // Create separate NFO for each multi-part file (default: false)
// Optional fields
ActressAsTag bool // Copy actress names to <tag> elements
IncludeOriginalPath bool // Include source filename in NFO
IncludeStreamDetails bool // Include video/audio stream information
IncludeFanart bool // Include fanart section
IncludeTrailer bool // Include trailer URLs
// Actress role options
AddGenericRole bool // Add generic "Actress" role to all actresses (default: false)
AltNameRole bool // Use alternate name (Japanese) in role field instead of name (default: false)
// Rating source
DefaultRatingSource string // Which rating to mark as default (default: "themoviedb")
// Static NFO fields
StaticTags []string // Static tags to add to all NFOs
StaticTagline string // Static tagline for all NFOs
StaticCredits []string // Static credits for all NFOs
// Database integration
TagDatabase *database.MovieTagRepository // Optional tag database for per-movie tags
// Output configuration
GroupActress bool // Replace multiple actresses with "@Group" (default: false)
}
Config holds NFO generation settings
func ConfigFromAppConfig ¶
func ConfigFromAppConfig(appCfg *config.NFOConfig, outputCfg *config.OutputConfig, metadataCfg *config.MetadataConfig, db *database.DB) *Config
ConfigFromAppConfig converts application config to NFO generator config Optional db parameter enables tag database lookups if metadata config has tag_database.enabled
Example ¶
ExampleConfigFromAppConfig demonstrates config conversion
package main
import (
"fmt"
)
func main() {
// Application config would typically come from config.yaml
appCfg := &struct {
FilenameTemplate string
FirstNameOrder bool
ActressLanguageJA bool
UnknownActressText string
IncludeFanart bool
IncludeTrailer bool
RatingSource string
IncludeStreamDetails bool
}{
FilenameTemplate: "<ID>.nfo",
FirstNameOrder: true,
ActressLanguageJA: false,
UnknownActressText: "Unknown",
IncludeFanart: true,
IncludeTrailer: true,
RatingSource: "themoviedb",
IncludeStreamDetails: false,
}
fmt.Printf("Filename template: %s\n", appCfg.FilenameTemplate)
fmt.Printf("Use Japanese names: %v\n", appCfg.ActressLanguageJA)
fmt.Printf("Include fanart: %v\n", appCfg.IncludeFanart)
}
Output: Filename template: <ID>.nfo Use Japanese names: false Include fanart: true
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns default NFO generation settings
type DataSource ¶
type DataSource struct {
Source string // "scraper:r18dev", "nfo", "merged", "empty"
Confidence float64 // 0.0-1.0 (for future use)
LastUpdated *time.Time // When this data was last updated
}
DataSource indicates where a field's data came from
type Fanart ¶
type Fanart struct {
Thumbs []Thumb `xml:"thumb,omitempty"`
}
Fanart contains fanart/background images
type FileInfo ¶
type FileInfo struct {
StreamDetails *StreamDetails `xml:"streamdetails,omitempty"`
}
FileInfo contains media file technical information
type Generator ¶
type Generator struct {
// contains filtered or unexported fields
}
Generator creates NFO files from movie metadata
func NewGenerator ¶
NewGenerator creates a new NFO generator
func (*Generator) Generate ¶
func (g *Generator) Generate(movie *models.Movie, outputPath string, partSuffix string, videoFilePath string) error
Generate creates an NFO file from a Movie model partSuffix: optional suffix for multi-part files (e.g., "-pt1", "-A") videoFilePath: optional path to video file for extracting stream details (empty string to skip)
Example ¶
ExampleGenerator_Generate demonstrates how to generate an NFO file
package main
import (
"fmt"
"os"
"time"
"github.com/spf13/afero"
"github.com/javinizer/javinizer-go/internal/models"
"github.com/javinizer/javinizer-go/internal/nfo"
)
func main() {
// Create a movie with metadata
releaseDate := time.Date(2020, 9, 13, 0, 0, 0, 0, time.UTC)
movie := &models.Movie{
ID: "IPX-535",
ContentID: "ipx00535",
Title: "Beautiful Day",
ReleaseDate: &releaseDate,
Runtime: 120,
Director: "Yamada Taro",
Maker: "IdeaPocket",
Label: "IP Premium",
Series: "Beautiful Days",
RatingScore: 8.5,
RatingVotes: 100,
Actresses: []models.Actress{
{
FirstName: "Momo",
LastName: "Sakura",
},
},
Genres: []models.Genre{
{Name: "Beautiful Girl"},
{Name: "Featured Actress"},
},
}
// Create generator with default config
gen := nfo.NewGenerator(afero.NewOsFs(), nfo.DefaultConfig())
// Generate NFO file (no part suffix for single file)
tmpDir := os.TempDir()
err := gen.Generate(movie, tmpDir, "", "")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println("NFO generated successfully")
}
Output: NFO generated successfully
func (*Generator) GenerateFromScraperResult ¶
func (g *Generator) GenerateFromScraperResult(result *models.ScraperResult, outputPath string) error
GenerateFromScraperResult creates an NFO from a ScraperResult
func (*Generator) MovieToNFO ¶
MovieToNFO converts a Movie model to NFO format videoFilePath: optional path to video file for extracting stream details (empty string to skip)
Example ¶
ExampleGenerator_MovieToNFO demonstrates converting a Movie to NFO structure
package main
import (
"fmt"
"time"
"github.com/spf13/afero"
"github.com/javinizer/javinizer-go/internal/models"
"github.com/javinizer/javinizer-go/internal/nfo"
)
func main() {
releaseDate := time.Date(2020, 9, 13, 0, 0, 0, 0, time.UTC)
movie := &models.Movie{
ID: "IPX-535",
Title: "Beautiful Day",
ReleaseDate: &releaseDate,
Runtime: 120,
Maker: "IdeaPocket",
}
gen := nfo.NewGenerator(afero.NewOsFs(), nfo.DefaultConfig())
nfoMovie := gen.MovieToNFO(movie, "")
fmt.Printf("ID: %s\n", nfoMovie.ID)
fmt.Printf("Title: %s\n", nfoMovie.Title)
fmt.Printf("Year: %d\n", nfoMovie.Year)
fmt.Printf("Runtime: %d\n", nfoMovie.Runtime)
fmt.Printf("Studio: %s\n", nfoMovie.Studio)
}
Output: ID: IPX-535 Title: Beautiful Day Year: 2020 Runtime: 120 Studio: IdeaPocket
func (*Generator) ScraperResultToNFO ¶
func (g *Generator) ScraperResultToNFO(result *models.ScraperResult) *Movie
ScraperResultToNFO converts a ScraperResult to NFO format
type MergeResult ¶
type MergeResult struct {
Merged *models.Movie
Provenance map[string]DataSource
Stats MergeStats
}
MergeResult contains the merged movie and metadata about the merge
func MergeMovieMetadata ¶
func MergeMovieMetadata(scraped, nfo *models.Movie, strategy MergeStrategy) (*MergeResult, error)
MergeMovieMetadata merges scraped and NFO data non-destructively scraped: Movie from scraper results nfo: Movie from existing NFO file strategy: How to handle conflicts
IMPORTANT: Zero values are treated as "empty" for primitive types: - int/float fields: 0 and 0.0 are considered absent data - bool fields: false is considered absent data This means explicit zero/false values cannot be distinguished from missing values. For fields where zero/false are meaningful, consider using pointer types (*int, *float64, *bool).
func MergeMovieMetadataWithOptions ¶
func MergeMovieMetadataWithOptions(scraped, nfo *models.Movie, scalarStrategy MergeStrategy, mergeArrays bool) (*MergeResult, error)
MergeMovieMetadataWithOptions merges scraped and NFO data with granular control scraped: Movie from scraper results nfo: Movie from existing NFO file scalarStrategy: How to handle scalar fields (PreferNFO or PreferScraper) mergeArrays: If true, combine arrays from both sources; if false, use scalarStrategy for arrays too
This provides independent control over: - Scalar fields (title, studio, etc): prefer NFO or prefer scraped - Array fields (actresses, genres): merge both sources or replace
type MergeStats ¶
type MergeStats struct {
TotalFields int
FromScraper int
FromNFO int
MergedArrays int
ConflictsResolved int // Both had data, chose one
EmptyFields int
}
MergeStats tracks what happened during the merge
type MergeStrategy ¶
type MergeStrategy int
MergeStrategy defines how to merge metadata from different sources
const ( // PreferScraper uses scraper data when available, falls back to NFO (default) PreferScraper MergeStrategy = iota // PreferNFO uses NFO data when available, falls back to scraper (conservative) PreferNFO // MergeArrays combines arrays from both sources and deduplicates MergeArrays // PreserveExisting never overwrites non-empty fields (strictest preservation) PreserveExisting // FillMissingOnly only populates completely empty fields (safe gap filling) FillMissingOnly )
func ParseMergeStrategy
deprecated
func ParseMergeStrategy(strategy string) MergeStrategy
ParseMergeStrategy converts a merge strategy string to MergeStrategy enum Valid values: "prefer-scraper", "prefer-nfo", "merge-arrays" Returns PreferNFO as default for Update Mode
Deprecated: This function is from the legacy single-parameter merge strategy system. Use ParseScalarStrategy() for scalar fields and ParseArrayStrategy() for array fields instead. The new two-parameter system provides finer-grained control with additional options like "preserve-existing" and "fill-missing-only" for scalar fields, and "merge"/"replace" for arrays.
func ParseScalarStrategy ¶
func ParseScalarStrategy(strategy string) MergeStrategy
ParseScalarStrategy converts scalar strategy string to MergeStrategy Valid values: "prefer-scraper", "prefer-nfo", "preserve-existing", "fill-missing-only" (case-insensitive) Returns PreferNFO as default
type Movie ¶
type Movie struct {
XMLName xml.Name `xml:"movie"`
// Basic identification
Title string `xml:"title,omitempty"`
OriginalTitle string `xml:"originaltitle,omitempty"`
SortTitle string `xml:"sorttitle,omitempty"`
// IDs
ID string `xml:"id,omitempty"`
UniqueID []UniqueID `xml:"uniqueid,omitempty"`
// Plot/Description
Plot string `xml:"plot,omitempty"`
Outline string `xml:"outline,omitempty"` // Short description
Tagline string `xml:"tagline,omitempty"`
// Time information
Runtime int `xml:"runtime,omitempty"` // in minutes
Year int `xml:"year,omitempty"` // Release year
ReleaseDate string `xml:"releasedate,omitempty"` // YYYY-MM-DD format
Premiered string `xml:"premiered,omitempty"` // YYYY-MM-DD format
// Rating
Ratings Ratings `xml:"ratings,omitempty"`
// People
Director string `xml:"director,omitempty"`
Actors []Actor `xml:"actor,omitempty"`
Credits string `xml:"credits,omitempty"` // Writer/credits
// Production info
Studio string `xml:"studio,omitempty"` // Production studio
Maker string `xml:"maker,omitempty"` // Custom field for JAV maker
Label string `xml:"label,omitempty"` // Custom field for JAV label
Set string `xml:"set,omitempty"` // Series name
// Categories
Genres []string `xml:"genre,omitempty"`
Tags []string `xml:"tag,omitempty"`
// Media
Thumb []Thumb `xml:"thumb,omitempty"`
Fanart *Fanart `xml:"fanart,omitempty"`
Trailer string `xml:"trailer,omitempty"`
// File info (optional)
FileInfo *FileInfo `xml:"fileinfo,omitempty"`
OriginalPath string `xml:"originalpath,omitempty"` // Original source filename
}
Movie represents a Kodi-compatible NFO movie structure
type ParseResult ¶
type ParseResult struct {
Movie *models.Movie
Warnings []string // Non-fatal parsing issues
Source string // File path for debugging
NFOTitle string // Raw <title> from NFO, used for display title preservation
}
ParseResult contains the parsed NFO data and any warnings
type Rating ¶
type Rating struct {
Name string `xml:"name,attr,omitempty"`
Max int `xml:"max,attr,omitempty"`
Default bool `xml:"default,attr,omitempty"`
Value float64 `xml:"value"`
Votes int `xml:"votes,omitempty"`
}
Rating represents a single rating source
type Ratings ¶
type Ratings struct {
Rating []Rating `xml:"rating,omitempty"`
}
Ratings contains rating information
type StreamDetails ¶
type StreamDetails struct {
Video []VideoStream `xml:"video,omitempty"`
Audio []AudioStream `xml:"audio,omitempty"`
Subtitle []SubtitleStream `xml:"subtitle,omitempty"`
}
StreamDetails contains video/audio/subtitle stream information
type SubtitleStream ¶
type SubtitleStream struct {
Language string `xml:"language,omitempty"`
}
SubtitleStream represents subtitle stream information
type Thumb ¶
type Thumb struct {
Aspect string `xml:"aspect,attr,omitempty"` // poster, banner, clearart, etc.
Preview string `xml:"preview,attr,omitempty"` // Preview URL
Value string `xml:",chardata"` // Main URL
}
Thumb represents a thumbnail/poster image
type UniqueID ¶
type UniqueID struct {
Type string `xml:"type,attr"`
Default bool `xml:"default,attr,omitempty"`
Value string `xml:",chardata"`
}
UniqueID represents a unique identifier with a type
type VideoStream ¶
type VideoStream struct {
Codec string `xml:"codec,omitempty"`
Aspect float64 `xml:"aspect,omitempty"`
Width int `xml:"width,omitempty"`
Height int `xml:"height,omitempty"`
DurationInSeconds int `xml:"durationinseconds,omitempty"`
StereoMode string `xml:"stereomode,omitempty"`
}
VideoStream represents video stream information