Testing data + transformation functionality

pull/3/head
Toni Melisma 3 years ago
parent 5a3fd3b21c
commit 77209b2203
No known key found for this signature in database
GPG Key ID: FFF9A7EDDEA34756

@ -2,16 +2,19 @@ package main
import (
"embed"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/cheggaaa/pb/v3"
"github.com/davidbyttow/govips/v2/vips"
"github.com/kr/pretty"
"github.com/alexflint/go-arg"
)
@ -142,16 +145,19 @@ func validateSourceAndGallery(source string, gallery string) (string, string) {
source, err = filepath.Abs(source)
if err != nil {
log.Fatal("error:", err.Error())
log.Println("error:", err.Error())
exit(1)
}
if !isDirectory(source) {
log.Fatal("Source directory doesn't exist:", source)
log.Println("Source directory doesn't exist:", source)
exit(1)
}
gallery, err = filepath.Abs(gallery)
if err != nil {
log.Fatal("error:", err.Error())
log.Println("error:", err.Error())
exit(1)
}
if !isDirectory(gallery) {
@ -159,11 +165,13 @@ func validateSourceAndGallery(source string, gallery string) (string, string) {
// and we're supposed to create gallery there during runtime
galleryParent, err := filepath.Abs(gallery + "/../")
if err != nil {
log.Fatal("error:", err.Error())
log.Println("error:", err.Error())
exit(1)
}
if !isDirectory(galleryParent) {
log.Fatal("Neither gallery directory or it's parent directory exist:", gallery)
log.Println("Neither gallery directory or it's parent directory exist:", gallery)
exit(1)
}
}
@ -260,7 +268,8 @@ func createDirectoryTree(absoluteDirectory string, parentDirectory string) (tree
// List directory contents
list, err := os.ReadDir(absoluteDirectory)
if err != nil {
log.Fatal("Couldn't list directory contents:", absoluteDirectory)
log.Println("Couldn't list directory contents:", absoluteDirectory)
exit(1)
}
// If it's a directory and it has media files somewhere, add it to directories
@ -276,7 +285,8 @@ func createDirectoryTree(absoluteDirectory string, parentDirectory string) (tree
} else if isMediaFile(entryAbsPath) {
entryFileInfo, err := entry.Info()
if err != nil {
log.Fatal("Couldn't stat file information for media file:", entry.Name())
log.Println("Couldn't stat file information for media file:", entry.Name())
exit(1)
}
entryFile := file{
name: entry.Name(),
@ -440,14 +450,26 @@ func createDirectory(destination string, dryRun bool, dirMode os.FileMode) {
} else {
err := os.Mkdir(destination, dirMode)
if err != nil {
log.Fatal("couldn't create directory", destination, err.Error())
log.Println("couldn't create directory", destination, err.Error())
exit(1)
}
}
}
}
func symlinkFile(sourceDir string, destDir string, filename string, dryRun bool) {
// TODO functionality
func symlinkFile(source string, destination string) {
if _, err := os.Stat(destination); err == nil {
err := os.Remove(destination)
if err != nil {
log.Println("couldn't remove symlink:", source, destination)
return
}
}
err := os.Symlink(source, destination)
if err != nil {
log.Println("couldn't symlink:", source, destination)
return
}
}
// TODO deprecate copyFile() function or use for originals
@ -460,24 +482,28 @@ func copyFile(sourceDir string, destDir string, filename string, dryRun bool) {
} else {
_, err := os.Stat(sourceFilename)
if err != nil {
log.Fatal("couldn't copy source file:", sourceFilename, err.Error())
log.Println("couldn't copy source file:", sourceFilename, err.Error())
exit(1)
}
sourceHandle, err := os.Open(sourceFilename)
if err != nil {
log.Fatal("couldn't open source file for copy:", sourceFilename, err.Error())
log.Println("couldn't open source file for copy:", sourceFilename, err.Error())
exit(1)
}
defer sourceHandle.Close()
destHandle, err := os.Create(destFilename)
if err != nil {
log.Fatal("couldn't create dest file:", destFilename, err.Error())
log.Println("couldn't create dest file:", destFilename, err.Error())
exit(1)
}
defer destHandle.Close()
_, err = io.Copy(destHandle, sourceHandle)
if err != nil {
log.Fatal("couldn't copy file:", sourceFilename, destFilename, err.Error())
log.Println("couldn't copy file:", sourceFilename, destFilename, err.Error())
exit(1)
}
}
}
@ -486,7 +512,8 @@ func copyFile(sourceDir string, destDir string, filename string, dryRun bool) {
func copyRootAssets(gallery directory, dryRun bool, fileMode os.FileMode) {
assetDirectoryListing, err := assets.ReadDir("assets")
if err != nil {
log.Fatal("couldn't open embedded assets:", err.Error())
log.Println("couldn't open embedded assets:", err.Error())
exit(1)
}
// Iterate through all the embedded assets
@ -500,11 +527,13 @@ func copyRootAssets(gallery directory, dryRun bool, fileMode os.FileMode) {
} else {
filebuffer, err := assets.ReadFile("assets/" + entry.Name())
if err != nil {
log.Fatal("couldn't open embedded asset:", entry.Name(), ":", err.Error())
log.Println("couldn't open embedded asset:", entry.Name(), ":", err.Error())
exit(1)
}
err = os.WriteFile(gallery.absPath+"/"+entry.Name(), filebuffer, fileMode)
if err != nil {
log.Fatal("couldn't write embedded asset:", gallery.absPath+"/"+entry.Name(), ":", err.Error())
log.Println("couldn't write embedded asset:", gallery.absPath+"/"+entry.Name(), ":", err.Error())
exit(1)
}
}
}
@ -517,11 +546,13 @@ func copyRootAssets(gallery directory, dryRun bool, fileMode os.FileMode) {
} else {
filebuffer, err := assets.ReadFile("assets/" + entry.Name())
if err != nil {
log.Fatal("couldn't open embedded asset:", entry.Name(), ":", err.Error())
log.Println("couldn't open embedded asset:", entry.Name(), ":", err.Error())
exit(1)
}
err = os.WriteFile(gallery.absPath+"/"+entry.Name(), filebuffer, fileMode)
if err != nil {
log.Fatal("couldn't write embedded asset:", gallery.absPath+"/"+entry.Name(), ":", err.Error())
log.Println("couldn't write embedded asset:", gallery.absPath+"/"+entry.Name(), ":", err.Error())
exit(1)
}
}
}
@ -543,25 +574,22 @@ func getGalleryDirectoryNames(galleryDirectory string, config configuration) (th
return
}
func createThumbnail(source string, destination string, config configuration) {
// TODO functionality
}
func createFullsize(source string, destination string, config configuration) {
// TODO functionality
func transformImage(source string, fullsizeDestination string, thumbnailDestination string, config configuration) {
if config.files.imageExtension == ".jpg" {
// First create full-size image
image, err := vips.NewImageFromFile(source)
if err != nil {
log.Println("couldn't open image:", source, err.Error())
log.Println("couldn't open full-size image:", source, err.Error())
return
}
err = image.AutoRotate()
if err != nil {
log.Println("couldn't autorotate image:", source, err.Error())
log.Println("couldn't autorotate full-size image:", source, err.Error())
return
}
// TODO document below
scale := float64(config.media.fullsizeMaxWidth) / float64(image.Width())
if (scale * float64(image.Height())) > float64(config.media.fullsizeMaxHeight) {
scale = float64(config.media.fullsizeMaxHeight) / float64(image.Height())
@ -569,29 +597,110 @@ func createFullsize(source string, destination string, config configuration) {
err = image.Resize(scale, vips.KernelAuto)
if err != nil {
log.Println("couldn't resize image:", source, err.Error())
log.Println("couldn't resize full-size image:", source, err.Error())
return
}
ep := vips.NewDefaultJPEGExportParams()
imageBytes, _, err := image.Export(ep)
fullsizeBuffer, _, err := image.Export(ep)
if err != nil {
log.Println("couldn't export full-size image:", source, err.Error())
return
}
err = os.WriteFile(fullsizeDestination, fullsizeBuffer, config.files.fileMode)
if err != nil {
log.Println("couldn't write full-size image:", fullsizeDestination, err.Error())
return
}
// After full-size image, create thumbnail
err = image.Thumbnail(config.media.thumbnailWidth, config.media.thumbnailHeight, vips.InterestingAttention)
if err != nil {
log.Println("couldn't export image:", source, destination, err.Error())
log.Println("couldn't crop thumbnail:", err.Error())
return
}
err = ioutil.WriteFile(destination, imageBytes, config.files.fileMode)
thumbnailBuffer, _, err := image.Export(ep)
if err != nil {
log.Println("couldn't write image:", destination, err.Error())
log.Println("couldn't export thumbnail image:", source, err.Error())
return
}
err = os.WriteFile(thumbnailDestination, thumbnailBuffer, config.files.fileMode)
if err != nil {
log.Println("couldn't write thumbnail image:", thumbnailDestination, err.Error())
return
}
} else {
log.Fatal("Can't figure out what format to convert full size image to:", destination)
log.Println("Can't figure out what format to convert full size image to:", source)
exit(1)
}
}
func createOriginal(source string, destination string, config configuration) {
// TODO functionality
func transformVideo(source string, fullsizeDestination string, thumbnailDestination string, config configuration) {
// Resize full-size video
ffmpegCommand := exec.Command("ffmpeg", "-y", "-i", source, "-pix_fmt", "yuv420p", "-vcodec", "libx264", "-acodec", "aac", "-movflags", "faststart", "-r", "24", "-vf", "scale='min("+strconv.Itoa(config.media.videoMaxSize)+",iw)':'min("+strconv.Itoa(config.media.videoMaxSize)+",ih)':force_original_aspect_ratio=decrease", "-crf", "28", "-loglevel", "fatal", fullsizeDestination)
// TODO capture stdout/err to bytes buffer instead
ffmpegCommand.Stdout = os.Stdout
ffmpegCommand.Stderr = os.Stderr
err := ffmpegCommand.Run()
if err != nil {
log.Println("Could not create full-size video transcode:", source)
return
}
// Create thumbnail image of video
ffmpegCommand2 := exec.Command("ffmpeg", "-y", "-i", source, "-ss", "00:00:00", "-vframes", "1", "-vf", fmt.Sprintf("scale=%d:%d:force_original_aspect_ratio=increase,crop=%d:%d", config.media.thumbnailWidth, config.media.thumbnailHeight, config.media.thumbnailWidth, config.media.thumbnailHeight), "-loglevel", "fatal", thumbnailDestination)
// TODO capture stdout/err to bytes buffer instead
ffmpegCommand2.Stdout = os.Stdout
ffmpegCommand2.Stderr = os.Stderr
err = ffmpegCommand2.Run()
if err != nil {
log.Println("Could not create thumbnail of video:", source)
return
}
// Take thumbnail and overlay triangle image on top of it
image, err := vips.NewImageFromFile(thumbnailDestination)
if err != nil {
log.Println("Could not open video thumbnail:", thumbnailDestination)
return
}
playbuttonOverlayBuffer, err := assets.ReadFile("assets/playbutton.png")
playbuttonOverlayImage, err := vips.NewImageFromBuffer(playbuttonOverlayBuffer)
if err != nil {
log.Println("Could not open play button overlay asset")
return
}
// Overlay play button in the middle of thumbnail picture
err = image.Composite(playbuttonOverlayImage, vips.BlendModeOver, (config.media.thumbnailWidth/2)-(playbuttonOverlayImage.Width()/2), (config.media.thumbnailHeight/2)-(playbuttonOverlayImage.Height()/2))
if err != nil {
log.Println("Could not composite play button overlay on top of:", thumbnailDestination)
return
}
ep := vips.NewDefaultJPEGExportParams()
imageBytes, _, err := image.Export(ep)
if err != nil {
log.Println("Could not export video thumnail:", thumbnailDestination)
return
}
err = os.WriteFile(thumbnailDestination, imageBytes, config.files.fileMode)
if err != nil {
log.Println("Could not write video thumnail:", thumbnailDestination)
return
}
}
func createOriginal(source string, destination string) {
// TODO add option to copy
symlinkFile(source, destination)
}
// createMedia takes the source directory, and creates a thumbnail, full-size
@ -607,25 +716,32 @@ func createMedia(source directory, gallerySubdirectory string, dryRun bool, conf
// TODO concurrency
for _, file := range source.files {
if !file.exists {
sourceFilepath := filepath.Join(source.absPath, file.name)
var destinationFilename string
thumbnailFilename := stripExtension(file.name) + config.files.imageExtension
var fullsizeFilename string
if isImageFile(file.name) {
destinationFilename = stripExtension(file.name) + config.files.imageExtension
fullsizeFilename = stripExtension(file.name) + config.files.imageExtension
} else if isVideoFile(file.name) {
destinationFilename = stripExtension(file.name) + config.files.videoExtension
fullsizeFilename = stripExtension(file.name) + config.files.videoExtension
} else {
log.Fatal("could not infer whether file is image or video:", sourceFilepath)
log.Println("could not infer whether file is image or video:", sourceFilepath)
exit(1)
}
thumbnailFilename := filepath.Join(thumbnailGalleryDirectory, destinationFilename)
fullsizeFilename := filepath.Join(fullsizeGalleryDirectory, destinationFilename)
originalFilename := filepath.Join(originalGalleryDirectory, destinationFilename)
thumbnailFilepath := filepath.Join(thumbnailGalleryDirectory, thumbnailFilename)
fullsizeFilepath := filepath.Join(fullsizeGalleryDirectory, fullsizeFilename)
originalFilepath := filepath.Join(originalGalleryDirectory, file.name)
if dryRun {
log.Println("converting:", sourceFilepath, thumbnailFilename, fullsizeFilename, originalFilename)
log.Println("Would convert:", sourceFilepath, thumbnailFilepath, fullsizeFilepath, originalFilepath)
} else {
createThumbnail(sourceFilepath, thumbnailFilename, config)
createFullsize(sourceFilepath, fullsizeFilename, config)
createOriginal(sourceFilepath, originalFilename, config)
if isImageFile(file.name) {
transformImage(sourceFilepath, fullsizeFilepath, thumbnailFilepath, config)
} else if isVideoFile(file.name) {
transformVideo(sourceFilepath, fullsizeFilepath, thumbnailFilepath, config)
} else {
log.Println("could not infer whether file is image or video(2):", sourceFilepath)
exit(1)
}
createOriginal(sourceFilepath, originalFilepath)
progressBar.Increment()
}
}
@ -667,8 +783,6 @@ func createGallery(depth int, source directory, gallery directory, dryRun bool,
}
for _, subdir := range source.subdirectories {
log.Println("recursing to:", subdir.name, subdir.relPath, subdir.absPath)
// Create respective source subdirectory also in gallery subdirectory
gallerySubdir := filepath.Join(gallery.absPath, subdir.relPath)
createDirectory(gallerySubdir, dryRun, config.files.directoryMode)
@ -746,9 +860,9 @@ func main() {
log.Println("Gallery already up to date!")
}
// log.Println("source:")
// pretty.Print(source)
log.Println("source:")
pretty.Print(source)
// log.Println("gallery:")
// pretty.Print(gallery)
log.Println("gallery:")
pretty.Print(gallery)
}

@ -12,9 +12,9 @@ require (
github.com/mattn/go-runewidth v0.0.10 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/stretchr/testify v1.6.1
golang.org/x/image v0.0.0-20210216034530-4410531fe030 // indirect
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/sys v0.0.0-20210219172841-57ea560cfca1 // indirect
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb // indirect
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 // indirect
golang.org/x/text v0.3.5 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)

@ -44,12 +44,12 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210216034530-4410531fe030 h1:lP9pYkih3DUSC641giIXa2XqfTIbbbRr0w2EOTA7wHA=
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -57,8 +57,8 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210219172841-57ea560cfca1 h1:mDSj8NPponP6fRpRDblAGl5bpSHjPulHtk5lGl0gLSY=
golang.org/x/sys v0.0.0-20210219172841-57ea560cfca1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

@ -0,0 +1 @@
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/2021-02-25 15.40.44.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

@ -0,0 +1,33 @@
.box {
cursor: pointer;
}
#modalMedia {
max-width: 100%;
max-height: calc(100% - 74px);
}
.modalImage {
object-fit: scale-down;
max-width: 100%;
}
video {
max-width: 100%;
max-height: 100%;
}
#modalDownload {
color: inherit;
}
#modalHeader,
#modalFooter {
height: 37px;
width: 360px;
}
.modalControl:hover,
.modalControl:focus {
background-color: rgba(0, 0, 0, 0.2);
}

@ -0,0 +1,150 @@
// check that the HTML page including us has set the pictures array
if (typeof pictures == 'undefined') {
throw new Error("pictures array not defined")
}
// Hard-coded configuration
const videoExtension = "mp4"
const videoMIMEType = "video/mp4"
// global variable maintains currently shown picture number (pictures[] array)
var currentPicture
// create hover effect shadow for all box elements
const hoverOnBox = (event) => {
event.target.classList.remove("box-shadow")
event.target.classList.remove("border-gray")
event.target.classList.add("box-shadow-large")
event.target.classList.add("border-gray-dark")
}
const hoverOffBox = (event) => {
event.target.classList.remove("border-gray-dark")
event.target.classList.remove("box-shadow-large")
event.target.classList.add("box-shadow")
event.target.classList.add("border-gray")
}
const registerBoxEventHandlers = (element) => {
element.addEventListener("mouseenter", hoverOnBox)
element.addEventListener("mouseleave", hoverOffBox)
}
var boxes = document.getElementsByClassName("box")
for (let box of boxes) {
registerBoxEventHandlers(box)
}
// create hover effect for modal navigation elements
// const hoverOnNav = (event) => {}
// logic to show and hide picture modal
const displayModal = (display) => {
if (display) {
document.getElementById("modal").hidden = false
document.getElementById("thumbnails").hidden = true
} else {
document.getElementById("thumbnails").hidden = false
document.getElementById("modal").hidden = true
document.getElementById("modalMedia").innerHTML = ""
window.location.hash = ""
}
}
// TODO add swipe support https://stackoverflow.com/questions/2264072/detect-a-finger-swipe-through-javascript-on-the-iphone-and-android
// modal previous and next picture button logic
const preload = (number) => {
var preloadLink = document.createElement("link")
preloadLink.rel = "prefetch"
preloadLink.href = encodeURI(pictures[number].fullsize)
const fileExtension = preloadLink.href.split("\.").pop()
if (fileExtension == videoExtension) {
preloadLink.as = "video"
} else {
preloadLink.as = "image"
}
document.head.appendChild(preloadLink)
}
const prevPicture = () => {
changePicture(getPrevPicture())
preload(getPrevPicture())
}
const getPrevPicture = () => {
if (!isNaN(currentPicture)) {
if (currentPicture === 0) {
return (pictures.length - 1)
} else if (currentPicture < 0 || currentPicture >= pictures.length) {
console.error("Invalid currentPicture, 0.." + pictures.length - 1 + ": " + currentPicture)
} else {
return (currentPicture - 1)
}
} else {
console.error("Invalid currentPicture, NaN: " + currentPicture)
}
}
const nextPicture = () => {
changePicture(getNextPicture())
preload(getNextPicture())
}
const getNextPicture = () => {
if (!isNaN(currentPicture)) {
if (currentPicture === pictures.length - 1) {
return (0)
} else if (currentPicture < 0 || currentPicture >= pictures.length) {
console.error("Invalid currentPicture, 0.." + pictures.length - 1 + ": " + currentPicture)
} else {
return (currentPicture + 1)
}
} else {
console.error("Invalid currentPicture, NaN: " + currentPicture)
}
}
// function to change picture in modal, used by hashNavigate, and next/prevPicture
const changePicture = (number) => {
thumbnailFilename = pictures[number].thumbnail
window.location.hash = pictures[number].filename
const fileExtension = pictures[number].fullsize.split("\.").pop()
if (fileExtension == videoExtension) {
document.getElementById("modalMedia").innerHTML = "<video controls><source src=\"" + encodeURI(pictures[number].fullsize) + "\" type=\"" + videoMIMEType + "\"></video>"
} else {
document.getElementById("modalMedia").innerHTML = "<img src=\"" + encodeURI(pictures[number].fullsize) + "\" alt=\"" + pictures[number].filename + "\" class=\"modalImage\">"
}
document.getElementById("modalDescription").innerHTML = pictures[number].filename
document.getElementById("modalDownload").href = pictures[number].original
currentPicture = number
}
// if URL links directly to thumbnail via hash link, open modal for that pic on page load
const hashNavigate = () => {
if (window.location.hash) {
const filename = decodeURI(window.location.hash.substring(1))
id = pictures.findIndex(item => item.filename == filename)
if (id != -1 && id >= 0 && id < pictures.length) {
changePicture(id)
displayModal(true)
} else {
displayModal(false)
console.error("Invalid thumbnail link provided after # in URI")
}
} else {
displayModal(false)
}
}
const checkKey = (event) => {
if (event.key === "ArrowLeft") {
prevPicture()
} else if (event.key === "ArrowRight") {
nextPicture()
} else if (event.key === "Escape") {
displayModal(false)
}
}
document.onkeydown = checkKey
window.onpopstate = hashNavigate

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 KiB

Loading…
Cancel
Save