2020-06-12 Serving image galleries via Gemini

As an experiment, I’m serving images via Gemini! Let me know what you think of the user interface. It’s a bit weird since you can’t actually scan the thumbnails. If you’re looking at newer galleries, there’s going to be textual descriptions. For older galleries, it’s just a long list of thumbnail and image links. I don’t see how that can be improved, so there you have it.

In order to do this, I added support for a gemini_config file in the wiki’s data directory. There, you can add more links to the main menu, and add your own selector interpretations.

And this is my gemini_config with the gallery support for Sitelen Mute.

# -*- mode: perl -*-
use Modern::Perl;
use Mojo::JSON;
use Mojo::DOM;
use File::Slurper qw(read_text read_binary read_dir);

our (@extensions, @main_menu_links);

push(@main_menu_links, "=> gemini://alexschroeder.ch/do/gallery Galleries");

push(@extensions, \&galleries);

my $parent = "/home/alex/alexschroeder.ch/gallery";

sub galleries {
  my $self = shift;
  my $url = shift;
  my $selector = shift;
  if ($selector eq "do/gallery") {
    $self->log(3, "Serving galleries");
    say "# Galleries";
    for my $dir (
      sort {
	my ($year_a, $title_a) = split(/-/, $a, 2);
	my ($year_b, $title_b) = split(/-/, $b, 2);
	return ($year_b <=> $year_a || $title_a cmp $title_b);
      } grep {
	-d "$parent/$_"
      } read_dir($parent)) {
      $self->print_link(ucfirst(NormalToFree($dir)), "do/gallery/" . FreeToNormal($dir));
    return 1;
  } elsif (my ($dir) = $selector =~ m!do/gallery/([^/?]*)$!) {
    if (not -d "$parent/$dir") {
      say "40 This is not actuall a gallery";
      return 1;
    if (not -r "$parent/$dir/data.json") {
      say "40 This gallery does not contain a data.json file like the one created by sitelen-mute or fgallery";
      return 1;
    my $bytes = read_binary("$parent/$dir/data.json");
    if (not $bytes) {
      say "40 Cannot read the data.json file in this gallery";
      return 1;
    my $data;
    eval { $data = decode_json $bytes };
    $self->log(1, "decode_json: $@") if $@;
    if ($@ or not %$data) {
      say "40 Cannot decode the data.json file in this gallery";
      return 1;
    $self->log(3, "Serving gallery $dir");
    if (-r "$parent/$dir/index.html") {
      my $dom = Mojo::DOM->new(read_text("$parent/$dir/index.html"));
      $self->log(3, "Parsed index.html");
      my $title = $dom->at('*[itemprop="name"]');
      $title = $title ? $title->text : ucfirst(NormalToFree($dir));
      say "# $title";
      my $description = $dom->at('*[itemprop="description"]');
      say $description->text if $description;
      say "## Images";
    } else {
      say "# " . ucfirst(NormalToFree($dir));
    for my $image (@{$data->{data}}) {
      say join("\n", @{$image->{caption}}) if $image->{caption};
      $self->print_link("Thumbnail", "do/gallery/" . FreeToNormal($dir) . "/" . $image->{thumb}->[0]);
      $self->print_link("Image", "do/gallery/" . FreeToNormal($dir) . "/" . $image->{img}->[0]);
    return 1;
  } elsif (my ($file, $extension) = $selector =~ m!do/gallery/([^/?]*/(?:thumbs|imgs)/[^/?]*\.(jpe?g|png))$!i) {
    if (not -r "$parent/$file") {
      say "40 Cannot read $file";
    } else {
      $self->success($extension =~ /^png$/i ? "image/png" : "image/jpg");
      $self->log(3, "Serving image $file");
    return 1;



Not as fancy as on the web (for obious reasons) but still looks good and is useable. I’d add filesizes to the links and some kind of imageid if there is no description in order to not get lost in a long list of Image Thumbnail Image ...

– baschdel 2020-06-13 15:52 UTC

Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Just say HELLO