youp0m/picture.go

170 lines
3.8 KiB
Go

package main
import (
"encoding/base64"
"errors"
"image"
_ "image/gif"
"image/jpeg"
_ "image/png"
"io"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strconv"
"time"
"github.com/nfnt/resize"
)
type Picture struct {
path string
basename string
Name string `json:"name"`
UploadTime time.Time `json:"upload_time"`
}
type ByUploadTime []Picture
func (a ByUploadTime) Len() int { return len(a) }
func (a ByUploadTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByUploadTime) Less(i, j int) bool {
return a[i].UploadTime.Sub(a[j].UploadTime).Nanoseconds() < 0
}
func getImages(dir string) ([]Picture, error) {
if files, err := ioutil.ReadDir(dir); err != nil {
return nil, err
} else {
pictures := make([]Picture, 0)
for _, file := range files {
if !file.IsDir() {
filename := file.Name()
pictures = append(pictures, Picture{
filepath.Join(dir, filename), // Path
filename, // Basename
filename[:len(filename)-len(filepath.Ext(filename))], // Sanitized filename
file.ModTime(), // UploadTime
})
}
}
sort.Sort(ByUploadTime(pictures))
return pictures, nil
}
}
func GetNextImages() ([]Picture, error) {
return getImages(NextImgDir)
}
func GetPublishedImages() ([]Picture, error) {
return getImages(PublishedImgDir)
}
func GetLastImage() (Picture, error) {
if picts, err := GetPublishedImages(); err != nil {
return Picture{}, err
} else {
return picts[len(picts)-1], nil
}
}
func getImage(flist func() ([]Picture, error), fname string) (Picture, error) {
if picts, err := flist(); err != nil {
return Picture{}, err
} else if pid, err := strconv.Atoi(fname); err == nil {
if pid < len(picts) {
return picts[pid], nil
} else {
return Picture{}, errors.New("Invalid picture identifier")
}
} else {
for _, pict := range picts {
if pict.Name == fname || pict.basename == fname {
return pict, nil
}
}
return Picture{}, errors.New("No such picture")
}
}
func GetPublishedImage(fname string) (Picture, error) {
return getImage(GetPublishedImages, fname)
}
func GetNextImage(fname string) (Picture, error) {
return getImage(GetNextImages, fname)
}
func UniqueImage(filename string) bool {
if pict, _ := GetPublishedImage(filename); pict.path != "" {
return false
} else {
if pict, _ := GetNextImage(filename); pict.path != "" {
return false
} else {
return true
}
}
}
func AddImage(filename string, blob io.ReadCloser) error {
// Check the name is not already used
if ok := UniqueImage(filename); !ok {
return errors.New("This filename is already used, please choose another one.")
// Convert to JPEG
} else if img, _, err := image.Decode(base64.NewDecoder(base64.StdEncoding, blob)); err != nil {
return err
// Save file
} else if fw, err := os.Create(filepath.Join(NextImgDir, filename+".jpg")); err != nil {
return err
} else if err := jpeg.Encode(fw, img, nil); err != nil {
return err
} else {
fw.Close()
thumb := resize.Thumbnail(300, 185, img, resize.Lanczos3)
// Save thumbnail
if fw, err := os.Create(filepath.Join(ThumbsDir, filename+".jpg")); err != nil {
return err
} else if err := jpeg.Encode(fw, thumb, nil); err != nil {
return err
} else {
fw.Close()
}
}
return nil
}
func (p Picture) Publish() error {
npath := filepath.Join(PublishedImgDir, p.basename)
if err := os.Rename(p.path, npath); err != nil {
return err
} else if err := os.Chtimes(npath, time.Now(), time.Now()); err != nil {
return err
} else {
return nil
}
}
func (p Picture) Unpublish() error {
if err := os.Rename(p.path, filepath.Join(NextImgDir, p.basename)); err != nil {
return err
} else {
return nil
}
}
func (p Picture) Remove() error {
if err := os.Remove(p.path); err != nil {
return err
} else {
return nil
}
}