From 96dbb5ccbceadd136a8065b73b237dba52a99879 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Tue, 15 Apr 2025 15:42:03 +0200 Subject: [PATCH] Config: Refactor command flags, reports, and client options Signed-off-by: Michael Mayer --- compose.armv7.yaml | 2 +- compose.intel.yaml | 2 +- compose.latest.yaml | 2 +- compose.local.yaml | 2 +- compose.nvidia.yaml | 2 +- compose.postgres.yaml | 2 +- compose.preview.yaml | 2 +- compose.yaml | 2 +- docker/develop/armv7/Dockerfile | 2 +- docker/develop/bookworm/Dockerfile | 2 +- docker/develop/bullseye/Dockerfile | 2 +- docker/develop/buster/Dockerfile | 2 +- docker/develop/impish/Dockerfile | 2 +- docker/develop/jammy/Dockerfile | 2 +- docker/develop/lunar/Dockerfile | 2 +- docker/develop/mantic/Dockerfile | 2 +- docker/develop/noble/Dockerfile | 2 +- docker/develop/oracular/Dockerfile | 2 +- frontend/package-lock.json | 40 +++++++-------- frontend/src/common/config.js | 13 +++++ frontend/src/component/auth/footer.vue | 7 ++- frontend/src/options/themes.js | 9 ++++ frontend/src/page/auth/login.vue | 2 +- internal/commands/commands_test.go | 2 +- internal/config/client_config.go | 4 ++ internal/config/client_config_test.go | 1 + internal/config/config.go | 15 +++--- internal/config/config_app.go | 17 ++++--- internal/config/config_auth.go | 5 ++ internal/config/config_auth_test.go | 15 ++++-- internal/config/config_const.go | 4 ++ internal/config/config_features.go | 1 + internal/config/config_oidc.go | 13 +++-- internal/config/config_site.go | 32 +++++++++--- internal/config/config_site_test.go | 9 ++++ internal/config/config_storage.go | 14 ++++- internal/config/config_vision.go | 7 --- internal/config/config_vision_test.go | 7 --- internal/config/flags.go | 26 +++++++--- internal/config/logs.go | 36 +++++++++++++ internal/config/options.go | 15 +++--- internal/config/options_report.go | 10 ++++ internal/config/pwa/config.go | 2 + internal/config/pwa/icon.go | 47 ++++++++++++++++- internal/config/pwa/icon_test.go | 16 +++++- internal/config/pwa/manifest.go | 2 +- internal/config/pwa/testdata/example.png | Bin 0 -> 17862 bytes internal/config/report.go | 3 +- internal/server/routes_static.go | 3 +- internal/thumb/fileinfo.go | 56 ++++++++++++++++++++ internal/thumb/fileinfo_test.go | 62 +++++++++++++++++++++++ 51 files changed, 427 insertions(+), 104 deletions(-) create mode 100644 internal/config/logs.go create mode 100644 internal/config/pwa/testdata/example.png create mode 100644 internal/thumb/fileinfo.go create mode 100644 internal/thumb/fileinfo_test.go diff --git a/compose.armv7.yaml b/compose.armv7.yaml index 6680cf517..8bce338ad 100644 --- a/compose.armv7.yaml +++ b/compose.armv7.yaml @@ -62,7 +62,7 @@ services: # PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # On-demand rendering size limit (default 7680, min 720, max 7680) PHOTOPRISM_JPEG_SIZE: 7680 # Size limit for converted image files in pixels (720-30000) - TF_CPP_MIN_LOG_LEVEL: 0 # Show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # Show TensorFlow log messages for development ## Enable TensorFlow AVX2 support for modern Intel CPUs (requires starting the container as root): # PHOTOPRISM_INIT: "tensorflow-amd64-avx2" ## Hardware video transcoding config (optional): diff --git a/compose.intel.yaml b/compose.intel.yaml index 17f101b52..826f90584 100644 --- a/compose.intel.yaml +++ b/compose.intel.yaml @@ -109,7 +109,7 @@ services: PHOTOPRISM_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, imaging, vips) PHOTOPRISM_THUMB_FILTER: "auto" # downscaling filter (imaging best to worst: blackman, lanczos, cubic, linear, nearest) PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development ## Intel Quick Sync Video (QSV) (https://docs.photoprism.app/getting-started/advanced/transcoding/#intel-quick-sync): PHOTOPRISM_FFMPEG_ENCODER: "intel" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi) PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840) diff --git a/compose.latest.yaml b/compose.latest.yaml index 4803d3bcf..7ccbacad1 100644 --- a/compose.latest.yaml +++ b/compose.latest.yaml @@ -57,7 +57,7 @@ services: # PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680) PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development working_dir: "/photoprism" volumes: - "./storage:/photoprism/storage" diff --git a/compose.local.yaml b/compose.local.yaml index a6933434e..1d1be8340 100644 --- a/compose.local.yaml +++ b/compose.local.yaml @@ -58,7 +58,7 @@ services: # PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680) PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development # PHOTOPRISM_INIT: "http gpu tensorflow" # Options: "update https gpu tensorflow davfs clitools clean" PHOTOPRISM_FFMPEG_ENCODER: "nvidia" # Options: "software", "intel", "nvidia", "apple", "raspberry" PHOTOPRISM_STORAGE_PATH: "/photoprism/storage" diff --git a/compose.nvidia.yaml b/compose.nvidia.yaml index af5033dc0..5882f3860 100644 --- a/compose.nvidia.yaml +++ b/compose.nvidia.yaml @@ -111,7 +111,7 @@ services: PHOTOPRISM_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, imaging, vips) PHOTOPRISM_THUMB_FILTER: "auto" # downscaling filter (imaging best to worst: blackman, lanczos, cubic, linear, nearest) PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development ## Nvidia Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/#nvidia-container-toolkit): NVIDIA_VISIBLE_DEVICES: "all" NVIDIA_DRIVER_CAPABILITIES: "all" diff --git a/compose.postgres.yaml b/compose.postgres.yaml index 5e8984bbd..af84f85b2 100644 --- a/compose.postgres.yaml +++ b/compose.postgres.yaml @@ -65,7 +65,7 @@ services: # PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680) PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development ## PostgreSQL Database Server ## Docs: https://www.postgresql.org/docs/ diff --git a/compose.preview.yaml b/compose.preview.yaml index fe39d117c..183d34c00 100644 --- a/compose.preview.yaml +++ b/compose.preview.yaml @@ -57,7 +57,7 @@ services: # PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680) PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development working_dir: "/photoprism" volumes: - "./storage:/photoprism/storage" diff --git a/compose.yaml b/compose.yaml index 08c73354d..7b6a4e5c1 100644 --- a/compose.yaml +++ b/compose.yaml @@ -118,7 +118,7 @@ services: PHOTOPRISM_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, imaging, vips) PHOTOPRISM_THUMB_FILTER: "auto" # downscaling filter (imaging best to worst: blackman, lanczos, cubic, linear, nearest) PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage) - TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development + TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development ## Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/): # PHOTOPRISM_FFMPEG_ENCODER: "software" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi) # PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840) diff --git a/docker/develop/armv7/Dockerfile b/docker/develop/armv7/Dockerfile index 5c0f45830..0e081079e 100644 --- a/docker/develop/armv7/Dockerfile +++ b/docker/develop/armv7/Dockerfile @@ -31,7 +31,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ TF_VERSION=1.15.2 \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ GOBIN="/usr/local/bin" \ diff --git a/docker/develop/bookworm/Dockerfile b/docker/develop/bookworm/Dockerfile index d7313a2a8..83c581110 100644 --- a/docker/develop/bookworm/Dockerfile +++ b/docker/develop/bookworm/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/bullseye/Dockerfile b/docker/develop/bullseye/Dockerfile index 197f68367..eacb1a5ab 100644 --- a/docker/develop/bullseye/Dockerfile +++ b/docker/develop/bullseye/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/buster/Dockerfile b/docker/develop/buster/Dockerfile index d930db2b4..72a96ae2a 100644 --- a/docker/develop/buster/Dockerfile +++ b/docker/develop/buster/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ NODE_ENV="production" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/impish/Dockerfile b/docker/develop/impish/Dockerfile index d49ed6172..0b2afe86f 100644 --- a/docker/develop/impish/Dockerfile +++ b/docker/develop/impish/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ NODE_ENV="production" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/jammy/Dockerfile b/docker/develop/jammy/Dockerfile index 87b6c95b4..a36be7659 100644 --- a/docker/develop/jammy/Dockerfile +++ b/docker/develop/jammy/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/lunar/Dockerfile b/docker/develop/lunar/Dockerfile index 45b31d7ca..13d35bee6 100644 --- a/docker/develop/lunar/Dockerfile +++ b/docker/develop/lunar/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/mantic/Dockerfile b/docker/develop/mantic/Dockerfile index 55e3555f0..a765ca9ce 100644 --- a/docker/develop/mantic/Dockerfile +++ b/docker/develop/mantic/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/noble/Dockerfile b/docker/develop/noble/Dockerfile index 91ba4546a..1bd54b123 100644 --- a/docker/develop/noble/Dockerfile +++ b/docker/develop/noble/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/docker/develop/oracular/Dockerfile b/docker/develop/oracular/Dockerfile index c571bdd03..c8dee7f4b 100644 --- a/docker/develop/oracular/Dockerfile +++ b/docker/develop/oracular/Dockerfile @@ -30,7 +30,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \ LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \ DEBIAN_FRONTEND="noninteractive" \ TMPDIR="/tmp" \ - TF_CPP_MIN_LOG_LEVEL=0 \ + TF_CPP_MIN_LOG_LEVEL=1 \ TF_ENABLE_ONEDNN_OPTS=1 \ MALLOC_ARENA_MAX=4 \ GOPATH="/go" \ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 09552167b..93b419de7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -3795,15 +3795,15 @@ } }, "node_modules/@pkgr/core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.2.tgz", - "integrity": "sha512-25L86MyPvnlQoX2MTIV2OiUcb6vJ6aRbFa9pbwByn95INKD5mFH2smgjDhq+fwJoqAgvgbdJLj6Tz7V9X5CFAQ==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz", + "integrity": "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://opencollective.com/pkgr" } }, "node_modules/@polka/url": { @@ -6342,9 +6342,9 @@ } }, "node_modules/cssdb": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.4.tgz", - "integrity": "sha512-3KSCVkjZJe/QxicVXnbyYSY26WsFc1YoMY7jep1ZKWMEVc7jEm6V2Xq2r+MX8WKQIuB7ofGbnr5iVI+aZpoSzg==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.5.tgz", + "integrity": "sha512-leAt8/hdTCtzql9ZZi86uYAmCLzVKpJMMdjbvOGVnXFXz/BWFpBmM1MHEHU/RqtPyRYmabVmEW1DtX3YGLuuLA==", "funding": [ { "type": "opencollective", @@ -6995,9 +6995,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.136", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.136.tgz", - "integrity": "sha512-kL4+wUTD7RSA5FHx5YwWtjDnEEkIIikFgWHR4P6fqjw1PPLlqYkxeOb++wAauAssat0YClCy8Y3C5SxgSkjibQ==", + "version": "1.5.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.137.tgz", + "integrity": "sha512-/QSJaU2JyIuTbbABAo/crOs+SuAZLS+fVVS10PVrIT9hrRkmZl8Hb0xPSkKRUUWHQtYzXHpQUW3Dy5hwMzGZkA==", "license": "ISC" }, "node_modules/emmet": { @@ -7747,9 +7747,9 @@ } }, "node_modules/eslint-webpack-plugin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-5.0.0.tgz", - "integrity": "sha512-iDhXf2r55KO1UhMfpus8oGp93wdNF+934q5kEkwa7qn3BH9f51QEC11xQidt+8jfqRnEYYZa2/8lhac7U/vqWw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-Ur100Vi+z0uP7j4Z8Ccah0pXmNHhl3f7P2hCYZj3mZCOSc33G5c1R/vZ4KCapwWikPgRyD4dkangx6JW3KaVFQ==", "license": "MIT", "dependencies": { "@types/eslint": "^9.6.1", @@ -10709,9 +10709,9 @@ } }, "node_modules/maplibre-gl": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.3.0.tgz", - "integrity": "sha512-qru6B6jHlDPR4Q9/P4W1zEPbPofR4wwYbrrjiHKWI7yLtyXmpJ1/G1KaIYDr5uNdFbPZ7uiZAWdqtfdNLmIhGg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.3.1.tgz", + "integrity": "sha512-Ihx+oUUSsZkjMou1Cw5J6silE+5OtFFQSPslWF9+7v4yFC/XDHrpsORYO9lWE4KZI0djCEUpZQJpkpnMArAbeA==", "license": "BSD-3-Clause", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", @@ -15270,12 +15270,12 @@ } }, "node_modules/synckit": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.3.tgz", - "integrity": "sha512-szhWDqNNI9etJUvbZ1/cx1StnZx8yMmFxme48SwR4dty4ioSY50KEZlpv0qAfgc1fpRzuh9hBXEzoCpJ779dLg==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz", + "integrity": "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==", "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.1", + "@pkgr/core": "^0.2.3", "tslib": "^2.8.1" }, "engines": { diff --git a/frontend/src/common/config.js b/frontend/src/common/config.js index e13fe3280..cef1de4dd 100644 --- a/frontend/src/common/config.js +++ b/frontend/src/common/config.js @@ -859,6 +859,10 @@ export default class Config { } getIcon() { + if (this.theme?.variables?.icon) { + return this.theme.variables.icon; + } + switch (this.get("appIcon")) { case "crisp": case "mint": @@ -869,6 +873,15 @@ export default class Config { } } + getLoginIcon() { + const loginTheme = themes.Get("login"); + if (loginTheme?.variables?.icon) { + return loginTheme?.variables?.icon; + } + + return this.getIcon(); + } + getVersion() { return this.version; } diff --git a/frontend/src/component/auth/footer.vue b/frontend/src/component/auth/footer.vue index a965fdf2f..66cac4e0c 100644 --- a/frontend/src/component/auth/footer.vue +++ b/frontend/src/component/auth/footer.vue @@ -5,7 +5,11 @@ - + + {{ loginInfo }} + {{ loginInfo }} + + {{ legalInfo }} {{ legalInfo }} @@ -32,6 +36,7 @@ export default { caption: config.values.siteCaption ? config.values.siteCaption : config.values.siteTitle, legalUrl: config.values.legalUrl, legalInfo: config.values.legalInfo, + loginInfo: config.values.loginInfo, config: config.values, rtl: this.$isRtl, }; diff --git a/frontend/src/options/themes.js b/frontend/src/options/themes.js index 4f3c9c930..166acd4a7 100644 --- a/frontend/src/options/themes.js +++ b/frontend/src/options/themes.js @@ -934,6 +934,15 @@ export const Set = (name, theme) => { themes[name] = theme; }; +// Assign adds or replaces multiple themes at once. +export const Assign = (t) => { + for (const theme of t) { + if (theme?.name && theme?.colors) { + Set(theme.name, theme); + } + } +}; + // Remove deletes a theme by name. export const Remove = (name) => { delete themes[name]; diff --git a/frontend/src/page/auth/login.vue b/frontend/src/page/auth/login.vue index 9961be344..0ae9e53be 100644 --- a/frontend/src/page/auth/login.vue +++ b/frontend/src/page/auth/login.vue @@ -131,7 +131,7 @@ zWeuT3_I&rG^?5z-^FH7Az2Eom_Z#NE&biKh&UMap>yn|q=Dxk0d#R|X_GxRW83Dg> zz(et61N!!lAK*s95zt0z8sB&UPxAb>WU@0_Qqsf2L&5_t;Y6~L zgrZOY4VWYh1_m&|u3nC0j3?O9^~iS$YIs*HiRerwIyr(U6fxFLZe)3WK+-K09GriU zb#(n^Cct2lo)~9Is04(f(pN-`8=&ns{=XsOJ&A;`m;lBPY-d|1vXiT=(_aw(0sf5z zU|c=D?U{U+#=+qS3s0rVf6ao8V>o!v0YjvKpfQ0$&`>BE4iSUE z(2#Gasw6ys_8k=}1%^VwFo+363Jrq*sNd)T;flkMG2hYto}v@U#L3D2dte)WcQ8m* zl@iEOAQ3$bmgq?F`cZxm5DREyJc)?0*LQQU#*+X&;BW{G0f9gfaM%`H7w_n*?MQF} z6hcTsK~RVk@Dm~lp?rQ~$n&dfzz|>n>fit(NFsDW+Qy(0#(F<7wABC#aG9SAe_{*) zm_nqbtub2|+71{S{12(N)|8!{Nluij*1>4wFH_HPqDARn$?^>gwvqUpc8d**lSd zP@xF^>$MS=)OA&o>~q~Q=eSc-tefe{E9 zB-k1bhXFYtg9U^lNFfM-lW~dg}~P^(03xb;*Ib)H|$oVe&1(G zv~dK=4PM#7$&JGHn+(RbfYUupzDn|K3D~UV1_=7|aU01rNqD^DuV`Nvwn0>}cfo2H&g?%H6*lr&HqtKN80kg$; z|2(jOq637rvoV>3ceEkf{xC9NOLrhJOq_rq_Hx~FrUu5|6~84mWt*xS$^Bb@rH2QS z$pILAw;Zqy&X&1!iH>*-X$!3SbsG9pmud`j;W!Klw++ho_85g!QHCmOC_|xAQfd%{ z3=ATTR8f(VQG-iMNuj=H`7haFj3>JRV<}|?ur|icp6t3sUJK(2z`o95^86+ww{N-u z%ao*+=l?}tWqV-8!g&E>gFTVbk$lCbTo6zuShUvHH1qm4!W-jVzJ0SNg1!!|Xw0{k z3bZFRGrU@XSb$q|et!9ZlEZ;NCifxs{M zS1epHzc3(f(^w-hcsK@$mjUA;NDLT3z{0`S(s(G?8bXkP5u{-_0%f$?641jI4~#s3 z?|w`$NHh$FMgZd{;_LXih34u+AX7#mWlF#EecfNuNuxp9jC)|S%D z0d|%AKT!+{k-;FO;9y`(044?qaLZzim4<<32nZ>H3=|lnP{2g^ZxoY3OQHUmV%tr^ z|G7p#T>f3EU*qAID4;m}r~B=k@iu>LrGFY>|AhA6hL#i@D}|Mk#(`l_EDVf5T4TT% zBoI4r87vBlK_QSBEHFI(5Awj@YJ?#m2*3vl#>yZdU<4KzMS=W*0u!(dUPc-&g}_?_ zb@g|Re!W?NpwMt2rnc^Cw$T12Sztgv^1quR|7k!`Lg;5eQAXy!EGPdop8f&pzcoG% zhXCe$0s#y|$^hX6R41@C0xktcL4jz3z^q{ey!8JZk}jxfr8?} zC^!~H`3BsxND)xLoyxyc=j+wq|F~EJqUUEQ{rjWopT^QZApQ5ox5lF|C~0Xhlz@{4 z5*fI~LL#Lgz?~9`0F_3;ka!eu5A@fG{QuVYf2$4@hKCT~P~a5<76wF+HJ$)Q0=G+G zDL4j(gF+Dm6ai?8|BX7o-XZ^wsY|~fM*mmq(mx>mx5od^t|tFK7+;d|zGtibl>BpN zy7jEK)qrYHTFkF6M9|x{i2rGH0dGjqz@71rTV%@JEe^Q5#r}uMM%fQcnE(9Vm~vcE zrl%ic$TqFF0z@1Hk^5>Ad*Y97Spg0M-owHEbzK@E4w91o*L5fiDGmaDYy&|7q@bv6 z_Q0g1047pWzwG(dHGh`;w`btO^FLSSpD@}Y{2Q;Yv*Uk<+jr8x@uOUv{dd@Xqx>5; zLsQDo`QPF9gZ4HY|7#xHV!DkVw*cQw{<8>Bz5%hneIopm*!i8oHah?JJiEpE8~v|Y z^verwz`0+SfVbw9uRmVb0}nr5_~RXcxsn9D&Sx~eZB0eB14;zmjs5wZ7!{RBTW(Z= zPMsl}Qd>mou%Q^Wi?io75s{K9tA=#2I`h3QzUJ=q6dmGzOUo|*;4}+bc8{9c=Ht$W z>pM4srNK8rbf0d(jN|nXkf_q8N)~552jqhPUFFw1GSS2yB{`}L%UMaK zqfHz8M2_}+Qud`Hv@QBV#;M>#OU)N%2*hND&apXS# zxVUVyHoyYby<*t-{v`y(Ou zH1-n=ZN%af9=_fgk3L$h*Qr>$@~FZj>;2{S$&t%rm+lJsAS7)>*Eyd??&zqu^vQd3 zzRM>v3~qY*s?wDOhFEPrDvRO0r_VY>(AYXm%7%5Mi)za1PZ#xpNj2ujVsT!T7j$=d z;rZ-QEpoi}_U-odH>ZO>@#nRLgm&wRBJXR{90F-2yMW$&G;fs0W>R}LMD#0Ms!P+p zgY15iAO6KON60DgCX=+(fv829NeOY8+{kLa?8j}wEiLGjODI;>+Dpms#T@knHrHFk z`S^Wutz;}^pct(*Fz3-U%f38p<03*I^VLUz@coaC!(&KBpfGr2$%ONwDCYM zL|CCm=!w9A7v|b2EN>O&?VD?G38f{Y(#&cv^q%_gHml7)9p%TbZc1L2sgT`WMZ3@a z7X5QBCWThMIgp3fw@cu+gTi-a^*^jQrj20t%i^$Lau`2X{o){P zs@={NsZ4qg$Z|&hASUNb)wEy1PG=f`>wY5X>}|)JaoFh_`jp5$qH-ki_;JCg+ur(C{(u@b94Fqqb;RJ2yYgu&D6 znKx(Jr|^p?9(wp8F|UP-JHv&?wLSgD?&U?b=Ydl3)_n1zc(!#>NC$mHShmm0&L-gq zo)@_@yShqxkLTZule&FOOZSNMW71(X6N8RXk)r0ox&-pcB9bzd65=wyNvX;%nx{d_ zU+C^Zf|S7-Yv&+p=OXOqOPp4Ej7%3NM9plv9=dl&&?HZyc%&0WNsv%#=7(H0D7eI`~Vo!IvSmPzvS|wPQ^RI>x~0X zV$2@X$$j7u3oS}gPG1(9jAz|(@$w^1y_v;vzW2N%IeDkpSY<>RE*EH-kx za3!5-yeio;VJUA^fwyS<(zm8n( z$=<{Ehpg1hN_o}>{Z~F;_Uo7VB=87g13IUxC^?|6A04%m<#=e(@dl}oy`7$khW=-Z zZmJ=ev!+>gZ(K>4syVDvbd78C%f#nT?D^}fb+UCK8tgF%t+Wwi17kr?vIk$K#$^-b zj~>4F)z83rlV7>DjTb$yrW8|x6QTOkto<~RWYSfcdvLU(Ilb#H`4ku-Hz-R#ox z`!x3Iwb9tkFEiQq_8-Ko3`;=mgcC$*lkc)JO3+?sps!Ww7hsl&uX#-V!r{DRWZPw^ zuCa-8^J;_V>d70k(|S9Va-1IY9#HVDOFrE*IyHj)6IiLD3H|cW>V_5eF$?fWvpPijOs%QR12KYVOyyDU_ylTYu9!EFZ z{>&`ea6xyVxo&!SKJVbMsnr)1LvQaLDa|#!CL+x(82hwkZnn_9Tkp9G;m8iwJ1aYT z4NGV{Xz{+0Je+68rUKb;T86p_y6rS$N?~%G>&36_MQ*atX%y@|*K8I8;k$LJqr3Ai z=zuRPd-BiADr$%fMdfk<(-|bad>&p1^bEFXTk>D!rA%h zSMwsmw1z(E_V<_J7Z=jIZDri&1{ddhTO!!=NfIIn2SAeCtbCbNR2kaAZ1+<-N3Mjl z(lRjS95lCA3Ji$8v!rwB4~c5yaRa;>DJ2tDVL?}%cNMg7xSw>nEdP0{EiUmB{IaQ= z*TjA1sV0O&SIl(dJqp(Dv^$ zZ%(;?BeRD!@uZRR8OFmyECTx;*C!MRO>71SPV}k9gx;LK4xN_lCG6du{Z7(0>u zkmX)V7V$=j%hJlgMtMa=KelIJVB_Wx{&nsEjqo1ru&meTZl@#>n&2UI`pu1{-6bC8 zQDbH7lBcf=c-eWA>`0FxdT}-vm`_eut(_?a9lPE^D8kCl`d!pX`*OdaQ*69ru4?Jy z{N)z$Hi7;7F->_&bTf*hRR_j=j!agZGNMu_lBr_XvvsMg5YA4(^ZXwGvI0q1S`R#`&1J+FK3Jb&r?%`r-YBWX;7R?WS|4 zxq`7c?NqjkWQk)zGa;hFg~2a#^nw#l3%M>1%Ubgri(L1~5!)#l?El6`nS+MAQDLP% zEy}^Mr;oSld`eYOTIMG@Xr2vg=zC(Z)9nH!)sdF8wdT)vjAti3AnpxWJJ*b&j+NL* zhPxNhvoA}~kmvRz9@l0u?+WvZ6JVp+PgwbEhsAm!!w*@%wA;+;>;uv9i|fbN%rXf1 z+={C2ynZ8+iY3;BnK~3W((8&mkuUcIV%SP$%Q5CI)X)7Fp36FID(XuJx<;2PBRI$i z(B@PzlV&J=N?W~DTyS0^f6Nuu?3BT<)Vt#PgRb4l(reMG&>){{G}NE#m9Z@7ar%cc zbev3GyKW4)4lgSa4UUExvh{H{hNMJ;#yH|IG|a1&_ja>L>1}jRX_Qv`kFBGI<`2cC zjn?&j7UX7Uj?}ZcHs;9ZcxpdQ%R-*z*^e8wOGo*{FJP%_^O6}Dc5%?ON9jo&6~2}o zF_Aa(VA?;et+b%FqGnwkeoMZ%?8M=z9kh47=ddS+I};i5+59x`e0jGXyYzHyj|#+! zL;UETo&ps`CC`(k$fyHShZ+O1iMaDGy=x(B+2geg`)4lpCnIUEeIA@+^t=)z8>+#9 z?SJpPJ{Zm8GhV8zXFx@_dmuTp_Z}$kY!&iVb}{GW<27voW^Y1N2o3b5`L9pM#>PC& z&K#Gq=+oq_TI`6>YusYcu5xR{VW)?>@)k! zD_VabqDDkUk^U>=_=6+8Mewa@@>oa|_Chj@!RchbK_bVE?n0Kn?!@9Z8_9wGPJn0bEz+~lPcPhV9y`si9 zj6;05kbSAc-SwQ`NY`XGuUSbOv&2qlZxv_cV~+a)_=1rR*&>-*(oJGWTrYVbc>jjmfs;K6!ejj@}m%r^^>F=lgAjOjKXm{BU;FhrMlM zop)nQ(M(+T882$|#;!ni;c?RDa{h+t$%yKe{u;X^zToRB0Z^QIWOE+c)v(GBt5Yfx-C1%wQtV_yf&ycPhr2LVLeKMhMAuGqa6AHrpPa)vugN;J9j6DVGm5* z{G_p)_7sV_q2Bc#B>V-47C92*gQXJUPe;%1G_;BtO-Z=T~oE%4qP%n&-QTl6#XgC+2+kz|C*}_FS7h&(4X>^-=J_ zc?=z#Sc`GZ)+Ns`8wk@BpW=P7(3;jJr+8c(CeF>M!B$v7x0n9QJnyD|T8jMqaz~Ql zW^~cD*o4)9TI<<%A6{{;k|iJiHeT84hsZNl8)19aQ)U*FUVeEiIrL`NaXmWu9L`lM z>^0NbW6ej)t5W+N1;T9c8U52`PYUPTu}lh;3xfH2CrcE9no8}Do(U*>z4)k!i;-Xa zS=;z{^rey(wv${Iejf5U$!`v{(Zsv;6Rh%HyyB#(%Mv|%^iEyKX^CU?uUmC*Pdyvk zw|Vj8!Odl+H+9ka>MX`uHp0TBI2)-c)lMj1R8T;kxJQ;~M)ncoy3F0$A#y!@=%XfEw7{#{9e}0#(ez361Ta3;x zc}z{;+MKcQ&1zS)dy%h2yve8cPhwZrgh(iBqI(7Q(w1<4)Sa$=_b@q?6T9R3pXp?b0{*Hs&muj%p56q}xsQq4M7*Na*Dhc^g9 zSI^I{#0S(;QN54N?N{_Uw7%NaT=T`^V;Ym5as&2`h%+faf5{De%|xH)S$I&Pc~9T1 z*{3u6+LW)c5(RgVcje}iF2ZfcuZ`u(ZGabn8|&0tiuGB5%g-nHt)t~sv{37Up&xwlkYc?*ftRF zW|~*|`TXY6bbhth$Msky%kv|BE1!-n=?%%GJ+*_y>hYjVlV#JxW5mL2+dIAe;J4W1 zWyKA`qPWf=&#pb5sF60lu`$L~6L)m}mgDK6L)?iid)VwxY@B`@*r8V5=Q#h^M1^_k zayKoz1k>7L!}H6RZ#hO8b1gFQ_)XCdt@PbSZY)pSwK!So1CHavyjfZ}UVJM4toJ*@ zH23;!X;iz}sodgc$32JJD|b}}?jdOtv*0+6*emx3?T?AqIGgPmW;PVcfM~~#Q7h4L z+LmD29f#z~7Dg{lNI2L_!0nq|PWO}wzL78q4|vp7ZJ8+hS+;srg(CrK!*FAKk?Y)~ zwj|xYsC0%ScNb-~u+^}Xxcz+ikffQCOCgJ)vUi!1y{BHr`+umNc3Ou#=WC_SJ6v@0 z6>%+T`Uom8KA#pIyR-2^%Sm_Xl28}sFV#bzE=Gg@;7YQIkBeF=se3m5bVGRDr++ZN z%6nXP2>qm4S+J`1gXrV1y4SWilTy>Q2K_RlOr=KXW^I9F2-|bsq>6<{Vz)|~_X`Er zG6r?sn);YQYn`S_m$<-9bwoIHBPxStN4B(h%Yt47)I#V<&`m=&^T1&GP_U+H7)_PM z$z0{O1IU+?i81$dU=eYO^Kz0Yd+j=|;Dz{vp>-d2o@_nF6v(e?g>PEvPFqs<>loDiB#x~nCaCBs`$>HM~VAbTf>i&T)mPi5#6 zr)wffz0f+fz}=J-QzEA7>>aZ~2s)OGU(L_h2_Sqa`ZOdyR}1gj@{` z;)zzJq3R)%!;}?H43B0r#JA;i$~ac_cHQlJC$DWdw7Gl+^ud*8klxvfuhGNRTH!tM zrWrr)ZHq-Y3#-KDLziO3xz#i~?Xv^S-9sVdir$^#W31v05I75b$F*m?PvZp-K8?Ko zT;Qcx&+~!uMT}q8jpM9|sW)^|td9%PJz)-E3x_E~!_(ULyryfwFsKC34(xc#(qhFw za$JvHQ2!ZgG<<)ix2OA!w{=~yZo1mAvmakCck3`ktXOeq4BzPwr?LDTiIKRf4Ly{! zQlAdilM%9kx5>%pY8eab-|W_{vb1oEeD%3bzciQYluw_z?F=g`TRW7W--hqW2xk-JgsU-=UB_B9g2T?yGN+g}>awE* z1tD}5688^lbS{|iC+@!%HBHM%x2L%H!@~OO<~80CW4pdUwAM5E)0y zWKLd82#=cREqS8h!l9weRtI6@Xz!Hc+?@c@N^wx-xFDk9qNUea%q^4h0h$q9SnSsS z(kV>$Xj1se{5)=1sKdU}(1z!wH6_f4mdBW!Vo4VZS8zg;5yJvP34DKaPBChz3g0Is z+UpF*qSse@YSILBjEtNYUyRX@eld~GNVh+SXfLk6AW79aB3ZRiyWYwsR_lNM4<#=I zL!WGNfO&s~RoG%hL< z?(Xh6Hr7hY?Yqlpt!M9X**%|&X7KSsWIZWr*T@y_8^@NOxiw9S^TGreun}(y2%M3+ zBLO4Gn@{go^CB$D9U1Dv+622CZCGInA!#$AdRPs%XZHI!B@TF1mU!j%az2~K_M75lkr^3-}{VH=)82M#mL`313 z8J)VEnBMiws#o|#XGfv8G`3zD`g{mK;iH0{(Bi`K)aeVR{Zp48_P#7ioE zT93Cjt{~576qiUB>Z-iFSonJKbY;TH*5g@2yf3G3U5?!sx7v7+e&BOSjGl|!UKInq zy)JBKgh=Pp13YxxX-$!!w`wsoZ1BpnO<-NzxP4Emi})RDW}KOe$kXFCFX4JE`%I{D z9LMQc>N-q}lK*JcHPI=!XnohRVq-9bE58AKi zwP!T~e6XHSGglTk@ha!sIcS_i#qBE_a~tE5#V0Saj$KkKh-uQtkwVDT56ehpNY_5j zF52R**5qi8PWw*(%ZRC{3gChuIZw=?n zfd7ocLY-2p!LZ9uaop_jM}{D3RvX*1%?GO=ah`sUsti^)|Da;cpci*QMG0i+DJY0F z8!&T>F6nrxW}A|{>94Ct{b{8Vv2d|8UXeV#IzF>VQaDTl&1%Z=F72;$@g(sipVm=V z@|{e{VD3}&nqk;=MdZLdE3qxt!V#wEHEc1oas%t~2_C|yyTA~o&Nu!Fawn+P!rOp% z5uT9vYWq7@aE#zWL>0Xwx+B0+Z|r%}h*RMhA)!)i%+53AhP#{1R^uZ)>@ zT}B&U!)sg9rb)$FJ^O&T#w`XGIMC2;%?{P)4xdbIf-j$|`IJvnT|`>kxxdBE3wq|J z0(m{dSaQ9j-^O3={JNOrm+l%V2Vm=)VQfqEAajJw(6_?yC zE^G9+NcD}pbjEImxlF{AXL6O~Gx|v-Mi2*?7pdjg$IPWH#Q45xQDkR3(~$wlemf#z z+&{=fk$mA*xHWG(gib{*4H;!Ur3nlxBnM-?EVZlMQ(Sb7ah*%P1=r8sxaDQWwVIUF z&wZ6{!S9ZYMsZhzei3wmTV`I*{Cd;Nj)*JA?v2<_eu;-Yxm4kc$V$(OI&aYY?1sjW z`{Di)>%A=0bSVZYfmL0c)1b*ccVu^~r^+`h8{cdDIJd5QVV03_z`T`38v5RT|4rRY z_^DDpk*w60X$;1hk*SS3sb)x&*V7lfy-WLg%k7vd!eJS`Iafni)B+lUF=|@oaUy$! zK0MPc2x1wUCD%djd_1Fjon8@@>byj&L~UtX+E;cHar_>6^#VDQPQdee{Iq?mo*=RSqx5rT1m%$(KFXUye>r5QdS6eH)G^u4kX?Y&=Wt^3uV6 zM>&&dBx@3_QnZW623%>0Bf4ZswsEqs8Kujyw`t+Ugmhl@!53a(Ubz*AX?O%^8cP3w z(}4`yl|~H<5Gm=$0a#Oj2`|&D4A`5hvih6MpicHKpf@8I=%!_i3I8+pd zqp@g5EdyU1)|e9({3_XRx#=1NmQ#G&K>zTg;0Lm9p(BLMEcK7a>QeUI@to|KPHj3Y z``J@B5W{iHJ*PjPrN?Dg+ePY55rw8it5BNj8pj_-L*M79C`Ob;rdi+44VS%h==Fpt zGv<#8*4=vCYvqFjG4u!On?j|_J6o%kNVG;%y?lYkbp?*U>6}dCDiu1l*fPm5hO|m3 zc)=?^xH)FbA0!th2e6vnL+4R|Jl)d@!EB z(P6+#X7YTP({ENVG>|#M{dfm%gi5-C*7qSZRlME3W$lu6^xzpG9<}PKMqw(txwpo% zw~p~!EhAxGO*wG67PAH_!#E9e-7s#9McklP>z(FRVQ38Es&dN6N|Zu?Kd&Z%!#MQ* z9;vd2WVu8Wa9wRATBy3q`zpzc;=X2poD3ikc z=)z06k8)hfavB$-kCJ8V1>JbiXf)omZeC0$~(Z4TiHRfE(Xg=}g&29IS39Bhe9cs75E zMPt!lyzshU!VwNFBeaE5SV9zU9Y!eWBGsaI)y%Eu!tU4972@@Z(N(5J*-ZU0_mB+% z_*Z9al!IS9MevoV#JUa#vhB+xvn$)pG+x1E$n3Yu+95 zduiwVX~jd2r3;SCF3>8zcA?#=?g;gw`tiZNe=+dz7Z#iGT>F$Gb}n-5NaQ^8S(E z>N32`OO}zrI^FqrTeRkG9R~j0#sg9PXo#QERf8+NQ?lBDiQ;16{1Mz~0!Dtqh62u> ze2R!&;mCpe+HZVpmpD|PHL`U3)MR3@!BFMT{;3O&9eo#DhkeQzXISskHs!mlM$Pux zoxeQ;fADSxIdms2U*Vc4r{CVrSxdGTvO_5!?=n&cIPB^S!sxP)nJZ-{daIthbD1QS z^S)4}iNm(Hw}XXW+4i0}5=WC@dY=o_Q#7H&aB1g~OrJCpPcw;o_q7}4k)E5IjfWqP z-L%PSS(TRS4QBr&M5am8Nfk+CaxfyaqD%V|l%GscX>_#2N>?_nro0u1ZhFM>X8aww z#N+anW7;RL#0+Q_O6Wai#AGzU^*QOAEjzf*Yf6B@I*;GktTGlyD{ju5Kesr+blN|* zrfz9y6I1-|%VNI&7w_}Fc@y!s-1wZWF}pmjik&;q{iJZl0<-V^WTfGT!o&5ZC^OWq zH>=hc*LfI|4b<+&q;~}x`LL`#^0|aOo*A&Y9+_KsxhIKsBHrwsOwHQ-sk7DOvb&z6 zY^A%YCJXs4(hi>^@GB;?YBVTZxt+|Ie{Xnr>T-*NDz*7XvqynPV`WED1bZ)Uh(CK5 z_Rhy5Eas}wN7nr#GHmV9T3fQuO~aBBDCt&wssqinIR&X=twU68i_| zjMC*R)^jY6t-I$C!kOa8J**|Wt*#gC(tG7k&2v}Jy_oTq@ls+<(vi#5?fFZqM!t8) z+)p&0sJP}Ymw^5(nCE}leb{XF)NB9MwRCUG;+S^>ovPEGtV(b?v&+9$SWpK7BZ1dc5`amPhDgr(=KJ@p=t6?@v>Bi#C~C%wV1 z;~~Sf-MQnK<;dXvq(hjiQR{sQ)V(ZGk045X5_A0a@vIxW%&zC$b@1roa3DnlY3qeu zSn3`lDum*8nP_VHsA47 zIjlXW)}aTschN`y$liN~a7j=by@Y@hPif($RBqEp5seYmE0O<8HgC z)tT0uou5fRBPi8c#=j?$>0{3YkI&`qGCI#K_7$r&d%PK&#d~G%4i0+y@IR^nzgL5e0I@0MKqkmw{ZXcEW)0+XVNtPrhAjzbjJKgf8-=YaN5Sr zvEC+b@!m}Tjk~jF4*HUU8Flx{Ex&i{EaMJ|P3qtplS>Zf4E7AzdE*O)P?asZw@hK? z+Dv3hC3SXex$@oS_P29UbD+u+qY+c=K2&+-i}1K4O|H0u7R0!EmjNc5+og{W4~s8A z={4?)h(4Her#D-JT0qH)R&Jg7mM!gXM2klyVk4)ucZoY@QyKFX3%uV6z4QUZr$m~{ z4)f?0wW4}t+>R~xU4F@rtT zv{OAXbs&yMn8~sLv*)24e0{pm`Yoo4# z#wA!O=#OCdSOxtr;haj% literal 0 HcmV?d00001 diff --git a/internal/config/report.go b/internal/config/report.go index f014feda6..ea8f16e67 100644 --- a/internal/config/report.go +++ b/internal/config/report.go @@ -28,6 +28,7 @@ func (c *Config) Report() (rows [][]string, cols []string) { {"password-reset-uri", c.PasswordResetUri()}, {"register-uri", c.RegisterUri()}, {"login-uri", c.LoginUri()}, + {"login-info", c.LoginInfo()}, {"session-maxage", fmt.Sprintf("%d", c.SessionMaxAge())}, {"session-timeout", fmt.Sprintf("%d", c.SessionTimeout())}, {"session-cache", fmt.Sprintf("%d", c.SessionCache())}, @@ -154,6 +155,7 @@ func (c *Config) Report() (rows [][]string, cols []string) { {"site-title", c.SiteTitle()}, {"site-caption", c.SiteCaption()}, {"site-description", c.SiteDescription()}, + {"site-favicon", c.SiteFavicon()}, {"site-preview", c.SitePreview()}, // CDN and Cross-Origin Resource Sharing (CORS). @@ -246,7 +248,6 @@ func (c *Config) Report() (rows [][]string, cols []string) { {"vision-api", fmt.Sprintf("%t", c.VisionApi())}, {"vision-uri", c.VisionUri()}, {"vision-key", strings.Repeat("*", utf8.RuneCountInString(c.VisionKey()))}, - {"tensorflow-version", c.TensorFlowVersion()}, {"nasnet-model-path", c.NasnetModelPath()}, {"facenet-model-path", c.FaceNetModelPath()}, {"nsfw-model-path", c.NSFWModelPath()}, diff --git a/internal/server/routes_static.go b/internal/server/routes_static.go index ef7d4b7e3..764ff1919 100644 --- a/internal/server/routes_static.go +++ b/internal/server/routes_static.go @@ -2,7 +2,6 @@ package server import ( "net/http" - "path/filepath" "github.com/gin-gonic/gin" @@ -42,7 +41,7 @@ func registerStaticRoutes(router *gin.Engine, conf *config.Config) { router.NoRoute(api.AbortNotFound) // Serves static favicon. - router.StaticFile(conf.BaseUri("/favicon.ico"), filepath.Join(conf.ImgPath(), "favicon.ico")) + router.StaticFile(conf.BaseUri("/favicon.ico"), conf.SiteFavicon()) // Serves static assets like js, css and font files. if dir := conf.StaticPath(); dir != "" { diff --git a/internal/thumb/fileinfo.go b/internal/thumb/fileinfo.go new file mode 100644 index 000000000..6e9e65e58 --- /dev/null +++ b/internal/thumb/fileinfo.go @@ -0,0 +1,56 @@ +package thumb + +import ( + "fmt" + "image" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "os" + "runtime/debug" + + _ "golang.org/x/image/bmp" + _ "golang.org/x/image/webp" + + "github.com/photoprism/photoprism/pkg/clean" + "github.com/photoprism/photoprism/pkg/fs" +) + +// FileInfo returns the image header info containing width and height. +func FileInfo(fileName string) (info image.Config, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("panic %s while decoding %s file info\nstack: %s", r, clean.Log(fileName), debug.Stack()) + } + }() + + // Resolve symlinks. + if fileName, err = fs.Resolve(fileName); err != nil { + return info, err + } + + file, err := os.Open(fileName) + + if err != nil || file == nil { + return info, err + } + + defer file.Close() + + // Reset file offset. + // see https://github.com/golang/go/issues/45902#issuecomment-1007953723 + _, err = file.Seek(0, 0) + + if err != nil { + return info, fmt.Errorf("%s on seek", err) + } + + // Decode image config (dimensions). + info, _, err = image.DecodeConfig(file) + + if err != nil { + return info, fmt.Errorf("%s while decoding file info", err) + } + + return info, err +} diff --git a/internal/thumb/fileinfo_test.go b/internal/thumb/fileinfo_test.go new file mode 100644 index 000000000..89e1afbea --- /dev/null +++ b/internal/thumb/fileinfo_test.go @@ -0,0 +1,62 @@ +package thumb + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/photoprism/photoprism/pkg/fs" +) + +func TestFileInfo(t *testing.T) { + t.Run("Jpeg", func(t *testing.T) { + fileName := fs.Abs("./testdata/example.jpg") + + if fileInfo, err := FileInfo(fileName); err != nil { + t.Fatal(err) + } else { + assert.Equal(t, 750, fileInfo.Width) + assert.Equal(t, 500, fileInfo.Height) + } + }) + t.Run("BrokenJpeg", func(t *testing.T) { + fileName := fs.Abs("./testdata/broken.jpg") + + if fileInfo, err := FileInfo(fileName); err != nil { + t.Fatal(err) + } else { + assert.Equal(t, 705, fileInfo.Width) + assert.Equal(t, 725, fileInfo.Height) + } + }) + t.Run("Png", func(t *testing.T) { + fileName := fs.Abs("./testdata/example.png") + + if fileInfo, err := FileInfo(fileName); err != nil { + t.Fatal(err) + } else { + assert.Equal(t, 100, fileInfo.Width) + assert.Equal(t, 67, fileInfo.Height) + } + }) + t.Run("Bmp", func(t *testing.T) { + fileName := fs.Abs("./testdata/example.bmp") + + if fileInfo, err := FileInfo(fileName); err != nil { + t.Fatal(err) + } else { + assert.Equal(t, 100, fileInfo.Width) + assert.Equal(t, 67, fileInfo.Height) + } + }) + t.Run("Gif", func(t *testing.T) { + fileName := fs.Abs("./testdata/example.bmp") + + if fileInfo, err := FileInfo(fileName); err != nil { + t.Fatal(err) + } else { + assert.Equal(t, 100, fileInfo.Width) + assert.Equal(t, 67, fileInfo.Height) + } + }) +}