diff --git a/cover.go b/cover.go index a2b10a2..8fee4d1 100644 --- a/cover.go +++ b/cover.go @@ -2,10 +2,12 @@ package main import ( "bytes" - "git.gitorious.org/go-pkg/epub.git" + "git.gitorious.org/go-pkg/epubgo.git" "github.com/nfnt/resize" "image" "image/jpeg" + "io" + "io/ioutil" "log" "os" "regexp" @@ -13,51 +15,68 @@ import ( "unicode/utf8" ) -func GetCover(e *epub.Epub, title string) (string, string) { - /* Try first common names */ - for _, p := range []string{"cover.jpg", "Images/cover.jpg", "cover.jpeg", "cover1.jpg", "cover1.jpeg"} { - img := e.Data(p) - if len(img) != 0 { - return storeImg(img, title, ".jpg") - } +func GetCover(e *epubgo.Epub, title string) (string, string) { + imgPath, smallPath := searchCommonCoverNames(e, title) + if imgPath != "" { + return imgPath, smallPath } /* search for img on the text */ exp, _ := regexp.Compile("<ima?g.*[(src)(href)]=[\"']([^\"']*(\\.[^\\.\"']*))[\"']") - it := e.Iterator(epub.EITERATOR_SPINE) - defer it.Close() - var err error = nil - txt := it.Curr() - for err == nil { - res := exp.FindStringSubmatch(txt) + it, errNext := e.Spine() + for errNext == nil { + file, err := it.Open() + if err != nil { + break + } + defer file.Close() + + txt, err := ioutil.ReadAll(file) + if err != nil { + break + } + res := exp.FindSubmatch(txt) if res != nil { - urlPart := strings.Split(it.CurrUrl(), "/") + href := string(res[1]) + urlPart := strings.Split(it.Url(), "/") url := strings.Join(urlPart[:len(urlPart)-1], "/") - if res[1][:3] == "../" { - res[1] = res[1][3:] + if href[:3] == "../" { + href = href[3:] url = strings.Join(urlPart[:len(urlPart)-2], "/") } - res[1] = strings.Replace(res[1], "%20", " ", -1) - res[1] = strings.Replace(res[1], "%27", "'", -1) - res[1] = strings.Replace(res[1], "%28", "(", -1) - res[1] = strings.Replace(res[1], "%29", ")", -1) + href = strings.Replace(href, "%20", " ", -1) + href = strings.Replace(href, "%27", "'", -1) + href = strings.Replace(href, "%28", "(", -1) + href = strings.Replace(href, "%29", ")", -1) if url == "" { - url = res[1] + url = href } else { - url = url + "/" + res[1] + url = url + "/" + href } - img := e.Data(url) - if len(img) != 0 { - return storeImg(img, title, res[2]) + img, err := e.OpenFile(url) + if err == nil { + defer img.Close() + return storeImg(img, title, string(res[2])) } } - txt, err = it.Next() + errNext = it.Next() } return "", "" } -func storeImg(img []byte, title, extension string) (string, string) { +func searchCommonCoverNames(e *epubgo.Epub, title string) (string, string) { + for _, p := range []string{"cover.jpg", "Images/cover.jpg", "cover.jpeg", "cover1.jpg", "cover1.jpeg"} { + img, err := e.OpenFile(p) + if err == nil { + defer img.Close() + return storeImg(img, title, ".jpg") + } + } + return "", "" +} + +func storeImg(img io.Reader, title, extension string) (string, string) { r, _ := utf8.DecodeRuneInString(title) folder := string(r) if _, err := os.Stat(COVER_PATH + folder); err != nil { @@ -86,8 +105,10 @@ func storeImg(img []byte, title, extension string) (string, string) { defer fSmall.Close() /* resize img */ + var img2 bytes.Buffer + img1 := io.TeeReader(img, &img2) jpgOptions := jpeg.Options{IMG_QUALITY} - imgResized, err := resizeImg(img, IMG_WIDTH_BIG) + imgResized, err := resizeImg(img1, IMG_WIDTH_BIG) if err != nil { log.Println("Error resizing big image:", err.Error()) return "", "" @@ -97,7 +118,7 @@ func storeImg(img []byte, title, extension string) (string, string) { log.Println("Error encoding big image:", err.Error()) return "", "" } - imgSmallResized, err := resizeImg(img, IMG_WIDTH_SMALL) + imgSmallResized, err := resizeImg(&img2, IMG_WIDTH_SMALL) if err != nil { log.Println("Error resizing small image:", err.Error()) return "", "" @@ -111,9 +132,8 @@ func storeImg(img []byte, title, extension string) (string, string) { return imgPath, imgPathSmall } -func resizeImg(imgBuff []byte, width uint) (image.Image, error) { - reader := bytes.NewReader(imgBuff) - img, _, err := image.Decode(reader) +func resizeImg(imgReader io.Reader, width uint) (image.Image, error) { + img, _, err := image.Decode(imgReader) if err != nil { return nil, err } diff --git a/database.go b/database.go index bc00874..775ab5d 100644 --- a/database.go +++ b/database.go @@ -106,7 +106,7 @@ func (d *DB) IncDownload(path string) error { } /* optional parameters: length and start index - * + * * Returns: list of books, number found and err */ func (d *DB) GetBooks(query bson.M, r ...int) (books []Book, num int, err error) { @@ -161,7 +161,7 @@ func (d *DB) GetDownloadedBooks(num int) (books []Book, err error) { } /* optional parameters: length and start index - * + * * Returns: list of books, number found and err */ func (d *DB) GetNewBooks(r ...int) (books []Book, num int, err error) { diff --git a/reader.go b/reader.go index 3f55c11..0aff43c 100644 --- a/reader.go +++ b/reader.go @@ -1,7 +1,8 @@ package main import ( - "git.gitorious.org/go-pkg/epub.git" + "git.gitorious.org/go-pkg/epubgo.git" + "io" "labix.org/v2/mgo/bson" "net/http" "regexp" @@ -67,52 +68,75 @@ func cleanLink(link string) string { return link } -/* return next and prev urls from document and the list of chapters */ -func chapterList(e *epub.Epub, file string, id string, base string) (string, string, []chapter) { - var chapters []chapter +func getNextPrev(e *epubgo.Epub, file string, id string, base string) (string, string) { + spine, err := e.Spine() + if err != nil { + return "", "" + } + prev := "" next := "" - tit := e.Titerator(epub.TITERATOR_NAVMAP) - defer tit.Close() + for err == nil { + if cleanLink(spine.Url()) == file { + break + } + prev = spine.Url() + err = spine.Next() + } + if err != nil { + return "", "" + } - activeIndx := -1 - depth := 0 - for ; tit.Valid(); tit.Next() { + prev = genLink(id, base, prev) + if spine.Next() == nil { + next = genLink(id, base, spine.Url()) + } + return next, prev +} + +func getChapters(e *epubgo.Epub, file string, id string, base string) []chapter { + nav, err := e.Navigation() + if err != nil { + return nil + } + chapters := listChapters(nav, 0) + + for i, c := range chapters { + chapters[i].Link = genLink(id, base, c.Link) + if cleanLink(c.Link) == file { + chapters[i].Active = true + } + } + return chapters +} + +func listChapters(nav *epubgo.NavigationIterator, depth int) []chapter { + var chapters []chapter + var err error = nil + for err == nil { var c chapter - c.Label = tit.Label() - c.Link = genLink(id, base, tit.Link()) - if cleanLink(tit.Link()) == file { - c.Active = true - activeIndx = len(chapters) - } - c.Depth = tit.Depth() - for c.Depth > depth { - c.In = append(c.In, true) - depth++ - } + c.Label = nav.Title() + c.Link = nav.Url() + c.Depth = depth for c.Depth < depth { c.Out = append(c.Out, true) depth-- } chapters = append(chapters, c) - } - /* if is the same chapter check the previous */ - i := activeIndx - 1 - for i >= 0 && strings.Contains(chapters[i].Link, "#") { - i-- + if nav.HasChildren() { + nav.In() + children := listChapters(nav, depth+1) + children[0].In = []bool{true} + children[len(children)-1].Out = []bool{true} + chapters = append(chapters, children...) + nav.Out() + } + err = nav.Next() } - if i >= 0 { - prev = chapters[i].Link - } - i = activeIndx + 1 - for i < len(chapters) && strings.Contains(chapters[i].Link, "#") { - i++ - } - if i < len(chapters) { - next = chapters[i].Link - } - return next, prev, chapters + chapters[0].In = []bool{true} + chapters[len(chapters)-1].Out = []bool{true} + return chapters } func readHandler(w http.ResponseWriter, r *http.Request) { @@ -138,17 +162,25 @@ func readHandler(w http.ResponseWriter, r *http.Request) { data.Back = "/book/" + id bookPath = BOOKS_PATH + data.Book.Path } - e, _ := epub.Open(bookPath, 0) + e, err := epubgo.Open(bookPath) + if err != nil { + http.NotFound(w, r) + return + } defer e.Close() if file == "" { - it := e.Iterator(epub.EITERATOR_LINEAR) - defer it.Close() - http.Redirect(w, r, base+id+"/"+it.CurrUrl(), http.StatusTemporaryRedirect) + it, err := e.Spine() + if err != nil { + http.NotFound(w, r) + return + } + http.Redirect(w, r, base+id+"/"+it.Url(), http.StatusTemporaryRedirect) return } data.S = GetStatus(w, r) - data.Next, data.Prev, data.Chapters = chapterList(e, file, id, base) + data.Next, data.Prev = getNextPrev(e, file, id, base) + data.Chapters = getChapters(e, file, id, base) data.Content = genLink(id, "/content/", file) loadTemplate(w, "read", data) } @@ -172,12 +204,18 @@ func contentHandler(w http.ResponseWriter, r *http.Request) { } else { bookPath = BOOKS_PATH + book.Path } - e, _ := epub.Open(bookPath, 0) + e, _ := epubgo.Open(bookPath) defer e.Close() if file == "" { http.NotFound(w, r) return } - w.Write(e.Data(file)) + html, err := e.OpenFile(file) + if err != nil { + http.NotFound(w, r) + return + } + defer html.Close() + io.Copy(w, html) } diff --git a/store.go b/store.go index efcc2dd..4cc8b7e 100644 --- a/store.go +++ b/store.go @@ -1,7 +1,7 @@ package main import ( - "git.gitorious.org/go-pkg/epub.git" + "git.gitorious.org/go-pkg/epubgo.git" "io" "log" "os" @@ -15,28 +15,35 @@ import ( func ParseFile(path string) (string, error) { book := map[string]interface{}{} - e, err := epub.Open(NEW_PATH+path, 0) + e, err := epubgo.Open(NEW_PATH + path) if err != nil { return "", err } defer e.Close() - title := cleanStr(strings.Join(e.Metadata(epub.EPUB_TITLE), ", ")) - book["title"] = title - book["author"] = parseAuthr(e.Metadata(epub.EPUB_CREATOR)) - book["contributor"] = cleanStr(strings.Join(e.Metadata(epub.EPUB_CONTRIB), ", ")) - book["publisher"] = cleanStr(strings.Join(e.Metadata(epub.EPUB_PUBLISHER), ", ")) - book["description"] = parseDescription(e.Metadata(epub.EPUB_DESCRIPTION)) - book["subject"] = parseSubject(e.Metadata(epub.EPUB_SUBJECT)) - book["date"] = parseDate(e.Metadata(epub.EPUB_DATE)) - book["lang"] = e.Metadata(epub.EPUB_LANG) - book["type"] = strings.Join(e.Metadata(epub.EPUB_TYPE), ", ") - book["format"] = strings.Join(e.Metadata(epub.EPUB_FORMAT), ", ") - book["source"] = strings.Join(e.Metadata(epub.EPUB_SOURCE), ", ") - book["relation"] = strings.Join(e.Metadata(epub.EPUB_RELATION), ", ") - book["coverage"] = strings.Join(e.Metadata(epub.EPUB_COVERAGE), ", ") - book["rights"] = strings.Join(e.Metadata(epub.EPUB_RIGHTS), ", ") - book["meta"] = strings.Join(e.Metadata(epub.EPUB_META), ", ") + for _, m := range e.MetadataFields() { + data, err := e.Metadata(m) + if err != nil { + continue + } + switch m { + case "creator": + book["author"] = parseAuthr(data) + case "description": + book[m] = parseDescription(data) + case "subject": + book[m] = parseSubject(data) + case "date": + book[m] = parseDate(data) + case "language": + book["lang"] = data + case "title", "contributor", "publisher": + book[m] = cleanStr(strings.Join(data, ", ")) + default: + book[m] = strings.Join(data, ", ") + } + } + title, _ := book["title"].(string) book["path"] = path cover, coverSmall := GetCover(e, title) book["cover"] = cover @@ -55,14 +62,8 @@ func StoreNewFile(name string, file io.Reader) (string, error) { } defer fw.Close() - const size = 1024 - var n int = size - buff := make([]byte, size) - for n == size { - n, err = file.Read(buff) - fw.Write(buff) - } - return path, nil + _, err = io.Copy(fw, file) + return path, err } func StoreBook(book Book) (path string, err error) { diff --git a/templates/read.html b/templates/read.html index ef3ebbf..5e3818e 100644 --- a/templates/read.html +++ b/templates/read.html @@ -19,13 +19,13 @@ <div class="row"> <div class="span4"> {{range .Chapters}} -{{range .Out}} -</ul> -{{end}} {{range .In}} <ul id="bookMenu" class="nav nav-list hidden-phone"> {{end}} <li {{if .Active}}class="active"{{end}}><a href="{{.Link}}">{{.Label}}</a></li> +{{range .Out}} +</ul> +{{end}} {{end}} {{if .Chapters}} </ul> diff --git a/upload.go b/upload.go index a09f72e..ba74729 100644 --- a/upload.go +++ b/upload.go @@ -44,7 +44,7 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { title, err := ParseFile(path) if err != nil { os.Remove(NEW_PATH + path) - sess.Notify("Problem uploading!", "The file '"+path+"' is not a well formed epub", "error") + sess.Notify("Problem uploading!", "The file '"+path+"' is not a well formed epub: "+err.Error(), "error") } else { uploaded = uploaded + " '" + title + "'" }