From ebfd8ac60d012f9ddcaefa707136b265d6daf13f Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Mon, 17 May 2021 14:39:23 -0500 Subject: [PATCH] *.go: fetching the books with progress bar Signed-off-by: Vincent Batts --- cmd/root.go | 19 +++++++----- pkg/goldenaudiobooks/golden.go | 56 ++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 56693c9..f79f6b0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -47,13 +47,16 @@ to quickly create a Cobra application.`, // Uncomment the following line if your bare application // has an action associated with it: Run: func(cmd *cobra.Command, args []string) { - b, err := goldenaudiobooks.BookScrape("https://goldenaudiobooks.com/the-water-dancer-oprahs-book-club-audiobook/") - if err != nil { - log.Fatal(err) - } - log.Debug(b) - if err = goldenaudiobooks.BookFetccher(b, ".", true); err != nil { - log.Fatal(err) + for _, arg := range args { + // "https://goldenaudiobooks.com/the-water-dancer-oprahs-book-club-audiobook/" + b, err := goldenaudiobooks.BookScrape(arg) + if err != nil { + log.Fatal(err) + } + log.Debug(b) + if err = goldenaudiobooks.BookFetcher(b, ".", viper.GetBool("create-local")); err != nil { + log.Fatal(err) + } } }, } @@ -79,6 +82,8 @@ func init() { // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + rootCmd.Flags().StringP("dest", "d", ".", "destination base for fetched books") + rootCmd.Flags().BoolP("create-local", "C", false, "create files in local directory") } // initConfig reads in config file and ENV variables if set. diff --git a/pkg/goldenaudiobooks/golden.go b/pkg/goldenaudiobooks/golden.go index fa717b6..6922c83 100644 --- a/pkg/goldenaudiobooks/golden.go +++ b/pkg/goldenaudiobooks/golden.go @@ -23,10 +23,17 @@ package goldenaudiobooks import ( "fmt" + "io" "net/http" + "net/url" + "os" + "path/filepath" + "strconv" "strings" "github.com/PuerkitoBio/goquery" + "github.com/cheggaaa/pb/v3" + log "github.com/sirupsen/logrus" ) type Book struct { @@ -62,7 +69,7 @@ func BookScrape(bookURL string) (*Book, error) { doc.Find(".lazy-hidden").Each(func(i int, s *goquery.Selection) { //title := s.Find("source").Text() if src, exists := s.Attr("src"); exists && strings.Contains(src, ".mp3") { - fmt.Println(i, src) + //fmt.Println(i, src) b.Files = append(b.Files, src) } }) @@ -72,6 +79,51 @@ func BookScrape(bookURL string) (*Book, error) { return &b, nil } -func BookFetccher(b *Book, dest string, mkdir bool) error { +// BookFetcher creates a folder in dest, from the title in Book, and downloads the files there. +// If no title is present, then one is generated and set in Book b. +func BookFetcher(b *Book, dest string, createLocal bool) error { + p := dest + if !createLocal { + p = filepath.Join(dest, b.Title) + if err := os.MkdirAll(p, os.FileMode(0755)); err != nil { + return err + } + } + log.Infof("Title: %q", b.Title) + + for _, f := range b.Files { + u, err := url.Parse(f) + if err != nil { + return err + } + fname := filepath.Base(u.Path) + fd, err := os.OpenFile(filepath.Join(p, fname), os.O_RDWR|os.O_CREATE, os.FileMode(0644)) + if err != nil { + return err + } + + log.Infof("Fetching %q", f) + resp, err := http.Get(f) + if err != nil { + return err + } + //log.Infof("%#v", resp) + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("status: %d; url: %q", resp.StatusCode, f) + } + size, err := strconv.ParseInt(resp.Header.Get("content-length"), 10, 64) + if err != nil { + size = -1 + } + bar := pb.Full.Start64(size) + + barReader := bar.NewProxyReader(resp.Body) + i, err := io.Copy(fd, barReader) + if err != nil { + return err + } + bar.Finish() + log.Infof("wrote %q (%d)", fname, i) + } return nil }