importeos

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package importeos parses ETC Eos ASCII showfiles into LacyLights domain objects.

Index

Constants

View Source
const (
	PaletteListNameColor     = "Color Palettes"
	PaletteListNameBeam      = "Beam Palettes"
	PaletteListNameFocus     = "Focus Palettes"
	PaletteListNameIntensity = "Intensity Palettes"
	PaletteListNamePreset    = "Presets"
)

Cue list names used by the importer to file synthesized palette/preset looks. Exported so the exporter can recognize the same lists when translating LacyLights state back to Eos ASCII; keeping the strings in one place avoids silent drift between the two halves of the round-trip.

Variables

View Source
var ErrAddressUnpatched = errors.New("eos: address is 0 (unpatched)")

ErrAddressUnpatched indicates the EOS patch entry has no DMX address (raw "0"). Callers may choose to skip such entries rather than fail the whole import.

View Source
var ErrNotImplemented = errors.New("import_eos: not implemented")

ErrNotImplemented is returned by methods that have not been implemented yet.

Functions

func NormalizeAddress

func NormalizeAddress(raw string) (universe int, address int, err error)

NormalizeAddress converts an EOS patch address string to a (universe, address) tuple. Accepts flat absolute ("1024"), dotted ("2.512"), and slashed ("3/100") forms. Universes are 1-based, addresses are 1-based and 1..512. Flat values are allowed to span multiple universes (e.g. flat=1024 → universe 2, address 512; flat=1025 → universe 3, address 1). Returns ErrAddressUnpatched for the literal value "0", which EOS uses to mark channels that exist in the show but are not patched to any DMX output.

func Parse

func Parse(r io.Reader) (*Show, *Collector, error)

Parse reads r as an Eos ASCII file and returns the AST plus a Collector containing any non-fatal warnings (e.g. UNKNOWN_DIRECTIVE).

Types

type ChanMove

type ChanMove struct {
	Channel int
	Value   int
}

ChanMove is a single tracked-intensity move within a cue. Format in source: "1@H00" → channel 1, hex 0x00.

type Collector

type Collector struct {
	// contains filtered or unexported fields
}

Collector accumulates warnings during a single import or export run.

func (*Collector) Add

func (c *Collector) Add(code WarningCode, severity Severity, message string, context map[string]string)

Add records a new warning.

func (*Collector) All

func (c *Collector) All() []Warning

All returns all warnings collected so far.

type Cue

type Cue struct {
	Number      string // "0.5", "5/2", etc. — without the part suffix once parsed
	Part        int    // 0 if not a part
	Label       string
	UnicodeText *string
	UpFade      float64
	UpDelay     float64
	DownFade    float64
	DownDelay   float64
	Follow      *float64
	Hang        *float64
	Block       bool
	IntBlock    bool
	ChanMoves   []ChanMove  // intensity moves (8-bit values)
	ParamMoves  []ParamMove // attribute moves with per-parameter values
}

Cue is a single cue (or cue part) within a list.

type CueList

type CueList struct {
	Number int
	Label  string
	Cues   []Cue
}

CueList holds one cue list and its cues.

type FakeDef

type FakeDef struct {
	ID              string
	Manufacturer    string
	Model           string
	ChannelParamIDs []int
}

FakeDef is the minimal fixture-definition shape used by the matcher's repo interface. The production adapter wraps *repositories.FixtureRepository to satisfy the same interface in Task 14.

type Group

type Group struct {
	Number      string
	Label       string
	UnicodeText *string
	Channels    []int
}

Group is one $Group block.

type Line

type Line struct {
	Lineno    int // 1-based source line number
	Kind      LineKind
	Indent    int      // count of leading spaces
	Directive string   // first whitespace-separated token (e.g. "$Personality", "Cue", "$$Manuf")
	Fields    []string // remaining whitespace-separated tokens
	Raw       string   // verbatim line content (without trailing newline)
}

Line is a single tokenized line.

type LineKind

type LineKind int

LineKind classifies a single physical line of an Eos ASCII file.

