223 lines
5.4 KiB
Go
223 lines
5.4 KiB
Go
// Package config defines Captioneer's command-line configuration.
|
|
package config
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
CurrentConfigVersion = 1
|
|
DefaultModelsDir = "models"
|
|
DefaultVADThreshold = 0.5
|
|
DefaultOverlayFontFamily = "Sans"
|
|
MinimumOverlayFinalLifetime = 3 * time.Second
|
|
DefaultModelTimeout = 30 * time.Second
|
|
DefaultModelShutdownTimeout = 2 * time.Second
|
|
)
|
|
|
|
type Mode string
|
|
|
|
const (
|
|
ModeFixed Mode = "fixed"
|
|
ModeVAD Mode = "vad"
|
|
)
|
|
|
|
type Settings struct {
|
|
Mode Mode
|
|
ChunkDuration time.Duration
|
|
ModelsDir string
|
|
Threads int
|
|
PreviewThresholdDB float64
|
|
VADThreshold float64
|
|
ModelAutoRestart bool
|
|
ModelTimeout time.Duration
|
|
ModelShutdownTimeout time.Duration
|
|
}
|
|
|
|
func DefaultSettings() Settings {
|
|
return Settings{
|
|
Mode: ModeVAD,
|
|
ChunkDuration: time.Second,
|
|
ModelsDir: DefaultModelsDir,
|
|
Threads: 2,
|
|
PreviewThresholdDB: -45,
|
|
VADThreshold: DefaultVADThreshold,
|
|
ModelAutoRestart: true,
|
|
ModelTimeout: DefaultModelTimeout,
|
|
ModelShutdownTimeout: DefaultModelShutdownTimeout,
|
|
}
|
|
}
|
|
|
|
type OutputMode string
|
|
|
|
const (
|
|
OutputTerminal OutputMode = "terminal"
|
|
OutputOverlay OutputMode = "overlay"
|
|
OutputBoth OutputMode = "both"
|
|
)
|
|
|
|
type OverlayBackend string
|
|
|
|
const (
|
|
BackendAuto OverlayBackend = "auto"
|
|
BackendWayland OverlayBackend = "wayland"
|
|
BackendX11 OverlayBackend = "x11"
|
|
)
|
|
|
|
type OverlaySettings struct {
|
|
Backend OverlayBackend
|
|
Opacity float64
|
|
FontSize int
|
|
FontFamily string
|
|
BottomMargin int
|
|
MaxWidth int
|
|
Monitor string
|
|
FinalTimeout time.Duration
|
|
ClickThrough bool
|
|
}
|
|
|
|
func DefaultOverlaySettings() OverlaySettings {
|
|
return OverlaySettings{
|
|
Backend: BackendAuto,
|
|
Opacity: 0.90,
|
|
FontSize: 28,
|
|
FontFamily: DefaultOverlayFontFamily,
|
|
BottomMargin: 100,
|
|
MaxWidth: 1200,
|
|
Monitor: "auto",
|
|
FinalTimeout: MinimumOverlayFinalLifetime,
|
|
ClickThrough: true,
|
|
}
|
|
}
|
|
|
|
type OutputSettings struct {
|
|
Overlay bool
|
|
History bool
|
|
StdoutCaptions bool
|
|
StderrDiagnostics bool
|
|
}
|
|
|
|
type GUISettings struct {
|
|
StartCaptions bool
|
|
MainWindowAlwaysOnTop bool
|
|
}
|
|
|
|
type TranscriptLogSettings struct {
|
|
Enabled bool
|
|
Directory string
|
|
}
|
|
|
|
type AppConfig struct {
|
|
Version int
|
|
Settings Settings
|
|
Overlay OverlaySettings
|
|
Outputs OutputSettings
|
|
GUI GUISettings
|
|
TranscriptLog TranscriptLogSettings
|
|
}
|
|
|
|
func DefaultAppConfig() AppConfig {
|
|
return AppConfig{
|
|
Version: CurrentConfigVersion,
|
|
Settings: DefaultSettings(),
|
|
Overlay: DefaultOverlaySettings(),
|
|
Outputs: OutputSettings{
|
|
Overlay: true,
|
|
History: true,
|
|
StdoutCaptions: false,
|
|
StderrDiagnostics: true,
|
|
},
|
|
GUI: GUISettings{StartCaptions: true},
|
|
TranscriptLog: TranscriptLogSettings{
|
|
Directory: DefaultTranscriptDirectory(),
|
|
},
|
|
}
|
|
}
|
|
|
|
type DesktopSettings struct {
|
|
Settings
|
|
Output OutputMode
|
|
Overlay OverlaySettings
|
|
}
|
|
|
|
func (s Settings) Validate() error {
|
|
if s.Mode != ModeFixed && s.Mode != ModeVAD {
|
|
return errors.New("--mode is required and must be either fixed or vad")
|
|
}
|
|
if s.ChunkDuration <= 0 {
|
|
return errors.New("--chunk-duration must be positive")
|
|
}
|
|
if s.Threads <= 0 {
|
|
return errors.New("--threads must be positive")
|
|
}
|
|
if s.VADThreshold < 0 || s.VADThreshold > 1 {
|
|
return errors.New("--vad-threshold must be between 0 and 1")
|
|
}
|
|
if s.ModelTimeout < 0 {
|
|
return errors.New("--model-timeout cannot be negative")
|
|
}
|
|
if s.ModelShutdownTimeout <= 0 {
|
|
return errors.New("--model-shutdown-timeout must be positive")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s DesktopSettings) Validate() error {
|
|
if err := s.Settings.Validate(); err != nil {
|
|
return err
|
|
}
|
|
if s.Output != OutputTerminal && s.Output != OutputOverlay && s.Output != OutputBoth {
|
|
return errors.New("--output is required and must be terminal, overlay, or both")
|
|
}
|
|
return s.Overlay.Validate()
|
|
}
|
|
|
|
func (s OverlaySettings) Validate() error {
|
|
if s.Backend != BackendAuto && s.Backend != BackendWayland && s.Backend != BackendX11 {
|
|
return errors.New("--overlay-backend must be auto, wayland, or x11")
|
|
}
|
|
if s.Opacity < 0 || s.Opacity > 1 {
|
|
return errors.New("--overlay-opacity must be between 0 and 1")
|
|
}
|
|
if s.FontSize <= 0 {
|
|
return errors.New("--overlay-font-size must be positive")
|
|
}
|
|
if strings.TrimSpace(s.FontFamily) == "" {
|
|
return errors.New("--overlay-font-family cannot be empty")
|
|
}
|
|
if s.BottomMargin < 0 {
|
|
return errors.New("--overlay-bottom-margin cannot be negative")
|
|
}
|
|
if s.MaxWidth <= 0 {
|
|
return errors.New("--overlay-max-width must be positive")
|
|
}
|
|
if s.FinalTimeout < 0 {
|
|
return errors.New("--overlay-final-timeout cannot be negative")
|
|
}
|
|
if s.FinalTimeout > 0 && s.FinalTimeout < MinimumOverlayFinalLifetime {
|
|
return errors.New("--overlay-final-timeout must be zero or at least 3s")
|
|
}
|
|
if s.Monitor == "" {
|
|
return errors.New("--overlay-monitor cannot be empty")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c AppConfig) Validate() error {
|
|
if c.Version != CurrentConfigVersion {
|
|
return errors.New("unsupported configuration version")
|
|
}
|
|
if err := c.Settings.Validate(); err != nil {
|
|
return err
|
|
}
|
|
if err := c.Overlay.Validate(); err != nil {
|
|
return err
|
|
}
|
|
if c.TranscriptLog.Enabled && strings.TrimSpace(c.TranscriptLog.Directory) == "" {
|
|
return errors.New("caption log directory cannot be empty when logging is enabled")
|
|
}
|
|
return nil
|
|
}
|