diff --git a/cmd/piwigo-cli/images_tag.go b/cmd/piwigo-cli/images_tag.go index 4afd17e..300fa3c 100644 --- a/cmd/piwigo-cli/images_tag.go +++ b/cmd/piwigo-cli/images_tag.go @@ -20,9 +20,16 @@ type ImagesTagCommand struct { TagName string `short:"T" long:"tag" description:"look up for the first image of this tagName"` ExcludeTags string `short:"x" long:"exclude" description:"exclude tag from selection"` KeepSurveyFilter bool `short:"k" long:"keep" description:"keep survey filter"` + MaxImages int `short:"m" long:"max" description:"loop on a maximum number of images" default:"1"` } func (c *ImagesTagCommand) Execute(args []string) error { + if c.MaxImages < 0 || c.MaxImages > 100 { + return fmt.Errorf("maxImages should be between 1 and 100") + } + if c.Id > 0 { + c.MaxImages = 1 + } p := piwigo.Piwigo{} if err := p.LoadConfig(); err != nil { @@ -34,7 +41,27 @@ func (c *ImagesTagCommand) Execute(args []string) error { return err } - if c.Id == 0 { + var tags struct { + Tags piwigotools.Tags `json:"tags"` + } + if err := p.Post("pwg.tags.getAdminList", nil, &tags); err != nil { + return err + } + + sort.Slice(tags.Tags, func(i, j int) bool { + return tags.Tags[i].Name < tags.Tags[j].Name + }) + + var exclude *regexp.Regexp + if c.ExcludeTags != "" { + exclude = regexp.MustCompile(c.ExcludeTags) + } + selectTags := tags.Tags.Selector(exclude, c.KeepSurveyFilter) + + imagesToTags := make([]int, 0, c.MaxImages) + if c.Id > 0 { + imagesToTags = append(imagesToTags, c.Id) + } else { data := &url.Values{} switch { @@ -47,93 +74,92 @@ func (c *ImagesTagCommand) Execute(args []string) error { } data.Set("order", "date_creation") - data.Set("per_page", "1") + data.Set("per_page", fmt.Sprint(c.MaxImages)) var results struct { Images []piwigotools.ImageDetails `json:"images"` } if err := p.Post("pwg.tags.getImages", data, &results); err != nil { return err } - - if len(results.Images) == 0 { - return fmt.Errorf("image not found") + for _, img := range results.Images { + imagesToTags = append(imagesToTags, img.Id) } - c.Id = results.Images[0].Id } - var imgDetails piwigotools.ImageDetails - if err := p.Post("pwg.images.getInfo", &url.Values{ - "image_id": []string{fmt.Sprint(c.Id)}, - }, &imgDetails); err != nil { - return err + for _, imgId := range imagesToTags { + for { + var imgDetails piwigotools.ImageDetails + if err := p.Post("pwg.images.getInfo", &url.Values{ + "image_id": []string{fmt.Sprint(imgId)}, + }, &imgDetails); err != nil { + return err + } + + img, err := imgDetails.Preview(25) + if err != nil { + return err + } + + fmt.Println("\033[2J") // clear screen + fmt.Println(img) + + t := table.NewWriter() + t.AppendRows([]table.Row{ + {"Id", imgDetails.Id}, + {"Name", imgDetails.Name}, + {"Url", imgDetails.Url}, + {"CreatedAt", imgDetails.DateCreation}, + {"Size", fmt.Sprintf("%d x %d", imgDetails.Width, imgDetails.Height)}, + {"Categories", strings.Join(imgDetails.Categories.Names(), "\n")}, + {"Tags", strings.Join(imgDetails.Tags.NamesWithAgeAt(&imgDetails.DateCreation), "\n")}, + }) + + t.SetOutputMirror(os.Stdout) + t.SetStyle(table.StyleLight) + t.Render() + + fmt.Println() + + sel := selectTags() + + fmt.Println("Selection:") + for _, name := range sel.NamesWithAgeAt(&imgDetails.DateCreation) { + fmt.Printf(" - %s\n", name) + } + + if len(sel) == 0 { + exit := false + survey.AskOne(&survey.Confirm{ + Message: "Selection is empty, exit:", + Default: false, + }, &exit) + if exit { + return nil + } + } + + confirmSel := false + survey.AskOne(&survey.Confirm{ + Message: "Confirm:", + Default: true, + }, &confirmSel) + + if !confirmSel { + continue + } + + fmt.Println("Applying changes...") + data := &url.Values{} + data.Set("image_id", fmt.Sprint(imgId)) + data.Set("multiple_value_mode", "replace") + data.Set("tag_ids", sel.JoinIds(",")) + + if err := p.Post("pwg.images.setInfo", data, nil); err != nil { + return err + } + fmt.Println("Done!") + break + } } - - var tags struct { - Tags piwigotools.Tags `json:"tags"` - } - if err := p.Post("pwg.tags.getAdminList", &url.Values{ - "image_id": []string{fmt.Sprint(c.Id)}, - }, &tags); err != nil { - return err - } - - sort.Slice(tags.Tags, func(i, j int) bool { - return tags.Tags[i].Name < tags.Tags[j].Name - }) - - img, err := imgDetails.Preview(25) - if err != nil { - return err - } - fmt.Println(img) - - t := table.NewWriter() - t.AppendRows([]table.Row{ - {"Id", imgDetails.Id}, - {"Name", imgDetails.Name}, - {"Url", imgDetails.Url}, - {"CreatedAt", imgDetails.DateCreation}, - {"Size", fmt.Sprintf("%d x %d", imgDetails.Width, imgDetails.Height)}, - {"Categories", strings.Join(imgDetails.Categories.Names(), "\n")}, - {"Tags", strings.Join(imgDetails.Tags.NamesWithAgeAt(&imgDetails.DateCreation), "\n")}, - }) - - t.SetOutputMirror(os.Stdout) - t.SetStyle(table.StyleLight) - t.Render() - - var exclude *regexp.Regexp - if c.ExcludeTags != "" { - exclude = regexp.MustCompile(c.ExcludeTags) - } - - sel := tags.Tags.Select(exclude, c.KeepSurveyFilter) - - fmt.Println("Selection:") - for _, name := range sel.NamesWithAgeAt(&imgDetails.DateCreation) { - fmt.Printf(" - %s\n", name) - } - - confirmSel := false - survey.AskOne(&survey.Confirm{ - Message: "Confirm:", - Default: true, - }, &confirmSel) - - if !confirmSel { - return nil - } - - fmt.Println("Applying changes...") - data := &url.Values{} - data.Set("image_id", fmt.Sprint(c.Id)) - data.Set("multiple_value_mode", "replace") - data.Set("tag_ids", sel.JoinIds(",")) - - if err := p.Post("pwg.images.setInfo", data, nil); err != nil { - return err - } - fmt.Println("Done!") - return nil } diff --git a/internal/piwigo/piwigotools/tags.go b/internal/piwigo/piwigotools/tags.go index 06361e4..0bd91aa 100644 --- a/internal/piwigo/piwigotools/tags.go +++ b/internal/piwigo/piwigotools/tags.go @@ -52,25 +52,31 @@ func (t Tags) JoinIds(sep string) string { return strings.Join(ids, sep) } -func (t Tags) Select(exclude *regexp.Regexp, keepFilter bool) Tags { - options := make([]string, len(t)) +func (t Tags) Selector(exclude *regexp.Regexp, keepFilter bool) func() Tags { + options := make([]string, 0, len(t)) tags := map[string]*Tag{} - for i, tag := range t { - options[i] = tag.Name + for _, tag := range t { + if exclude != nil && exclude.MatchString(tag.Name) { + continue + } + options = append(options, tag.Name) tags[tag.Name] = tag } - answer := []string{} - prompt := &survey.MultiSelect{ - Message: "Tags:", - Options: options, - PageSize: 20, - } - survey.AskOne(prompt, &answer, survey.WithKeepFilter(keepFilter)) + return func() Tags { + answer := []string{} - result := make([]*Tag, len(answer)) - for i, a := range answer { - result[i] = tags[a] + survey.AskOne(&survey.MultiSelect{ + Message: "Tags:", + Options: options, + PageSize: 20, + }, &answer, survey.WithKeepFilter(keepFilter)) + + result := make([]*Tag, len(answer)) + for i, a := range answer { + result[i] = tags[a] + } + return result } - return result + }