Using epubgo to handle epubs

This commit is contained in:
Las Zenow 2013-04-01 14:05:04 +02:00
parent d46c3b72b6
commit d994d6b91f
6 changed files with 167 additions and 108 deletions

View file

@ -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
}

View file

@ -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) {

124
reader.go
View file

@ -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)
}

View file

@ -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) {

View file

@ -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>

View file

@ -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 + "'"
}