const (
	// LineBlank is an empty line or whitespace-only line.
	LineBlank LineKind = iota
	// LineComment is a line starting with `!`.
	LineComment
	// LineDirective is a directive line (any non-blank, non-comment line).
	// Directive names start with `$` (top-level), `$$` (sub-directive), or
	// are bare identifiers like `Cue`, `Up`, `Down`, `Text`, etc.
	LineDirective
	// LineSidecar is a "$$ LACYLIGHTS:..." sidecar comment line.
	LineSidecar
)

type Mapper

type Mapper struct {
	// contains filtered or unexported fields
}

Mapper applies a parsed Show + Sidecar to LacyLights repos.

func (*Mapper) Apply

func (m *Mapper) Apply(ctx context.Context, show *Show, sidecar Sidecar, opts Options, warn *Collector) (*Result, error)

Apply maps the parsed show into the database.

type MatchResult

type MatchResult struct {
	ExistingDefinitionID string
	SynthesizedDef       *models.FixtureDefinition
	SynthesizedChannels  []models.ChannelDefinition
	ChannelFingerprint   string
}

MatchResult is the matcher's verdict for one personality.

type Matcher

type Matcher struct {
	// contains filtered or unexported fields
}

Matcher resolves Eos personalities to LacyLights fixture definitions.

func NewMatcher

func NewMatcher(repo MatcherRepo, table *ParamTable) *Matcher

NewMatcher constructs a matcher.

func (*Matcher) Match

func (m *Matcher) Match(ctx context.Context, pers Personality) (MatchResult, []Warning, error)

Match attempts to find an existing definition; otherwise synthesizes one.

type MatcherRepo

type MatcherRepo interface {
	FindMatchingDefinition(ctx context.Context, mfg, model string, paramIDs []int) (*FakeDef, error)
}

MatcherRepo is the subset of FixtureRepository the matcher needs.

type Options

type Options struct {
	TargetProjectID *string
	NewProjectName  *string
	GroupID         *string
}

Options configures an import run.

type Palette

type Palette struct {
	Number      string
	Label       string
	UnicodeText *string
	ChanMoves   []ChanMove
	ParamMoves  []ParamMove
}

Palette is a Color/Beam/Focus/Intensity palette or a Preset.

type ParamMove

type ParamMove struct {
	Channel int
	Values  []ParamValue
}

ParamMove is one channel's attribute moves within a cue. Format in source: "$$Param 41 1@0 12@255 13@201 14@236 204@0". First field is channel, remaining are paramID@value pairs.

type ParamTable

type ParamTable struct {
	// contains filtered or unexported fields
}

ParamTable maps EOS parameter IDs to LacyLights ChannelType values.

func NewParamTable

func NewParamTable(pts []ParamType) *ParamTable

NewParamTable builds a lookup from a parsed $ParamType list. Unknown IDs map to generated.ChannelTypeOther.

func (*ParamTable) ChannelType

func (t *ParamTable) ChannelType(id int) generated.ChannelType

ChannelType returns the LacyLights ChannelType for an EOS parameter ID.

type ParamType

type ParamType struct {
	ID        int
	Category  int
	LongName  string
	ShortName string
}

ParamType is one row of the $ParamType table.

type ParamValue

type ParamValue struct {
	ParamID int
	Value   int
}

ParamValue is one paramID/value pair.

type ParseError

type ParseError struct {
	Lineno int
	Msg    string
}

ParseError is returned for fatal parser failures.

func (*ParseError) Error

func (e *ParseError) Error() string

type PatchEntry

type PatchEntry struct {
	Channel       int
	AddressRaw    string // e.g. "1.512", "513", or "1/512"
	PersonalityID int
	Label         string  // from "Text" sub-directive
	UnicodeText   *string // from $$UText, decoded
}

PatchEntry is a single $Patch line plus its sub-directives.

type PersChannel

type PersChannel struct {
	ParamID   int
	Size      int // 1 = 8-bit, 2 = 16-bit
	Offset    int // 1-based MSB offset
	Offset16  int // 1-based LSB offset (for 16-bit), else 0
	HomeValue int
	Flags     string // e.g. "S" for Snap
}

PersChannel describes one channel of a personality.

type Personality

type Personality struct {
	ID        int
	Manuf     string
	Model     string
	Dcid      string
	Footprint int
	Channels  []PersChannel
}

Personality is one $Personality block.

type Result

