diff --git a/cmd/watch_command.go b/cmd/watch_command.go new file mode 100644 index 0000000..60cf7ef --- /dev/null +++ b/cmd/watch_command.go @@ -0,0 +1,134 @@ +package cmd + +import ( + "fmt" + "github.com/belphemur/CBZOptimizer/converter" + "github.com/belphemur/CBZOptimizer/converter/constant" + "github.com/belphemur/CBZOptimizer/utils" + "github.com/pablodz/inotifywaitgo/inotifywaitgo" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/thediveo/enumflag/v2" + "log" + "runtime" + "strings" + "sync" +) + +func init() { + if runtime.GOOS != "linux" { + return + } + command := &cobra.Command{ + Use: "watch [folder]", + Short: "Watch a folder for new CBZ files", + Long: "Watch a folder for new CBZ files.\nIt will watch a folder for new CBZ files and optimize them.", + RunE: WatchCommand, + Args: cobra.ExactArgs(1), + } + formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + _ = formatFlag.RegisterCompletion(command, "format", constant.HelpText) + + command.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + _ = viper.BindPFlag("quality", command.Flags().Lookup("quality")) + + command.Flags().BoolP("override", "o", false, "Override the original CBZ files") + _ = viper.BindPFlag("override", command.Flags().Lookup("override")) + + command.PersistentFlags().VarP( + formatFlag, + "format", "f", + fmt.Sprintf("Format to convert the images to: %s", constant.ListAll())) + command.PersistentFlags().Lookup("format").NoOptDefVal = constant.DefaultConversion.String() + _ = viper.BindPFlag("format", command.PersistentFlags().Lookup("format")) + + AddCommand(command) +} +func WatchCommand(cmd *cobra.Command, args []string) error { + path := args[0] + if path == "" { + return fmt.Errorf("path is required") + } + + if !utils.IsValidFolder(path) { + return fmt.Errorf("the path needs to be a folder") + } + + quality, err := cmd.Flags().GetUint8("quality") + if err != nil { + return fmt.Errorf("invalid quality value") + } + + override, err := cmd.Flags().GetBool("override") + if err != nil { + return fmt.Errorf("invalid quality value") + } + + chapterConverter, err := converter.Get(converterType) + if err != nil { + return fmt.Errorf("failed to get chapterConverter: %v", err) + } + + err = chapterConverter.PrepareConverter() + if err != nil { + return fmt.Errorf("failed to prepare converter: %v", err) + } + + events := make(chan inotifywaitgo.FileEvent) + errors := make(chan error) + var wg sync.WaitGroup + + wg.Add(1) + go func() { + defer wg.Done() + inotifywaitgo.WatchPath(&inotifywaitgo.Settings{ + Dir: path, + FileEvents: events, + ErrorChan: errors, + Options: &inotifywaitgo.Options{ + Recursive: true, + Events: []inotifywaitgo.EVENT{ + inotifywaitgo.MOVE, + inotifywaitgo.CLOSE_WRITE, + }, + Monitor: true, + }, + Verbose: true, + }) + }() + + wg.Add(1) + go func() { + defer wg.Done() + for event := range events { + log.Printf("[Event]%s, %v\n", event.Filename, event.Events) + + if !strings.HasSuffix(strings.ToLower(event.Filename), ".cbz") { + continue + } + + for _, e := range event.Events { + switch e { + case inotifywaitgo.CLOSE_WRITE, inotifywaitgo.MOVE: + err := utils.Optimize(chapterConverter, event.Filename, quality, override) + if err != nil { + errors <- fmt.Errorf("error processing file %s: %w", event.Filename, err) + } + default: + // ignored + } + } + } + }() + + wg.Add(1) + go func() { + defer wg.Done() + for err := range errors { + log.Printf("Error: %v\n", err) + } + }() + + wg.Wait() + return nil +}