processor

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: GPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

internal/processor/apply.go

internal/processor/name.go

internal/processor/processor.go

internal/processor/regex.go

internal/processor/sort.go

internal/processor/types.go

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotMedia indicates the input is not a recognized main media type.
	ErrNotMedia = errors.New("not a main media file")

	// ErrNoMainMediaFound indicates a directory input did not contain a recognized main media file.
	ErrNoMainMediaFound = errors.New("no main media found in directory")

	// ErrInputMissing indicates the input path was removed before processing.
	ErrInputMissing = errors.New("input path no longer exists")

	// ErrUncategorized indicates the processor could not determine Movies vs Shows.
	ErrUncategorized = errors.New("unable to categorize media")

	// ErrAmbiguousShow indicates multiple possible show folders matched with no clear choice.
	ErrAmbiguousShow = errors.New("ambiguous show folder match")
)

Sentinel errors used by Plan() so higher layers (worker/watch) can decide what to do.

Functions

func IsSuppressedResult

func IsSuppressedResult(r Result) bool

IsSuppressedResult reports whether r is an expected non-event that callers should silently ignore rather than surface as a SKIPPED item. Covers inputs that are not media files, directories with no media, and inputs that disappeared before processing.

func ProcessEach

func ProcessEach(ctx context.Context, proc Processor, req Request, onResult func(Result)) error

ProcessEach calls proc.Process with onResult wired as the result callback. The caller must not set req.OnResult. Returns the error from Process.

Types

type Category

type Category string

Category represents Mintmedia's two canonical library targets.

const (
	CategoryMovie Category = "Movies"
	CategoryShow  Category = "Shows"
)

type Config

type Config struct {
	DropFolder string

	MoviesDir string
	ShowsDir  string

	MainMediaExtensions      []string // includes leading dots
	AssociatedFileExtensions []string // includes leading dots

	// Naming: patterns used to strip junk tags from release names.
	// These are regex patterns expressed as strings (ideally compiled once during processor init).
	MediaTagBlacklist []string
}

Config contains the processor-relevant configuration. This is a "resolved" config: paths should be absolute and validated.

type Move

type Move struct {
	Source string // absolute or input-resolved source path
	Dest   string // absolute destination path
	Kind   string // "main" or "associated"
}

Move describes an intended file move.

type NoMainMediaFoundError

type NoMainMediaFoundError struct {
	Path     string
	MaxDepth int
	DepthHit bool
}

NoMainMediaFoundError wraps ErrNoMainMediaFound and carries depth context.

func (*NoMainMediaFoundError) Error

func (e *NoMainMediaFoundError) Error() string

func (*NoMainMediaFoundError) Unwrap

func (e *NoMainMediaFoundError) Unwrap() error

type ParseMovieError

type ParseMovieError struct {
	BaseName string
	FileName string
}

ParseMovieError indicates a failure to parse movie info from names.

func (*ParseMovieError) Error

func (e *ParseMovieError) Error() string

type ParseShowError

type ParseShowError struct {
	BaseName string
	FileName string
}

ParseShowError indicates a failure to parse show info from names.

func (*ParseShowError) Error

func (e *ParseShowError) Error() string

type PartialPlanError

type PartialPlanError struct {
	Issues []PlanIssue
}

PartialPlanError indicates that some items were skipped but planning succeeded for others.

func (*PartialPlanError) Error

func (e *PartialPlanError) Error() string

type Plan

type Plan struct {
	// Input
	InputPath    string
	CategoryHint Category

	// Category decision
	Category Category

	// Main media selection
	MainSourcePath string // chosen main media file (may equal InputPath if InputPath is a file)
	MainExt        string // includes leading dot, e.g. ".mkv"
	MainBaseName   string // basename of MainSourcePath

	// Parsed identity (one of Movie or Show fields will be populated based on Category)
	MovieTitle string // e.g. "Get Smart (2008)"

	ShowName string // e.g. "Stranger Things"
	ShowYear string // e.g. "2016" or "" if unknown/not used
	Season   int    // e.g. 5
	Episode  int    // e.g. 8

	// Destination computation
	DestDir      string // directory containing main file
	DestRadix    string // base filename without extension used for main and associated files
	DestMainPath string // full destination path for the main file (DestDir + DestRadix + MainExt)

	// Associated files to move (if any)
	Associated []Move

	// Cleanup intent (optional; not all Apply implementations will honor this initially)
	DeleteEmptyInputDir bool
}

Plan is the deterministic result of analyzing an input. It should be stable and testable, and should not depend on global state.

type PlanIssue

type PlanIssue struct {
	Path string
	Err  error
}

PlanIssue captures a skipped path and the associated error.

type Processor

type Processor interface {
	Plan(ctx context.Context, req Request) ([]Plan, error)
	Apply(ctx context.Context, plans []Plan) ([]Result, error)
	Process(ctx context.Context, req Request) error
	SortCandidates(ctx context.Context, paths []string) ([]string, []SortError, error)
}

Processor is the core media decision+execution engine. Plan should be deterministic and side-effect free except for filesystem reads (stat/list). Apply performs the actual filesystem modifications (moves, logging events). Process delivers each result via req.OnResult as it is produced; the return value is an error only.

func New

func New(cfg Config, xfer Transferer, logger logging.Logger) (Processor, error)

New constructs a Processor with the provided dependencies. cfg should already contain absolute, resolved paths.

type Request

type Request struct {
	InputPath    string
	CategoryHint Category
	// OnResult receives each processing result as soon as it is available.
	// It is optional and is ignored when nil.
	// Contract: callbacks are invoked synchronously by Process, in result order,
	// and complete before Process returns.
	OnResult func(Result)
}

Request describes a single processing request. It is intentionally small. - InputPath can be a file or a directory. - CategoryHint is optional; if set, it should be CategoryMovie or CategoryShow.

type Result

type Result struct {
	Plan    Plan
	Applied bool

	// Handled indicates the processor intentionally handled the item without producing a library move
	// (e.g., ignored unsupported items, inputs with no main media, etc.).
	Handled bool
	Reason  string
}

Result reports the outcome of applying a plan.

type SortError

type SortError struct {
	Path string
	Err  error
}

SortError records a path excluded from SortCandidates because its filename could not be parsed as a recognizable media title.

func SortCandidates

func SortCandidates(ctx context.Context, proc Processor, paths []string) ([]string, []SortError, error)

SortCandidates returns paths in media-aware order: movies first (alphabetical by title), then shows (alphabetical by name, then season, then episode). Non-media paths are silently dropped. Paths that appear to be media but whose names cannot be parsed are omitted from sorted and reported in errs. A non-nil err signals a fatal failure (e.g. context canceled); in that case both sorted and errs are nil.

type Transferer

type Transferer interface {
	Move(ctx context.Context, src, dst string) error
}

Transferer moves a file from src -> dst. Implementations should try rename first and fall back to copy+atomic finalize on cross-filesystem.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL