Giter Site home page Giter Site logo

inlustra / the-photo-gallery Goto Github PK

View Code? Open in Web Editor NEW
89.0 4.0 5.0 266 KB

A simple, featureless (By design) full-width photo gallery.

Home Page: https://gallery.thenairn.com

Dockerfile 6.03% Shell 0.18% TypeScript 87.46% JavaScript 5.15% CSS 1.17%
image-gallery photo-gallery photos react-gallery react-image-lightbox react-photo-gallery

the-photo-gallery's Introduction

The Photo Gallery

A simple, featureless (By design) full-width photo gallery.

Updates in v0.0.4

  • Allow the regen api to regenerate specific directories
    • You can POST or GET (Or just load) the regen api url and have the server immediately regenerate.

Updates in v0.0.3

  • Imagor support
    • Allows us to support all file types (HEIC... etc)
    • Better control over the generated file types
  • Support for image blur disabling
    • If you have thousands of photos, blurs can be expensive and not really necessary if you have a fast connection to the server
  • Directory support (beta)
    • You can now nest your photos in directories
    • Just navigate to /mydir and the server will statically generate the photos within /photos/mydir
    • It's worth noting that the changing of images and having them dynamically update is not currently built-in

Features

  • Full width photo display
  • Lightbox built-in
  • Directory Support
  • Automatic image optimization courtesy of NextJS and team
  • Generation of loading blurs
  • Statically generated, the server just serves regular HTML + JS, once deployed to production, it's quick
  • Automatic dynamic regeneration should you edit/remove/add photos
  • Can handle hundreds (And thousands?) of images at a time
  • Lazy loading as you scroll
  • Full screen toggle
  • Imagor integration
    • Allows us to support almost all image file types! (HEIC... etc)
    • Allows us to support thousands of images as, while using the imagor processor, we don't generate blurs and other potentially heavy attributes, whilst generating thumbnails at runtime
    • See here for how to get started
  • Image sorting
    • Numerical file names (1.jpg, 2.jpg, 3.jpg...)
    • Created time
    • Regular file names (a.jpg, b.jpg...) (2022-10-09.jpg, 2022-10-10.jpg...)
    • Reverse of any of the above!

Example

These are my midjourney creations, this website was built for my wedding and as such, real photos look a lot better!

Demo

brave_d1trqa2sbR.mp4

Why?

I've honestly not been able to find a simple plug and play photo sharing website for sharing the wedding photos.

