summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-06 10:58:58 +0300
committerPaul Buetow <paul@buetow.org>2026-04-06 10:58:58 +0300
commit23160bce9a18a70080a85dda6e9c654499aba7f7 (patch)
treeec0f9930233aef96a221980310073081679bb4bb /cmd
parent95dd36d28d18615ad3f8dd7122a404850dcb39f8 (diff)
refactor: remove Viper coupling from processor package (DIP)
Resolve all Viper config values once at startup in cmd/totalrecall/main.go via the new newProcessorConfig() helper. The exported processor.Config struct replaces the internal viperConfig type, and NewProcessor now accepts *Config instead of querying Viper internally. The processor package no longer imports Viper at all. Tests are updated to pass Config values directly, eliminating the viper.Set/Reset boilerplate that coupled tests to the global singleton. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/totalrecall/main.go49
1 files changed, 47 insertions, 2 deletions
diff --git a/cmd/totalrecall/main.go b/cmd/totalrecall/main.go
index a3523ce..9e64897 100644
--- a/cmd/totalrecall/main.go
+++ b/cmd/totalrecall/main.go
@@ -4,8 +4,10 @@ import (
"fmt"
"os"
"path/filepath"
+ "strings"
"github.com/spf13/cobra"
+ "github.com/spf13/viper"
"codeberg.org/snonux/totalrecall/internal/archive"
"codeberg.org/snonux/totalrecall/internal/cli"
@@ -16,6 +18,48 @@ import (
"codeberg.org/snonux/totalrecall/internal/story"
)
+// newProcessorConfig reads all Viper-sourced settings in a single pass and
+// returns a fully-resolved processor.Config. Centralising all Viper access
+// here means the processor package is free of any Viper dependency, which
+// improves testability and removes tight coupling to the global config singleton.
+func newProcessorConfig() *processor.Config {
+ return &processor.Config{
+ // Translation & phonetic
+ TranslationProvider: strings.TrimSpace(viper.GetString("translation.provider")),
+ PhoneticProvider: strings.TrimSpace(viper.GetString("phonetic.provider")),
+ TranslationGeminiModel: viper.GetString("translation.gemini_model"),
+
+ // Audio
+ AudioProvider: strings.ToLower(strings.TrimSpace(viper.GetString("audio.provider"))),
+ AudioFormat: strings.ToLower(strings.TrimSpace(viper.GetString("audio.format"))),
+ AudioFormatSet: viper.IsSet("audio.format"),
+ GeminiTTSModel: strings.TrimSpace(viper.GetString("audio.gemini_tts_model")),
+ GeminiVoice: strings.TrimSpace(viper.GetString("audio.gemini_voice")),
+ OpenAIVoice: strings.TrimSpace(viper.GetString("audio.openai_voice")),
+ OpenAIModel: viper.GetString("audio.openai_model"),
+ OpenAIModelSet: viper.IsSet("audio.openai_model"),
+ OpenAISpeed: viper.GetFloat64("audio.openai_speed"),
+ OpenAISpeedSet: viper.IsSet("audio.openai_speed"),
+ OpenAIInstruction: viper.GetString("audio.openai_instruction"),
+ OpenAIInstructionSet: viper.IsSet("audio.openai_instruction"),
+
+ // Image
+ ImageProvider: strings.ToLower(strings.TrimSpace(viper.GetString("image.provider"))),
+ ImageOpenAIModel: viper.GetString("image.openai_model"),
+ ImageOpenAIModelSet: viper.IsSet("image.openai_model"),
+ ImageOpenAISize: viper.GetString("image.openai_size"),
+ ImageOpenAISizeSet: viper.IsSet("image.openai_size"),
+ ImageOpenAIQuality: viper.GetString("image.openai_quality"),
+ ImageOpenAIQualitySet: viper.IsSet("image.openai_quality"),
+ ImageOpenAIStyle: viper.GetString("image.openai_style"),
+ ImageOpenAIStyleSet: viper.IsSet("image.openai_style"),
+ ImageNanoBananaModel: strings.TrimSpace(viper.GetString("image.nanobanana_model")),
+ ImageNanoBananaModelSet: viper.IsSet("image.nanobanana_model"),
+ ImageNanoBananaTextModel: strings.TrimSpace(viper.GetString("image.nanobanana_text_model")),
+ ImageNanoBananaTextModelSet: viper.IsSet("image.nanobanana_text_model"),
+ }
+}
+
func main() {
// Create flags instance
flags := cli.NewFlags()
@@ -83,8 +127,9 @@ func runCommand(cmd *cobra.Command, args []string, flags *cli.Flags) error {
fmt.Printf("Note: Using image size 1024x1024 for DALL-E 3 (use --openai-image-size to override)\n")
}
- // Create processor
- proc := processor.NewProcessor(flags)
+ // Resolve all Viper config values once here so the processor never touches
+ // the global Viper singleton directly (Dependency Inversion Principle).
+ proc := processor.NewProcessor(flags, newProcessorConfig())
// Handle batch processing
if flags.BatchFile != "" {