package cmd import ( "fmt" "os" "strconv" "strings" "gitea.dcglab.co.uk/steve/arrman/radarr" ) type RadarrClient interface { List() ([]radarr.Movie, error) Lookup(term string) ([]radarr.Movie, error) LookupIMDB(imdbID string) (*radarr.Movie, error) Get(id int) (*radarr.Movie, error) QualityProfiles() ([]radarr.QualityProfile, error) RootFolders() ([]radarr.RootFolder, error) Add(m radarr.Movie) (*radarr.Movie, error) } func filterMovies(movies []radarr.Movie, term string) []radarr.Movie { lower := strings.ToLower(term) var filtered []radarr.Movie for _, m := range movies { if strings.Contains(strings.ToLower(m.Title), lower) { filtered = append(filtered, m) } } return filtered } func FilmList(client RadarrClient, term string, includeExternal bool, jsonOut bool) error { var movies []radarr.Movie var err error if term != "" && includeExternal { movies, err = client.Lookup(term) } else { movies, err = client.List() if err == nil && term != "" { movies = filterMovies(movies, term) } } if err != nil { return err } if jsonOut { out := make([]jsonMovie, len(movies)) for i, m := range movies { out[i] = movieToJSON(m) } return writeJSON(out) } if len(movies) == 0 { fmt.Println("No films found") return nil } for _, m := range movies { hasFile := "no" if m.HasFile { hasFile = "yes" } fmt.Printf("%s (%d) — %s — HasFile: %s\n", m.Title, m.Year, m.Status, hasFile) } return nil } func FilmAdd(client RadarrClient, args []string, jsonOut bool) error { term, profile, rootfolder, err := parseAddArgs(args) if err != nil { return err } profileID, err := strconv.Atoi(profile) if err != nil { return fmt.Errorf("--profile must be a number") } var movie *radarr.Movie // Check if term looks like an IMDB ID (starts with "tt") if strings.HasPrefix(term, "tt") { m, err := client.LookupIMDB(term) if err != nil { return fmt.Errorf("No film found with IMDB ID %s", term) } if m.Title == "" { return fmt.Errorf("No film found with IMDB ID %s", term) } movie = m } else { results, err := client.Lookup(term) if err != nil { return err } if len(results) == 0 { return fmt.Errorf("No films found for '%s'", term) } // Rank results by similarity titles := make([]string, len(results)) for i, m := range results { titles[i] = m.Title } ranked := rankMatches(term, titles) if ranked[0].Similarity >= fuzzyThreshold { movie = &results[ranked[0].Index] } else { if jsonOut { suggestions := jsonSuggestions{ Error: fmt.Sprintf("no match for '%s'", term), Suggestions: make([]jsonSuggestion, 0), } limit := 5 if len(ranked) < limit { limit = len(ranked) } for _, rm := range ranked[:limit] { m := results[rm.Index] suggestions.Suggestions = append(suggestions.Suggestions, jsonSuggestion{ Title: m.Title, Year: m.Year, ImdbID: m.ImdbID, }) } writeJSON(suggestions) return fmt.Errorf("no match found") } fmt.Fprintf(os.Stderr, "No match for '%s'. Did you mean:\n", term) limit := 5 if len(ranked) < limit { limit = len(ranked) } for _, rm := range ranked[:limit] { m := results[rm.Index] fmt.Fprintf(os.Stderr, " %s (%d) — IMDB ID: %s\n", m.Title, m.Year, m.ImdbID) } return fmt.Errorf("no match found") } } if movie.ID != 0 { return fmt.Errorf("'%s' (%d) is already in your library", movie.Title, movie.Year) } movie.QualityProfileID = profileID movie.RootFolderPath = rootfolder movie.Monitored = true movie.MinimumAvailability = "released" movie.AddOptions = &radarr.AddOptions{SearchForMovie: true} result, err := client.Add(*movie) if err != nil { return err } if jsonOut { return writeJSON(jsonAdded{ Status: "added", Title: result.Title, Year: result.Year, ImdbID: result.ImdbID, }) } fmt.Printf("Added: %s (%d) — IMDB ID: %s\n", result.Title, result.Year, result.ImdbID) return nil } func FilmSummary(client RadarrClient, term string, jsonOut bool) error { if term == "" { return fmt.Errorf("usage: arrman film summary