Add movie search and add flow (M2)
Movies view with debounced Radarr lookup, detail pane, and an add dialog (quality profile, root folder, monitored, search now). Global shortcuts are suspended while typing or in a dialog. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rivo/tview"
|
||||
|
||||
"git.stinnesbeck.com/nils/arr-tui/internal/arr"
|
||||
"git.stinnesbeck.com/nils/arr-tui/internal/radarr"
|
||||
)
|
||||
|
||||
// movieLabel is the one-line list entry for a movie.
|
||||
func movieLabel(m radarr.Movie) string {
|
||||
label := tview.Escape(m.Title)
|
||||
if m.Year > 0 {
|
||||
label += fmt.Sprintf(" (%d)", m.Year)
|
||||
}
|
||||
if m.InLibrary() {
|
||||
label += " [green]✓[-]"
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
// movieDetails renders the detail pane text for a movie.
|
||||
func movieDetails(m radarr.Movie) string {
|
||||
var b strings.Builder
|
||||
title := tview.Escape(m.Title)
|
||||
if m.Year > 0 {
|
||||
title += fmt.Sprintf(" (%d)", m.Year)
|
||||
}
|
||||
fmt.Fprintf(&b, "[::b]%s[::-]\n", title)
|
||||
|
||||
var facts []string
|
||||
if r := m.Rating(); r > 0 {
|
||||
facts = append(facts, fmt.Sprintf("★ %.1f", r))
|
||||
}
|
||||
if m.Runtime > 0 {
|
||||
facts = append(facts, fmt.Sprintf("%dh%02dm", m.Runtime/60, m.Runtime%60))
|
||||
}
|
||||
if len(m.Genres) > 0 {
|
||||
facts = append(facts, tview.Escape(strings.Join(m.Genres, ", ")))
|
||||
}
|
||||
if len(facts) > 0 {
|
||||
b.WriteString(strings.Join(facts, " · ") + "\n")
|
||||
}
|
||||
if m.Studio != "" {
|
||||
fmt.Fprintf(&b, "Studio: %s\n", tview.Escape(m.Studio))
|
||||
}
|
||||
if m.Status != "" {
|
||||
fmt.Fprintf(&b, "Status: %s\n", tview.Escape(m.Status))
|
||||
}
|
||||
switch {
|
||||
case m.HasFile:
|
||||
b.WriteString("[green]In library, downloaded[-]\n")
|
||||
case m.InLibrary():
|
||||
b.WriteString("[yellow]In library, not downloaded[-]\n")
|
||||
}
|
||||
if m.Overview != "" {
|
||||
b.WriteString("\n" + tview.Escape(m.Overview) + "\n")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// profileIndex returns the index of the profile named name, or 0.
|
||||
func profileIndex(profiles []arr.QualityProfile, name string) int {
|
||||
for i, p := range profiles {
|
||||
if strings.EqualFold(p.Name, name) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// folderIndex returns the index of the root folder at path, or 0.
|
||||
func folderIndex(folders []arr.RootFolder, path string) int {
|
||||
for i, f := range folders {
|
||||
if strings.TrimRight(f.Path, "/") == strings.TrimRight(path, "/") {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user