169 lines
7.7 KiB
Org Mode

#+TITLE: Static photo albums with llgal
#+DATE: 2023-01-29
* Prologue
I used to create photo albums on [[][flickr]] for our vacations. I even had
a paid pro account for a few years. While I have backups of all my
photos, it still felt off to show these albums using somebody else's
computer. They might disappear any day. Since I have the storage
capacity and some time to waste I set out to self-host photo albums.
* Nextcloud Photos
My first layer of photo backups is a self-hosted [[][Nextcloud]]. I am using
the Nextcloud android app to automatically upload pictures when on
WiFi. So I might as well use the built-in Nextcloud Photos 2.0[fn::Why
is there not way to link to a description of this thing? There is a
GitHub page and it's described on [[][]] but
you can't direct-link to it‽].
Unfortunately it's not quite there yet. In increasing order of
1) Video buffering is not a thing.
2) Videos do not get a preview image.
3) It is very confused about ordering. The order in the photo app is
correct but when added to the gallery sometimes two photos switch
places. There is some mumbling about mtime vs. ctime vs. exiff data
in some forum, but that's not the problem here. First of all, no
matter how Nextcloud sorts the picture it would always arrive at
the same ordering. I did not edit the photos, so mtime and ctime
are the same. But also note that the order in the photo app is
correct. It only gets confused when photos are added to an
album. The photo album tells a story. It is really bad if the
"arrival at home" photo is shown before the "last night of the
vacation" photo.
4) The absolute deal-breaker is that it does not work though. The
whole idea is to share a link to the album for anonymous users. You
can do that, and it shows you the album with thumbnails. But as
soon as you click on a photo or start the slide show it wants you
to login. I suspect you need to enable sharing via link to every
photo in the album to make it work. There does not seem to be a way
to do this in bulk so I did not try it. I have also found a
discussion online where people argue for years along the lines of
"it does not work" - "yes it does" - "no it does not". That was
tiresome and they are still going on. There was some mumbling that
you need to enable federation in Nextcloud to make anonymous albums
work, but I have that on and it still does not work.
* llgal
I then remembered that I had used a static photo album generator
before: [[][llgal]]. But I never tried to make it "pretty" or convert all my
flickr albums to it.
** Setup
llgal is in OpenBSD ports, so it can be installed with ~pkg_add~. I
store all my albums as sub-folders in ~/var/www/ and
then run ~llgal~. I was experimenting a bit with the command line
flags to figure out what I need.
I then setup a =~/.llgal/llgalrc= file. With that in place I can run
~llgal~ in the top level photos directory and it will (re-)create all
albums as needed.
I downloaded a sample file from [[][GitHub]] and edited for my needs. You
can see the resulting file [[file:llgal/llgalrc.txt][here]].
These are the things I configured:
thumbnails_per_row = 3
thumbnail_height_max = 240
thumbnail_width_max = 240
MVI_link_to_target = 1
DIR_link_to_target = 1
slide_width_max = 700
slide_height_max = 700
show_all_exif_tags = 1
credits_text = "Copyright © 2014 - 2023 Florian Obser. All rights reserved."
exclude = "^js$"
sort_criteria = "revtime"
recursive = 1
link_subgalleries = 1
** Video thumbnails
llgal does not create thumbnails for video files (yet) so I had to
hack around that a bit.
First we use ~ffmpeg~ to create the thumbnails:
#+begin_src shell
for i in *.mp4; do
ffmpeg -ss 1 -i ${i} -frames:v 1 -vf "scale=240:-1" \
We grab one frame (=-frames:v 1=), one second into the video (=-ss
1=), and scale it to 240 pixels wide while keeping the aspect ratio
(=-vf "scale=240:-1"=). We store the thumbnail in the ~.llgal~
sub-directory, where ~llgal~ stores its own thumbnails and scaled
images. The config file has this:
# Additional prefix of user-provided scaled images
# user_scaled_image_filenameprefix = "my"
# Additional prefix of user-provided thumbnails
# user_thumbnail_image_filenameprefix = "my"
I have not worked out what that does, but I am using the "my" prefix
because of this.
llgal does not pick up these thumbnails but we can use the /captions/
file to show them. First we are creating /captions files in all
albums: ~llgal --gc~. This creates =.llgal/captions= in all albums.
It creates lines for all photos and videos that we can edit, for
videos it looks like this:
MVI: VID_20230120_124000.mp4 ---- Open movie VID_20230120_124000.mp4 ----
And we can change it to this to show the thumbnail[fn::I am using an
emacs macro for that. YMMV.]:
MVI: VID_20230120_124000.mp4 ---- <img src=".llgal/my_thump_VID_20230120_124000.mp4.jpg" /><br /> Open movie ----
I am using the same trick to have thumbnails for the top-level [[][album
overview]]. The only difference is that it is a =DIR= line instead of
** Keyboard and swipe navigation.
llgal links to [[][]] as an example. Those albums use
[[][hammer.js]] for swipe navigation and [[][mousetrap]] for keyboard navigation.
I have copied =slidetemplate.html= from =/usr/local/share/llgal= to
=~/.llgal= and edited it: [[file:llgal/slidetemplate.html.txt][slidetemplate.html]].
We need to include the JavaScript files in the header:
#+begin_src html
<script type="text/javascript" src="/js/mousetrap.min.js"></script>
<script type="text/javascript" src="/js/hammer.min.js"></script>
Set the =id= for the navigation links:
#+begin_src html
<p class="center">
<a id="prevslide" href="<!--PREV-SLIDE-->"><!--PREV-SLIDE-LINK-TEXT--></a>
&nbsp; &nbsp; &nbsp;
<a id="indexlink" href="<!--INDEX-FILE-->"><!--INDEX-LINK-TEXT--></a>
&nbsp; &nbsp; &nbsp;
<a id="nextslide" href="<!--NEXT-SLIDE-->"><!--NEXT-SLIDE-LINK-TEXT--></a>
And then hook up JavaScript to the navigation links:
#+begin_src html
<script type="text/javascript">
// Script for keyboard navigation
var prev = document.getElementById("prevslide").href;
var next = document.getElementById("nextslide").href;
Mousetrap.bind('left', function () { location.href = prev; });
Mousetrap.bind('right', function () { location.href = next; });
Mousetrap.bind('h', function () { location.href = indexlink; });
Mousetrap.bind('j', function () { location.href = prev; });
Mousetrap.bind('k', function () { location.href = next; });
<script type="text/javascript">
// Script for touch gestures (Hammerjs)
var slide = document.getElementById('slide-container');
var mc = new Hammer(slide);
mc.on("swiperight", function(ev) { location.href = next; });
mc.on("swipeleft", function(ev) { location.href = prev; });
This seems to disable pinch-zooming on the image itself on android. I
have not figured out why that is. The hammerjs documentation talks
about pinch, but my understanding is that it should just work. It does
not though...
* Epilogue
This was not a lot of work, please enjoy the first [[][album from our trip
to Malta in 2023]].
Time permitting I will convert more albums from flickr and google
photos in the future.