about summary refs log tree commit diff
path: root/bundles/immich/files
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2025-09-07 17:32:13 +0200
committerRobert Günzler <r@gnzler.io>2025-09-07 17:42:42 +0200
commit38be6c13f76e893cf47636257071b440dec0c5b2 (patch)
treef7ded3235a7e3362cbd1ed3d91523968fe0faf90 /bundles/immich/files
initial commit
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'bundles/immich/files')
-rwxr-xr-xbundles/immich/files/immich-api-tool49
-rw-r--r--bundles/immich/files/immich.yaml27
-rw-r--r--bundles/immich/files/kube.yaml104
-rw-r--r--bundles/immich/files/secret.yaml12
4 files changed, 192 insertions, 0 deletions
diff --git a/bundles/immich/files/immich-api-tool b/bundles/immich/files/immich-api-tool
new file mode 100755
index 0000000..d0a1a41
--- /dev/null
+++ b/bundles/immich/files/immich-api-tool
@@ -0,0 +1,49 @@
+#!/bin/sh
+set -eu
+
+API_URL=https://photos.gzr.im/api
+API_KEY=zaJUJGHpFqY9OA6kAhuauTj9tC1YVfA8umtZc6ls8U
+
+request() {
+  ENDPOINT=${1:?}
+  shift 1
+
+  curl -sSfL "${API_URL}${ENDPOINT}" \
+    -H "x-api-key: $API_KEY" \
+    -H 'Content-Type: application/json' \
+    "$@"
+}
+
+validateAccessToken() {
+  request '/auth/validateToken' -X POST >/dev/null
+}
+
+# returns full json response
+searchFavorites() {
+  request '/search/metadata' \
+    -H 'Accept: application/json' \
+    -d '{"isFavorite": true}'
+}
+
+# requires '{"assetIds":["list","of","ids",...]}' on stdin
+# downloads to PWD
+downloadArchive() {
+  request '/download/archive' \
+    -H 'Accept: application/octet-stream' \
+    -d @- \
+    -o "archive.zip" \
+    --no-silent
+}
+
+main() {
+  validateAccessToken || exit 1
+
+  # download favorites as archive
+  searchFavorites |
+    jq '[.assets.items[].id] | {assetIds:.}' -rc |
+    downloadArchive
+}
+
+test -n "${DEBUG:-}" && set -x
+main
+exit 0
diff --git a/bundles/immich/files/immich.yaml b/bundles/immich/files/immich.yaml
new file mode 100644
index 0000000..fd2454a
--- /dev/null
+++ b/bundles/immich/files/immich.yaml
@@ -0,0 +1,27 @@
+storageTemplate:
+  enabled: false
+  hashVerificationEnabled: true
+  template: '{{y}}/{{MM}}-{{MMM}}/{{filetype}}_{{y}}{{MM}}{{dd}}_{{HH}}{{mm}}{{ss}}.{{ext}}'
+
+machineLearning:
+  enabled: false
+  # url:
+
+passwordLogin:
+  enabled: false
+oauth:
+  enabled: true
+  autoLaunch: true
+  autoRegister: true
+  clientId: immich
+  clientSecret: '${repo.vault.password_for("authelia_client_secret_immich")}'
+  issuerUrl: https://login.gzr.im/.well-known/openid-configuration
+  # scope: 'openid email profile'
+  # profileSigningAlgorithm: none
+  # defaultStorageQuota: 0
+  # signingAlgorithm: RS256
+  # storageLabelClaim: preferred_username
+  # storageQuotaClaim: immich_quota
+  buttonText: 'Login with SSO'
+  # mobileOverrideEnabled: false
+  # mobileRedirectUri: https://photos.gzr.im/api/oauth/mobile-redirect
diff --git a/bundles/immich/files/kube.yaml b/bundles/immich/files/kube.yaml
new file mode 100644
index 0000000..523c073
--- /dev/null
+++ b/bundles/immich/files/kube.yaml
@@ -0,0 +1,104 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: immich
+  labels:
+    traefik.enable: true
+    traefik.http.routers.immich.tls: true
+    traefik.http.routers.immich.tls.certresolver: le
+    traefik.http.routers.immich.entrypoints: http,https
+    traefik.http.routers.immich.rule: Host(`photos.gzr.im`)
+    traefik.http.routers.immich.service: immich
+    traefik.http.services.immich.loadbalancer.server.port: 2283
+
+    # TODO: https://immich.app/docs/features/monitoring
+    #       https://github.com/immich-app/immich/blob/v1.121.0/docker/prometheus.yml
+    #
+    # metrics
+    # traefik.http.routers.immich-metrics.entrypoints: metrics
+    # traefik.http.routers.immich-metrics.rule: Path(`/metrics/immich`)
+    # traefik.http.routers.immich-metrics.middlewares: replacepath-metrics
+spec:
+  restartPolicy: Always
+  dnsPolicy: Default
+  containers:
+    - name: immich
+      image: ghcr.io/immich-app/immich-server:v1.140.1
+      envFrom:
+        - secretRef:
+            name: immich
+      env:
+        - name: IMMICH_CONFIG_FILE
+          value: /immich.yaml
+      ports:
+        - containerPort: 2283
+          protocol: TCP
+          # NOTE: required to make tv app work
+          hostPort: 2283
+      volumeMounts:
+        - name: config
+          mountPath: /immich.yaml
+        - name: data
+          mountPath: /usr/src/app/upload
+        - name: media
+          mountPath: /media
+          readOnly: true
+      # resources:
+      #   limits:
+      #     cpu: 300m
+      #     memory: 512Mi
+    - name: redis
+      image: docker.io/redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8
+      livenessProbe:
+        exec:
+          command: ["sh", "-c", "redis-cli ping || exit 1"]
+    - name: postgres
+      image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
+      envFrom:
+        - secretRef:
+            name: immich
+      env:
+        - name: POSTGRES_INITDB_ARGS
+          value: --data-checksums
+      volumeMounts:
+        - name: pg-data
+          mountPath: /var/lib/postgresql/data
+      livenessProbe:
+        exec:
+          command:
+            - /bin/sh
+            - -c
+            - pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1
+            # ; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
+      command:
+        - docker-entrypoint.sh
+        - -c
+        - shared_preload_libraries=vectors.so
+        - -c
+        - search_path="$$user", public, vectors
+        - -c
+        - logging_collector=on
+        - -c
+        - max_wal_size=2GB
+        - -c
+        - shared_buffers=512MB
+        - -c
+        - wal_compression=on
+
+  volumes:
+    - name: config
+      hostPath:
+        path: /var/lib/immich/immich.yaml
+        type: File
+    - name: data
+      hostPath:
+        path: /var/lib/immich/app
+        type: DirectoryOrCreate
+    - name: pg-data
+      hostPath:
+        path: /var/lib/immich/db
+        type: DirectoryOrCreate
+    - name: media
+      hostPath:
+        path: /media/hayasui/media
+        type: Directory
diff --git a/bundles/immich/files/secret.yaml b/bundles/immich/files/secret.yaml
new file mode 100644
index 0000000..daf0f4f
--- /dev/null
+++ b/bundles/immich/files/secret.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Secret
+metadata:
+    name: immich
+data:
+    DB_USERNAME: ${repo.libs.util.base64("immich")}
+    POSTGRES_USER: ${repo.libs.util.base64("immich")}
+    DB_PASSWORD: ${repo.vault.password_for("immich_db_pw").b64encode().value}
+    POSTGRES_PASSWORD: ${repo.vault.password_for("immich_db_pw").b64encode().value}
+    DB_DATABASE_NAME: ${repo.libs.util.base64("immich")}
+    POSTGRES_DB: ${repo.libs.util.base64("immich")}
+    DB_HOSTNAME: ${repo.libs.util.base64(f"localhost")}