Using epubgo to handle epubs
This commit is contained in:
parent
d46c3b72b6
commit
d994d6b91f
6 changed files with 167 additions and 108 deletions
86
cover.go
86
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
|
||||
}
|
||||
|
|
|
@ -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
124
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)
|
||||
}
|
||||
|
|
53
store.go
53
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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 + "'"
|
||||
}
|
||||
|
|
Reference in a new issue