Files
2026-03-12 22:13:57 +00:00

167 lines
3.9 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strings"
"gitea.dcglab.co.uk/steve/arrman/cmd"
"gitea.dcglab.co.uk/steve/arrman/radarr"
"gitea.dcglab.co.uk/steve/arrman/sonarr"
)
// Version is set at build time via -ldflags.
var Version = "dev"
func main() {
loadEnv()
if len(os.Args) >= 2 && os.Args[1] == "version" {
fmt.Println(Version)
return
}
// Extract global --json flag from any position in args
filteredArgs, jsonOutput := extractFlag(os.Args[1:], "--json")
if len(filteredArgs) < 2 {
usage()
os.Exit(1)
}
domain := filteredArgs[0]
action := filteredArgs[1]
rest := filteredArgs[2:]
tlsSkip := strings.EqualFold(os.Getenv("ARRMAN_TLS_SKIP_VERIFY"), "true")
var err error
switch domain {
case "tv":
sonarrURL := requireEnv("SONARR_URL")
sonarrKey := requireEnv("SONARR_API_KEY")
client := sonarr.NewClient(sonarrURL, sonarrKey, tlsSkip)
err = runTV(client, action, rest, jsonOutput)
case "film", "films":
radarrURL := requireEnv("RADARR_URL")
radarrKey := requireEnv("RADARR_API_KEY")
client := radarr.NewClient(radarrURL, radarrKey, tlsSkip)
err = runFilm(client, action, rest, jsonOutput)
default:
fmt.Fprintf(os.Stderr, "Unknown domain: %s\n", domain)
usage()
os.Exit(1)
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
func extractFlag(args []string, flag string) ([]string, bool) {
var remaining []string
found := false
for _, a := range args {
if a == flag {
found = true
} else {
remaining = append(remaining, a)
}
}
return remaining, found
}
func runTV(client cmd.SonarrClient, action string, args []string, jsonOutput bool) error {
switch action {
case "list":
rest, inclExt := extractFlag(args, "--include-external")
term := strings.Join(rest, " ")
return cmd.TVList(client, term, inclExt, jsonOutput)
case "add":
return cmd.TVAdd(client, args, jsonOutput)
case "summary":
term := strings.Join(args, " ")
return cmd.TVSummary(client, term, jsonOutput)
case "profiles":
return cmd.TVProfiles(client, jsonOutput)
case "rootfolders":
return cmd.TVRootFolders(client, jsonOutput)
default:
return fmt.Errorf("unknown tv action: %s", action)
}
}
func runFilm(client cmd.RadarrClient, action string, args []string, jsonOutput bool) error {
switch action {
case "list":
rest, inclExt := extractFlag(args, "--include-external")
term := strings.Join(rest, " ")
return cmd.FilmList(client, term, inclExt, jsonOutput)
case "add":
return cmd.FilmAdd(client, args, jsonOutput)
case "summary":
term := strings.Join(args, " ")
return cmd.FilmSummary(client, term, jsonOutput)
case "profiles":
return cmd.FilmProfiles(client, jsonOutput)
case "rootfolders":
return cmd.FilmRootFolders(client, jsonOutput)
default:
return fmt.Errorf("unknown film action: %s", action)
}
}
func usage() {
fmt.Fprintln(os.Stderr, `Usage: arrman [--json] <domain> <action> [args...]
Domains: tv, film, films
Actions:
list [title] [--include-external] List/search library (add flag to include external sources)
add <term> --profile <id> --rootfolder <path> Add new
summary <term> Show details
profiles List quality profiles
rootfolders List root folders
Global flags:
--json Output results as structured JSON`)
}
func loadEnv() {
f, err := os.Open(".env")
if err != nil {
return
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
continue
}
key := strings.TrimSpace(parts[0])
val := strings.TrimSpace(parts[1])
if os.Getenv(key) == "" {
os.Setenv(key, val)
}
}
}
func requireEnv(key string) string {
val := os.Getenv(key)
if val == "" {
fmt.Fprintf(os.Stderr, "Error: %s is not set. Check your .env file.\n", key)
os.Exit(1)
}
return val
}