package main import ( "errors" "io" "io/ioutil" "image" _ "image/gif" "image/jpeg" _ "image/png" "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(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 } }