summaryrefslogtreecommitdiff
path: root/cmd/dlgbook/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/dlgbook/main.go')
-rw-r--r--cmd/dlgbook/main.go175
1 files changed, 175 insertions, 0 deletions
diff --git a/cmd/dlgbook/main.go b/cmd/dlgbook/main.go
new file mode 100644
index 0000000..3aa8015
--- /dev/null
+++ b/cmd/dlgbook/main.go
@@ -0,0 +1,175 @@
+package main
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+ "path"
+ "strings"
+ "unicode"
+)
+
+const usage = `Usage: dlgbook bookid [-a author] [-y year] [-t title] [savedir]
+
+Downloads all pages from a Google Book, using the getgbook
+tool, extracting the date, author name and title from
+Google Books (unless given as arguments to dlgbook), and
+saves them into a directory named YEAR_AUTHORSURNAME_Title
+`
+
+// formatAuthors formats a list of authors by just selecting
+// the first one listed, and returning the uppercased final
+// name.
+func formatAuthors(authors []string) string {
+ if len(authors) == 0 {
+ return ""
+ }
+
+ s := authors[0]
+
+ parts := strings.Fields(s)
+ if len(parts) > 1 {
+ s = parts[len(parts)-1]
+ }
+
+ s = strings.ToUpper(s)
+
+ return s
+}
+
+// mapTitle is a function for strings.Map to strip out
+// unwanted characters from the title.
+func mapTitle(r rune) rune {
+ if !unicode.IsLetter(r) {
+ return -1
+ }
+ return r
+}
+
+// formatTitle formats a title to our preferences, notably
+// by stripping spaces and punctuation characters.
+func formatTitle(title string) string {
+ return strings.Map(mapTitle, title)
+}
+
+// getMetadata queries Google Books for metadata we care about
+// and returns it formatted as we need it.
+func getMetadata(id string) (string, string, string, error) {
+ var author, title, year string
+ url := fmt.Sprintf("https://www.googleapis.com/books/v1/volumes/%s", id)
+
+ // designed to be unmarshalled by encoding/json's Unmarshal()
+ type bookInfo struct {
+ VolumeInfo struct {
+ Title string
+ Authors []string
+ PublishedDate string
+ }
+ }
+
+ resp, err := http.Get(url)
+ if err != nil {
+ return author, title, year, fmt.Errorf("Error downloading metadata %s: %v", url, err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return author, title, year, fmt.Errorf("Error downloading metadata %s: %v", url, err)
+ }
+
+ b, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return author, title, year, fmt.Errorf("Error reading metadata %s: %v", url, err)
+ }
+
+ v := bookInfo{}
+ err = json.Unmarshal(b, &v)
+ if err != nil {
+ return author, title, year, fmt.Errorf("Error parsing metadata %s: %v", url, err)
+ }
+
+ author = formatAuthors(v.VolumeInfo.Authors)
+ title = formatTitle(v.VolumeInfo.Title)
+ year = v.VolumeInfo.PublishedDate
+
+ return author, title, year, nil
+}
+
+func main() {
+ author := flag.String("author", "", "Set author, rather than autodetecting")
+ title := flag.String("title", "", "Set title, rather than autodetecting")
+ year := flag.String("year", "", "Set year, rather than autodetecting")
+ flag.Usage = func() {
+ fmt.Fprintf(flag.CommandLine.Output(), usage)
+ flag.PrintDefaults()
+ }
+ flag.Parse()
+
+ if flag.NArg() < 1 {
+ flag.Usage()
+ return
+ }
+ bookid := flag.Arg(0)
+
+ if *author == "" || *title == "" || *year == "" {
+ a, t, y, err := getMetadata(bookid)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if *author == "" {
+ *author = a
+ }
+ if *title == "" {
+ *title = t
+ }
+ if *year == "" {
+ *year = y
+ }
+ }
+
+ dir := fmt.Sprintf("%s_%s_%s", *year, *author, *title)
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ log.Fatalf("Couldn't create directory %s: %v", dir, err)
+ }
+ cmd := exec.Command("getgbook", bookid)
+ cmd.Dir = dir
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ err = cmd.Run()
+ if err != nil {
+ log.Fatalf("Error running getgbook %s: %v", bookid, err)
+ }
+
+ // getgbook downloads into bookid directory, so move files out of
+ // there directly into dir
+ tmpdir := path.Join(dir, bookid)
+ f, err := os.Open(tmpdir)
+ if err != nil {
+ log.Fatalf("Failed to open %s to move files: %v", tmpdir, err)
+ }
+ files, err := f.Readdir(0)
+ if err != nil {
+ log.Fatalf("Failed to readdir %s to move files: %v", tmpdir, err)
+ }
+ for _, v := range files {
+ orig := path.Join(tmpdir, v.Name())
+ new := path.Join(dir, v.Name())
+ err = os.Rename(orig, new)
+ if err != nil {
+ log.Fatalf("Failed to move %s to %s: %v", orig, new, err)
+ }
+ }
+
+ err = os.Remove(tmpdir)
+ if err != nil {
+ log.Fatalf("Failed to remove temporary directory %s: %v", tmpdir, err)
+ }
+
+ fmt.Printf("Successfully download to %s\n", dir)
+}