My goals were:

  • Mount a directory with photos in it (So that the wife can manage and delete the photos she doesn't want)
  • Reduce bandwidth costs of sharing photos
  • Allow images to be enlarged
  • Take up the full screen width
  • Static HTML - why should my server be hammered every render?

I already host a ton of stuff using Caddy so wanted a simple container to route traffic to.

Getting Started

docker-compose.yml

version: "2.4"
services:
  thephotogallery:
    container_name: thephotogallery
    image: inlustra/the-photo-gallery:0.0.4
    ports:
      - 3000:3000
    volumes:
      - {YOUR_PHOTOS_DIRECTORY}:/app/public/photos:ro
      - {A_STORAGE_LOCATION}:/app/storage
    environment:
      PAGE_TITLE: 'The Photo Gallery'
      PAGE_HEADER_TEXT: 'Inlustra'
      PAGE_SHOW_FULLSCREEN_BUTTON: 'true'
      PHOTO_SORT: numerical_file_name
      PHOTO_DEFAULT_REVERSE: 'false'
    restart: unless-stopped

Configuration

The photo gallery is configured entirely with environment variables:

Environment Variable Description Options (default)
PAGE_HEADER_TEXT Text at the top of the screen string
PAGE_SHOW_FULLSCREEN_BUTTON Whether or not the page should have the fullscreen button boolean
PAGE_TITLE Title that appears in the tab in your browser string
PHOTO_DEFAULT_REVERSE Whether the photos should be by default reversed on the page boolean
PHOTO_SORT Sort order for images numerical_file_name, file_name, modified_at, image_taken_date
IMAGOR_CLIENT_BASE_URL The Imagor base url for the client to fetch images, e.g for docker with exposed port: http://localhost:8000/ _
IMAGOR_IMAGE_FILTERS Any extra image filters to be requested by imagor, must start with: ':', example: ':hue(290):saturation(100)' string
IMAGOR_IMAGE_FORMAT Image format to be requested by Imagor, defaults to webp jpeg, png, gif, webp, tiff, avif
IMAGOR_SECRET Set this if you have set the IMAGOR_SECRET environment variable within imagor _
IMAGOR_SERVER_BASE_URL The Imagor base url for the container to fetch metadata, e.g for docker: http://imagor:8000/ *
NODE_DISABLE_BLUR_GENERATION Disable the blur generation, will significantly speed up build. Not recommended but required for *very* large directories. boolean
NODE_USE_EMBEDDED_THUMBNAILS During generation, if the photo has an embedded thumbnail, this can be used instead a blur boolean

A couple of extra notes:

  • PHOTO_SORT:

    • image_taken_date: (DEFAULT) Will sort by the date since the photos were taken, this uses EXIF data from the photo (Worth noting that not all images will have this data available)
    • file_name: Sorts based on file name [a.jpg, b.jpg.... z.jpg]
    • numerical_file_name: Sorts based on file name using numbers [1.jpg, 2.jpg... 99.jpg], this is particularly useful when your file names are not in a set string format [01.jpg, 02.jpg, 99.jpg]
    • modified_at: Sort based on the last modification date of the photo
  • PHOTO_USE_EMBEDDED_THUMBNAILS: This will use the embedded thumbnails instead of generating a blur. Defaults to false, this is not really recomended but might be useful for a smaller amount of larger images. (775 full pictures with this environment variable set to true caused the initial page download to go from 225kb to 15MB)

Imagor

As of v0.0.3, we now support Imagor!

Imagor is a self hosted service that we can use to generate images ourselves.

Benefits

  • Support all file types
  • Uses a much better (Read sturdy) implementation to get metadata and exif data about images

Caveats

  • Thumbnails will be hosted by yourself instead of using the next services
  • More setup
  • With control over the thumbnails, if you do intend on storing thousands of these, you'll need to rotate/delete images
    • This is a non-issue for small photo libraries
    • If the size of images within a directory is > threshold MB then delete the oldest within that directory
      • Would love to know if anyone knows of any tool that could solve this? (Logrotate or something?)

Getting Started with Imagor

docker-compose.yml

version: "2.4"
services:
  thephotogallery:
    container_name: thephotogallery
    image: inlustra/the-photo-gallery:0.0.4
    ports:
      - 2070:3000
    volumes:
      # - ${BASE_DIR}/favicon.ico:/app/public/favicon.ico:ro # Use this to replace the favicon
      - ${BASE_DIR}/public/photos:/app/public/photos:ro
      - ${BASE_DIR}/storage/cache:/app/storage
    environment:
      PAGE_TITLE: "The Photo Gallery"
      PAGE_HEADER_TEXT: "Inlustra"
      PAGE_SHOW_FULLSCREEN_BUTTON: "false"
      PHOTO_DEFAULT_REVERSE: "false"
      PHOTO_USE_EMBEDDED_THUMBNAILS: "false"
      IMAGOR_SERVER_BASE_URL: "http://imagor:8000" # Uses Imagor internal docker port
      IMAGOR_CLIENT_BASE_URL: "http://localhost:4567" # Uses Imagor external docker port
    depends_on:
      - imagor
    restart: unless-stopped

  imagor:
    image: shumc/imagor:latest
    volumes:
      - ${BASE_DIR}/public/photos:/mnt/public/photos
      - ${BASE_DIR}/storage/imagor:/mnt/result
    environment:
      PORT: 8000
      IMAGOR_UNSAFE: 1 # unsafe URL for testing

      # Keep the next 2 the same to ensure that we don't store duplicates of the images within Imagor
      FILE_LOADER_BASE_DIR: /mnt/public # enable file loader by specifying base dir
      FILE_STORAGE_BASE_DIR: /mnt/public # enable file storage by specifying base dir

      FILE_STORAGE_MKDIR_PERMISSION: 0755
      FILE_STORAGE_WRITE_PERMISSION: 0666

      FILE_RESULT_STORAGE_BASE_DIR: /mnt/result # This is the cache storage folder
      FILE_RESULT_STORAGE_MKDIR_PERMISSION: 0755
      FILE_RESULT_STORAGE_WRITE_PERMISSION: 0666
    ports:
      - "4567:8000"

the-photo-gallery's People

Contributors

inlustra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

the-photo-gallery's Issues

Imagor cannot handle commas in the filename and reverse proxy woes.

So, to start there is a bug somewhere, commas as in ',' in the photo filename cause a crash. Probably on the imagor end, but things crash any way.

Basically this does not compute: http://imagor:8000/unsafe/meta/photos/00060-1597646341-invicible,_il.png it does fine without imagor though.

Also I could not make IMAGOR_SECRET: work at all, no matter if I had quotes or no quotes, spaces or something else, it would not even fire up local metadata rebuild. (That's the initial file detection and meta collection for the cache part).

DEBUG imagor/imagor.go:209 sign-mismatch {"params": {"path":"meta/photos/00041-3113491024-giant_scifi_s.png","image":"photos/00041-3113491024-giant_scifi_s.png","hash":"nic5S3sU80NEMe7Xr1ycuDQ1KyA=","meta":true}, "expected": "wf68iIiITTt0UjbQ9BJ_MfOTftY="}

Hashes would never match.

And I might be too wooden, but I cant for the life of me make the combo work via reverse proxy with https. Tried it with nginx and caddy (must admit a lot nicer..). Though it's a very weird kind of broken. (this is with IMAGOR_UNSAFE: 1, since I could not boot up otherwise, without pre-built cache that is).

I have a very simple reverse proxy (seems to work.. I did try messing with rewrites and headers before in nginx to try to make non unsafe one work, but to no avail, though granted I'm not that bright with that).

example.com  {
  reverse_proxy localhost:2070
  handle_path /img/* {
    reverse_proxy  localhost:2080
  }
}

with IMAGOR_CLIENT_BASE_URL: "https://example.com/img/"

And it kind-of works.. but, if there are any brackets ( or ) it suddenly does not. So if you ask for https://example.com/img/unsafe/828x552/filters:format(webp)/photos/00020-1594330263-postapocalypt.png you get error 400:

DEBUG imagor/imagor.go:295 load {"params": {"path":"828x552/filters:format%28webp%29/photos/00020-1594330263-postapocalypt.png","image":"filters:format(webp)/photos/00020-1594330263-postapocalypt.png","unsafe":true,"width":828,"height":552}, "error": "imagor: 400 invalid"}

Yet if you do not use any format(), everything works just dandy aka https://example.com/img/unsafe/828x552/photos/00020-1594330263-postapocalypt.png

DEBUG   imagor/imagor.go:522    suppress        {"key": "828x552/photos/00020-1594330263-postapocalypt.png"}
DEBUG   vips/processor.go:100   vips    {"log": "created imageRef 0xc000128dc0"}
INFO    vips/processor.go:102   VIPS    {"log": "selected loader is image source"}
INFO    vips/processor.go:102   VIPS    {"log": "input size is 768 x 512"}
INFO    vips/processor.go:102   VIPS    {"log": "loading with factor 1 pre-shrink"}
INFO    vips/processor.go:102   VIPS    {"log": "pre-shrunk size is 768 x 512"}
INFO    vips/processor.go:102   VIPS    {"log": "converting to processing space srgb"}
INFO    vips/processor.go:102   VIPS    {"log": "residual scale 1.07812 x 1.07812"}
INFO    vips/processor.go:102   VIPS    {"log": "converting to output space srgb"}
INFO    vips/processor.go:102   VIPS    {"log": "cropping to 828x552"}
DEBUG   vips/process.go:229     image   {"width": 828, "height": 552, "page_height": 552}
DEBUG   vips/processor.go:100   vips    {"log": "closing image 0xc000128dc0"}
DEBUG   vips/processor.go:100   vips    {"log": "closing source 0xc000128d40"}
DEBUG   imagor/imagor.go:329    processed       {"params": {"path":"828x552/photos/00020-1594330263-postapocalypt.png","image":"photos/00020-1594330263-postapocalypt.png","unsafe":true,"width":828,"height":552}}
DEBUG   imagor/imagor.go:482    saved   {"key": "828x552/photos/00020-1594330263-postapocalypt.png"}

If you ask for non-existent file and request has brackets - you still get 400 instead of 404, so must be the brackets..

imagor/imagor.go:295 load {"params": {"path":"828x552/filters:format%28webp%29/photos/00020-1594330263-postapocalypt.webp","image":"filters:format(webp)/photos/00020-1594330263-postapocalypt.webp","unsafe":true,"width":828,"height":552}, "error": "imagor: 400 invalid"}

Result seems to be the same in both nginx and caddy.
Yet brackets work just fine via the http port (though have not tried to get it through reverse-proxy in a non-https manner).

The proxy stuff is likely a user-error of some kind since I never really messed much with stuff that has similar backends (though tips would be appreciated), but IMAGOR_SECRET seems to be broken in some way or the other. ( If it's not me beeing dumb, then it's either wrong path gets hashed, which I imagine will be true with reverse proxy to /img/, though it seems to me that only part of the URL get hashed, and it would not really matter what host or port it was on, but we did not get that far haha, so probably something to do with "excluding /unsafe/".

Question: Support for videos?

Hi,

your software looks very promising, thanks for your work! Do you have any plans to support videos with thumbnail (maybe as animated gif) generation?

Question/Feature request: PNG metadata for ML-created images.

First of all thanks for this great project, since it's indeed incredibly hard to find anything for a ready-to-go image display site, with basically a dump directory interface. So it's a godsend that this project exists.

A bit of pretext, I've recently got a new GPU, and... got into messing about with Stable Diffusion, and was becoming a bother to friends on messengers sending them pics ;) So I kinda thought a small simple gallery site that just displays what is dumped into a directory with some simple modify-date sort must be easy to come by :) Apparently it aint haha.

As a fellow connoisseur of AI generated imagery, it would be rather cool to add the ability to display creation parameters when viewing in full screen under the picture. SD saves it's image generation parameters in a tEXt field inside a PNG with a key=parameters.

As I imagine I might not be the only one looking at this project to display ML images to friends, it might be a cool addition. Plus probably the same can be used for displaying relevant (date, place e.t.c.) EXIF for your wedding photos too :)

Docker support for Arm64

Thank you for this cool gallery!
Please publish a container for arm64 to dockerhub, this would make it possible to use your application on devices like the RaspberryPi.

TypeError: handler is not a function

Hi,
I wanted to try out your gallery on a Synology NAS via Docker.
Upon start this error happens

TypeError: handler is not a function
    at Server.<anonymous> (/app/server.js:19:11)
    at Server.emit (node:events:513:28)
    at parserOnIncoming (node:_http_server:980:12)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:128:17)
Error regenerating...
Request failed with status code 500

Found your r/selfhosted thread and someone there had the same issue it seems on another NAS. (https://www.reddit.com/r/selfhosted/comments/y1lig3/first_release_of_thephotogallery_a_simple/)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.