type Result struct {
	ProjectID                string
	FixtureDefinitionsCount  int
	FixtureInstancesCount    int
	LooksCount               int
	CueListsCount            int
	CuesCount                int
	GroupsCount              int
	Warnings                 []Warning
	SynthesizedDefinitionIDs []string
}

Result is returned from a successful import.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service handles Eos ASCII import operations.

func NewService

func NewService() *Service

NewService constructs an empty Service. Use NewServiceWithDeps in production.

func (*Service) Import

func (s *Service) Import(ctx context.Context, r io.Reader, opts Options) (*Result, error)

Import reads an Eos ASCII showfile from r and applies it to the database.

type Severity

type Severity string

Severity is the severity of a non-fatal warning produced by the importer or exporter.

const (
	SeverityInfo Severity = "INFO"
	SeverityWarn Severity = "WARN"
)

type Show

type Show struct {
	Ident          string // e.g. "3:0"
	Manufacturer   string // e.g. "ETC"
	Console        string // e.g. "Eos"
	Format         string // e.g. "3.20"
	SoftwareString string // raw text from $$Software ... line
	Title          string // $$Title value
	ParamTypes     []ParamType
	Personalities  []Personality
	Patch          []PatchEntry
	CueLists       []CueList
	ColorPalettes  []Palette
	BeamPalettes   []Palette
	FocusPalettes  []Palette
	IntensPalettes []Palette
	Presets        []Palette
	Groups         []Group
	UnknownLines   []int    // 1-based line numbers we skipped
	SidecarLines   []string // raw "$$ LACYLIGHTS:..." lines for the sidecar reader
}

Show is the root of the parsed Eos ASCII AST.

type Sidecar

type Sidecar struct {
	Version       int
	LookBoards    []SidecarLookBoard
	FadeBehaviors []SidecarFadeBehavior
	SynthDefs     []SidecarSynthDef
}

Sidecar holds parsed `$$ LACYLIGHTS:` records from an Eos ASCII file.

func ReadSidecar

func ReadSidecar(rawLines []string, warn *Collector) Sidecar

ReadSidecar parses raw sidecar lines into a Sidecar struct. Malformed records are skipped and reported via the supplied collector.

type SidecarFadeBehavior

type SidecarFadeBehavior struct {
	InstanceRefID string                       `json:"instanceRefId"`
	Channels      []SidecarFadeBehaviorChannel `json:"channels"`
}

SidecarFadeBehavior captures non-default per-channel fade behaviors.

type SidecarFadeBehaviorChannel

type SidecarFadeBehaviorChannel struct {
	Offset   int    `json:"offset"`
	Behavior string `json:"behavior"` // "FADE" | "SNAP" | "SNAP_END"
}

SidecarFadeBehaviorChannel describes one channel's behavior.

type SidecarLookBoard

type SidecarLookBoard struct {
	RefID   string                   `json:"refId"`
	Name    string                   `json:"name"`
	Buttons []SidecarLookBoardButton `json:"buttons"`
}

SidecarLookBoard describes a LacyLights look board.

type SidecarLookBoardButton

type SidecarLookBoardButton struct {
	LookRefID string `json:"lookRefId"`
	X         int    `json:"x"`
	Y         int    `json:"y"`
	Color     string `json:"color"`
}

SidecarLookBoardButton describes one button on a look board.

type SidecarSynthDef

type SidecarSynthDef struct {
	DefRefID           string `json:"defRefId"`
	Manufacturer       string `json:"manufacturer"`
	Model              string `json:"model"`
	ChannelFingerprint string `json:"channelFingerprint"`
}

SidecarSynthDef marks a fixture definition that was synthesized on a prior import.

type Snapshot

type Snapshot struct {
	CueNumber     string
	CuePart       int
	ChannelLevels map[int]int         // channel → 0..255 (intensity)
	ParamLevels   map[int]map[int]int // channel → paramID → 0..255
	UpFade        float64
	UpDelay       float64
	DownFade      float64
	DownDelay     float64
	Follow        *float64
	Hang          *float64
	Block         bool
	IntBlock      bool
	Label         string
	UnicodeText   *string
}

Snapshot is the fully resolved per-channel state for one cue.

type Tracker

type Tracker struct{}

Tracker walks a cue list applying tracking semantics.

func NewTracker

func NewTracker() *Tracker

