| gio | 404e237 | 2025-07-11 12:50:26 +0400 | [diff] [blame] | 1 | import ( |
| 2 | "encoding/yaml" |
| 3 | "encoding/json" |
| 4 | ) |
| 5 | |
| 6 | input: { |
| 7 | network: #Network @name(Network) |
| 8 | subdomain: string @name(Subdomain) |
| 9 | mapEnabled: bool | *false @name(Map) |
| 10 | storageSize: string | *"10Gi" @name(Storage Size) |
| 11 | } |
| 12 | |
| 13 | _domain: "\(input.subdomain).\(input.network.domain)" |
| 14 | url: "https://\(_domain)" |
| 15 | |
| 16 | name: "Immich" |
| 17 | namespace: "app-immich" |
| 18 | readme: "Self-hosted photo and video management solution" |
| 19 | description: "Easily back up, organize, and manage your photos on your own server. Immich helps you browse, search and organize your photos and videos with ease, without sacrificing your privacy." |
| 20 | icon: """ |
| 21 | <svg width='50px' height='50px' version="1.1" id="Flower" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" |
| 22 | viewBox="0 0 792 792" style="enable-background:new 0 0 792 792;" xml:space="preserve"> |
| 23 | <style type="text/css"> |
| 24 | .st0{fill:#FA2921;} |
| 25 | .st1{fill:#ED79B5;} |
| 26 | .st2{fill:#FFB400;} |
| 27 | .st3{fill:#1E83F7;} |
| 28 | .st4{fill:#18C249;} |
| 29 | </style> |
| 30 | <g id="Flower_00000077325900055813483940000000694823054982625702_"> |
| 31 | <path class="st0" d="M375.48,267.63c38.64,34.21,69.78,70.87,89.82,105.42c34.42-61.56,57.42-134.71,57.71-181.3 |
| 32 | c0-0.33,0-0.63,0-0.91c0-68.94-68.77-95.77-128.01-95.77s-128.01,26.83-128.01,95.77c0,0.94,0,2.2,0,3.72 |
| 33 | C300.01,209.24,339.15,235.47,375.48,267.63z"/> |
| 34 | <path class="st1" d="M164.7,455.63c24.15-26.87,61.2-55.99,103.01-80.61c44.48-26.18,88.97-44.47,128.02-52.84 |
| 35 | c-47.91-51.76-110.37-96.24-154.6-110.91c-0.31-0.1-0.6-0.19-0.86-0.28c-65.57-21.3-112.34,35.81-130.64,92.15 |
| 36 | c-18.3,56.34-14.04,130.04,51.53,151.34C162.05,454.77,163.25,455.16,164.7,455.63z"/> |
| 37 | <path class="st2" d="M681.07,302.19c-18.3-56.34-65.07-113.45-130.64-92.15c-0.9,0.29-2.1,0.68-3.54,1.15 |
| 38 | c-3.75,35.93-16.6,81.27-35.96,125.76c-20.59,47.32-45.84,88.27-72.51,118c69.18,13.72,145.86,12.98,190.26-1.14 |
| 39 | c0.31-0.1,0.6-0.2,0.86-0.28C695.11,432.22,699.37,358.52,681.07,302.19z"/> |
| 40 | <path class="st3" d="M336.54,510.71c-11.15-50.39-14.8-98.36-10.7-138.08c-64.03,29.57-125.63,75.23-153.26,112.76 |
| 41 | c-0.19,0.26-0.37,0.51-0.53,0.73c-40.52,55.78-0.66,117.91,47.27,152.72c47.92,34.82,119.33,53.54,159.86-2.24 |
| 42 | c0.56-0.76,1.3-1.78,2.19-3.01C363.28,602.32,347.02,558.08,336.54,510.71z"/> |
| 43 | <path class="st4" d="M617.57,482.52c-35.33,7.54-82.42,9.33-130.72,4.66c-51.37-4.96-98.11-16.32-134.63-32.5 |
| 44 | c8.33,70.03,32.73,142.73,59.88,180.6c0.19,0.26,0.37,0.51,0.53,0.73c40.52,55.78,111.93,37.06,159.86,2.24 |
| 45 | c47.92-34.82,87.79-96.95,47.27-152.72C619.2,484.77,618.46,483.75,617.57,482.52z"/> |
| 46 | </g> |
| 47 | </svg>""" |
| 48 | |
| 49 | out: { |
| 50 | ingress: { |
| 51 | immich: { |
| 52 | auth: enabled: false |
| 53 | network: input.network |
| 54 | subdomain: input.subdomain |
| 55 | service: { |
| 56 | name: "immich-server" |
| 57 | port: _httpPort |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | // TODO(gio): configure busybox |
| 63 | images: { |
| 64 | immich: { |
| 65 | registry: "ghcr.io" |
| 66 | repository: "immich-app" |
| 67 | name: "immich-server" |
| 68 | tag: "v1.135.3" |
| 69 | pullPolicy: "IfNotPresent" |
| 70 | } |
| 71 | ml: { |
| 72 | registry: "ghcr.io" |
| 73 | repository: "immich-app" |
| 74 | name: "immich-machine-learning" |
| 75 | tag: "v1.135.3" |
| 76 | pullPolicy: "IfNotPresent" |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | charts: { |
| 81 | immich: { |
| 82 | kind: "GitRepository" |
| 83 | address: "https://code.v1.dodo.cloud/helm-charts" |
| 84 | branch: "main" |
| 85 | path: "charts/immich" |
| 86 | } |
| 87 | oauth2Client: { |
| 88 | kind: "GitRepository" |
| 89 | address: "https://code.v1.dodo.cloud/helm-charts" |
| 90 | branch: "main" |
| 91 | path: "charts/oauth2-client" |
| 92 | } |
| 93 | resourceRenderer: { |
| 94 | kind: "GitRepository" |
| 95 | address: "https://code.v1.dodo.cloud/helm-charts" |
| 96 | branch: "main" |
| 97 | path: "charts/resource-renderer" |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | volume: immich: size: input.storageSize |
| 102 | |
| 103 | _httpPort: 2283 |
| 104 | _oauth2ClientSecretName: "oauth2-client" |
| 105 | |
| 106 | helm: { |
| 107 | "oauth2-client": { |
| 108 | chart: charts.oauth2Client |
| 109 | info: "Creating OAuth2 client" |
| 110 | // TODO(gio): remove once hydra maester is installed as part of dodo itself |
| 111 | dependsOn: [{ |
| 112 | name: "auth" |
| 113 | namespace: "\(global.namespacePrefix)core-auth" |
| 114 | }] |
| 115 | values: { |
| 116 | name: "\(release.namespace)-immich" |
| 117 | secretName: _oauth2ClientSecretName |
| 118 | grantTypes: ["authorization_code"] |
| 119 | responseTypes: ["code"] |
| 120 | scope: "openid profile email groups" |
| 121 | redirectUris: [ |
| 122 | "app.immich:///oauth-callback", |
| 123 | "https://\(_domain)/auth/login", |
| 124 | "https://\(_domain)/user-settings", |
| 125 | ] |
| 126 | tokenEndpointAuthMethod: "client_secret_post" |
| 127 | hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local" |
| 128 | } |
| 129 | } |
| 130 | "config-renderer": { |
| 131 | chart: charts.resourceRenderer |
| 132 | info: "Generating Immich configuration" |
| 133 | values: { |
| 134 | name: "config-renderer" |
| 135 | secretName: _oauth2ClientSecretName |
| 136 | resourceTemplate: yaml.Marshal({ |
| 137 | apiVersion: "v1" |
| 138 | kind: "ConfigMap" |
| 139 | metadata: { |
| 140 | name: _immichConfigMapName |
| 141 | namespace: "\(release.namespace)" |
| 142 | } |
| 143 | data: { |
| 144 | "immich-config.json": json.Marshal({ |
| 145 | { |
| 146 | "ffmpeg": { |
| 147 | "crf": 23 |
| 148 | "threads": 0 |
| 149 | "preset": "ultrafast" |
| 150 | "targetVideoCodec": "h264" |
| 151 | "acceptedVideoCodecs": ["h264"] |
| 152 | "targetAudioCodec": "aac" |
| 153 | "acceptedAudioCodecs": ["aac", "mp3", "libopus", "pcm_s16le"] |
| 154 | "acceptedContainers": ["mov", "ogg", "webm"] |
| 155 | "targetResolution": "720" |
| 156 | "maxBitrate": "0" |
| 157 | "bframes": -1 |
| 158 | "refs": 0 |
| 159 | "gopSize": 0 |
| 160 | "temporalAQ": false |
| 161 | "cqMode": "auto" |
| 162 | "twoPass": false |
| 163 | "preferredHwDevice": "auto" |
| 164 | "transcode": "required" |
| 165 | "tonemap": "hable" |
| 166 | "accel": "disabled" |
| 167 | "accelDecode": false |
| 168 | } |
| 169 | "backup": { |
| 170 | "database": { |
| 171 | "enabled": true |
| 172 | "cronExpression": "0 02 * * *" |
| 173 | "keepLastAmount": 14 |
| 174 | } |
| 175 | } |
| 176 | "job": { |
| 177 | "backgroundTask": { |
| 178 | "concurrency": 5 |
| 179 | } |
| 180 | "smartSearch": { |
| 181 | "concurrency": 2 |
| 182 | } |
| 183 | "metadataExtraction": { |
| 184 | "concurrency": 5 |
| 185 | } |
| 186 | "faceDetection": { |
| 187 | "concurrency": 2 |
| 188 | } |
| 189 | "search": { |
| 190 | "concurrency": 5 |
| 191 | } |
| 192 | "sidecar": { |
| 193 | "concurrency": 5 |
| 194 | } |
| 195 | "library": { |
| 196 | "concurrency": 5 |
| 197 | } |
| 198 | "migration": { |
| 199 | "concurrency": 5 |
| 200 | } |
| 201 | "thumbnailGeneration": { |
| 202 | "concurrency": 3 |
| 203 | } |
| 204 | "videoConversion": { |
| 205 | "concurrency": 1 |
| 206 | } |
| 207 | "notifications": { |
| 208 | "concurrency": 5 |
| 209 | } |
| 210 | } |
| 211 | "logging": { |
| 212 | "enabled": true |
| 213 | "level": "log" |
| 214 | } |
| 215 | "machineLearning": { |
| 216 | "enabled": true |
| 217 | "urls": ["http://immich-machine-learning:3003"] |
| 218 | "clip": { |
| 219 | "enabled": true |
| 220 | "modelName": "ViT-B-32__openai" |
| 221 | } |
| 222 | "duplicateDetection": { |
| 223 | "enabled": true |
| 224 | "maxDistance": 0.01 |
| 225 | } |
| 226 | "facialRecognition": { |
| 227 | "enabled": true |
| 228 | "modelName": "buffalo_l" |
| 229 | "minScore": 0.7 |
| 230 | "maxDistance": 0.5 |
| 231 | "minFaces": 3 |
| 232 | } |
| 233 | } |
| 234 | "map": { |
| 235 | "enabled": input.mapEnabled |
| 236 | "lightStyle": "https://tiles.immich.cloud/v1/style/light.json" |
| 237 | "darkStyle": "https://tiles.immich.cloud/v1/style/dark.json" |
| 238 | } |
| 239 | "reverseGeocoding": { |
| 240 | "enabled": true |
| 241 | } |
| 242 | "metadata": { |
| 243 | "faces": { |
| 244 | "import": false |
| 245 | } |
| 246 | } |
| 247 | "oauth": { |
| 248 | "autoLaunch": true |
| 249 | "autoRegister": true |
| 250 | "buttonText": "Login with dodo" |
| 251 | "clientId": "{{ .client_id }}" |
| 252 | "clientSecret": "{{ .client_secret }}" |
| 253 | "defaultStorageQuota": null |
| 254 | "enabled": true |
| 255 | "issuerUrl": "https://hydra.\(networks.public.domain)" |
| 256 | "mobileOverrideEnabled": false |
| 257 | "mobileRedirectUri": "" |
| 258 | "scope": "openid email profile" |
| 259 | "signingAlgorithm": "RS256" |
| 260 | "profileSigningAlgorithm": "none" |
| 261 | "storageLabelClaim": "preferred_username" |
| 262 | "storageQuotaClaim": "immich_quota" |
| 263 | } |
| 264 | "passwordLogin": { |
| 265 | "enabled": false |
| 266 | } |
| 267 | "storageTemplate": { |
| 268 | "enabled": false |
| 269 | "hashVerificationEnabled": true |
| 270 | "template": "{{`{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}`}}" |
| 271 | } |
| 272 | "image": { |
| 273 | "thumbnail": { |
| 274 | "format": "webp" |
| 275 | "size": 250 |
| 276 | "quality": 80 |
| 277 | } |
| 278 | "preview": { |
| 279 | "format": "jpeg" |
| 280 | "size": 1440 |
| 281 | "quality": 80 |
| 282 | } |
| 283 | "colorspace": "p3" |
| 284 | "extractEmbedded": false |
| 285 | } |
| 286 | "newVersionCheck": { |
| 287 | "enabled": true |
| 288 | } |
| 289 | "trash": { |
| 290 | "enabled": true |
| 291 | "days": 30 |
| 292 | } |
| 293 | "theme": { |
| 294 | "customCss": "" |
| 295 | } |
| 296 | "library": { |
| 297 | "scan": { |
| 298 | "enabled": true |
| 299 | "cronExpression": "0 0 * * *" |
| 300 | } |
| 301 | "watch": { |
| 302 | "enabled": false |
| 303 | } |
| 304 | } |
| 305 | "server": { |
| 306 | "externalDomain": "https://\(_domain)" |
| 307 | "loginPageMessage": "" |
| 308 | } |
| 309 | "notifications": { |
| 310 | "smtp": { |
| 311 | "enabled": false |
| 312 | "from": "" |
| 313 | "replyTo": "" |
| 314 | "transport": { |
| 315 | "ignoreCert": false |
| 316 | "host": "" |
| 317 | "port": 587 |
| 318 | "username": "" |
| 319 | "password": "" |
| 320 | } |
| 321 | } |
| 322 | } |
| 323 | "user": { |
| 324 | "deleteDelay": 7 |
| 325 | } |
| 326 | }}) |
| 327 | } |
| 328 | }) |
| 329 | } |
| 330 | } |
| 331 | immich: { |
| 332 | chart: charts.immich |
| 333 | info: "Installing Immich server" |
| 334 | values: { |
| 335 | image: tag: "v1.135.3" |
| 336 | immich: existingConfiguration: _immichConfigMapName |
| 337 | persistence: library: existingClaim: "immich" |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | _immichConfigMapName: "immich-config" |