1
0
Fork 0
mirror of https://github.com/alangrainger/immich-public-proxy.git synced 2024-12-28 03:41:58 +00:00

Add #10 - Single item as a gallery

This commit is contained in:
Alan Grainger 2024-11-04 20:23:34 +01:00
parent 0afc820f7b
commit 71feba9ce8
10 changed files with 87 additions and 54 deletions

View file

@ -1,3 +0,0 @@
IMMICH_URL=http://localhost:2283
PORT=3000
CACHE_AGE=2592000

View file

@ -48,17 +48,7 @@ Here is an example setup for [securing Immich behind mTLS](./docs/securing-immic
1. Download the [docker-compose.yml](https://github.com/alangrainger/immich-public-proxy/blob/main/docker-compose.yml) file.
2. Create a `.env` file to configure the app:
```
IMMICH_URL=http://localhost:2283
PORT=3000
CACHE_AGE=2592000
```
- `IMMICH_URL` is the URL to access Immich in your local network. This is not your public URL.
- `PORT` is the external port you want for the docker container.
- `CACHE_AGE` this is setting the Cache-Control header, to tell the visitor's browser to cache the assets. Set to 0 to disable caching. By default this is 30 days.
2. Update the value for `IMMICH_URL` in your docker-compose file to point to your local URL for Immich. This should not be a public URL.
3. Start the docker container:
@ -102,7 +92,7 @@ If the shared link has expired or any of the assets have been put in the Immich
## Additional configuration
The gallery is created using [lightGallery](https://github.com/sachinchoolur/lightGallery). You can adjust various settings to customise how your gallery displays.
There are some additional configuration options you can change, for example the way the gallery is set up.
1. Make a copy of [config.json](https://github.com/alangrainger/immich-public-proxy/blob/main/app/config.json) in the same folder as your `docker-compose.yml`.
@ -115,10 +105,13 @@ The gallery is created using [lightGallery](https://github.com/sachinchoolur/lig
3. Restart your container and your custom configuration should be active.
### lightGallery
The gallery is created using [lightGallery](https://github.com/sachinchoolur/lightGallery).
You can find all of lightGallery's settings here:
https://www.lightgalleryjs.com/docs/settings/
For example, to disable the download button for images, you would change `download` to `false`:
For example, to disable the download button for images, you would edit the `lightGallery` section and change `download` to `false`:
```json
{

View file

@ -1,4 +1,11 @@
{
"ipp": {
"responseHeaders": {
"Cache-Control": "public, max-age=2592000"
},
"singleImageGallery": false,
"singleItemAutoOpen": true
},
"lightGallery": {
"controls": true,
"download": true,

View file

@ -1,6 +1,6 @@
{
"name": "immich-public-proxy",
"version": "1.3.6",
"version": "1.3.7",
"scripts": {
"dev": "ts-node src/index.ts",
"build": "npx tsc",

54
app/src/functions.ts Normal file
View file

@ -0,0 +1,54 @@
import dayjs from 'dayjs'
import { Request, Response } from 'express-serve-static-core'
import { ImageSize } from './types'
let config = {}
try {
const configJson = require('../config.json')
if (typeof configJson === 'object') config = configJson
} catch (e) { }
/**
* Get a configuration option using dotted notation.
*
* @param path
* @param [defaultOption] - Specify a default option to return if no configuation value is found
*
* @example
* getConfigOption('ipp.singleImageGallery')
*/
export const getConfigOption = (path: string, defaultOption?: unknown) => {
const value = path.split('.').reduce((obj: { [key: string]: unknown }, key) => (obj || {})[key], config)
if (value === undefined) {
return defaultOption
} else {
return value
}
}
/**
* Output a console.log message with timestamp
*/
export const log = (message: string) => console.log(dayjs().format() + ' ' + message)
/**
* Sanitise the data for an incoming query string `size` parameter
* e.g. https://example.com/share/abc...xyz?size=thumbnail
*/
export function getSize (req: Request) {
return req.query?.size === 'thumbnail' ? ImageSize.thumbnail : ImageSize.original
}
export function toString (value: unknown) {
return typeof value === 'string' ? value : ''
}
/**
* Add response headers from config.json
*/
export function addResponseHeaders (res: Response) {
Object.entries(getConfigOption('ipp.responseHeaders', {}) as { [key: string]: string })
.forEach(([header, value]) => {
res.set(header, value)
})
}

View file

@ -1,6 +1,6 @@
import { Asset, AssetType, ImageSize, IncomingShareRequest, SharedLink, SharedLinkResult } from './types'
import dayjs from 'dayjs'
import { log } from './index'
import { getConfigOption, log } from './functions'
import render from './render'
import { Response } from 'express-serve-static-core'
import { encrypt } from './encrypt'
@ -70,12 +70,13 @@ class Immich {
// This is an individual item (not a gallery)
log('Serving link ' + request.key)
const asset = link.assets[0]
if (asset.type === AssetType.image) {
// For photos, output the image directly
if (asset.type === AssetType.image && !getConfigOption('ipp.singleImageGallery')) {
// For photos, output the image directly unless configured to show a gallery
await render.assetBuffer(res, link.assets[0], request.size)
} else if (asset.type === AssetType.video) {
// For videos, show the video as a web player
await render.gallery(res, link, 1)
} else {
// Show a gallery page
const openItem = getConfigOption('ipp.singleItemAutoOpen', true) ? 1 : 0
await render.gallery(res, link, openItem)
}
} else {
// Multiple images - render as a gallery

View file

@ -2,19 +2,19 @@ import express from 'express'
import immich from './immich'
import render from './render'
import dayjs from 'dayjs'
import { AssetType, ImageSize } from './types'
import { Request } from 'express-serve-static-core'
import { AssetType } from './types'
import { decrypt } from './encrypt'
import { log, getSize, toString, addResponseHeaders } from './functions'
require('dotenv').config()
const app = express()
// Add the EJS view engine, to render the gallery page
app.set('view engine', 'ejs')
// Serve static assets from the /public folder
app.use(express.static('public'))
// For parsing the password unlock form
app.use(express.json())
// Serve static assets from the /public folder
app.use(express.static('public', { setHeaders: addResponseHeaders }))
// An incoming request for a shared link
app.get('/share/:key', async (req, res) => {
@ -34,7 +34,7 @@ app.post('/unlock', async (req, res) => {
// Output the buffer data for a photo or video
app.get('/:type(photo|video)/:key/:id', async (req, res) => {
res.set('Cache-Control', 'public, max-age=' + process.env.CACHE_AGE)
addResponseHeaders(res)
// Check for valid key and ID
if (immich.isKey(req.params.key) && immich.isId(req.params.id)) {
let password
@ -83,23 +83,6 @@ app.get('*', (req, res) => {
res.status(404).send()
})
/**
* Output a console.log message with timestamp
*/
export const log = (message: string) => console.log(dayjs().format() + ' ' + message)
/**
* Sanitise the data for an incoming query string `size` parameter
* e.g. https://example.com/share/abc...xyz?size=thumbnail
*/
const getSize = (req: Request) => {
return req.query?.size === 'thumbnail' ? ImageSize.thumbnail : ImageSize.original
}
const toString = (value: unknown) => {
return typeof value === 'string' ? value : ''
}
app.listen(3000, () => {
console.log(dayjs().format() + ' Server started')
})

View file

@ -1,16 +1,13 @@
import immich from './immich'
import { Response } from 'express-serve-static-core'
import { Asset, AssetType, ImageSize, SharedLink } from './types'
import { getConfigOption } from './functions'
class Render {
lgConfig = {}
lgConfig
constructor () {
try {
// Import user-provided lightGallery config (if exists)
const config = require('../config.json')
if (typeof config === 'object' && config.lightGallery) this.lgConfig = config.lightGallery
} catch (e) { }
this.lgConfig = getConfigOption('lightGallery', {})
}
async assetBuffer (res: Response, asset: Asset, size?: ImageSize) {
@ -61,7 +58,7 @@ class Render {
items,
openItem,
title: this.title(share),
lgConfig: this.lgConfig
lgConfig: getConfigOption('lightGallery', {})
})
}

View file

@ -4,8 +4,9 @@ services:
container_name: immich-public-proxy
restart: always
ports:
- ${PORT}:3000
env_file: .env
- "3000:3000"
environment:
- IMMICH_URL=http://localhost:2283
healthcheck:
test: wget -q http://localhost:3000/healthcheck || exit 1
start_period: 10s