NewTracker returns a fresh tracker.

func (*Tracker) ResolveCueList

func (t *Tracker) ResolveCueList(
	cues []Cue,
	colorPalettes, beamPalettes, focusPalettes, intensPalettes, presets []Palette,
) []Snapshot

ResolveCueList resolves each cue against cumulative state. Palette references in $$Param values are resolved against the supplied palette tables (currently unused since EOS exports inline values; reserved for future palette-ref syntax).

type Warning

type Warning struct {
	Code     WarningCode
	Severity Severity
	Message  string
	Context  map[string]string
}

Warning is a structured non-fatal warning emitted during import or export.

type WarningCode

type WarningCode string

WarningCode classifies a structured warning so the UI/MCP can group them.

const (
	WarnSynthesizedFixture WarningCode = "SYNTHESIZED_FIXTURE"
	WarnEffectSkipped      WarningCode = "EFFECT_SKIPPED"
	WarnSubmasterSkipped   WarningCode = "SUBMASTER_SKIPPED"
	WarnMagicSheetSkipped  WarningCode = "MAGIC_SHEET_SKIPPED"
	WarnPartitionSkipped   WarningCode = "PARTITION_SKIPPED"
	WarnActionSkipped      WarningCode = "ACTION_SKIPPED"
	WarnCurveSkipped       WarningCode = "CURVE_SKIPPED"
	WarnUnknownDirective   WarningCode = "UNKNOWN_DIRECTIVE"
	WarnFadeBehaviorLost   WarningCode = "FADE_BEHAVIOR_LOST"
	WarnUTextDecode        WarningCode = "UTEXT_DECODE"
	WarnSidecarInvalid     WarningCode = "SIDECAR_INVALID"
	WarnSidecarUnresolved  WarningCode = "SIDECAR_UNRESOLVED"
	WarnUnpatchedChannel   WarningCode = "UNPATCHED_CHANNEL"
	WarnUnpatchedInstance  WarningCode = "UNPATCHED_INSTANCE"
	WarnLookValuesInvalid  WarningCode = "LOOK_VALUES_INVALID"
	WarnGroupsSkipped      WarningCode = "GROUPS_SKIPPED"
	WarnAddressConflict    WarningCode = "ADDRESS_CONFLICT"
	// WarnGroupAutoAssigned is emitted by the GraphQL resolver layer
	// (not the parser/mapper) when a multi-group user gets their new
	// imported project silently assigned to groupIDs[0]. Listed here
	// so the registry of every code a client may receive lives in one
	// canonical place, even though the warning is produced outside
	// import_eos.
	WarnGroupAutoAssigned WarningCode = "GROUP_AUTO_ASSIGNED"
	// WarnPersonalityIDInSynthRange fires when an incoming $Personality
	// uses an ID at or above the LacyLights synthesized range (>= 90001),
	// which could collide on re-export.
	WarnPersonalityIDInSynthRange WarningCode = "PERSONALITY_ID_IN_SYNTH_RANGE"
	// WarnPatchExtendedFields fires when a $Patch line has more than the
	// 5 fields documented for the library-driven form. Extra fields are
	// ignored; the warning surfaces the variance for review.
	WarnPatchExtendedFields WarningCode = "PATCH_EXTENDED_FIELDS"
	// WarnPatchAmbiguousFields fires when both candidate persID positions
	// in a $Patch line resolve to known personality IDs. The parser falls
	// through to user-authored ordering as the safe default.
	WarnPatchAmbiguousFields WarningCode = "PATCH_AMBIGUOUS_FIELDS"
	// WarnGroupChannelUnresolved fires when a $Group block references an
	// EOS channel number that wasn't patched in the same file. The group
	// is created with the resolvable members; missing channels surface as
	// one warning per miss for review.
	WarnGroupChannelUnresolved WarningCode = "GROUP_CHANNEL_UNRESOLVED"
	// WarnExportEmptyGroupSkipped fires during export when a FixtureGroup
	// has no patched members in the project. The writer skips the group
	// rather than emitting an empty $Group block; the warning surfaces
	// the skip for review.
	WarnExportEmptyGroupSkipped WarningCode = "EXPORT_EMPTY_GROUP_SKIPPED"
)

Jump to

Keyboard shortcuts

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