Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
@ -1,44 +1,344 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsVideoFile(t *testing.T) {
|
||||
assert.Equal(t, isVideoFile("test.txt"), false, "false positive")
|
||||
assert.Equal(t, isVideoFile(""), false, "false positive")
|
||||
assert.Equal(t, isVideoFile("test.mp4"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.mov"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.3gp"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.avi"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.mts"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.m4v"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.mpg"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.MP4"), true, "false negative")
|
||||
}
|
||||
|
||||
func TestIsImageFile(t *testing.T) {
|
||||
assert.Equal(t, isImageFile("test.txt"), false, "false positive")
|
||||
assert.Equal(t, isImageFile(""), false, "false positive")
|
||||
assert.Equal(t, isImageFile("test.jpg"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.JPG"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.jpeg"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.heic"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.png"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.tif"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.tiff"), true, "false negative")
|
||||
}
|
||||
|
||||
func TestIsMediaFile(t *testing.T) {
|
||||
assert.Equal(t, isMediaFile("test.txt"), false, "false positive")
|
||||
assert.Equal(t, isMediaFile("test.jpg"), true, "false negative")
|
||||
assert.Equal(t, isMediaFile("test.mp4"), true, "false negative")
|
||||
var exitCount = 0
|
||||
|
||||
func testExit(ret int) {
|
||||
exitCount = exitCount + 1
|
||||
return
|
||||
}
|
||||
func TestValidateSourceAndGallery(t *testing.T) {
|
||||
originalExit := exit
|
||||
defer func() { exit = originalExit }()
|
||||
exit = testExit
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
exitCountBefore := exitCount
|
||||
_, _ = validateSourceAndGallery(tempDir+"/nonexistent", tempDir+"/gallery")
|
||||
assert.EqualValues(t, exitCountBefore+1, exitCount, "validateArgs did not exit")
|
||||
|
||||
exitCountBefore = exitCount
|
||||
_, _ = validateSourceAndGallery(tempDir, tempDir+"/gallery/nonexistent")
|
||||
assert.EqualValues(t, exitCountBefore+1, exitCount, "validateArgs did not exit")
|
||||
|
||||
exitCountBefore = exitCount
|
||||
_, _ = validateSourceAndGallery(tempDir, tempDir+"/gallery")
|
||||
assert.EqualValues(t, exitCountBefore, exitCount, "validateArgs did not exit")
|
||||
}
|
||||
|
||||
func TestIsDirectory(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
err = os.Mkdir(tempDir+"/subdir", 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create subdirectory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/subdir")
|
||||
assert.True(t, isDirectory(tempDir+"/subdir"))
|
||||
|
||||
err = os.Symlink(tempDir+"/subdir", tempDir+"/symlink")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/symlink")
|
||||
assert.True(t, isDirectory(tempDir+"/symlink"))
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/file")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/file")
|
||||
assert.False(t, isDirectory(tempDir+"/file"))
|
||||
|
||||
assert.False(t, isDirectory(tempDir+"/nonexistent"))
|
||||
}
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/file")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/file")
|
||||
assert.True(t, exists(tempDir+"/file"))
|
||||
|
||||
assert.False(t, exists(tempDir+"/nonexistent"))
|
||||
}
|
||||
|
||||
func TestDirHasMediaFiles(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/file.raw")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/file.raw")
|
||||
|
||||
assert.True(t, dirHasMediafiles(tempDir))
|
||||
}
|
||||
|
||||
func TestDirHasMediaFilesFailing(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/file.txt")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/file.txt")
|
||||
|
||||
assert.False(t, dirHasMediafiles(tempDir))
|
||||
}
|
||||
|
||||
func TestDirHasMediaFilesRecurse(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
err = os.Mkdir(tempDir+"/subdir", 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create subdirectory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/subdir")
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/subdir/file.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/subdir/file.jpg")
|
||||
|
||||
assert.True(t, dirHasMediafiles(tempDir))
|
||||
}
|
||||
|
||||
func TestDirHasMediaFilesRecurseFailing(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
err = os.Mkdir(tempDir+"/subdir", 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create subdirectory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/subdir")
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/subdir/file.txt")
|
||||
if err != nil {
|
||||
t.Error("couldn't create symlink")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/subdir/file.txt")
|
||||
|
||||
assert.False(t, dirHasMediafiles(tempDir))
|
||||
}
|
||||
|
||||
func TestIsXxxFile(t *testing.T) {
|
||||
assert.True(t, isVideoFile("test.mp4"))
|
||||
assert.False(t, isVideoFile("test.jpg"))
|
||||
assert.False(t, isVideoFile("test.txt"))
|
||||
assert.True(t, isImageFile("test.jpg"))
|
||||
assert.False(t, isImageFile("test.mp4"))
|
||||
assert.False(t, isImageFile("test.txt"))
|
||||
assert.True(t, isMediaFile("test.mp4"))
|
||||
assert.True(t, isMediaFile("test.jpg"))
|
||||
assert.False(t, isMediaFile("test.txt"))
|
||||
}
|
||||
|
||||
func TestCopyRootAssets(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
var tempGallery directory
|
||||
tempGallery.absPath = tempDir
|
||||
|
||||
config := initializeConfig()
|
||||
|
||||
copyRootAssets(tempGallery, false, config)
|
||||
|
||||
assert.FileExists(t, tempDir+"/back.png")
|
||||
assert.FileExists(t, tempDir+"/folder.png")
|
||||
assert.FileExists(t, tempDir+"/fastgallery.css")
|
||||
assert.FileExists(t, tempDir+"/fastgallery.js")
|
||||
assert.FileExists(t, tempDir+"/feather.min.js")
|
||||
assert.FileExists(t, tempDir+"/primer.css")
|
||||
}
|
||||
|
||||
func TestStripExtension(t *testing.T) {
|
||||
assert.Equal(t, stripExtension("../tmp/filename.txt"), "../tmp/filename", "mismatch")
|
||||
assert.Equal(t, stripExtension("/tmp/filename.txt"), "/tmp/filename", "mismatch")
|
||||
assert.Equal(t, stripExtension("filename.txt"), "filename", "mismatch")
|
||||
assert.Equal(t, "file", stripExtension("file.jpg"))
|
||||
assert.NotEqual(t, "file", stripExtension("file/"))
|
||||
}
|
||||
|
||||
func TestReservedDirectory(t *testing.T) {
|
||||
myConfig := initializeConfig()
|
||||
|
||||
assert.True(t, reservedDirectory(myConfig.files.thumbnailDir, myConfig))
|
||||
assert.True(t, reservedDirectory(myConfig.files.fullsizeDir, myConfig))
|
||||
assert.True(t, reservedDirectory(myConfig.files.originalDir, myConfig))
|
||||
assert.False(t, reservedDirectory("diipadaapa", myConfig))
|
||||
}
|
||||
|
||||
func TestCreateDirectory(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
myConfig := initializeConfig()
|
||||
|
||||
createDirectory(tempDir+"/xyz", true, myConfig.files.directoryMode)
|
||||
assert.NoDirExists(t, tempDir+"/xyz")
|
||||
|
||||
createDirectory(tempDir+"/xyz", false, myConfig.files.directoryMode)
|
||||
assert.DirExists(t, tempDir+"/xyz")
|
||||
os.RemoveAll(tempDir + "/xyz")
|
||||
}
|
||||
|
||||
func TestCreateDirectoryTree(t *testing.T) {
|
||||
myConfig := initializeConfig()
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "fastgallery-test-")
|
||||
if err != nil {
|
||||
t.Error("couldn't create temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Create source directory with two files, a subdir with third file
|
||||
err = os.Mkdir(tempDir+"/source", 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create source subdirectory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/source")
|
||||
|
||||
emptyFile, err := os.Create(tempDir + "/source/file.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create file")
|
||||
}
|
||||
defer emptyFile.Close()
|
||||
defer os.RemoveAll(tempDir + "/source/file.jpg")
|
||||
|
||||
emptyFile2, err := os.Create(tempDir + "/source/file2.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create file2")
|
||||
}
|
||||
defer emptyFile2.Close()
|
||||
defer os.RemoveAll(tempDir + "/source/file2.jpg")
|
||||
|
||||
err = os.Mkdir(tempDir+"/source/subdir", 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create source subdirectory's subdirectory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/source/subdir")
|
||||
|
||||
emptyFile3, err := os.Create(tempDir + "/source/subdir/file.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create file in subdir")
|
||||
}
|
||||
defer emptyFile3.Close()
|
||||
defer os.RemoveAll(tempDir + "/source/subdir/file.jpg")
|
||||
|
||||
// Create gallery subdirectory with one matching file
|
||||
err = os.Mkdir(tempDir+"/gallery", 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create gallery subdirectory")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/gallery")
|
||||
|
||||
err = os.Mkdir(tempDir+"/gallery/"+myConfig.files.fullsizeDir, 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create gallery subdirectory for fullsize")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/gallery/" + myConfig.files.fullsizeDir)
|
||||
|
||||
err = os.Mkdir(tempDir+"/gallery/"+myConfig.files.thumbnailDir, 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create gallery subdirectory for thumbnail")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/gallery/" + myConfig.files.thumbnailDir)
|
||||
|
||||
err = os.Mkdir(tempDir+"/gallery/"+myConfig.files.originalDir, 0755)
|
||||
if err != nil {
|
||||
t.Error("couldn't create gallery subdirectory for original")
|
||||
}
|
||||
defer os.RemoveAll(tempDir + "/gallery/" + myConfig.files.originalDir)
|
||||
|
||||
emptyFile4, err := os.Create(tempDir + "/gallery/" + myConfig.files.originalDir + "/file.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create original gallery file")
|
||||
}
|
||||
defer emptyFile4.Close()
|
||||
defer os.RemoveAll(tempDir + "/gallery/" + myConfig.files.originalDir + "/file.jpg")
|
||||
|
||||
emptyFile5, err := os.Create(tempDir + "/gallery/" + myConfig.files.thumbnailDir + "/file.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create original gallery file")
|
||||
}
|
||||
defer emptyFile5.Close()
|
||||
defer os.RemoveAll(tempDir + "/gallery/" + myConfig.files.thumbnailDir + "/file.jpg")
|
||||
|
||||
// Ensure thumbnail file is newer than source file
|
||||
err = os.Chtimes(tempDir+"/gallery/"+myConfig.files.thumbnailDir+"/file.jpg", time.Now(), time.Now())
|
||||
if err != nil {
|
||||
t.Error("couldn't change mtime/atime")
|
||||
}
|
||||
|
||||
emptyFile6, err := os.Create(tempDir + "/gallery/" + myConfig.files.fullsizeDir + "/file.jpg")
|
||||
if err != nil {
|
||||
t.Error("couldn't create original gallery file")
|
||||
}
|
||||
defer emptyFile6.Close()
|
||||
defer os.RemoveAll(tempDir + "/gallery/" + myConfig.files.fullsizeDir + "/file.jpg")
|
||||
|
||||
source := createDirectoryTree(tempDir+"/source", "")
|
||||
gallery := createDirectoryTree(tempDir+"/gallery", "")
|
||||
|
||||
compareDirectoryTrees(&source, &gallery, myConfig)
|
||||
|
||||
changes := countChanges(source)
|
||||
|
||||
assert.EqualValues(t, 2, changes)
|
||||
}
|
||||
|
||||
// TODO tests for
|
||||
// createGallery
|
||||
// - exists, doesn't exist, some gallery files exist / some don't
|
||||
// - thumbnail modified earlier than original or vice versa
|
||||
|
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsVideoFile(t *testing.T) {
|
||||
assert.Equal(t, isVideoFile("test.txt"), false, "false positive")
|
||||
assert.Equal(t, isVideoFile(""), false, "false positive")
|
||||
assert.Equal(t, isVideoFile("test.mp4"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.mov"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.3gp"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.avi"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.mts"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.m4v"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.mpg"), true, "false negative")
|
||||
assert.Equal(t, isVideoFile("test.MP4"), true, "false negative")
|
||||
}
|
||||
|
||||
func TestIsImageFile(t *testing.T) {
|
||||
assert.Equal(t, isImageFile("test.txt"), false, "false positive")
|
||||
assert.Equal(t, isImageFile(""), false, "false positive")
|
||||
assert.Equal(t, isImageFile("test.jpg"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.JPG"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.jpeg"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.heic"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.png"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.tif"), true, "false negative")
|
||||
assert.Equal(t, isImageFile("test.tiff"), true, "false negative")
|
||||
}
|
||||
|
||||
func TestIsMediaFile(t *testing.T) {
|
||||
assert.Equal(t, isMediaFile("test.txt"), false, "false positive")
|
||||
assert.Equal(t, isMediaFile("test.jpg"), true, "false negative")
|
||||
assert.Equal(t, isMediaFile("test.mp4"), true, "false negative")
|
||||
}
|
||||
|
||||
func TestStripExtension(t *testing.T) {
|
||||
assert.Equal(t, stripExtension("../tmp/filename.txt"), "../tmp/filename", "mismatch")
|
||||
assert.Equal(t, stripExtension("/tmp/filename.txt"), "/tmp/filename", "mismatch")
|
||||
assert.Equal(t, stripExtension("filename.txt"), "filename", "mismatch")
|
||||
}
|
@ -1,14 +1,19 @@
|
||||
module github.com/tonimelisma/fastgallery
|
||||
module fastgallery
|
||||
|
||||
go 1.15
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/cheggaaa/pb/v3 v3.0.5
|
||||
github.com/davidbyttow/govips/v2 v2.2.0
|
||||
github.com/alexflint/go-arg v1.3.0
|
||||
github.com/cheggaaa/pb/v3 v3.0.6
|
||||
github.com/davidbyttow/govips/v2 v2.5.0
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
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-20201208152932-35266b937fa6 // indirect
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 // indirect
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb // indirect
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
|
||||
golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||
)
|
||||
|
@ -1,67 +1,72 @@
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
|
||||
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
|
||||
github.com/alexflint/go-arg v1.3.0 h1:UfldqSdFWeLtoOuVRosqofU4nmhI1pYEbT4ZFS34Bdo=
|
||||
github.com/alexflint/go-arg v1.3.0/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM=
|
||||
github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70=
|
||||
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
|
||||
github.com/cheggaaa/pb/v3 v3.0.6 h1:ULPm1wpzvj60FvmCrX7bIaB80UgbhI+zSaQJKRfCbAs=
|
||||
github.com/cheggaaa/pb/v3 v3.0.6/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davidbyttow/govips/v2 v2.2.0 h1:O21ykVQNJ7LYxpa7yG6TN2g2VF/WonOksljCD2jQK4o=
|
||||
github.com/davidbyttow/govips/v2 v2.2.0/go.mod h1:goq38QD8XEMz2aWEeucEZqRxAWsemIN40vbUqfPfTAw=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/davidbyttow/govips/v2 v2.5.0 h1:CLSVkXwZYfF7bOR5bZwlUFL1TIWXwyuNF33UrlKscM4=
|
||||
github.com/davidbyttow/govips/v2 v2.5.0/go.mod h1:goq38QD8XEMz2aWEeucEZqRxAWsemIN40vbUqfPfTAw=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/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 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/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=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d h1:9fH9JvLNoSpsDWcXJ4dSE3lZW99Z3OCUZLr07g60U6o=
|
||||
golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d/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=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -0,0 +1 @@
|
||||
/home/toni/sdk/go1.16/bin/go run cmd/fastgallery/main.go /home/toni/gallerytest/temp1/ /tmp/gallerytest
|
After Width: | Height: | Size: 300 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 187 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 314 KiB |
After Width: | Height: | Size: 178 KiB |
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/2020-05-22 16.41.02.heic
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/2021-01-01 17.11.35.heic
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/2021-01-02 23.51.34.mp4
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/2021-02-22 15.36.43-1.heic
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/2021-02-25 15.40.44.png
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/_DSC9363_DxO.jpg
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/_DSC9439.jpg
|
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 20 KiB |
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
|
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1,171 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>source</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="fastgallery.css" rel="stylesheet">
|
||||
|
||||
<link href="primer.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-gray">
|
||||
<div id="thumbnails">
|
||||
<h1 class="px-2 pb-2 my-0 m-md-3 m-lg-4">source</h1>
|
||||
|
||||
<!-- Thumbnail view. First subfolders. -->
|
||||
<div class="container-xl m-0 m-md-2 m-lg-3">
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<a href="subdir">
|
||||
<img class="box border border-gray box-shadow width-fit" src="folder.png" alt="subdir">
|
||||
</a>
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">subdir</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2020-05-22 16.41.02.jpg" alt="2020-05-22 16.41.02.heic" onclick="changePicture(0);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2020-05-22 16.41.02.heic</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-01-01 17.11.35.jpg" alt="2021-01-01 17.11.35.heic" onclick="changePicture(1);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-01-01 17.11.35.heic</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-01-02 23.51.34.jpg" alt="2021-01-02 23.51.34.mp4" onclick="changePicture(2);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-01-02 23.51.34.mp4</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-02-22 15.36.43-1.jpg" alt="2021-02-22 15.36.43-1.heic" onclick="changePicture(3);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-02-22 15.36.43-1.heic</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-02-25 15.40.44.jpg" alt="2021-02-25 15.40.44.png" onclick="changePicture(4);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-02-25 15.40.44.png</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/_DSC9363_DxO.jpg" alt="_DSC9363_DxO.jpg" onclick="changePicture(5);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">_DSC9363_DxO.jpg</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/_DSC9439.jpg" alt="_DSC9439.jpg" onclick="changePicture(6);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">_DSC9439.jpg</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal which shows individual pictures full-screen.
|
||||
Covers thumbnail view. Hidden by default, unless URL contains
|
||||
hashtag and thumbnail name. -->
|
||||
<div class="position-fixed top-0 left-0 width-full height-full d-flex flex-column flex-justify-center flex-items-center box border border-gray box-shadow bg-gray" id="modal" hidden>
|
||||
<div class="bg-gray clearfix position-absolute top-0 p-1" id="modalHeader">
|
||||
<div class="float-right modalControl float-left" onclick="displayModal(false);">
|
||||
<i data-feather="x"></i>
|
||||
</div>
|
||||
<div class="float-right modalControl float-left">
|
||||
<a href="#" id="modalDownload" download>
|
||||
<i data-feather="download"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modalMedia" class="d-flex flex-justify-center"></div>
|
||||
<div class="bg-gray position-absolute bottom-0 d-flex flex-justify-center p-1" id="modalFooter">
|
||||
<div class="float-left modalControl float-left" onclick="prevPicture();">
|
||||
<i data-feather="chevron-left"></i>
|
||||
</div>
|
||||
<div class="mx-auto float-left width-fit css-truncate css-truncate-target" id="modalDescription"></div>
|
||||
<div class="float-right modalControl float-left" onclick="nextPicture();">
|
||||
<i data-feather="chevron-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statically generated javascript array of pictures on this page -->
|
||||
<script>
|
||||
const pictures = [
|
||||
|
||||
|
||||
{
|
||||
thumbnail: "_thumbnail/2020-05-22 16.41.02.jpg",
|
||||
fullsize: "_fullsize/2020-05-22 16.41.02.jpg",
|
||||
original: "_original/2020-05-22 16.41.02.heic",
|
||||
filename: "2020-05-22 16.41.02.heic"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-01-01 17.11.35.jpg",
|
||||
fullsize: "_fullsize/2021-01-01 17.11.35.jpg",
|
||||
original: "_original/2021-01-01 17.11.35.heic",
|
||||
filename: "2021-01-01 17.11.35.heic"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-01-02 23.51.34.jpg",
|
||||
fullsize: "_fullsize/2021-01-02 23.51.34.mp4",
|
||||
original: "_original/2021-01-02 23.51.34.mp4",
|
||||
filename: "2021-01-02 23.51.34.mp4"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-02-22 15.36.43-1.jpg",
|
||||
fullsize: "_fullsize/2021-02-22 15.36.43-1.jpg",
|
||||
original: "_original/2021-02-22 15.36.43-1.heic",
|
||||
filename: "2021-02-22 15.36.43-1.heic"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-02-25 15.40.44.jpg",
|
||||
fullsize: "_fullsize/2021-02-25 15.40.44.jpg",
|
||||
original: "_original/2021-02-25 15.40.44.png",
|
||||
filename: "2021-02-25 15.40.44.png"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/_DSC9363_DxO.jpg",
|
||||
fullsize: "_fullsize/_DSC9363_DxO.jpg",
|
||||
original: "_original/_DSC9363_DxO.jpg",
|
||||
filename: "_DSC9363_DxO.jpg"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/_DSC9439.jpg",
|
||||
fullsize: "_fullsize/_DSC9439.jpg",
|
||||
original: "_original/_DSC9439.jpg",
|
||||
filename: "_DSC9439.jpg"
|
||||
}
|
||||
|
||||
]
|
||||
</script>
|
||||
|
||||
<script src="fastgallery.js"></script>
|
||||
|
||||
<script src="feather.min.js"></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 416 KiB |
After Width: | Height: | Size: 354 KiB |
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/subdir/2021-01-13 18.19.20.heic
|
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/subdir/2021-02-04 13.46.20.heic
|
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>subdir</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="../fastgallery.css" rel="stylesheet">
|
||||
|
||||
<link href="../primer.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-gray">
|
||||
<div id="thumbnails">
|
||||
<h1 class="px-2 pb-2 my-0 m-md-3 m-lg-4">subdir</h1>
|
||||
|
||||
<!-- Thumbnail view. First subfolders. -->
|
||||
<div class="container-xl m-0 m-md-2 m-lg-3">
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<a href="../">
|
||||
<img class="box border border-gray box-shadow width-fit" src="../back.png" alt="Back">
|
||||
</a>
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">Back</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<a href="subsubdir">
|
||||
<img class="box border border-gray box-shadow width-fit" src="../folder.png" alt="subsubdir">
|
||||
</a>
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">subsubdir</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-01-13 18.19.20.jpg" alt="2021-01-13 18.19.20.heic" onclick="changePicture(0);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-01-13 18.19.20.heic</span>
|
||||
</div>
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-02-04 13.46.20.jpg" alt="2021-02-04 13.46.20.heic" onclick="changePicture(1);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-02-04 13.46.20.heic</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal which shows individual pictures full-screen.
|
||||
Covers thumbnail view. Hidden by default, unless URL contains
|
||||
hashtag and thumbnail name. -->
|
||||
<div class="position-fixed top-0 left-0 width-full height-full d-flex flex-column flex-justify-center flex-items-center box border border-gray box-shadow bg-gray" id="modal" hidden>
|
||||
<div class="bg-gray clearfix position-absolute top-0 p-1" id="modalHeader">
|
||||
<div class="float-right modalControl float-left" onclick="displayModal(false);">
|
||||
<i data-feather="x"></i>
|
||||
</div>
|
||||
<div class="float-right modalControl float-left">
|
||||
<a href="#" id="modalDownload" download>
|
||||
<i data-feather="download"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modalMedia" class="d-flex flex-justify-center"></div>
|
||||
<div class="bg-gray position-absolute bottom-0 d-flex flex-justify-center p-1" id="modalFooter">
|
||||
<div class="float-left modalControl float-left" onclick="prevPicture();">
|
||||
<i data-feather="chevron-left"></i>
|
||||
</div>
|
||||
<div class="mx-auto float-left width-fit css-truncate css-truncate-target" id="modalDescription"></div>
|
||||
<div class="float-right modalControl float-left" onclick="nextPicture();">
|
||||
<i data-feather="chevron-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statically generated javascript array of pictures on this page -->
|
||||
<script>
|
||||
const pictures = [
|
||||
|
||||
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-01-13 18.19.20.jpg",
|
||||
fullsize: "_fullsize/2021-01-13 18.19.20.jpg",
|
||||
original: "_original/2021-01-13 18.19.20.heic",
|
||||
filename: "2021-01-13 18.19.20.heic"
|
||||
}
|
||||
|
||||
,
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-02-04 13.46.20.jpg",
|
||||
fullsize: "_fullsize/2021-02-04 13.46.20.jpg",
|
||||
original: "_original/2021-02-04 13.46.20.heic",
|
||||
filename: "2021-02-04 13.46.20.heic"
|
||||
}
|
||||
|
||||
]
|
||||
</script>
|
||||
|
||||
<script src="../fastgallery.js"></script>
|
||||
|
||||
<script src="../feather.min.js"></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 207 KiB |
@ -0,0 +1 @@
|
||||
/home/toni/go/src/github.com/tonimelisma/fastgallery/testing/source/subdir/subsubdir/2021-02-17 18.59.30.heic
|
After Width: | Height: | Size: 20 KiB |
@ -0,0 +1,93 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>subsubdir</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="../../fastgallery.css" rel="stylesheet">
|
||||
|
||||
<link href="../../primer.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-gray">
|
||||
<div id="thumbnails">
|
||||
<h1 class="px-2 pb-2 my-0 m-md-3 m-lg-4">subsubdir</h1>
|
||||
|
||||
<!-- Thumbnail view. First subfolders. -->
|
||||
<div class="container-xl m-0 m-md-2 m-lg-3">
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<a href="../">
|
||||
<img class="box border border-gray box-shadow width-fit" src="../../back.png" alt="Back">
|
||||
</a>
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">Back</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="col-4 col-md-3 col-lg-2 float-left p-md-2 p-lg-3">
|
||||
<img class="box border border-gray box-shadow width-fit" src="_thumbnail/2021-02-17 18.59.30.jpg" alt="2021-02-17 18.59.30.heic" onclick="changePicture(0);displayModal(true);">
|
||||
<span class="px-2 pb-2 width-fit css-truncate css-truncate-target">2021-02-17 18.59.30.heic</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal which shows individual pictures full-screen.
|
||||
Covers thumbnail view. Hidden by default, unless URL contains
|
||||
hashtag and thumbnail name. -->
|
||||
<div class="position-fixed top-0 left-0 width-full height-full d-flex flex-column flex-justify-center flex-items-center box border border-gray box-shadow bg-gray" id="modal" hidden>
|
||||
<div class="bg-gray clearfix position-absolute top-0 p-1" id="modalHeader">
|
||||
<div class="float-right modalControl float-left" onclick="displayModal(false);">
|
||||
<i data-feather="x"></i>
|
||||
</div>
|
||||
<div class="float-right modalControl float-left">
|
||||
<a href="#" id="modalDownload" download>
|
||||
<i data-feather="download"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modalMedia" class="d-flex flex-justify-center"></div>
|
||||
<div class="bg-gray position-absolute bottom-0 d-flex flex-justify-center p-1" id="modalFooter">
|
||||
<div class="float-left modalControl float-left" onclick="prevPicture();">
|
||||
<i data-feather="chevron-left"></i>
|
||||
</div>
|
||||
<div class="mx-auto float-left width-fit css-truncate css-truncate-target" id="modalDescription"></div>
|
||||
<div class="float-right modalControl float-left" onclick="nextPicture();">
|
||||
<i data-feather="chevron-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statically generated javascript array of pictures on this page -->
|
||||
<script>
|
||||
const pictures = [
|
||||
|
||||
|
||||
{
|
||||
thumbnail: "_thumbnail/2021-02-17 18.59.30.jpg",
|
||||
fullsize: "_fullsize/2021-02-17 18.59.30.jpg",
|
||||
original: "_original/2021-02-17 18.59.30.heic",
|
||||
filename: "2021-02-17 18.59.30.heic"
|
||||
}
|
||||
|
||||
]
|
||||
</script>
|
||||
|
||||
<script src="../../fastgallery.js"></script>
|
||||
|
||||
<script src="../../feather.min.js"></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 721 KiB |
After Width: | Height: | Size: 3.0 MiB |
After Width: | Height: | Size: 2.2 MiB |