From e5eefb5ca6ddfd77b49b12c817278fc7fada7226 Mon Sep 17 00:00:00 2001 From: cybardev Date: Sat, 2 Mar 2024 20:00:39 -0400 Subject: [PATCH] fix: play correct entry from list others: limit list length, add list item shortcuts, mainly use Video instead of VID, respect terminal background colour in list --- cmd/ytgo/search.go | 44 ++++++++++++++++++++++---------------------- cmd/ytgo/ui.go | 45 ++++++++++++++++++++++++--------------------- cmd/ytgo/vid.go | 19 +++++++++---------- cmd/ytgo/yt.go | 12 ++++++------ 4 files changed, 61 insertions(+), 59 deletions(-) diff --git a/cmd/ytgo/search.go b/cmd/ytgo/search.go index 7951c2a..8a0bc46 100644 --- a/cmd/ytgo/search.go +++ b/cmd/ytgo/search.go @@ -11,26 +11,18 @@ import ( "slices" ) -func fetch(u string) (string, error) { - res, err := http.Get(u) +func NthVID(query string, n int) (VID, error) { + vids, err := getVIDs(query) if err != nil { - return "", err + return VID(""), err } - defer res.Body.Close() - - body, err := io.ReadAll(res.Body) - if err != nil { - return "", err + if n <= 0 || n > len(vids) { + return "", errors.New("no video found") } - return string(body), nil -} - -func search(query string) (string, error) { - params := url.Values{"search_query": []string{query}}.Encode() - return fetch(YtURL + "results?" + params) + return vids[n-1], nil } -func getVideos(query string) ([]VID, error) { +func getVIDs(query string) ([]VID, error) { res, err := search(query) if err != nil { return nil, err @@ -48,20 +40,28 @@ func getVideos(query string) ([]VID, error) { return vids, nil } -func NthVideo(query string, n int) (VID, error) { - vids, err := getVideos(query) +func search(query string) (string, error) { + params := url.Values{"search_query": []string{query}}.Encode() + return fetch(YtURL + "results?" + params) +} + +func fetch(u string) (string, error) { + res, err := http.Get(u) if err != nil { return "", err } - if n <= 0 || n > len(vids) { - return "", errors.New("no video found") + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return "", err } - return vids[n-1], nil + return string(body), nil } func fetchVideoInfo(id VID) (Video, error) { - j := "%(.{id,title,channel,duration_string,original_url})#j" - out, err := exec.Command("yt-dlp", "-O", j, YtURL+"watch?v="+string(id)).Output() + j := "%(.{id,title,channel,duration_string})#j" + out, err := exec.Command("yt-dlp", "-O", j, id.URL()).Output() if err != nil { return Video{}, err } diff --git a/cmd/ytgo/ui.go b/cmd/ytgo/ui.go index a909d84..7f152e7 100644 --- a/cmd/ytgo/ui.go +++ b/cmd/ytgo/ui.go @@ -4,19 +4,22 @@ import ( "fmt" "sync" + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) -func VIDFromMenu(query string) (VID, error) { - vids, err := getVideos(query) +func VideoFromMenu(query string) (Video, error) { + vids, err := getVIDs(query) if err != nil { - return "", err + return Video{}, err } - m := make(VideoMap, len(vids)) - return menuUI(&vids, &m) + n := min(10, len(vids)) + v := vids[:n] + m := make(VideoMap, n) + return menuUI(&v, &m) } -func menuUI(vids *[]VID, m *VideoMap) (VID, error) { +func menuUI(vids *[]VID, m *VideoMap) (Video, error) { var wg sync.WaitGroup wg.Add(len(*vids)) @@ -27,14 +30,9 @@ func menuUI(vids *[]VID, m *VideoMap) (VID, error) { wg.Wait() - var v VID + tview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault app := tview.NewApplication() - list := videoList(app, &v, m, vids) - err := app.SetRoot(list, true).EnableMouse(true).Run() - if err != nil { - return "", err - } - return v, nil + return chooseFromList(app, m, vids) } func mapVideos(id VID, m *VideoMap, wg *sync.WaitGroup) error { @@ -47,22 +45,27 @@ func mapVideos(id VID, m *VideoMap, wg *sync.WaitGroup) error { return nil } -func videoList(app *tview.Application, selected *VID, m *VideoMap, vids *[]VID) *tview.List { +func chooseFromList(app *tview.Application, m *VideoMap, vids *[]VID) (Video, error) { + var selected Video + l := tview.NewList() l = l. AddItem("Quit", "Press to exit", 'q', func() { - *selected = "" + selected = Video{} app.Stop() }) - var v Video - for _, vid := range *vids { - v = (*m)[vid] - l.AddItem("\n"+v.Title, v.Desc(), 0, func() { - *selected = vid + for i, vid := range *vids { + v := (*m)[vid] + l.AddItem(v.Title, v.Desc(), rune(i+48), func() { + selected = v app.Stop() }) } - return l + err := app.SetRoot(l, true).EnableMouse(true).Run() + if err != nil { + return Video{}, err + } + return selected, nil } diff --git a/cmd/ytgo/vid.go b/cmd/ytgo/vid.go index f74cea5..6b865c7 100644 --- a/cmd/ytgo/vid.go +++ b/cmd/ytgo/vid.go @@ -11,30 +11,25 @@ const YtURL = "https://www.youtube.com/" type VideoMap map[VID]Video +type VID string + type Video struct { Id VID `json:"id"` Title string `json:"title"` Channel string `json:"channel"` Duration string `json:"duration_string"` - Url string `json:"original_url"` } func (v Video) Desc() string { return fmt.Sprintf("(%s) [%s]", v.Channel, v.Duration) } -type VID string - -func (v VID) URL() string { - return YtURL + "watch?v=" + string(v) -} - -func (v VID) Play(m bool) error { +func (v Video) Play(m bool) error { bestaudio, novideo := "", "" if m { bestaudio, novideo = "--ytdl-format=bestaudio", "--no-video" } - cmd := exec.Command("mpv", bestaudio, novideo, v.URL()) + cmd := exec.Command("mpv", bestaudio, novideo, v.Id.URL()) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -45,10 +40,14 @@ func (v VID) Play(m bool) error { return nil } +func (v VID) URL() string { + return YtURL + "watch?v=" + string(v) +} + func VIDfromURL(s string) (VID, error) { u, err := url.Parse(s) if err != nil { - return "", err + return VID(""), err } return VID(u.Query().Get("v")), nil } diff --git a/cmd/ytgo/yt.go b/cmd/ytgo/yt.go index a551ec0..ff624c4 100644 --- a/cmd/ytgo/yt.go +++ b/cmd/ytgo/yt.go @@ -31,26 +31,26 @@ func main() { } // play media from YT or display URL - var v VID + var v Video var err error if f { - v, err = VIDfromURL(query) + v.Id, err = VIDfromURL(query) } else { if l { - v, err = VIDFromMenu(query) - if err == nil && v == "" { + v, err = VideoFromMenu(query) + if err == nil && (v == Video{}) { fmt.Println("No video selected.\nExiting...") return } } else { - v, err = NthVideo(query, n) + v.Id, err = NthVID(query, n) } } if err != nil { log.Fatalln(err) } if u { - fmt.Println(v.URL()) + fmt.Println(v.Id.URL()) } else { err = v.Play(m) if err != nil {