Add gallery admin and video media support.

This updates gallery handling to support video playback with generated poster thumbnails, adds authenticated admin upload/delete flows, and improves dev/runtime behavior including reliable thumbnail generation and media-safe response handling.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-02 23:01:02 +12:00
parent 509e7ccb43
commit 45b31be9a7
22 changed files with 1002 additions and 217 deletions

View File

@@ -19,11 +19,12 @@ type Image struct {
URL string
ThumbURL string
HeroURL string
IsVideo bool
Date time.Time
Year int
}
// List returns JPEG images from dir and subfolders (newest first).
// List returns gallery JPEGs and videos from dir and subfolders (newest first).
// Skips generated thumbs/ and hero/ directories.
func List(dir string) ([]Image, error) {
var images []Image
@@ -37,7 +38,7 @@ func List(dir string) ([]Image, error) {
}
return nil
}
if !isJPEG(d.Name()) {
if !isGalleryMedia(d.Name()) {
return nil
}
@@ -53,6 +54,7 @@ func List(dir string) ([]Image, error) {
album := albumFromRel(rel)
cKey, cLabel := collectionFromRel(rel)
date, year := imageDate(path, d.Name())
video := isVideo(d.Name())
images = append(images, Image{
RelPath: rel,
Album: album,
@@ -62,6 +64,7 @@ func List(dir string) ([]Image, error) {
URL: "/images/" + URLPath(rel),
ThumbURL: derivativeURL(dir, thumbDirName, rel),
HeroURL: derivativeURL(dir, heroDirName, rel),
IsVideo: video,
Date: date,
Year: year,
})
@@ -158,8 +161,15 @@ func safeRelPath(rel string) bool {
}
func derivativeURL(imagesDir, subdir, rel string) string {
if _, err := os.Stat(filepath.Join(imagesDir, subdir, filepath.FromSlash(rel))); err == nil {
return "/images/" + subdir + "/" + URLPath(rel)
lookup := rel
if subdir == thumbDirName || subdir == heroDirName {
lookup = thumbLookupRel(rel)
}
if isVideo(filepath.Base(rel)) && subdir == heroDirName {
return ""
}
if _, err := os.Stat(filepath.Join(imagesDir, subdir, filepath.FromSlash(lookup))); err == nil {
return "/images/" + subdir + "/" + URLPath(lookup)
}
return ""
}