first commit again
This commit is contained in:
commit
f3c53283f8
383
!/index.html
Normal file
383
!/index.html
Normal file
|
@ -0,0 +1,383 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="../icon.png" rel="shortcut icon"/>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
color: rgb(224,220,220);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
line-height: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
div#bottom {
|
||||||
|
background-color: rgba(198, 192, 192, 0.6);
|
||||||
|
bottom: 0;
|
||||||
|
color: black;
|
||||||
|
height: auto;
|
||||||
|
left: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
padding: 8px 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: none; }
|
||||||
|
div#main {
|
||||||
|
/* background-color: rgb(112, 107, 107); */
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
background-position: 0 0, 16px 16px;
|
||||||
|
background-size: 32px 32px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: calc(60px - 1vw);
|
||||||
|
}
|
||||||
|
div#top_center {
|
||||||
|
background-color: rgb(104, 100, 100);
|
||||||
|
color: rgb(224,220,220);
|
||||||
|
height: calc(60px - 1vw);
|
||||||
|
left: 25%;
|
||||||
|
font-size: calc(36px - 1vw);
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 8px 32px;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
top: 0;
|
||||||
|
right: 25%;
|
||||||
|
}
|
||||||
|
div#top_left {
|
||||||
|
background-color: rgb(104, 100, 100);
|
||||||
|
color: rgb(224,220,220);
|
||||||
|
height: calc(60px - 1vw);
|
||||||
|
left: 0;
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 8px 32px;
|
||||||
|
position: absolute;
|
||||||
|
text-align: left;
|
||||||
|
top: 0;
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
div#top_right {
|
||||||
|
background-color: rgb(104, 100, 100);
|
||||||
|
color: rgb(224,220,220);
|
||||||
|
height: calc(60px - 1vw);
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 8px 32px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: right;
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
span:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
span:active {
|
||||||
|
color: rgb(178, 56, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.disabled {
|
||||||
|
cursor: default;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="top_left">
|
||||||
|
<span id="back">back</span>
|
||||||
|
</div>
|
||||||
|
<div id="top_center">
|
||||||
|
<span id="previous">previous</span> | <span id="play">play</span> | <span id="next">next</span>
|
||||||
|
</div>
|
||||||
|
<div id="top_right">
|
||||||
|
<span id="small">1080p</span> | <span id="large">original</span>
|
||||||
|
</div>
|
||||||
|
<div id="main"></div>
|
||||||
|
<div id="bottom">loading...</div>
|
||||||
|
</body>
|
||||||
|
<script type="text/javascript" src="../js/jquery-3.3.1.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../js/hammer.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var path
|
||||||
|
var current, previous, next
|
||||||
|
var img
|
||||||
|
var imageWidth, imageHeight, imageRatio
|
||||||
|
var timeout
|
||||||
|
var back = document.getElementById('back')
|
||||||
|
var previous = document.getElementById('previous')
|
||||||
|
var playPause = document.getElementById('play')
|
||||||
|
var next = document.getElementById('next')
|
||||||
|
var small = document.getElementById('small')
|
||||||
|
var large = document.getElementById('large')
|
||||||
|
var main = document.getElementById('main')
|
||||||
|
var bottom = document.getElementById('bottom')
|
||||||
|
var elements = {
|
||||||
|
27: back,
|
||||||
|
32: playPause,
|
||||||
|
37: previous,
|
||||||
|
39: next,
|
||||||
|
187: large,
|
||||||
|
189: small
|
||||||
|
}
|
||||||
|
var captions
|
||||||
|
$.getJSON("../js/captions.json", function(data) {
|
||||||
|
captions = data;
|
||||||
|
})
|
||||||
|
var hammertime = new Hammer(main)
|
||||||
|
hammertime.get('swipe').set({velocity: 3.0})
|
||||||
|
function hammerIt(elm) {
|
||||||
|
hammertime = new Hammer(elm, {});
|
||||||
|
hammertime.get('pinch').set({
|
||||||
|
enable: true
|
||||||
|
});
|
||||||
|
var posX = 0,
|
||||||
|
posY = 0,
|
||||||
|
scale = 1,
|
||||||
|
last_scale = 1,
|
||||||
|
last_posX = 0,
|
||||||
|
last_posY = 0,
|
||||||
|
max_pos_x = 0,
|
||||||
|
max_pos_y = 0,
|
||||||
|
transform = "",
|
||||||
|
el = elm;
|
||||||
|
|
||||||
|
hammertime.on('pan pinch panend pinchend', function(ev) {
|
||||||
|
|
||||||
|
//pan
|
||||||
|
if (scale != 1) {
|
||||||
|
posX = last_posX + ev.deltaX;
|
||||||
|
posY = last_posY + ev.deltaY;
|
||||||
|
max_pos_x = Math.ceil((scale - 1) * el.clientWidth / 2);
|
||||||
|
max_pos_y = Math.ceil((scale - 1) * el.clientHeight / 2);
|
||||||
|
if (posX > max_pos_x) {
|
||||||
|
posX = max_pos_x;
|
||||||
|
}
|
||||||
|
if (posX < -max_pos_x) {
|
||||||
|
posX = -max_pos_x;
|
||||||
|
}
|
||||||
|
if (posY > max_pos_y) {
|
||||||
|
posY = max_pos_y;
|
||||||
|
}
|
||||||
|
if (posY < -max_pos_y) {
|
||||||
|
posY = -max_pos_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//pinch
|
||||||
|
if (ev.type == "pinch") {
|
||||||
|
scale = Math.max(.999, Math.min(last_scale * (ev.scale), 4));
|
||||||
|
}
|
||||||
|
if(ev.type == "pinchend"){last_scale = scale;}
|
||||||
|
|
||||||
|
//panend
|
||||||
|
if(ev.type == "panend"){
|
||||||
|
last_posX = posX < max_pos_x ? posX : max_pos_x;
|
||||||
|
last_posY = posY < max_pos_y ? posY : max_pos_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale != 1) {
|
||||||
|
transform =
|
||||||
|
"translate3d(" + posX + "px," + posY + "px, 0) " +
|
||||||
|
"scale3d(" + scale + ", " + scale + ", 1)";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform) {
|
||||||
|
el.style.webkitTransform = transform;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get(url, callback) {
|
||||||
|
var request = new XMLHttpRequest()
|
||||||
|
request.open('GET', url, true)
|
||||||
|
request.onreadystatechange = function() {
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
if (request.status == 200) {
|
||||||
|
callback(request.responseText, null)
|
||||||
|
} else {
|
||||||
|
callback(null, {
|
||||||
|
code: request.status,
|
||||||
|
text: request.statusText
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.send()
|
||||||
|
}
|
||||||
|
function loadImage() {
|
||||||
|
if (!['small', 'large'].includes(localStorage['pix.size'])) {
|
||||||
|
localStorage['pix.size'] = 'small'
|
||||||
|
}
|
||||||
|
small.className = localStorage['pix.size'] == 'small'
|
||||||
|
? 'disabled' : ''
|
||||||
|
large.className = localStorage['pix.size'] == 'large'
|
||||||
|
? 'disabled' : ''
|
||||||
|
bottom.style.display = 'block'
|
||||||
|
img = document.createElement('img')
|
||||||
|
img.style.position = 'absolute'
|
||||||
|
img.onload = function() {
|
||||||
|
imageWidth = img.width
|
||||||
|
imageHeight = img.height
|
||||||
|
imageRatio = imageWidth / imageHeight
|
||||||
|
onResize()
|
||||||
|
document.title = path.split('/').pop().toUpperCase()
|
||||||
|
// uncomment below for no captions
|
||||||
|
// bottom.style.display = 'none'
|
||||||
|
main.innerHTML = ''
|
||||||
|
main.appendChild(img)
|
||||||
|
//var img_alt = captions[current.split('/').pop()]
|
||||||
|
var img_alt = captions[current.split('/').slice(-2).join('/')]
|
||||||
|
if (img_alt != "") {
|
||||||
|
img.setAttribute('alt', img_alt)
|
||||||
|
bottom.innerHTML = img_alt
|
||||||
|
} else {
|
||||||
|
bottom.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.setAttribute('src', '../' + (
|
||||||
|
localStorage['pix.size'] == 'small'
|
||||||
|
? current.replace('/', '/1080/') : current
|
||||||
|
))
|
||||||
|
hammerIt(img)
|
||||||
|
}
|
||||||
|
function mod(a, b) {
|
||||||
|
return (a % b + b) % b
|
||||||
|
}
|
||||||
|
function onHashchange() {
|
||||||
|
bottom.innerHTML = 'loading...'
|
||||||
|
current = null
|
||||||
|
previous = null
|
||||||
|
next = null
|
||||||
|
var hash = document.location.hash.slice(1)
|
||||||
|
if (!hash) return
|
||||||
|
var parts = hash.split('/')
|
||||||
|
var name = parts.pop().replace(/%20/g, ' ')
|
||||||
|
path = parts.join('/')
|
||||||
|
get('../' + path + '/index.html', function(html, error) {
|
||||||
|
if (error) return
|
||||||
|
var matches = html.match(/src="(.*?)"/g).map(function(match) {
|
||||||
|
return match.slice(5, -1).replace(/^256\//g, '')
|
||||||
|
})
|
||||||
|
var index = matches.indexOf(name)
|
||||||
|
if (index == -1) return
|
||||||
|
current = path + '/' + name
|
||||||
|
previous = path + '/' + matches[mod(index - 1, matches.length)]
|
||||||
|
next = path + '/' + matches[mod(index + 1, matches.length)]
|
||||||
|
loadImage()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function onKeydown(e) {
|
||||||
|
elements[e.keyCode] && elements[e.keyCode].onclick()
|
||||||
|
}
|
||||||
|
function onResize() {
|
||||||
|
var screenWidth = window.innerWidth
|
||||||
|
var screenHeight = window.innerHeight - 32
|
||||||
|
var screenRatio = screenWidth / screenHeight
|
||||||
|
var isSmaller = imageWidth < screenWidth
|
||||||
|
&& imageHeight < screenHeight
|
||||||
|
var isWider = imageRatio > screenRatio
|
||||||
|
img.style.width = (
|
||||||
|
isSmaller ? imageWidth
|
||||||
|
: isWider ? screenWidth
|
||||||
|
: screenHeight * imageRatio
|
||||||
|
) + 'px'
|
||||||
|
img.style.height = (
|
||||||
|
isSmaller ? imageHeight
|
||||||
|
: isWider ? screenWidth / imageRatio
|
||||||
|
: screenHeight
|
||||||
|
) + 'px'
|
||||||
|
img.style.left = (
|
||||||
|
isSmaller ? (screenWidth - imageWidth) / 2
|
||||||
|
: isWider ? 0
|
||||||
|
: (screenWidth - screenHeight * imageRatio) / 2
|
||||||
|
) + 'px'
|
||||||
|
img.style.top = (
|
||||||
|
isSmaller ? (screenHeight - imageHeight) / 2
|
||||||
|
: isWider ? (screenHeight - screenWidth / imageRatio) / 2
|
||||||
|
: 0
|
||||||
|
) + 'px'
|
||||||
|
}
|
||||||
|
function pause() {
|
||||||
|
timeout && clearTimeout(timeout)
|
||||||
|
timeout = null
|
||||||
|
}
|
||||||
|
function play() {
|
||||||
|
pause()
|
||||||
|
timeout = setTimeout(playing, 5000)
|
||||||
|
function playing() {
|
||||||
|
document.location.hash = next.replace(/ /g, '%20')
|
||||||
|
timeout = setTimeout(playing, 5000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
back.onclick = function() {
|
||||||
|
document.location = '../' + path
|
||||||
|
}
|
||||||
|
previous.onclick = function() {
|
||||||
|
document.location.hash = previous.replace(/ /g, '%20')
|
||||||
|
timeout && play()
|
||||||
|
}
|
||||||
|
playPause.onclick = function() {
|
||||||
|
if (playPause.innerHTML == 'play') {
|
||||||
|
playPause.innerHTML = 'pause'
|
||||||
|
play()
|
||||||
|
} else {
|
||||||
|
playPause.innerHTML = 'play'
|
||||||
|
pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.onclick = function() {
|
||||||
|
document.location.hash = next.replace(/ /g, '%20')
|
||||||
|
timeout && play()
|
||||||
|
}
|
||||||
|
small.onclick = function() {
|
||||||
|
localStorage['pix.size'] = 'small'
|
||||||
|
loadImage()
|
||||||
|
}
|
||||||
|
large.onclick = function() {
|
||||||
|
localStorage['pix.size'] = 'large'
|
||||||
|
loadImage()
|
||||||
|
}
|
||||||
|
hammertime.on("swiperight", function(ev) {
|
||||||
|
document.location.hash = previous.replace(/ /g, '%20')
|
||||||
|
timeout && play()
|
||||||
|
})
|
||||||
|
hammertime.on("swipeleft", function(ev) {
|
||||||
|
document.location.hash = next.replace(/ /g, '%20')
|
||||||
|
timeout && play()
|
||||||
|
})
|
||||||
|
hammertime.on("tap", function(ev) {
|
||||||
|
var screenWidth = window.innerWidth
|
||||||
|
var clickX = ev.center.x
|
||||||
|
console.log(screenWidth)
|
||||||
|
if (clickX > screenWidth/2) {
|
||||||
|
document.location.hash = next.replace(/ /g, '%20')
|
||||||
|
timeout && play()
|
||||||
|
} else {
|
||||||
|
document.location.hash = previous.replace(/ /g, '%20')
|
||||||
|
timeout && play()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
window.onhashchange = onHashchange
|
||||||
|
window.onkeydown = onKeydown
|
||||||
|
window.onresize = onResize
|
||||||
|
onHashchange()
|
||||||
|
</script>
|
||||||
|
</html>
|
30
README.md
Normal file
30
README.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Some changes to a minimal photo gallery (pix)
|
||||||
|
* works with jpg (ignores png/other)
|
||||||
|
|
||||||
|
+ tap for previous/next
|
||||||
|
+ photos can have user defined captions
|
||||||
|
+ album titles
|
||||||
|
|
||||||
|
_____
|
||||||
|
Create folders ("albums") here, copy images into these folders.
|
||||||
|
|
||||||
|
To generate images (1080, 256), create HTML, run
|
||||||
|
python3 pix.py
|
||||||
|
|
||||||
|
pix.py to be run again if edit album.html and index.html, change the CSS, enable/disable captions, etc. or if photos are added/delete/renamed.
|
||||||
|
____
|
||||||
|
Captions -> to create json template using album and file names, run
|
||||||
|
python3 write_captionsJSON.py
|
||||||
|
|
||||||
|
-> generates captions.json in js folder {album/image.ext: "enter-caption-here", ...}
|
||||||
|
-> open captions.json in txt editor to edit / enter captions
|
||||||
|
* write_CaptionsJSON.py can be run again in case files are added/deleted
|
||||||
|
____
|
||||||
|
The image viewer supports the following keyboard shortcuts:
|
||||||
|
|
||||||
|
Escape Back
|
||||||
|
Left Previous
|
||||||
|
Space Play/Pause
|
||||||
|
Right Next
|
||||||
|
Minus 1080p
|
||||||
|
Plus Original
|
97
album.html
Normal file
97
album.html
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{title}</title>
|
||||||
|
<link href="../icon.png" rel="shortcut icon"/>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
color: rgb(128, 128, 128);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: rgb(192, 192, 192);
|
||||||
|
color: white;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
letter-spacing: 1.5px;
|
||||||
|
line-height: 18px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
div#main {
|
||||||
|
background-color: rgb(162, 155, 152);
|
||||||
|
background-position: 0 0, 16px 16px;
|
||||||
|
background-size: 32px 32px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 96px;
|
||||||
|
}
|
||||||
|
div#main > div {
|
||||||
|
display: inline-block;
|
||||||
|
height: 128px;
|
||||||
|
margin: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: center;
|
||||||
|
width: 128px;
|
||||||
|
}
|
||||||
|
div#main > div:after {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
div#top {
|
||||||
|
background-color: rgb(104, 100, 100);
|
||||||
|
color: #cc4039;
|
||||||
|
height: 32px;
|
||||||
|
left: 0;
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
div#top > a {
|
||||||
|
color: rgb(224,220,220);
|
||||||
|
}
|
||||||
|
div#top_title {
|
||||||
|
background-color: rgba(153, 147, 144, 1);
|
||||||
|
color: black;
|
||||||
|
height: 32px;
|
||||||
|
left: 0;
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 8px 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 48px;
|
||||||
|
}
|
||||||
|
img.landscape {
|
||||||
|
height: 128px;
|
||||||
|
margin-left: -32px;
|
||||||
|
}
|
||||||
|
img.portrait {
|
||||||
|
width: 128px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="top">
|
||||||
|
<a href="../"><< all images</a>
|
||||||
|
</div>
|
||||||
|
<div id="top_title">
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
<div id="main">
|
||||||
|
<!--# You can edit this file, but only above this line. #-->
|
||||||
|
<!--# You can edit this file, but only below this line. #-->
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
72
index.html
Normal file
72
index.html
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Albums</title>
|
||||||
|
<link href="pix.png" rel="shortcut icon"/>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
/* color: rgb(128, 128, 128); */
|
||||||
|
color: rgb(196, 65, 50);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: rgb(215, 214, 214);
|
||||||
|
color: black;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
line-height: 18px;
|
||||||
|
/* text-transform: uppercase; */
|
||||||
|
}
|
||||||
|
div#main {
|
||||||
|
background-color: rgb(215, 214, 214);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 48px;
|
||||||
|
background-position: 0 0, 16px 16px;
|
||||||
|
background-size: 32px 32px;
|
||||||
|
}
|
||||||
|
div#top {
|
||||||
|
background-color: rgb(210, 207, 207);
|
||||||
|
color: #b23832;
|
||||||
|
height: 32px;
|
||||||
|
left: 0;
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 8px 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
div#top > a {
|
||||||
|
color: #b23832;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
color: rgb(192, 192, 192);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 32px;
|
||||||
|
padding: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="top">
|
||||||
|
<a href="../../"><< back</a>
|
||||||
|
</div>
|
||||||
|
<div id="main">
|
||||||
|
<!--# You can edit this file, but only above this line. #-->
|
||||||
|
<!--# You can edit this file, but only below this line. #-->
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
js/hammer.min.js
vendored
Normal file
7
js/hammer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
js/jquery-3.3.1.min.js
vendored
Normal file
2
js/jquery-3.3.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
104
pix.py
Normal file
104
pix.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import codecs
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from PIL import Image, ExifTags
|
||||||
|
'''
|
||||||
|
# You can edit the following line with login details
|
||||||
|
#REMOTE_PATH = 'user@server:path-to-galleryAlbums/'
|
||||||
|
if not REMOTE_PATH.endswith('/'):
|
||||||
|
REMOTE_PATH += '/'
|
||||||
|
'''
|
||||||
|
# Size of thumbnails
|
||||||
|
SIZE_THUMBNAIL = 256
|
||||||
|
# Size of low-resolution images
|
||||||
|
SIZE_SMALL = 1080
|
||||||
|
|
||||||
|
def create_directory(path):
|
||||||
|
dirname = os.path.dirname(path)
|
||||||
|
if not os.path.exists(dirname):
|
||||||
|
os.mkdir(dirname)
|
||||||
|
|
||||||
|
def write_html(source, target, html, title=''):
|
||||||
|
with codecs.open(source, 'r', encoding='utf-8') as f:
|
||||||
|
html_original = f.read()
|
||||||
|
html_original = re.sub('\{title\}', title.title(), html_original)
|
||||||
|
indent = html_original.split('<!--#')[0].split('\n')[-1]
|
||||||
|
html = re.sub('\n', '\n{}'.format(indent), '\n{}\n'.format(html))
|
||||||
|
with codecs.open(target, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(re.sub(
|
||||||
|
'(?<=#-->).*?(?=<!--#)', html, html_original, flags=re.DOTALL
|
||||||
|
))
|
||||||
|
|
||||||
|
html_index = '<ul>'
|
||||||
|
# For each album
|
||||||
|
for path in [f for f in sorted(os.listdir('./')) if os.path.isdir(f) and f != '!' and f.lower() != 'videos' and f.lower() != 'js']:
|
||||||
|
html_index += ('\n <li><a href="{0}">{0}</a></li>'.format(path))
|
||||||
|
html_album = ''
|
||||||
|
# For each image
|
||||||
|
for name in [f for f in sorted(os.listdir(path)) if f.lower().endswith('.jpg')]:
|
||||||
|
path_large = os.path.join(path, name)
|
||||||
|
path_small = os.path.join(path, str(SIZE_SMALL), name)
|
||||||
|
path_thumbnail = os.path.join(path, str(SIZE_THUMBNAIL), name)
|
||||||
|
print(path_large)
|
||||||
|
image = Image.open(path_large)
|
||||||
|
# Fix orientation
|
||||||
|
exif = {
|
||||||
|
ExifTags.TAGS[k]: v
|
||||||
|
for k, v in (image._getexif() or {}).items()
|
||||||
|
if k in ExifTags.TAGS
|
||||||
|
}
|
||||||
|
orientation = exif.get('Orientation', 1)
|
||||||
|
if orientation == 6:
|
||||||
|
image = image.rotate(-90, expand=True)
|
||||||
|
elif orientation == 8:
|
||||||
|
image = image.rotate(90, expand=True)
|
||||||
|
if orientation != 1:
|
||||||
|
image.save(path_large)
|
||||||
|
ratio = image.size[0] / image.size[1]
|
||||||
|
# Create low-resolution image
|
||||||
|
if not os.path.exists(path_small):
|
||||||
|
create_directory(path_small)
|
||||||
|
image.resize(
|
||||||
|
(int(round(SIZE_SMALL * ratio)), SIZE_SMALL)
|
||||||
|
if ratio > 1 else
|
||||||
|
(SIZE_SMALL, int(round(SIZE_SMALL / ratio))),
|
||||||
|
Image.ANTIALIAS
|
||||||
|
).save(path_small)
|
||||||
|
# Create thumbnail
|
||||||
|
if not os.path.exists(path_thumbnail):
|
||||||
|
create_directory(path_thumbnail)
|
||||||
|
image.resize(
|
||||||
|
(SIZE_THUMBNAIL, int(round(SIZE_THUMBNAIL / ratio)))
|
||||||
|
if ratio > 1 else
|
||||||
|
(int(round(SIZE_THUMBNAIL * ratio)), SIZE_THUMBNAIL),
|
||||||
|
Image.ANTIALIAS
|
||||||
|
).save(path_thumbnail)
|
||||||
|
# Create HTML
|
||||||
|
html_album += (
|
||||||
|
'{0}<div><a href="../!/#{1}/{2}">'
|
||||||
|
'<img class="{3}" src="{4}/{2}"/></a></div>'
|
||||||
|
).format(
|
||||||
|
'' if not html_album else '\n', path, name,
|
||||||
|
'landscape' if ratio > 1 else 'portrait', SIZE_THUMBNAIL
|
||||||
|
)
|
||||||
|
# Cleanup
|
||||||
|
for p in [
|
||||||
|
os.path.join(path, str(SIZE_SMALL)),
|
||||||
|
os.path.join(path, str(SIZE_THUMBNAIL))
|
||||||
|
]:
|
||||||
|
for n in [f for f in os.listdir(p) if f.lower().endswith('.jpg')]:
|
||||||
|
if not os.path.exists(os.path.join(path, n)):
|
||||||
|
os.remove(os.path.join(p, n))
|
||||||
|
# Write album HTML
|
||||||
|
write_html(
|
||||||
|
'album.html', os.path.join(path, 'index.html'), html_album, path
|
||||||
|
)
|
||||||
|
html_index += '\n</ul>'
|
||||||
|
# Write index HTML
|
||||||
|
write_html('index.html', 'index.html', html_index)
|
||||||
|
|
||||||
|
# Alternatively, you can comment this out and use FTP / run rsync separately
|
||||||
|
'''
|
||||||
|
print("Syncing albums...")
|
||||||
|
os.system('rsync -av --ignore-existing ./ "{}"'.format(REMOTE_PATH))
|
||||||
|
'''
|
30
write_captionsJSON.py
Normal file
30
write_captionsJSON.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
#usage: python3 write_captionsJSON.py
|
||||||
|
|
||||||
|
# do not overwrite existing captions
|
||||||
|
if not os.path.exists("js/captions.json"):
|
||||||
|
captions = {}
|
||||||
|
else:
|
||||||
|
captions = json.load(open("js/captions.json"))
|
||||||
|
subprocess.call(['cp', 'js/captions.json', 'js/captions.json.back'])
|
||||||
|
# CleanUp needed for renamed files (?how)
|
||||||
|
# cleanup deleted images
|
||||||
|
captions = { k : v for k,v in captions.items() if os.path.exists(k)}
|
||||||
|
|
||||||
|
# For each album
|
||||||
|
for path in [f for f in os.listdir('./') if os.path.isdir(f) and f != '!' and not 'videos' in f and f != 'js']:
|
||||||
|
# For each image
|
||||||
|
for name in [f for f in sorted(os.listdir(path)) if f.lower().endswith('.jpg')]:
|
||||||
|
path_name = path + "/" + name
|
||||||
|
if path_name not in captions.keys():
|
||||||
|
captions[path_name] = ""
|
||||||
|
|
||||||
|
# write 'sorted dict' to file
|
||||||
|
with open("js/captions.json","w") as j:
|
||||||
|
json.dump(OrderedDict(sorted(captions.items())), j, indent=2)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user