2012-08-15 11:40:19 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-08-30 13:17:50 -05:00
|
|
|
log "github.com/cihub/seelog"
|
|
|
|
|
2013-04-16 02:33:40 +02:00
|
|
|
"bytes"
|
2014-08-21 19:24:23 -05:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
2013-04-16 02:33:40 +02:00
|
|
|
"io/ioutil"
|
|
|
|
"mime/multipart"
|
2014-08-21 19:24:23 -05:00
|
|
|
"regexp"
|
2013-04-16 02:33:40 +02:00
|
|
|
"strings"
|
2014-08-30 01:25:16 -05:00
|
|
|
|
|
|
|
"git.gitorious.org/go-pkg/epubgo.git"
|
|
|
|
"git.gitorious.org/trantor/trantor.git/database"
|
|
|
|
"git.gitorious.org/trantor/trantor.git/storage"
|
2012-08-20 14:25:18 +02:00
|
|
|
)
|
|
|
|
|
2014-08-21 19:24:23 -05:00
|
|
|
func InitUpload(database *database.DB, store *storage.Store) {
|
2013-05-03 00:43:26 +02:00
|
|
|
uploadChannel = make(chan uploadRequest, CHAN_SIZE)
|
2014-08-21 19:24:23 -05:00
|
|
|
go uploadWorker(database, store)
|
2013-05-03 00:43:26 +02:00
|
|
|
}
|
2013-04-16 02:33:40 +02:00
|
|
|
|
2013-05-03 00:43:26 +02:00
|
|
|
var uploadChannel chan uploadRequest
|
2013-04-16 02:34:15 +02:00
|
|
|
|
2013-05-03 00:43:26 +02:00
|
|
|
type uploadRequest struct {
|
2013-07-16 22:56:48 +02:00
|
|
|
file multipart.File
|
|
|
|
filename string
|
2013-05-03 00:43:26 +02:00
|
|
|
}
|
2013-04-16 02:34:15 +02:00
|
|
|
|
2014-08-21 19:24:23 -05:00
|
|
|
func uploadWorker(database *database.DB, store *storage.Store) {
|
2013-09-23 16:27:31 +02:00
|
|
|
db := database.Copy()
|
|
|
|
defer db.Close()
|
|
|
|
|
2013-05-03 00:43:26 +02:00
|
|
|
for req := range uploadChannel {
|
2014-08-21 19:24:23 -05:00
|
|
|
processFile(req, db, store)
|
2013-07-16 22:56:48 +02:00
|
|
|
}
|
|
|
|
}
|
2013-05-03 00:43:26 +02:00
|
|
|
|
2014-08-21 19:24:23 -05:00
|
|
|
func processFile(req uploadRequest, db *database.DB, store *storage.Store) {
|
2013-07-16 22:56:48 +02:00
|
|
|
defer req.file.Close()
|
2013-05-03 00:43:26 +02:00
|
|
|
|
2013-07-16 22:56:48 +02:00
|
|
|
epub, err := openMultipartEpub(req.file)
|
|
|
|
if err != nil {
|
2014-02-11 13:13:43 +01:00
|
|
|
log.Warn("Not valid epub uploaded file ", req.filename, ": ", err)
|
2013-07-16 22:56:48 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
defer epub.Close()
|
2013-05-03 00:43:26 +02:00
|
|
|
|
2014-08-21 19:24:23 -05:00
|
|
|
book, id := parseFile(epub, store)
|
2013-07-16 22:56:48 +02:00
|
|
|
req.file.Seek(0, 0)
|
2014-08-21 19:24:23 -05:00
|
|
|
size, err := store.Store(id, req.file, EPUB_FILE)
|
2013-07-16 22:56:48 +02:00
|
|
|
if err != nil {
|
2014-08-21 19:24:23 -05:00
|
|
|
log.Error("Error storing book (", id, "): ", err)
|
2013-07-16 22:56:48 +02:00
|
|
|
return
|
2012-08-15 13:58:16 +02:00
|
|
|
}
|
2013-07-16 22:56:48 +02:00
|
|
|
|
2013-09-18 23:56:49 +02:00
|
|
|
book["filesize"] = size
|
2014-06-29 19:41:29 -05:00
|
|
|
err = db.AddBook(book)
|
2013-07-23 22:40:35 +02:00
|
|
|
if err != nil {
|
2014-08-21 19:24:23 -05:00
|
|
|
log.Error("Error storing metadata (", id, "): ", err)
|
2013-07-23 22:40:35 +02:00
|
|
|
return
|
|
|
|
}
|
2014-02-11 13:13:43 +01:00
|
|
|
log.Info("File uploaded: ", req.filename)
|
2013-05-03 00:43:26 +02:00
|
|
|
}
|
2012-09-12 00:19:19 +02:00
|
|
|
|
2013-09-23 16:27:31 +02:00
|
|
|
func uploadPostHandler(h handler) {
|
2013-07-16 22:56:48 +02:00
|
|
|
problem := false
|
|
|
|
|
2013-09-23 16:27:31 +02:00
|
|
|
h.r.ParseMultipartForm(20000000)
|
|
|
|
filesForm := h.r.MultipartForm.File["epub"]
|
2013-07-16 22:56:48 +02:00
|
|
|
for _, f := range filesForm {
|
|
|
|
file, err := f.Open()
|
|
|
|
if err != nil {
|
2014-02-11 13:13:43 +01:00
|
|
|
log.Error("Can not open uploaded file ", f.Filename, ": ", err)
|
2013-09-23 16:27:31 +02:00
|
|
|
h.sess.Notify("Upload problem!", "There was a problem with book "+f.Filename, "error")
|
2013-07-16 22:56:48 +02:00
|
|
|
problem = true
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
uploadChannel <- uploadRequest{file, f.Filename}
|
|
|
|
}
|
2013-05-03 00:43:26 +02:00
|
|
|
|
2013-07-16 22:56:48 +02:00
|
|
|
if !problem {
|
|
|
|
if len(filesForm) > 0 {
|
2013-09-23 16:27:31 +02:00
|
|
|
h.sess.Notify("Upload successful!", "Thank you for your contribution", "success")
|
2013-07-16 22:56:48 +02:00
|
|
|
} else {
|
2013-09-23 16:27:31 +02:00
|
|
|
h.sess.Notify("Upload problem!", "No books where uploaded.", "error")
|
2013-07-16 22:56:48 +02:00
|
|
|
}
|
2013-05-03 00:43:26 +02:00
|
|
|
}
|
2013-09-23 16:27:31 +02:00
|
|
|
uploadHandler(h)
|
2013-04-16 02:34:15 +02:00
|
|
|
}
|
|
|
|
|
2013-09-23 16:27:31 +02:00
|
|
|
func uploadHandler(h handler) {
|
2012-09-12 00:19:19 +02:00
|
|
|
var data uploadData
|
2013-09-23 16:27:31 +02:00
|
|
|
data.S = GetStatus(h)
|
2012-09-12 00:19:19 +02:00
|
|
|
data.S.Upload = true
|
2014-08-30 01:25:16 -05:00
|
|
|
loadTemplate(h, "upload", data)
|
2012-08-15 11:40:19 +02:00
|
|
|
}
|
2013-04-16 02:33:40 +02:00
|
|
|
|
|
|
|
type uploadData struct {
|
|
|
|
S Status
|
|
|
|
}
|
|
|
|
|
|
|
|
func openMultipartEpub(file multipart.File) (*epubgo.Epub, error) {
|
|
|
|
buff, _ := ioutil.ReadAll(file)
|
|
|
|
reader := bytes.NewReader(buff)
|
|
|
|
return epubgo.Load(reader, int64(len(buff)))
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:24:23 -05:00
|
|
|
func parseFile(epub *epubgo.Epub, store *storage.Store) (metadata map[string]interface{}, id string) {
|
2013-04-16 02:33:40 +02:00
|
|
|
book := map[string]interface{}{}
|
|
|
|
for _, m := range epub.MetadataFields() {
|
|
|
|
data, err := epub.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":
|
2015-01-22 23:02:00 -06:00
|
|
|
book["lang"] = GuessLang(epub, data)
|
2013-04-16 02:33:40 +02:00
|
|
|
case "title", "contributor", "publisher":
|
|
|
|
book[m] = cleanStr(strings.Join(data, ", "))
|
|
|
|
case "identifier":
|
|
|
|
attr, _ := epub.MetadataAttr(m)
|
|
|
|
for i, d := range data {
|
|
|
|
if attr[i]["scheme"] == "ISBN" {
|
|
|
|
book["isbn"] = d
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
book[m] = strings.Join(data, ", ")
|
|
|
|
}
|
|
|
|
}
|
2014-08-21 19:24:23 -05:00
|
|
|
|
|
|
|
id = genId()
|
2015-01-22 23:02:00 -06:00
|
|
|
book["id"] = id
|
2014-08-21 19:24:23 -05:00
|
|
|
book["cover"] = GetCover(epub, id, store)
|
|
|
|
return book, id
|
|
|
|
}
|
|
|
|
|
|
|
|
func genId() string {
|
|
|
|
b := make([]byte, 12)
|
|
|
|
rand.Read(b)
|
|
|
|
return base64.URLEncoding.EncodeToString(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
func cleanStr(str string) string {
|
|
|
|
str = strings.Replace(str, "'", "'", -1)
|
|
|
|
exp, _ := regexp.Compile("&[^;]*;")
|
|
|
|
str = exp.ReplaceAllString(str, "")
|
|
|
|
exp, _ = regexp.Compile("[ ,]*$")
|
|
|
|
str = exp.ReplaceAllString(str, "")
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseAuthr(creator []string) []string {
|
|
|
|
exp1, _ := regexp.Compile("^(.*\\( *([^\\)]*) *\\))*$")
|
|
|
|
exp2, _ := regexp.Compile("^[^:]*: *(.*)$")
|
|
|
|
res := make([]string, len(creator))
|
|
|
|
for i, s := range creator {
|
|
|
|
auth := exp1.FindStringSubmatch(s)
|
|
|
|
if auth != nil {
|
|
|
|
res[i] = cleanStr(strings.Join(auth[2:], ", "))
|
|
|
|
} else {
|
|
|
|
auth := exp2.FindStringSubmatch(s)
|
|
|
|
if auth != nil {
|
|
|
|
res[i] = cleanStr(auth[1])
|
|
|
|
} else {
|
|
|
|
res[i] = cleanStr(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseDescription(description []string) string {
|
|
|
|
str := cleanStr(strings.Join(description, "\n"))
|
|
|
|
str = strings.Replace(str, "</p>", "\n", -1)
|
|
|
|
exp, _ := regexp.Compile("<[^>]*>")
|
|
|
|
str = exp.ReplaceAllString(str, "")
|
|
|
|
str = strings.Replace(str, "&", "&", -1)
|
|
|
|
str = strings.Replace(str, "<", "<", -1)
|
|
|
|
str = strings.Replace(str, ">", ">", -1)
|
|
|
|
str = strings.Replace(str, "\\n", "\n", -1)
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseSubject(subject []string) []string {
|
|
|
|
var res []string
|
|
|
|
for _, s := range subject {
|
|
|
|
res = append(res, strings.Split(s, " / ")...)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseDate(date []string) string {
|
|
|
|
if len(date) == 0 {
|
|
|
|
return ""
|
2013-07-23 22:41:04 +02:00
|
|
|
}
|
2014-08-21 19:24:23 -05:00
|
|
|
return strings.Replace(date[0], "Unspecified: ", "", -1)
|
2013-04-16 02:33:40 +02:00
|
|
|
}
|