Skip to content
Snippets Groups Projects
Commit d4b72fa0 authored by ale's avatar ale
Browse files

generate thumbnails

parent 3599ba3c
Branches
Tags
No related merge requests found
......@@ -168,11 +168,9 @@ func doSearch(db *liber.Database, query string) {
}
func doHttpServer(db *liber.Database, addr string) {
storage := &liber.FileStorage{
Root: *bookDir,
Nesting: 2,
}
server := liber.NewHttpServer(db, storage, addr)
storage := liber.NewFileStorage(expandTilde(*bookDir), 2)
cache := liber.NewFileStorage(filepath.Join(expandTilde(*databaseDir), "cache"), 2)
server := liber.NewHttpServer(db, storage, cache, addr)
log.Fatal(server.ListenAndServe())
}
......@@ -217,7 +215,7 @@ func main() {
log.SetOutput(logf)
}
doUpdate(db, *bookDir)
doUpdate(db, expandTilde(*bookDir))
} else if *remotesync != "" {
doSync(db, *remotesync)
} else if *search {
......
......@@ -2,6 +2,7 @@ package liber
import (
"bytes"
cryptorand "crypto/rand"
"encoding/binary"
"encoding/json"
"errors"
......@@ -34,6 +35,13 @@ func (id BookId) Key() []byte {
return buf.Bytes()
}
func init() {
// Seed the RNG to a random value.
var seed int64
binary.Read(cryptorand.Reader, binary.LittleEndian, &seed)
rand.Seed(seed)
}
func NewID() BookId {
return BookId(rand.Int63())
}
......
......@@ -11,6 +11,13 @@ type FileStorage struct {
Nesting int
}
func NewFileStorage(root string, nesting int) *FileStorage {
return &FileStorage{
Root: root,
Nesting: nesting,
}
}
// Path of the file corresponding to the given key, relative to the
// root directory.
func (s *FileStorage) Path(key string) string {
......
......@@ -2,7 +2,7 @@
<div class="row">
<div class="book-icon">
{{if .CoverPath}}
<img src="/book/cover/{{.Id}}">
<img src="/book/thumb/{{.Id}}">
{{end}}
</div>
<div class="book-body">
......
......@@ -9,6 +9,7 @@ import (
"io"
"log"
"net/http"
"os/exec"
"path/filepath"
"strconv"
"strings"
......@@ -26,6 +27,7 @@ var (
type uiServer struct {
db *Database
storage *FileStorage
cache *FileStorage
}
type pagination struct {
......@@ -186,6 +188,46 @@ func (s *uiServer) handleShowCover(book *Book, w http.ResponseWriter, req *http.
http.ServeContent(w, req, "", time.Time{}, f)
}
const thumbnailSize = "150x150"
func (s *uiServer) handleShowThumbnail(book *Book, w http.ResponseWriter, req *http.Request) {
if book.CoverPath == "" {
http.NotFound(w, req)
return
}
w.Header().Set("Cache-Control", "public")
cachedPath := s.cache.Path(fmt.Sprintf("%d.thumb.jpg", book.Id))
if cachedFile, err := s.cache.Open(cachedPath); err == nil {
// Thumbnail is cached.
defer cachedFile.Close()
w.Header().Set("ETag", "T"+book.Id.String())
http.ServeContent(w, req, "", time.Time{}, cachedFile)
return
}
cachedFile, err := s.cache.Create(cachedPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer cachedFile.Close()
data, err := exec.Command("convert", book.CoverPath, "-geometry", thumbnailSize,
"-quality", "60", "jpeg:-").Output()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "image/jpeg")
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
w.Header().Set("ETag", "T"+book.Id.String())
cachedFile.Write(data)
w.Write(data)
}
func (s *uiServer) handleHome(w http.ResponseWriter, req *http.Request) {
render("index.html", w, nil)
}
......@@ -199,7 +241,7 @@ func render(templateName string, w http.ResponseWriter, ctx interface{}) {
io.Copy(w, &buf)
}
func NewHttpServer(db *Database, storage *FileStorage, addr string) *http.Server {
func NewHttpServer(db *Database, storage, cache *FileStorage, addr string) *http.Server {
var err error
tpl, err = template.New("liber").Funcs(template.FuncMap{
"join": strings.Join,
......@@ -209,7 +251,7 @@ func NewHttpServer(db *Database, storage *FileStorage, addr string) *http.Server
}
syncsrv := &syncServer{db, storage}
uisrv := &uiServer{db, storage}
uisrv := &uiServer{db, storage, cache}
r := mux.NewRouter()
r.Handle("/static/{path:.*}", http.StripPrefix("/static/",
......@@ -217,6 +259,7 @@ func NewHttpServer(db *Database, storage *FileStorage, addr string) *http.Server
r.HandleFunc("/api/sync/upload", syncsrv.handleSyncUpload).Methods("POST")
r.HandleFunc("/api/sync/diff", syncsrv.handleDiffRequest).Methods("POST")
r.Handle("/book/cover/{id:[0-9]+}", uisrv.withBook(uisrv.handleShowCover))
r.Handle("/book/thumb/{id:[0-9]+}", uisrv.withBook(uisrv.handleShowThumbnail))
r.Handle("/book/{id:[0-9]+}", uisrv.withBook(uisrv.handleShowBook))
r.Handle("/dl/{id:[0-9]+}", uisrv.withBook(uisrv.handleDownloadBook))
r.HandleFunc("/suggest", uisrv.handleAutocomplete)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment