mirror of
https://github.com/immich-app/immich.git
synced 2024-09-21 10:37:20 +00:00
Merge branch 'main' into chore/backup-wakelock
This commit is contained in:
commit
59a0747ffb
9
.github/ISSUE_TEMPLATE/config.yml
vendored
9
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,11 +1,14 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: I have a question or need support
|
||||
- name: ✋ I have a question or need support
|
||||
url: https://discord.immich.app
|
||||
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
|
||||
- name: Feature Request
|
||||
- name: 📷 My photo or video has a date, time, or timezone problem
|
||||
url: https://github.com/immich-app/immich/discussions/12650
|
||||
about: Upload a sample file to this discussion and we will take a look
|
||||
- name: 🌟 Feature request
|
||||
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
||||
about: Please use our GitHub Discussion for making feature requests.
|
||||
- name: I'm unsure where to go
|
||||
- name: 🫣 I'm unsure where to go
|
||||
url: https://discord.immich.app
|
||||
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!
|
||||
|
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
@ -5,8 +5,8 @@
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"restart": true,
|
||||
"port": 9230,
|
||||
"name": "Immich Server",
|
||||
"port": 9231,
|
||||
"name": "Immich API Server",
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"localRoot": "${workspaceFolder}/server"
|
||||
},
|
||||
@ -14,8 +14,8 @@
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"restart": true,
|
||||
"port": 9231,
|
||||
"name": "Immich Microservices",
|
||||
"port": 9230,
|
||||
"name": "Immich Workers",
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"localRoot": "${workspaceFolder}/server"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM node:20.17.0-alpine3.20@sha256:1a526b97cace6b4006256570efa1a29cd1fe4b96a5301f8d48e87c5139438a45 AS core
|
||||
FROM node:20.17.0-alpine3.20@sha256:2d07db07a2df6830718ae2a47db6fedce6745f5bcd174c398f2acdda90a11c03 AS core
|
||||
|
||||
WORKDIR /usr/src/open-api/typescript-sdk
|
||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||
|
47
cli/package-lock.json
generated
47
cli/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.18",
|
||||
"version": "2.2.19",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.18",
|
||||
"version": "2.2.19",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"fast-glob": "^3.3.2",
|
||||
@ -24,7 +24,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
@ -52,14 +52,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -1324,9 +1324,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.3.tgz",
|
||||
"integrity": "sha512-/wdGiWRkMOm53gAsSyFMXFZHbVg7C6CbkrzHNpaHoYfsUWPg7m6ZRKtvQjgvQ9i8WT540a3ydRlRQbxjY30XxQ==",
|
||||
"version": "20.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
|
||||
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3409,9 +3409,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
||||
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@ -3436,9 +3436,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.41",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
|
||||
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
|
||||
"version": "8.4.47",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -3457,8 +3457,8 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.7",
|
||||
"picocolors": "^1.0.1",
|
||||
"source-map-js": "^1.2.0"
|
||||
"picocolors": "^1.1.0",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
@ -3827,10 +3827,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@ -4210,14 +4211,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz",
|
||||
"integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==",
|
||||
"version": "5.4.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz",
|
||||
"integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.41",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.18",
|
||||
"version": "2.2.19",
|
||||
"description": "Command Line Interface (CLI) for Immich",
|
||||
"type": "module",
|
||||
"exports": "./dist/index.js",
|
||||
@ -20,7 +20,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
|
@ -2,37 +2,37 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.40.0"
|
||||
constraints = "4.40.0"
|
||||
version = "4.41.0"
|
||||
constraints = "4.41.0"
|
||||
hashes = [
|
||||
"h1:GP2N1tXrmpxu+qEDvFAmkfv9aeZNhag3bchyJpGpYbU=",
|
||||
"h1:HDJKZBQkVU0kQl4gViQ5L7EcFLn9hB0iuvO+ORJiDS4=",
|
||||
"h1:KrbeEsZoCJOnnX68yNI5h3QhMjc5bBCQW4yvYaEFq3s=",
|
||||
"h1:LelwnzU0OVn6g2+T9Ub9XdpC+vbheraIL/qgXhWBs/k=",
|
||||
"h1:TIq9CynfWrKgCxKL97Akj89cYlvJKn/AL4UXogd8/FM=",
|
||||
"h1:Uoy5oPdm1ipDG7yIMCUN1IXMpsTGXahPw3I0rVA/6wA=",
|
||||
"h1:Wunfpm+IZhENdoimrh4iXiakVnCsfKOHo80yJUjMQXM=",
|
||||
"h1:cRdCuahMOFrNyldnCInqGQRBT1DTkRPSfPnaf5r05iw=",
|
||||
"h1:k+zpXg8BO7gdbTIfSGyQisHhs5aVWQVbPLa5uUdr2UA=",
|
||||
"h1:kWNrzZ8Rh0OpHikexkmwJIIucD6SMZPi4oGyDsKJitw=",
|
||||
"h1:lomfTTjK78BdSEVTFcJUBQRy7IQHuGQImMaPWaYpfgQ=",
|
||||
"h1:oWcWlZe52ZRyLQciNe94RaWzhHifSTu03nlK0uL7rlM=",
|
||||
"h1:p3JJrhGEPlPQP7Uwy9FNMdvqCyD8tuT4lnXuJ+pSF/M=",
|
||||
"h1:wtB0sKxG2K/H41hWJI4uJdImWquuaP34Sip5LmfE410=",
|
||||
"zh:01742e5946f936548f8e42120287ffc757abf97e7cbbe34e25c266a438fb54fd",
|
||||
"zh:08d81f5a5aab4cc269f983b8c6b5be0e278105136aca9681740802619577371f",
|
||||
"zh:0d75131ba70902cfc94a7a5900369bdde56528b2aad6e10b164449cc97d57396",
|
||||
"zh:3890a715a012e197541daacdacb8cceec6d364814daa4640ddfe98a8ba9036cb",
|
||||
"zh:58254ce5ebe1faed4664df86210c39d660bcdc60280f17b25fe4d4dbea21ea8c",
|
||||
"zh:6b0abc1adbc2edee79368ce9f7338ebcb5d0bf941e8d7d9ac505b750f20f80a2",
|
||||
"zh:81cc415d1477174a1ca288d25fdb57e5ee488c2d7f61f265ef995b255a53b0ce",
|
||||
"zh:8680140c7fe5beaefe61c5cfa471bf88422dc0c0f05dad6d3cb482d4ffd22be4",
|
||||
"h1:0mc+YrjQrcctGrGYDmzlcqcgSv9MYB74rvMaZylIKC8=",
|
||||
"h1:0zUx4vk4jOORQqn6xHBF7dO6N6bielFHdJ0mgF4Obn8=",
|
||||
"h1:AsIZW3uLFNOZO7kL/K7/Y/S0IYxUV9Hz85NNk/3TTsA=",
|
||||
"h1:FSgYM4+LHMbX/a4Y1kx7FPPWmXqS3/MQYzvjMJHHHWM=",
|
||||
"h1:Tx6Nh3BWP1x9L3KK/Eyi+ET0T26g3+jf1jyiuqpNIis=",
|
||||
"h1:VRI9wu8P43xxfpeTndRwsisLnqncfnmEYMOEH5zH4pQ=",
|
||||
"h1:YxQqmiES/Yanq/VfGqBEqg+VIO7FGhO88aKoWFHyGIg=",
|
||||
"h1:ZWHiaesjgDLKWlfdNj0oKyj/DWdxcfsO6NINu39zfpY=",
|
||||
"h1:a2aCgDDBz3ccrr8YstIMl7VFnKo1xZAp+rOv59PPJ7U=",
|
||||
"h1:aRyv8tB6wBAF9lKsLEdiHyCqnK5LfZq0FqMXCcUB4UU=",
|
||||
"h1:lXpuO7zv2uD2GzPE1ARxznreRAh+QHTc2lAJ7iOoFgY=",
|
||||
"h1:sA1xq0QNQ4fH8SHXouYNq50xirVD18SamKQwPsBQrrY=",
|
||||
"h1:v7sHvKq7oqMYPn47ULHFyIQsKD9o+6Xg/uHbxQUixEw=",
|
||||
"h1:wo/x4atWyXuWGlfR6h5nH0YwBAmBwTRY27HtWP8ycLo=",
|
||||
"zh:339d26e06dc6fb299ea8aad9476a60fd65bb1d40631ae8eeb81cddf2dd2bebc8",
|
||||
"zh:3dec2ad96ac2c283fd34ce65781b55c4edbb4d5c5cb53da8e31537176c0ed562",
|
||||
"zh:5f63a5f8080319a2fff09d4d49944829fa708723436520787cfb60725ced80cf",
|
||||
"zh:67162c28ccea71cb8141ed15c0637e35621354ebe14878e0b75a8f160fc5505d",
|
||||
"zh:6ac1e07f5347b6395aca690ed22101bb25e957d25f986f760ff673a7adfd5ef6",
|
||||
"zh:70282a723c7b52fcabde2baad41c864ed3a8d69f0c4d27a6b6933cac434cffc6",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:a491d26236122ccb83dac8cb490d2c0aa1f4d3a0b4abe99300fd49b1a624f42f",
|
||||
"zh:a70d9c469dc8d55715ba77c9d1a4ede1fdebf79e60ee18438a0844868db54e0d",
|
||||
"zh:a7fcb7d5c4222e14ec6d9a15adf8b9a083d84b102c3d0e4a0d102df5a1360b62",
|
||||
"zh:b4f9677174fabd199c8ebd2e9e5eb3528cf887e700569a4fb61eef4e070cec5e",
|
||||
"zh:c27f0f7519221d75dae4a3787a59e05acd5cc9a0d30a390eff349a77d20d52e6",
|
||||
"zh:db00d8605dbf43ca42fe1481a6c67fdcaa73debb7d2a0f613cb95ae5c5e7150e",
|
||||
"zh:924cd23abc326c6b3914e2cd9c94c7832c2552e1e9ae258fb9fd9aedaa5f7ce7",
|
||||
"zh:a4b75e4c239879296259e7d54f1befbc7fdc16da2d62d1294e9f73add4cae61e",
|
||||
"zh:a6ceb08feb63b00c7141783b31e45a154c76fd8cdebbdf371074805f0053572d",
|
||||
"zh:afae1843f9ba85f2f6d94108c65cf43a457e83531a632d44d863e935160cb2ba",
|
||||
"zh:bd6628ce60c778960a5755f7010b7e2cc5c6ff0341a21c175341b28058ec843d",
|
||||
"zh:cd30866a1ff99d72b5fa1699db582fa4f25562e6ab21dcc6870324f3056108e0",
|
||||
"zh:df5924cca691a8220aaaebb5cb55c3d6c32ff0a881f198695eff28155eb12b54",
|
||||
"zh:e78d0696c941aba58df1cb36b8a0d25cd5f3963f01d9338fdbda74db58afdd49",
|
||||
]
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.40.0"
|
||||
version = "4.41.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,37 +2,37 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.40.0"
|
||||
constraints = "4.40.0"
|
||||
version = "4.41.0"
|
||||
constraints = "4.41.0"
|
||||
hashes = [
|
||||
"h1:GP2N1tXrmpxu+qEDvFAmkfv9aeZNhag3bchyJpGpYbU=",
|
||||
"h1:HDJKZBQkVU0kQl4gViQ5L7EcFLn9hB0iuvO+ORJiDS4=",
|
||||
"h1:KrbeEsZoCJOnnX68yNI5h3QhMjc5bBCQW4yvYaEFq3s=",
|
||||
"h1:LelwnzU0OVn6g2+T9Ub9XdpC+vbheraIL/qgXhWBs/k=",
|
||||
"h1:TIq9CynfWrKgCxKL97Akj89cYlvJKn/AL4UXogd8/FM=",
|
||||
"h1:Uoy5oPdm1ipDG7yIMCUN1IXMpsTGXahPw3I0rVA/6wA=",
|
||||
"h1:Wunfpm+IZhENdoimrh4iXiakVnCsfKOHo80yJUjMQXM=",
|
||||
"h1:cRdCuahMOFrNyldnCInqGQRBT1DTkRPSfPnaf5r05iw=",
|
||||
"h1:k+zpXg8BO7gdbTIfSGyQisHhs5aVWQVbPLa5uUdr2UA=",
|
||||
"h1:kWNrzZ8Rh0OpHikexkmwJIIucD6SMZPi4oGyDsKJitw=",
|
||||
"h1:lomfTTjK78BdSEVTFcJUBQRy7IQHuGQImMaPWaYpfgQ=",
|
||||
"h1:oWcWlZe52ZRyLQciNe94RaWzhHifSTu03nlK0uL7rlM=",
|
||||
"h1:p3JJrhGEPlPQP7Uwy9FNMdvqCyD8tuT4lnXuJ+pSF/M=",
|
||||
"h1:wtB0sKxG2K/H41hWJI4uJdImWquuaP34Sip5LmfE410=",
|
||||
"zh:01742e5946f936548f8e42120287ffc757abf97e7cbbe34e25c266a438fb54fd",
|
||||
"zh:08d81f5a5aab4cc269f983b8c6b5be0e278105136aca9681740802619577371f",
|
||||
"zh:0d75131ba70902cfc94a7a5900369bdde56528b2aad6e10b164449cc97d57396",
|
||||
"zh:3890a715a012e197541daacdacb8cceec6d364814daa4640ddfe98a8ba9036cb",
|
||||
"zh:58254ce5ebe1faed4664df86210c39d660bcdc60280f17b25fe4d4dbea21ea8c",
|
||||
"zh:6b0abc1adbc2edee79368ce9f7338ebcb5d0bf941e8d7d9ac505b750f20f80a2",
|
||||
"zh:81cc415d1477174a1ca288d25fdb57e5ee488c2d7f61f265ef995b255a53b0ce",
|
||||
"zh:8680140c7fe5beaefe61c5cfa471bf88422dc0c0f05dad6d3cb482d4ffd22be4",
|
||||
"h1:0mc+YrjQrcctGrGYDmzlcqcgSv9MYB74rvMaZylIKC8=",
|
||||
"h1:0zUx4vk4jOORQqn6xHBF7dO6N6bielFHdJ0mgF4Obn8=",
|
||||
"h1:AsIZW3uLFNOZO7kL/K7/Y/S0IYxUV9Hz85NNk/3TTsA=",
|
||||
"h1:FSgYM4+LHMbX/a4Y1kx7FPPWmXqS3/MQYzvjMJHHHWM=",
|
||||
"h1:Tx6Nh3BWP1x9L3KK/Eyi+ET0T26g3+jf1jyiuqpNIis=",
|
||||
"h1:VRI9wu8P43xxfpeTndRwsisLnqncfnmEYMOEH5zH4pQ=",
|
||||
"h1:YxQqmiES/Yanq/VfGqBEqg+VIO7FGhO88aKoWFHyGIg=",
|
||||
"h1:ZWHiaesjgDLKWlfdNj0oKyj/DWdxcfsO6NINu39zfpY=",
|
||||
"h1:a2aCgDDBz3ccrr8YstIMl7VFnKo1xZAp+rOv59PPJ7U=",
|
||||
"h1:aRyv8tB6wBAF9lKsLEdiHyCqnK5LfZq0FqMXCcUB4UU=",
|
||||
"h1:lXpuO7zv2uD2GzPE1ARxznreRAh+QHTc2lAJ7iOoFgY=",
|
||||
"h1:sA1xq0QNQ4fH8SHXouYNq50xirVD18SamKQwPsBQrrY=",
|
||||
"h1:v7sHvKq7oqMYPn47ULHFyIQsKD9o+6Xg/uHbxQUixEw=",
|
||||
"h1:wo/x4atWyXuWGlfR6h5nH0YwBAmBwTRY27HtWP8ycLo=",
|
||||
"zh:339d26e06dc6fb299ea8aad9476a60fd65bb1d40631ae8eeb81cddf2dd2bebc8",
|
||||
"zh:3dec2ad96ac2c283fd34ce65781b55c4edbb4d5c5cb53da8e31537176c0ed562",
|
||||
"zh:5f63a5f8080319a2fff09d4d49944829fa708723436520787cfb60725ced80cf",
|
||||
"zh:67162c28ccea71cb8141ed15c0637e35621354ebe14878e0b75a8f160fc5505d",
|
||||
"zh:6ac1e07f5347b6395aca690ed22101bb25e957d25f986f760ff673a7adfd5ef6",
|
||||
"zh:70282a723c7b52fcabde2baad41c864ed3a8d69f0c4d27a6b6933cac434cffc6",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:a491d26236122ccb83dac8cb490d2c0aa1f4d3a0b4abe99300fd49b1a624f42f",
|
||||
"zh:a70d9c469dc8d55715ba77c9d1a4ede1fdebf79e60ee18438a0844868db54e0d",
|
||||
"zh:a7fcb7d5c4222e14ec6d9a15adf8b9a083d84b102c3d0e4a0d102df5a1360b62",
|
||||
"zh:b4f9677174fabd199c8ebd2e9e5eb3528cf887e700569a4fb61eef4e070cec5e",
|
||||
"zh:c27f0f7519221d75dae4a3787a59e05acd5cc9a0d30a390eff349a77d20d52e6",
|
||||
"zh:db00d8605dbf43ca42fe1481a6c67fdcaa73debb7d2a0f613cb95ae5c5e7150e",
|
||||
"zh:924cd23abc326c6b3914e2cd9c94c7832c2552e1e9ae258fb9fd9aedaa5f7ce7",
|
||||
"zh:a4b75e4c239879296259e7d54f1befbc7fdc16da2d62d1294e9f73add4cae61e",
|
||||
"zh:a6ceb08feb63b00c7141783b31e45a154c76fd8cdebbdf371074805f0053572d",
|
||||
"zh:afae1843f9ba85f2f6d94108c65cf43a457e83531a632d44d863e935160cb2ba",
|
||||
"zh:bd6628ce60c778960a5755f7010b7e2cc5c6ff0341a21c175341b28058ec843d",
|
||||
"zh:cd30866a1ff99d72b5fa1699db582fa4f25562e6ab21dcc6870324f3056108e0",
|
||||
"zh:df5924cca691a8220aaaebb5cb55c3d6c32ff0a881f198695eff28155eb12b54",
|
||||
"zh:e78d0696c941aba58df1cb36b8a0d25cd5f3963f01d9338fdbda74db58afdd49",
|
||||
]
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.40.0"
|
||||
version = "4.41.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ output "immich_app_branch_subdomain" {
|
||||
}
|
||||
|
||||
output "immich_app_branch_pages_hostname" {
|
||||
value = cloudflare_record.immich_app_branch_subdomain.value
|
||||
value = cloudflare_record.immich_app_branch_subdomain.content
|
||||
}
|
||||
|
||||
output "pages_project_name" {
|
||||
|
@ -43,6 +43,7 @@ services:
|
||||
ports:
|
||||
- 3001:3001
|
||||
- 9230:9230
|
||||
- 9231:9231
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
|
@ -21,6 +21,8 @@ The recommended way to backup and restore the Immich database is to use the `pg_
|
||||
It is not recommended to directly backup the `DB_DATA_LOCATION` folder. Doing so while the database is running can lead to a corrupted backup that cannot be restored.
|
||||
:::
|
||||
|
||||
### Manual Backup and Restore
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Linux system" label="Linux system" default>
|
||||
|
||||
@ -29,10 +31,11 @@ docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgre
|
||||
```
|
||||
|
||||
```bash title='Restore'
|
||||
docker compose down -v # CAUTION! Deletes all Immich data to start from scratch.
|
||||
# rm -rf DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch.
|
||||
docker compose down -v # CAUTION! Deletes all Immich data to start from scratch
|
||||
## Uncomment the next line and replace DB_DATA_LOCATION with your Postgres path to permanently reset the Postgres database
|
||||
# rm -rf DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch
|
||||
docker compose pull # Update to latest version of Immich (if desired)
|
||||
docker compose create # Create Docker containers for Immich apps without running them.
|
||||
docker compose create # Create Docker containers for Immich apps without running them
|
||||
docker start immich_postgres # Start Postgres server
|
||||
sleep 10 # Wait for Postgres server to start up
|
||||
gunzip < "/path/to/backup/dump.sql.gz" \
|
||||
@ -49,10 +52,11 @@ docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgre
|
||||
```
|
||||
|
||||
```powershell title='Restore'
|
||||
docker compose down -v # CAUTION! Deletes all Immich data to start from scratch.
|
||||
# Remove-Item -Recurse -Force DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch.
|
||||
docker compose down -v # CAUTION! Deletes all Immich data to start from scratch
|
||||
## Uncomment the next line and replace DB_DATA_LOCATION with your Postgres path to permanently reset the Postgres database
|
||||
# Remove-Item -Recurse -Force DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch
|
||||
docker compose pull # Update to latest version of Immich (if desired)
|
||||
docker compose create # Create Docker containers for Immich apps without running them.
|
||||
docker compose create # Create Docker containers for Immich apps without running them
|
||||
docker start immich_postgres # Start Postgres server
|
||||
sleep 10 # Wait for Postgres server to start up
|
||||
gc "C:\path\to\backup\dump.sql" | docker exec -i immich_postgres psql --username=postgres # Restore Backup
|
||||
@ -68,6 +72,8 @@ Note that for the database restore to proceed properly, it requires a completely
|
||||
Some deployment methods make it difficult to start the database without also starting the server or microservices. In these cases, you may set the environmental variable `DB_SKIP_MIGRATIONS=true` before starting the services. This will prevent the server from running migrations that interfere with the restore process. Note that both the server and microservices must have this variable set to prevent the migrations from running. Be sure to remove this variable and restart the services after the database is restored.
|
||||
:::
|
||||
|
||||
### Automatic Database Backups
|
||||
|
||||
The database dumps can also be automated (using [this image](https://github.com/prodrigestivill/docker-postgres-backup-local)) by editing the docker compose file to match the following:
|
||||
|
||||
```yaml
|
||||
@ -157,7 +163,7 @@ for more info read the [release notes](https://github.com/immich-app/immich/rele
|
||||
|
||||
- The Immich database containing all the information to allow the system to function properly.
|
||||
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
|
||||
- Stored in `UPLOAD_LOCATION/postgres`.
|
||||
- Stored in `DB_DATA_LOCATION`.
|
||||
|
||||
:::danger
|
||||
A backup of this folder does not constitute a backup of your database!
|
||||
@ -203,7 +209,7 @@ When you turn off the storage template engine, it will leave the assets in `UPLO
|
||||
|
||||
- The Immich database containing all the information to allow the system to function properly.
|
||||
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
|
||||
- Stored in `UPLOAD_LOCATION/postgres`.
|
||||
- Stored in `DB_DATA_LOCATION`.
|
||||
|
||||
:::danger
|
||||
A backup of this folder does not constitute a backup of your database!
|
||||
|
@ -8,13 +8,11 @@ Immich supports the option to send notifications via Email for the following eve
|
||||
|
||||
## SMTP settings
|
||||
|
||||
You can access the settings panel from the web at `Administration -> Settings -> Notification settings`
|
||||
You can access the settings panel from the web at `Administration -> Settings -> Notification settings`.
|
||||
|
||||
Under Email, enter the following details to connect with SMTP servers.
|
||||
Under Email, enter the required details to connect with an SMTP server.
|
||||
|
||||
You can use the following [guide](/docs/guides/smtp-gmail) to use Gmail's SMTP server.
|
||||
|
||||
<img src={require('./img/email-settings.png').default} width="80%" title="SMTP settings" />
|
||||
You can use [this guide](/docs/guides/smtp-gmail) to use Gmail's SMTP server.
|
||||
|
||||
## User's notifications settings
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 218 KiB |
@ -106,7 +106,7 @@ in User `settings.json` (`cmd + shift + p` and search for `Open User Settings JS
|
||||
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
||||
"editor.suggestSelection": "first",
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.wordBasedSuggestions": false,
|
||||
"editor.wordBasedSuggestions": "off",
|
||||
"editor.defaultFormatter": "Dart-Code.dart-code"
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele
|
||||
|
||||
- The GPU must have compute capability 5.2 or greater.
|
||||
- The server must have the official NVIDIA driver installed.
|
||||
- The installed driver must be >= 545 (it must support CUDA 12.3.2).
|
||||
- The installed driver must be >= 535 (it must support CUDA 12.2).
|
||||
- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed.
|
||||
|
||||
#### OpenVINO
|
||||
|
19
docs/docs/guides/scaling-immich.md
Normal file
19
docs/docs/guides/scaling-immich.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Scaling Immich
|
||||
|
||||
Immich is built with modern deployment practices in mind, and the backend is designed to be able to run multiple instances in parallel. When doing this, the only requirement you need to be aware of is that every instance needs to be connected to the shared infrastructure. That means they should all have access to the same Postgres and Redis instances, and have the same files mounted into the containers.
|
||||
|
||||
Scaling can be useful for many reasons. Maybe you have a gaming PC that you want to use for transcoding and thumbnail generation, or perhaps you run a Kubernetes cluster across a handful of powerful servers that you want to make use of.
|
||||
|
||||
:::info
|
||||
If you only have a single machine to run Immich on, scaling to multiple containers is unlikely to provide any benefit. An Immich container will run multiple background tasks at once, and you can increase their number from the admin panel.
|
||||
:::
|
||||
|
||||
The details of how to scale across multiple machines will vary widely between different environments and require some knowledge to set up, and as such this guide gives no specific instructions. In some cases scaling up can be as easy as incrementing the amount of replicas on a Kubernetes deployment, in others it might need you to configure network tunnels or NFS mounts. The details are left as an exercise for the reader ;)
|
||||
|
||||
## Workers
|
||||
|
||||
By default, each running `immich-server` container comes with multiple internal workers. If you're scaling up only to handle more background tasks, you can choose to disable the worker responsible for the API. See [workers](../administration/jobs-workers.md) for more detail.
|
||||
|
||||
## Scaling down
|
||||
|
||||
In the same way you can scale up to multiple containers, you can also choose to scale down. All state is stored in Postgres, Redis, and the filesystem so there is no risk in stopping a running immich-server container, for example if you want to use your GPU to play some games. As long as there is an API worker running you will still be able to browse Immich, and jobs will wait to be processed until there is a worker available for them.
|
@ -80,6 +80,10 @@ The Compose file './docker-compose.yml' is invalid because:
|
||||
See the previous paragraph about installing from the official docker repository.
|
||||
:::
|
||||
|
||||
:::info Health check start interval
|
||||
If you get an error `can't set healthcheck.start_interval as feature require Docker Engine v25 or later`, it helps to comment out the line for `start_interval` in the `database` section of the `docker-compose.yml` file.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
For more information on how to use the application, please refer to the [Post Installation](/docs/install/post-install.mdx) guide.
|
||||
:::
|
||||
|
@ -8,6 +8,7 @@ import StorageTemplate from '/docs/partials/_storage-template.md';
|
||||
import MobileAppDownload from '/docs/partials/_mobile-app-download.md';
|
||||
import MobileAppLogin from '/docs/partials/_mobile-app-login.md';
|
||||
import MobileAppBackup from '/docs/partials/_mobile-app-backup.md';
|
||||
import ServerBackup from '/docs/partials/_server-backup.md';
|
||||
|
||||
# Post Install Steps
|
||||
|
||||
@ -33,6 +34,10 @@ A list of common steps to take after installing Immich include:
|
||||
|
||||
<MobileAppLogin />
|
||||
|
||||
## Step 6 - Backup Your Library
|
||||
## Step 6 - Upload Your Library
|
||||
|
||||
<MobileAppBackup />
|
||||
|
||||
## Step 7 - Setup Server Backups
|
||||
|
||||
<ServerBackup />
|
||||
|
2
docs/docs/partials/_server-backup.md
Normal file
2
docs/docs/partials/_server-backup.md
Normal file
@ -0,0 +1,2 @@
|
||||
Now that you have imported some pictures, you should setup server backups to preserve your memories.
|
||||
You can do so by following our [backup guide](/docs/administration/backup-and-restore.md).
|
@ -1,16 +1,20 @@
|
||||
import {
|
||||
mdiBug,
|
||||
mdiCalendarToday,
|
||||
mdiCrosshairsOff,
|
||||
mdiDatabase,
|
||||
mdiLeadPencil,
|
||||
mdiLockOff,
|
||||
mdiLockOutline,
|
||||
mdiSecurity,
|
||||
mdiSpeedometerSlow,
|
||||
mdiTrashCan,
|
||||
mdiWeb,
|
||||
mdiWrap,
|
||||
} from '@mdi/js';
|
||||
import Layout from '@theme/Layout';
|
||||
import React from 'react';
|
||||
import { Item as TimelineItem, Timeline } from '../components/timeline';
|
||||
import { Timeline, Item as TimelineItem } from '../components/timeline';
|
||||
|
||||
const withLanguage = (date: Date) => (language: string) => date.toLocaleDateString(language);
|
||||
|
||||
@ -96,6 +100,51 @@ const items: Item[] = [
|
||||
link: { url: 'https://github.com/immich-app/immich/pull/6787', text: '#6787' },
|
||||
date: new Date(2024, 0, 31),
|
||||
},
|
||||
{
|
||||
icon: mdiBug,
|
||||
iconColor: 'green',
|
||||
title: 'ESM imports are cursed',
|
||||
description:
|
||||
'Prior to Node.js v20.8 using --experimental-vm-modules in a CommonJS project that imported an ES module that imported a CommonJS modules would create a segfault and crash Node.js',
|
||||
link: {
|
||||
url: 'https://github.com/immich-app/immich/pull/6719',
|
||||
text: '#6179',
|
||||
},
|
||||
date: new Date(2024, 0, 9),
|
||||
},
|
||||
{
|
||||
icon: mdiDatabase,
|
||||
iconColor: 'gray',
|
||||
title: 'PostgreSQL parameters are cursed',
|
||||
description: `PostgresSQL has a limit of ${Number(65535).toLocaleString()} parameters, so bulk inserts can fail with large datasets.`,
|
||||
link: {
|
||||
url: 'https://github.com/immich-app/immich/pull/6034',
|
||||
text: '#6034',
|
||||
},
|
||||
date: new Date(2023, 11, 28),
|
||||
},
|
||||
{
|
||||
icon: mdiSecurity,
|
||||
iconColor: 'gold',
|
||||
title: 'Secure contexts are cursed',
|
||||
description: `Some web features like the clipboard API only work in "secure contexts" (ie. https or localhost)`,
|
||||
link: {
|
||||
url: 'https://github.com/immich-app/immich/issues/2981',
|
||||
text: '#2981',
|
||||
},
|
||||
date: new Date(2023, 5, 26),
|
||||
},
|
||||
{
|
||||
icon: mdiTrashCan,
|
||||
iconColor: 'gray',
|
||||
title: 'TypeORM deletes are cursed',
|
||||
description: `The remove implementation in TypeORM mutates the input, deleting the id property from the original object.`,
|
||||
link: {
|
||||
url: 'https://github.com/typeorm/typeorm/issues/7024#issuecomment-948519328',
|
||||
text: 'typeorm#6034',
|
||||
},
|
||||
date: new Date(2023, 1, 23),
|
||||
},
|
||||
];
|
||||
|
||||
export default function CursedKnowledgePage(): JSX.Element {
|
||||
|
4
docs/static/archived-versions.json
vendored
4
docs/static/archived-versions.json
vendored
@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"label": "v1.115.0",
|
||||
"url": "https://v1.115.0.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.114.0",
|
||||
"url": "https://v1.114.0.archive.immich.app"
|
||||
|
20
e2e/package-lock.json
generated
20
e2e/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich-e2e",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
@ -15,7 +15,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
@ -45,7 +45,7 @@
|
||||
},
|
||||
"../cli": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.18",
|
||||
"version": "2.2.19",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
@ -64,7 +64,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
@ -92,14 +92,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -1516,9 +1516,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.3.tgz",
|
||||
"integrity": "sha512-/wdGiWRkMOm53gAsSyFMXFZHbVg7C6CbkrzHNpaHoYfsUWPg7m6ZRKtvQjgvQ9i8WT540a3ydRlRQbxjY30XxQ==",
|
||||
"version": "20.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
|
||||
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@ -25,7 +25,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
|
@ -545,6 +545,48 @@ describe('/asset', () => {
|
||||
expect(status).toEqual(200);
|
||||
});
|
||||
|
||||
it('should not allow linking two photos', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.put(`/assets/${user1Assets[0].id}`)
|
||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||
.send({ livePhotoVideoId: user1Assets[1].id });
|
||||
|
||||
expect(body).toEqual(errorDto.badRequest('Live photo video must be a video'));
|
||||
expect(status).toEqual(400);
|
||||
});
|
||||
|
||||
it('should not allow linking a video owned by another user', async () => {
|
||||
const asset = await utils.createAsset(user2.accessToken, { assetData: { filename: 'example.mp4' } });
|
||||
const { status, body } = await request(app)
|
||||
.put(`/assets/${user1Assets[0].id}`)
|
||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||
.send({ livePhotoVideoId: asset.id });
|
||||
|
||||
expect(body).toEqual(errorDto.badRequest('Live photo video does not belong to the user'));
|
||||
expect(status).toEqual(400);
|
||||
});
|
||||
|
||||
it('should link a motion photo', async () => {
|
||||
const asset = await utils.createAsset(user1.accessToken, { assetData: { filename: 'example.mp4' } });
|
||||
const { status, body } = await request(app)
|
||||
.put(`/assets/${user1Assets[0].id}`)
|
||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||
.send({ livePhotoVideoId: asset.id });
|
||||
|
||||
expect(status).toEqual(200);
|
||||
expect(body).toMatchObject({ id: user1Assets[0].id, livePhotoVideoId: asset.id });
|
||||
});
|
||||
|
||||
it('should unlink a motion photo', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.put(`/assets/${user1Assets[0].id}`)
|
||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||
.send({ livePhotoVideoId: null });
|
||||
|
||||
expect(status).toEqual(200);
|
||||
expect(body).toMatchObject({ id: user1Assets[0].id, livePhotoVideoId: null });
|
||||
});
|
||||
|
||||
it('should update date time original when sidecar file contains DateTimeOriginal', async () => {
|
||||
const sidecarData = `<?xpacket begin='?' id='W5M0MpCehiHzreSzNTczkc9d'?>
|
||||
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 12.40'>
|
||||
|
@ -83,7 +83,7 @@ describe('/libraries', () => {
|
||||
refreshedAt: null,
|
||||
assetCount: 0,
|
||||
importPaths: [],
|
||||
exclusionPatterns: [],
|
||||
exclusionPatterns: expect.any(Array),
|
||||
}),
|
||||
);
|
||||
});
|
||||
@ -270,7 +270,7 @@ describe('/libraries', () => {
|
||||
refreshedAt: null,
|
||||
assetCount: 0,
|
||||
importPaths: [],
|
||||
exclusionPatterns: [],
|
||||
exclusionPatterns: expect.any(Array),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
@ -94,6 +94,7 @@ export const signupResponseDto = {
|
||||
quotaSizeInBytes: null,
|
||||
status: 'active',
|
||||
license: null,
|
||||
profileChangedAt: expect.any(String),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ download:
|
||||
locale_code: nb-NO
|
||||
- file: mobile/assets/i18n/sv-SE.json
|
||||
locale_code: sv-SE
|
||||
- file: mobile/assets/i18n/mn.json
|
||||
- file: mobile/assets/i18n/mn-MN.json
|
||||
locale_code: mn
|
||||
- file: mobile/assets/i18n/ko-KR.json
|
||||
locale_code: ko-KR
|
||||
|
@ -1,6 +1,6 @@
|
||||
ARG DEVICE=cpu
|
||||
|
||||
FROM python:3.11-bookworm@sha256:20c1819af5af3acba0b2b66074a2615e398ceee6842adf03cd7ad5f8d0ee3daf AS builder-cpu
|
||||
FROM python:3.11-bookworm@sha256:157a371e60389919fe4a72dff71ce86eaa5234f59114c23b0b346d0d02c74d39 AS builder-cpu
|
||||
|
||||
FROM builder-cpu AS builder-openvino
|
||||
|
||||
@ -34,7 +34,7 @@ RUN python3 -m venv /opt/venv
|
||||
COPY poetry.lock pyproject.toml ./
|
||||
RUN poetry install --sync --no-interaction --no-ansi --no-root --with ${DEVICE} --without dev
|
||||
|
||||
FROM python:3.11-slim-bookworm@sha256:ed4e985674f478c90ce879e9aa224fbb772c84e39b4aed5155b9e2280f131039 AS prod-cpu
|
||||
FROM python:3.11-slim-bookworm@sha256:669bbd08353610485a94d5d0c976b4b6498c55280fe42c00f7581f85ee9f3121 AS prod-cpu
|
||||
|
||||
FROM prod-cpu AS prod-openvino
|
||||
|
||||
@ -49,7 +49,12 @@ RUN apt-get update && \
|
||||
apt-get remove wget -yqq && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
FROM nvidia/cuda:12.3.2-cudnn9-runtime-ubuntu22.04@sha256:fa44193567d1908f7ca1f3abf8623ce9c63bc8cba7bcfdb32702eb04d326f7a8 AS prod-cuda
|
||||
FROM nvidia/cuda:12.2.2-runtime-ubuntu22.04@sha256:94c1577b2cd9dd6c0312dc04dff9cb2fdce2b268018abc3d7c2dbcacf1155000 AS prod-cuda
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -yqq libcudnn9-cuda-12 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3
|
||||
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
|
||||
|
@ -71,7 +71,6 @@ class InferenceModel(ABC):
|
||||
f"immich-app/{clean_name(self.model_name)}",
|
||||
cache_dir=self.cache_dir,
|
||||
local_dir=self.cache_dir,
|
||||
local_dir_use_symlinks=False,
|
||||
ignore_patterns=ignore_patterns,
|
||||
)
|
||||
|
||||
|
@ -13,7 +13,6 @@ from app.config import log
|
||||
from app.models.base import InferenceModel
|
||||
from app.models.transforms import decode_cv2
|
||||
from app.schemas import FaceDetectionOutput, FacialRecognitionOutput, ModelFormat, ModelSession, ModelTask, ModelType
|
||||
from app.sessions import has_batch_axis
|
||||
|
||||
|
||||
class FaceRecognizer(InferenceModel):
|
||||
@ -27,7 +26,7 @@ class FaceRecognizer(InferenceModel):
|
||||
|
||||
def _load(self) -> ModelSession:
|
||||
session = self._make_session(self.model_path)
|
||||
if self.batch and not has_batch_axis(session):
|
||||
if self.batch and str(session.get_inputs()[0].shape[0]) != "batch":
|
||||
self._add_batch_axis(self.model_path)
|
||||
session = self._make_session(self.model_path)
|
||||
self.model = ArcFaceONNX(
|
||||
|
@ -1,5 +0,0 @@
|
||||
from app.schemas import ModelSession
|
||||
|
||||
|
||||
def has_batch_axis(session: ModelSession) -> bool:
|
||||
return not isinstance(session.get_inputs()[0].shape[0], int) or session.get_inputs()[0].shape[0] < 0
|
@ -124,7 +124,6 @@ class TestBase:
|
||||
"immich-app/ViT-B-32__openai",
|
||||
cache_dir=encoder.cache_dir,
|
||||
local_dir=encoder.cache_dir,
|
||||
local_dir_use_symlinks=False,
|
||||
ignore_patterns=["*.armnn"],
|
||||
)
|
||||
|
||||
@ -136,7 +135,6 @@ class TestBase:
|
||||
"immich-app/ViT-B-32__openai",
|
||||
cache_dir=encoder.cache_dir,
|
||||
local_dir=encoder.cache_dir,
|
||||
local_dir_use_symlinks=False,
|
||||
ignore_patterns=[],
|
||||
)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM mambaorg/micromamba:bookworm-slim@sha256:29174348bd09352e5f1b1f6756cf1d00021487b8340fae040e91e4f98e954ce5 AS builder
|
||||
FROM mambaorg/micromamba:bookworm-slim@sha256:5f32c5742e2248f2ca07ccae6861371321aba37372bf8e1a80d6f728f1ab4418 AS builder
|
||||
|
||||
ENV TRANSFORMERS_CACHE=/cache \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
108
machine-learning/poetry.lock
generated
108
machine-learning/poetry.lock
generated
@ -680,13 +680,13 @@ test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-slim"
|
||||
version = "0.112.2"
|
||||
version = "0.114.2"
|
||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fastapi_slim-0.112.2-py3-none-any.whl", hash = "sha256:c023f74768f187af142c2fe5ff9e4ca3c4c1940bbde7df008cb283532422a23f"},
|
||||
{file = "fastapi_slim-0.112.2.tar.gz", hash = "sha256:75b8eb0c6ee05a20270da7a527ac7ad53b83414602f42b68f7027484dab3aedb"},
|
||||
{file = "fastapi_slim-0.114.2-py3-none-any.whl", hash = "sha256:52ae76c53a30ad0fa96beb84c1bf4bef9c72e88c2f7c0473e836f01d7ac3ca6b"},
|
||||
{file = "fastapi_slim-0.114.2.tar.gz", hash = "sha256:76d0a450826fb0fa740268be55ef04c44807da87a94fbbf5f16338b5a4a2d321"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1963,36 +1963,36 @@ reference = ["Pillow", "google-re2"]
|
||||
|
||||
[[package]]
|
||||
name = "onnxruntime"
|
||||
version = "1.19.0"
|
||||
version = "1.19.2"
|
||||
description = "ONNX Runtime is a runtime accelerator for Machine Learning models"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "onnxruntime-1.19.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6ce22a98dfec7b646ae305f52d0ce14a189a758b02ea501860ca719f4b0ae04b"},
|
||||
{file = "onnxruntime-1.19.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19019c72873f26927aa322c54cf2bf7312b23451b27451f39b88f57016c94f8b"},
|
||||
{file = "onnxruntime-1.19.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8eaa16df99171dc636e30108d15597aed8c4c2dd9dbfdd07cc464d57d73fb275"},
|
||||
{file = "onnxruntime-1.19.0-cp310-cp310-win32.whl", hash = "sha256:0eb0f8dbe596fd0f4737fe511fdbb17603853a7d204c5b2ca38d3c7808fc556b"},
|
||||
{file = "onnxruntime-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:616092d54ba8023b7bc0a5f6d900a07a37cc1cfcc631873c15f8c1d6e9e184d4"},
|
||||
{file = "onnxruntime-1.19.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a2b53b3c287cd933e5eb597273926e899082d8c84ab96e1b34035764a1627e17"},
|
||||
{file = "onnxruntime-1.19.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e94984663963e74fbb468bde9ec6f19dcf890b594b35e249c4dc8789d08993c5"},
|
||||
{file = "onnxruntime-1.19.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f379d1f050cfb55ce015d53727b78ee362febc065c38eed81512b22b757da73"},
|
||||
{file = "onnxruntime-1.19.0-cp311-cp311-win32.whl", hash = "sha256:4ccb48faea02503275ae7e79e351434fc43c294c4cb5c4d8bcb7479061396614"},
|
||||
{file = "onnxruntime-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:9cdc8d311289a84e77722de68bd22b8adfb94eea26f4be6f9e017350faac8b18"},
|
||||
{file = "onnxruntime-1.19.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:1b59eaec1be9a8613c5fdeaafe67f73a062edce3ac03bbbdc9e2d98b58a30617"},
|
||||
{file = "onnxruntime-1.19.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be4144d014a4b25184e63ce7a463a2e7796e2f3df931fccc6a6aefa6f1365dc5"},
|
||||
{file = "onnxruntime-1.19.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10d7e7d4ca7021ce7f29a66dbc6071addf2de5839135339bd855c6d9c2bba371"},
|
||||
{file = "onnxruntime-1.19.0-cp312-cp312-win32.whl", hash = "sha256:87f2c58b577a1fb31dc5d92b647ecc588fd5f1ea0c3ad4526f5f80a113357c8d"},
|
||||
{file = "onnxruntime-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:8a1f50d49676d7b69566536ff039d9e4e95fc482a55673719f46528218ecbb94"},
|
||||
{file = "onnxruntime-1.19.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:71423c8c4b2d7a58956271534302ec72721c62a41efd0c4896343249b8399ab0"},
|
||||
{file = "onnxruntime-1.19.0-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d63630d45e9498f96e75bbeb7fd4a56acb10155de0de4d0e18d1b6cbb0b358a"},
|
||||
{file = "onnxruntime-1.19.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3bfd15db1e8794d379a86c1a9116889f47f2cca40cc82208fc4f7e8c38e8522"},
|
||||
{file = "onnxruntime-1.19.0-cp38-cp38-win32.whl", hash = "sha256:3b098003b6b4cb37cc84942e5f1fe27f945dd857cbd2829c824c26b0ba4a247e"},
|
||||
{file = "onnxruntime-1.19.0-cp38-cp38-win_amd64.whl", hash = "sha256:cea067a6541d6787d903ee6843401c5b1332a266585160d9700f9f0939443886"},
|
||||
{file = "onnxruntime-1.19.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:c4fcff12dc5ca963c5f76b9822bb404578fa4a98c281e8c666b429192799a099"},
|
||||
{file = "onnxruntime-1.19.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6dcad8a4db908fbe70b98c79cea1c8b6ac3316adf4ce93453136e33a524ac59"},
|
||||
{file = "onnxruntime-1.19.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bc449907c6e8d99eee5ae5cc9c8fdef273d801dcd195393d3f9ab8ad3f49522"},
|
||||
{file = "onnxruntime-1.19.0-cp39-cp39-win32.whl", hash = "sha256:947febd48405afcf526e45ccff97ff23b15e530434705f734870d22ae7fcf236"},
|
||||
{file = "onnxruntime-1.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:f60be47eff5ee77fd28a466b0fd41d7debc42a32179d1ddb21e05d6067d7b48b"},
|
||||
{file = "onnxruntime-1.19.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:84fa57369c06cadd3c2a538ae2a26d76d583e7c34bdecd5769d71ca5c0fc750e"},
|
||||
{file = "onnxruntime-1.19.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdc471a66df0c1cdef774accef69e9f2ca168c851ab5e4f2f3341512c7ef4666"},
|
||||
{file = "onnxruntime-1.19.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e3a4ce906105d99ebbe817f536d50a91ed8a4d1592553f49b3c23c4be2560ae6"},
|
||||
{file = "onnxruntime-1.19.2-cp310-cp310-win32.whl", hash = "sha256:4b3d723cc154c8ddeb9f6d0a8c0d6243774c6b5930847cc83170bfe4678fafb3"},
|
||||
{file = "onnxruntime-1.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:17ed7382d2c58d4b7354fb2b301ff30b9bf308a1c7eac9546449cd122d21cae5"},
|
||||
{file = "onnxruntime-1.19.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:d863e8acdc7232d705d49e41087e10b274c42f09e259016a46f32c34e06dc4fd"},
|
||||
{file = "onnxruntime-1.19.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dfe4f660a71b31caa81fc298a25f9612815215a47b286236e61d540350d7b6"},
|
||||
{file = "onnxruntime-1.19.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a36511dc07c5c964b916697e42e366fa43c48cdb3d3503578d78cef30417cb84"},
|
||||
{file = "onnxruntime-1.19.2-cp311-cp311-win32.whl", hash = "sha256:50cbb8dc69d6befad4746a69760e5b00cc3ff0a59c6c3fb27f8afa20e2cab7e7"},
|
||||
{file = "onnxruntime-1.19.2-cp311-cp311-win_amd64.whl", hash = "sha256:1c3e5d415b78337fa0b1b75291e9ea9fb2a4c1f148eb5811e7212fed02cfffa8"},
|
||||
{file = "onnxruntime-1.19.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:68e7051bef9cfefcbb858d2d2646536829894d72a4130c24019219442b1dd2ed"},
|
||||
{file = "onnxruntime-1.19.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d2d366fbcc205ce68a8a3bde2185fd15c604d9645888703785b61ef174265168"},
|
||||
{file = "onnxruntime-1.19.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:477b93df4db467e9cbf34051662a4b27c18e131fa1836e05974eae0d6e4cf29b"},
|
||||
{file = "onnxruntime-1.19.2-cp312-cp312-win32.whl", hash = "sha256:9a174073dc5608fad05f7cf7f320b52e8035e73d80b0a23c80f840e5a97c0147"},
|
||||
{file = "onnxruntime-1.19.2-cp312-cp312-win_amd64.whl", hash = "sha256:190103273ea4507638ffc31d66a980594b237874b65379e273125150eb044857"},
|
||||
{file = "onnxruntime-1.19.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:636bc1d4cc051d40bc52e1f9da87fbb9c57d9d47164695dfb1c41646ea51ea66"},
|
||||
{file = "onnxruntime-1.19.2-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5bd8b875757ea941cbcfe01582970cc299893d1b65bd56731e326a8333f638a3"},
|
||||
{file = "onnxruntime-1.19.2-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b2046fc9560f97947bbc1acbe4c6d48585ef0f12742744307d3364b131ac5778"},
|
||||
{file = "onnxruntime-1.19.2-cp38-cp38-win32.whl", hash = "sha256:31c12840b1cde4ac1f7d27d540c44e13e34f2345cf3642762d2a3333621abb6a"},
|
||||
{file = "onnxruntime-1.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:016229660adea180e9a32ce218b95f8f84860a200f0f13b50070d7d90e92956c"},
|
||||
{file = "onnxruntime-1.19.2-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:006c8d326835c017a9e9f74c9c77ebb570a71174a1e89fe078b29a557d9c3848"},
|
||||
{file = "onnxruntime-1.19.2-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df2a94179a42d530b936f154615b54748239c2908ee44f0d722cb4df10670f68"},
|
||||
{file = "onnxruntime-1.19.2-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fae4b4de45894b9ce7ae418c5484cbf0341db6813effec01bb2216091c52f7fb"},
|
||||
{file = "onnxruntime-1.19.2-cp39-cp39-win32.whl", hash = "sha256:dc5430f473e8706fff837ae01323be9dcfddd3ea471c900a91fa7c9b807ec5d3"},
|
||||
{file = "onnxruntime-1.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:38475e29a95c5f6c62c2c603d69fc7d4c6ccbf4df602bd567b86ae1138881c49"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2473,13 +2473,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.2"
|
||||
version = "8.3.3"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"},
|
||||
{file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"},
|
||||
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"},
|
||||
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2816,13 +2816,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.8.0"
|
||||
version = "13.8.1"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "rich-13.8.0-py3-none-any.whl", hash = "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc"},
|
||||
{file = "rich-13.8.0.tar.gz", hash = "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4"},
|
||||
{file = "rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06"},
|
||||
{file = "rich-13.8.1.tar.gz", hash = "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2834,29 +2834,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:97f58fda4e309382ad30ede7f30e2791d70dd29ea17f41970119f55bdb7a45c3"},
|
||||
{file = "ruff-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3b061e49b5cf3a297b4d1c27ac5587954ccb4ff601160d3d6b2f70b1622194dc"},
|
||||
{file = "ruff-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:34e2824a13bb8c668c71c1760a6ac7d795ccbd8d38ff4a0d8471fdb15de910b1"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bddfbb8d63c460f4b4128b6a506e7052bad4d6f3ff607ebbb41b0aa19c2770d1"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ced3eeb44df75353e08ab3b6a9e113b5f3f996bea48d4f7c027bc528ba87b672"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47021dff5445d549be954eb275156dfd7c37222acc1e8014311badcb9b4ec8c1"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d7bd20dc07cebd68cc8bc7b3f5ada6d637f42d947c85264f94b0d1cd9d87384"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:500f166d03fc6d0e61c8e40a3ff853fa8a43d938f5d14c183c612df1b0d6c58a"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42844ff678f9b976366b262fa2d1d1a3fe76f6e145bd92c84e27d172e3c34500"},
|
||||
{file = "ruff-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70452a10eb2d66549de8e75f89ae82462159855e983ddff91bc0bce6511d0470"},
|
||||
{file = "ruff-0.6.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65a533235ed55f767d1fc62193a21cbf9e3329cf26d427b800fdeacfb77d296f"},
|
||||
{file = "ruff-0.6.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2e2c23cef30dc3cbe9cc5d04f2899e7f5e478c40d2e0a633513ad081f7361b5"},
|
||||
{file = "ruff-0.6.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8a136aa7d228975a6aee3dd8bea9b28e2b43e9444aa678fb62aeb1956ff2351"},
|
||||
{file = "ruff-0.6.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f92fe93bc72e262b7b3f2bba9879897e2d58a989b4714ba6a5a7273e842ad2f8"},
|
||||
{file = "ruff-0.6.3-py3-none-win32.whl", hash = "sha256:7a62d3b5b0d7f9143d94893f8ba43aa5a5c51a0ffc4a401aa97a81ed76930521"},
|
||||
{file = "ruff-0.6.3-py3-none-win_amd64.whl", hash = "sha256:746af39356fee2b89aada06c7376e1aa274a23493d7016059c3a72e3b296befb"},
|
||||
{file = "ruff-0.6.3-py3-none-win_arm64.whl", hash = "sha256:14a9528a8b70ccc7a847637c29e56fd1f9183a9db743bbc5b8e0c4ad60592a82"},
|
||||
{file = "ruff-0.6.3.tar.gz", hash = "sha256:183b99e9edd1ef63be34a3b51fee0a9f4ab95add123dbf89a71f7b1f0c991983"},
|
||||
{file = "ruff-0.6.4-py3-none-linux_armv6l.whl", hash = "sha256:c4b153fc152af51855458e79e835fb6b933032921756cec9af7d0ba2aa01a258"},
|
||||
{file = "ruff-0.6.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:bedff9e4f004dad5f7f76a9d39c4ca98af526c9b1695068198b3bda8c085ef60"},
|
||||
{file = "ruff-0.6.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d02a4127a86de23002e694d7ff19f905c51e338c72d8e09b56bfb60e1681724f"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7862f42fc1a4aca1ea3ffe8a11f67819d183a5693b228f0bb3a531f5e40336fc"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eebe4ff1967c838a1a9618a5a59a3b0a00406f8d7eefee97c70411fefc353617"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:932063a03bac394866683e15710c25b8690ccdca1cf192b9a98260332ca93408"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:50e30b437cebef547bd5c3edf9ce81343e5dd7c737cb36ccb4fe83573f3d392e"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c44536df7b93a587de690e124b89bd47306fddd59398a0fb12afd6133c7b3818"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ea086601b22dc5e7693a78f3fcfc460cceabfdf3bdc36dc898792aba48fbad6"},
|
||||
{file = "ruff-0.6.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b52387d3289ccd227b62102c24714ed75fbba0b16ecc69a923a37e3b5e0aaaa"},
|
||||
{file = "ruff-0.6.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0308610470fcc82969082fc83c76c0d362f562e2f0cdab0586516f03a4e06ec6"},
|
||||
{file = "ruff-0.6.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:803b96dea21795a6c9d5bfa9e96127cc9c31a1987802ca68f35e5c95aed3fc0d"},
|
||||
{file = "ruff-0.6.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:66dbfea86b663baab8fcae56c59f190caba9398df1488164e2df53e216248baa"},
|
||||
{file = "ruff-0.6.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:34d5efad480193c046c86608dbba2bccdc1c5fd11950fb271f8086e0c763a5d1"},
|
||||
{file = "ruff-0.6.4-py3-none-win32.whl", hash = "sha256:f0f8968feea5ce3777c0d8365653d5e91c40c31a81d95824ba61d871a11b8523"},
|
||||
{file = "ruff-0.6.4-py3-none-win_amd64.whl", hash = "sha256:549daccee5227282289390b0222d0fbee0275d1db6d514550d65420053021a58"},
|
||||
{file = "ruff-0.6.4-py3-none-win_arm64.whl", hash = "sha256:ac4b75e898ed189b3708c9ab3fc70b79a433219e1e87193b4f2b77251d058d14"},
|
||||
{file = "ruff-0.6.4.tar.gz", hash = "sha256:ac3b5bfbee99973f80aa1b7cbd1c9cbce200883bdd067300c22a6cc1c7fba212"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "machine-learning"
|
||||
version = "1.114.0"
|
||||
version = "1.115.0"
|
||||
description = ""
|
||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
859
mobile/.isar-cargo.lock
Normal file
859
mobile/.isar-cargo.lock
Normal file
@ -0,0 +1,859 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.63.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "enum_dispatch"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float_next_after"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "intmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee87fd093563344074bacf24faa0bb0227fb6969fb223e922db798516de924d6"
|
||||
|
||||
[[package]]
|
||||
name = "isar"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"intmap",
|
||||
"isar-core",
|
||||
"itertools",
|
||||
"jni",
|
||||
"ndk-context",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"serde_json",
|
||||
"threadpool",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isar-core"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"crossbeam-channel",
|
||||
"enum_dispatch",
|
||||
"float_next_after",
|
||||
"intmap",
|
||||
"itertools",
|
||||
"libc",
|
||||
"mdbx-sys",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"snafu",
|
||||
"widestring",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdbx-sys"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"cmake",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "ndk-context"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "snafu"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6"
|
||||
dependencies = [
|
||||
"doc-comment",
|
||||
"snafu-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snafu-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threadpool"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||
dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "xxhash-rust"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
]
|
@ -35,8 +35,8 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 158,
|
||||
"android.injected.version.name" => "1.114.0",
|
||||
"android.injected.version.code" => 159,
|
||||
"android.injected.version.name" => "1.115.0",
|
||||
}
|
||||
)
|
||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||
|
@ -414,7 +414,7 @@
|
||||
"search_filter_people_title": "Select people",
|
||||
"search_page_categories": "Categorías",
|
||||
"search_page_favorites": "Favoritos",
|
||||
"search_page_motion_photos": "Fotos en .ovimiento",
|
||||
"search_page_motion_photos": "Fotos en movimiento",
|
||||
"search_page_no_objects": "No hay información de objetos disponible",
|
||||
"search_page_no_places": "No hay información de lugares disponible",
|
||||
"search_page_people": "Personas",
|
||||
@ -589,4 +589,4 @@
|
||||
"viewer_remove_from_stack": "Eliminar de la pila",
|
||||
"viewer_stack_use_as_main_asset": "Utilizar como recurso principal",
|
||||
"viewer_unstack": "Desapilar"
|
||||
}
|
||||
}
|
||||
|
@ -589,4 +589,4 @@
|
||||
"viewer_remove_from_stack": "Remove from Stack",
|
||||
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
||||
"viewer_unstack": "Un-Stack"
|
||||
}
|
||||
}
|
@ -401,7 +401,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
CURRENT_PROJECT_VERSION = 175;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@ -543,7 +543,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
CURRENT_PROJECT_VERSION = 175;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@ -571,7 +571,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
CURRENT_PROJECT_VERSION = 175;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
@ -58,11 +58,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.114.0</string>
|
||||
<string>1.115.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>173</string>
|
||||
<string>175</string>
|
||||
<key>FLTEnableImpeller</key>
|
||||
<true/>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
|
@ -19,7 +19,7 @@ platform :ios do
|
||||
desc "iOS Release"
|
||||
lane :release do
|
||||
increment_version_number(
|
||||
version_number: "1.114.0"
|
||||
version_number: "1.115.0"
|
||||
)
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number + 1,
|
||||
|
@ -164,12 +164,13 @@ class Album {
|
||||
}
|
||||
|
||||
extension AssetsHelper on IsarCollection<Album> {
|
||||
Future<void> store(Album a) async {
|
||||
Future<Album> store(Album a) async {
|
||||
await put(a);
|
||||
await a.owner.save();
|
||||
await a.thumbnail.save();
|
||||
await a.sharedUsers.save();
|
||||
await a.assets.save();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
|
21
mobile/lib/interfaces/album.interface.dart
Normal file
21
mobile/lib/interfaces/album.interface.dart
Normal file
@ -0,0 +1,21 @@
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
|
||||
abstract interface class IAlbumRepository {
|
||||
Future<int> count({bool? local});
|
||||
Future<Album> create(Album album);
|
||||
Future<Album?> getById(int id);
|
||||
Future<Album?> getByName(
|
||||
String name, {
|
||||
bool? shared,
|
||||
bool? remote,
|
||||
});
|
||||
Future<Album> update(Album album);
|
||||
Future<void> delete(int albumId);
|
||||
Future<List<Album>> getAll({bool? shared});
|
||||
Future<void> removeUsers(Album album, List<User> users);
|
||||
Future<void> addAssets(Album album, List<Asset> assets);
|
||||
Future<void> removeAssets(Album album, List<Asset> assets);
|
||||
Future<Album> recalculateMetadata(Album album);
|
||||
}
|
8
mobile/lib/interfaces/asset.interface.dart
Normal file
8
mobile/lib/interfaces/asset.interface.dart
Normal file
@ -0,0 +1,8 @@
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
|
||||
abstract interface class IAssetRepository {
|
||||
Future<List<Asset>> getByAlbum(Album album, {User? notOwnedBy});
|
||||
Future<void> deleteById(List<int> ids);
|
||||
}
|
5
mobile/lib/interfaces/backup.interface.dart
Normal file
5
mobile/lib/interfaces/backup.interface.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||
|
||||
abstract interface class IBackupRepository {
|
||||
Future<List<String>> getIdsBySelection(BackupSelection backup);
|
||||
}
|
5
mobile/lib/interfaces/user.interface.dart
Normal file
5
mobile/lib/interfaces/user.interface.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
|
||||
abstract interface class IUserRepository {
|
||||
Future<List<User>> getByIds(List<String> ids);
|
||||
}
|
85
mobile/lib/repositories/album.repository.dart
Normal file
85
mobile/lib/repositories/album.repository.dart
Normal file
@ -0,0 +1,85 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/album.interface.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
final albumRepositoryProvider =
|
||||
Provider((ref) => AlbumRepository(ref.watch(dbProvider)));
|
||||
|
||||
class AlbumRepository implements IAlbumRepository {
|
||||
final Isar _db;
|
||||
|
||||
AlbumRepository(
|
||||
this._db,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<int> count({bool? local}) {
|
||||
if (local == true) return _db.albums.where().localIdIsNotNull().count();
|
||||
if (local == false) return _db.albums.where().remoteIdIsNotNull().count();
|
||||
return _db.albums.count();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Album> create(Album album) =>
|
||||
_db.writeTxn(() => _db.albums.store(album));
|
||||
|
||||
@override
|
||||
Future<Album?> getByName(String name, {bool? shared, bool? remote}) {
|
||||
var query = _db.albums.filter().nameEqualTo(name);
|
||||
if (shared != null) {
|
||||
query = query.sharedEqualTo(shared);
|
||||
}
|
||||
if (remote == true) {
|
||||
query = query.localIdIsNull();
|
||||
} else if (remote == false) {
|
||||
query = query.remoteIdIsNull();
|
||||
}
|
||||
return query.findFirst();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Album> update(Album album) =>
|
||||
_db.writeTxn(() => _db.albums.store(album));
|
||||
|
||||
@override
|
||||
Future<void> delete(int albumId) =>
|
||||
_db.writeTxn(() => _db.albums.delete(albumId));
|
||||
|
||||
@override
|
||||
Future<List<Album>> getAll({bool? shared}) {
|
||||
final baseQuery = _db.albums.filter();
|
||||
QueryBuilder<Album, Album, QAfterFilterCondition>? query;
|
||||
if (shared != null) {
|
||||
query = baseQuery.sharedEqualTo(true);
|
||||
}
|
||||
return query?.findAll() ?? _db.albums.where().findAll();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Album?> getById(int id) => _db.albums.get(id);
|
||||
|
||||
@override
|
||||
Future<void> removeUsers(Album album, List<User> users) =>
|
||||
_db.writeTxn(() => album.sharedUsers.update(unlink: users));
|
||||
|
||||
@override
|
||||
Future<void> addAssets(Album album, List<Asset> assets) =>
|
||||
_db.writeTxn(() => album.assets.update(link: assets));
|
||||
|
||||
@override
|
||||
Future<void> removeAssets(Album album, List<Asset> assets) =>
|
||||
_db.writeTxn(() => album.assets.update(unlink: assets));
|
||||
|
||||
@override
|
||||
Future<Album> recalculateMetadata(Album album) async {
|
||||
album.startDate = await album.assets.filter().fileCreatedAtProperty().min();
|
||||
album.endDate = await album.assets.filter().fileCreatedAtProperty().max();
|
||||
album.lastModifiedAssetTimestamp =
|
||||
await album.assets.filter().updatedAtProperty().max();
|
||||
return album;
|
||||
}
|
||||
}
|
31
mobile/lib/repositories/asset.repository.dart
Normal file
31
mobile/lib/repositories/asset.repository.dart
Normal file
@ -0,0 +1,31 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
final assetRepositoryProvider =
|
||||
Provider((ref) => AssetRepository(ref.watch(dbProvider)));
|
||||
|
||||
class AssetRepository implements IAssetRepository {
|
||||
final Isar _db;
|
||||
|
||||
AssetRepository(
|
||||
this._db,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getByAlbum(Album album, {User? notOwnedBy}) {
|
||||
var query = album.assets.filter();
|
||||
if (notOwnedBy != null) {
|
||||
query = query.not().ownerIdEqualTo(notOwnedBy.isarId);
|
||||
}
|
||||
return query.findAll();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteById(List<int> ids) =>
|
||||
_db.writeTxn(() => _db.assets.deleteAll(ids));
|
||||
}
|
20
mobile/lib/repositories/backup.repository.dart
Normal file
20
mobile/lib/repositories/backup.repository.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/backup.interface.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
final backupRepositoryProvider =
|
||||
Provider((ref) => BackupRepository(ref.watch(dbProvider)));
|
||||
|
||||
class BackupRepository implements IBackupRepository {
|
||||
final Isar _db;
|
||||
|
||||
BackupRepository(
|
||||
this._db,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<List<String>> getIdsBySelection(BackupSelection backup) =>
|
||||
_db.backupAlbums.filter().selectionEqualTo(backup).idProperty().findAll();
|
||||
}
|
20
mobile/lib/repositories/user.repository.dart
Normal file
20
mobile/lib/repositories/user.repository.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
final userRepositoryProvider =
|
||||
Provider((ref) => UserRepository(ref.watch(dbProvider)));
|
||||
|
||||
class UserRepository implements IUserRepository {
|
||||
final Isar _db;
|
||||
|
||||
UserRepository(
|
||||
this._db,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<List<User>> getByIds(List<String> ids) async =>
|
||||
(await _db.users.getAllById(ids)).cast();
|
||||
}
|
@ -5,6 +5,10 @@ import 'dart:io';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/interfaces/album.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/backup.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:immich_mobile/models/albums/album_add_asset_response.model.dart';
|
||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
@ -12,11 +16,13 @@ import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/repositories/album.repository.dart';
|
||||
import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/repositories/backup.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/sync.service.dart';
|
||||
import 'package:immich_mobile/services/user.service.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
@ -26,7 +32,10 @@ final albumServiceProvider = Provider(
|
||||
ref.watch(apiServiceProvider),
|
||||
ref.watch(userServiceProvider),
|
||||
ref.watch(syncServiceProvider),
|
||||
ref.watch(dbProvider),
|
||||
ref.watch(albumRepositoryProvider),
|
||||
ref.watch(assetRepositoryProvider),
|
||||
ref.watch(userRepositoryProvider),
|
||||
ref.watch(backupRepositoryProvider),
|
||||
),
|
||||
);
|
||||
|
||||
@ -34,7 +43,10 @@ class AlbumService {
|
||||
final ApiService _apiService;
|
||||
final UserService _userService;
|
||||
final SyncService _syncService;
|
||||
final Isar _db;
|
||||
final IAlbumRepository _albumRepository;
|
||||
final IAssetRepository _assetRepository;
|
||||
final IUserRepository _userRepository;
|
||||
final IBackupRepository _backupAlbumRepository;
|
||||
final Logger _log = Logger('AlbumService');
|
||||
Completer<bool> _localCompleter = Completer()..complete(false);
|
||||
Completer<bool> _remoteCompleter = Completer()..complete(false);
|
||||
@ -43,16 +55,12 @@ class AlbumService {
|
||||
this._apiService,
|
||||
this._userService,
|
||||
this._syncService,
|
||||
this._db,
|
||||
this._albumRepository,
|
||||
this._assetRepository,
|
||||
this._userRepository,
|
||||
this._backupAlbumRepository,
|
||||
);
|
||||
|
||||
QueryBuilder<BackupAlbum, BackupAlbum, QAfterFilterCondition>
|
||||
selectedAlbumsQuery() =>
|
||||
_db.backupAlbums.filter().selectionEqualTo(BackupSelection.select);
|
||||
QueryBuilder<BackupAlbum, BackupAlbum, QAfterFilterCondition>
|
||||
excludedAlbumsQuery() =>
|
||||
_db.backupAlbums.filter().selectionEqualTo(BackupSelection.exclude);
|
||||
|
||||
/// Checks all selected device albums for changes of albums and their assets
|
||||
/// Updates the local database and returns `true` if there were any changes
|
||||
Future<bool> refreshDeviceAlbums() async {
|
||||
@ -65,12 +73,12 @@ class AlbumService {
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
bool changes = false;
|
||||
try {
|
||||
final List<String> excludedIds =
|
||||
await excludedAlbumsQuery().idProperty().findAll();
|
||||
final List<String> selectedIds =
|
||||
await selectedAlbumsQuery().idProperty().findAll();
|
||||
final List<String> excludedIds = await _backupAlbumRepository
|
||||
.getIdsBySelection(BackupSelection.exclude);
|
||||
final List<String> selectedIds = await _backupAlbumRepository
|
||||
.getIdsBySelection(BackupSelection.select);
|
||||
if (selectedIds.isEmpty) {
|
||||
final numLocal = await _db.albums.where().localIdIsNotNull().count();
|
||||
final numLocal = await _albumRepository.count(local: true);
|
||||
if (numLocal > 0) {
|
||||
_syncService.removeAllLocalAlbumsAndAssets();
|
||||
}
|
||||
@ -194,8 +202,8 @@ class AlbumService {
|
||||
),
|
||||
);
|
||||
if (remote != null) {
|
||||
Album album = await Album.remote(remote);
|
||||
await _db.writeTxn(() => _db.albums.store(album));
|
||||
final Album album = await Album.remote(remote);
|
||||
await _albumRepository.create(album);
|
||||
return album;
|
||||
}
|
||||
} catch (e) {
|
||||
@ -212,8 +220,7 @@ class AlbumService {
|
||||
for (int round = 0;; round++) {
|
||||
final proposedName = "$baseName${round == 0 ? "" : " ($round)"}";
|
||||
|
||||
if (null ==
|
||||
await _db.albums.filter().nameEqualTo(proposedName).findFirst()) {
|
||||
if (null == await _albumRepository.getByName(proposedName)) {
|
||||
return proposedName;
|
||||
}
|
||||
}
|
||||
@ -268,20 +275,15 @@ class AlbumService {
|
||||
|
||||
Future<void> _updateAssets(
|
||||
int albumId, {
|
||||
Iterable<Asset> add = const [],
|
||||
Iterable<Asset> remove = const [],
|
||||
}) {
|
||||
return _db.writeTxn(() async {
|
||||
final album = await _db.albums.get(albumId);
|
||||
if (album == null) return;
|
||||
await album.assets.update(link: add, unlink: remove);
|
||||
album.startDate =
|
||||
await album.assets.filter().fileCreatedAtProperty().min();
|
||||
album.endDate = await album.assets.filter().fileCreatedAtProperty().max();
|
||||
album.lastModifiedAssetTimestamp =
|
||||
await album.assets.filter().updatedAtProperty().max();
|
||||
await _db.albums.put(album);
|
||||
});
|
||||
List<Asset> add = const [],
|
||||
List<Asset> remove = const [],
|
||||
}) async {
|
||||
final album = await _albumRepository.getById(albumId);
|
||||
if (album == null) return;
|
||||
await _albumRepository.addAssets(album, add);
|
||||
await _albumRepository.removeAssets(album, remove);
|
||||
await _albumRepository.recalculateMetadata(album);
|
||||
await _albumRepository.update(album);
|
||||
}
|
||||
|
||||
Future<bool> addAdditionalUserToAlbum(
|
||||
@ -298,13 +300,9 @@ class AlbumService {
|
||||
AddUsersDto(albumUsers: albumUsers),
|
||||
);
|
||||
if (result != null) {
|
||||
album.sharedUsers
|
||||
.addAll((await _db.users.getAllById(sharedUserIds)).cast());
|
||||
album.sharedUsers.addAll(await _userRepository.getByIds(sharedUserIds));
|
||||
album.shared = result.shared;
|
||||
await _db.writeTxn(() async {
|
||||
await _db.albums.put(album);
|
||||
await album.sharedUsers.save();
|
||||
});
|
||||
await _albumRepository.update(album);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
@ -321,7 +319,7 @@ class AlbumService {
|
||||
);
|
||||
if (result != null) {
|
||||
album.activityEnabled = enabled;
|
||||
await _db.writeTxn(() => _db.albums.put(album));
|
||||
await _albumRepository.update(album);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
@ -332,29 +330,29 @@ class AlbumService {
|
||||
|
||||
Future<bool> deleteAlbum(Album album) async {
|
||||
try {
|
||||
final userId = Store.get(StoreKey.currentUser).isarId;
|
||||
if (album.owner.value?.isarId == userId) {
|
||||
final user = Store.get(StoreKey.currentUser);
|
||||
if (album.owner.value?.isarId == user.isarId) {
|
||||
await _apiService.albumsApi.deleteAlbum(album.remoteId!);
|
||||
}
|
||||
if (album.shared) {
|
||||
final foreignAssets =
|
||||
await album.assets.filter().not().ownerIdEqualTo(userId).findAll();
|
||||
await _db.writeTxn(() => _db.albums.delete(album.id));
|
||||
final List<Album> albums =
|
||||
await _db.albums.filter().sharedEqualTo(true).findAll();
|
||||
await _assetRepository.getByAlbum(album, notOwnedBy: user);
|
||||
await _albumRepository.delete(album.id);
|
||||
|
||||
final List<Album> albums = await _albumRepository.getAll(shared: true);
|
||||
final List<Asset> existing = [];
|
||||
for (Album a in albums) {
|
||||
for (Album album in albums) {
|
||||
existing.addAll(
|
||||
await a.assets.filter().not().ownerIdEqualTo(userId).findAll(),
|
||||
await _assetRepository.getByAlbum(album, notOwnedBy: user),
|
||||
);
|
||||
}
|
||||
final List<int> idsToRemove =
|
||||
_syncService.sharedAssetsToRemove(foreignAssets, existing);
|
||||
if (idsToRemove.isNotEmpty) {
|
||||
await _db.writeTxn(() => _db.assets.deleteAll(idsToRemove));
|
||||
await _assetRepository.deleteById(idsToRemove);
|
||||
}
|
||||
} else {
|
||||
await _db.writeTxn(() => _db.albums.delete(album.id));
|
||||
await _albumRepository.delete(album.id);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
@ -390,7 +388,7 @@ class AlbumService {
|
||||
: response
|
||||
.where((e) => e.success)
|
||||
.map((e) => assets.firstWhere((a) => a.remoteId == e.id));
|
||||
await _updateAssets(album.id, remove: toRemove);
|
||||
await _updateAssets(album.id, remove: toRemove.toList());
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
@ -410,12 +408,10 @@ class AlbumService {
|
||||
);
|
||||
|
||||
album.sharedUsers.remove(user);
|
||||
await _db.writeTxn(() async {
|
||||
await album.sharedUsers.update(unlink: [user]);
|
||||
final a = await _db.albums.get(album.id);
|
||||
// trigger watcher
|
||||
await _db.albums.put(a!);
|
||||
});
|
||||
await _albumRepository.removeUsers(album, [user]);
|
||||
final a = await _albumRepository.getById(album.id);
|
||||
// trigger watcher
|
||||
await _albumRepository.update(a!);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
@ -436,7 +432,7 @@ class AlbumService {
|
||||
),
|
||||
);
|
||||
album.name = newAlbumTitle;
|
||||
await _db.writeTxn(() => _db.albums.put(album));
|
||||
await _albumRepository.update(album);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
@ -445,14 +441,8 @@ class AlbumService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Album?> getAlbumByName(String name, bool remoteOnly) async {
|
||||
return _db.albums
|
||||
.filter()
|
||||
.optional(remoteOnly, (q) => q.localIdIsNull())
|
||||
.nameEqualTo(name)
|
||||
.sharedEqualTo(false)
|
||||
.findFirst();
|
||||
}
|
||||
Future<Album?> getAlbumByName(String name, bool remoteOnly) =>
|
||||
_albumRepository.getByName(name, remote: remoteOnly ? true : null);
|
||||
|
||||
///
|
||||
/// Add the uploaded asset to the selected albums
|
||||
|
@ -12,6 +12,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/main.dart';
|
||||
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||
import 'package:immich_mobile/models/backup/success_upload_asset.model.dart';
|
||||
import 'package:immich_mobile/repositories/album.repository.dart';
|
||||
import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/repositories/backup.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
import 'package:immich_mobile/services/album.service.dart';
|
||||
import 'package:immich_mobile/services/hash.service.dart';
|
||||
import 'package:immich_mobile/services/localization.service.dart';
|
||||
@ -355,12 +359,23 @@ class BackgroundService {
|
||||
AppSettingsService settingService = AppSettingsService();
|
||||
AppSettingsService settingsService = AppSettingsService();
|
||||
PartnerService partnerService = PartnerService(apiService, db);
|
||||
AlbumRepository albumRepository = AlbumRepository(db);
|
||||
AssetRepository assetRepository = AssetRepository(db);
|
||||
UserRepository userRepository = UserRepository(db);
|
||||
BackupRepository backupAlbumRepository = BackupRepository(db);
|
||||
HashService hashService = HashService(db, this);
|
||||
SyncService syncSerive = SyncService(db, hashService);
|
||||
UserService userService =
|
||||
UserService(apiService, db, syncSerive, partnerService);
|
||||
AlbumService albumService =
|
||||
AlbumService(apiService, userService, syncSerive, db);
|
||||
AlbumService albumService = AlbumService(
|
||||
apiService,
|
||||
userService,
|
||||
syncSerive,
|
||||
albumRepository,
|
||||
assetRepository,
|
||||
userRepository,
|
||||
backupAlbumRepository,
|
||||
);
|
||||
BackupService backupService =
|
||||
BackupService(apiService, db, settingService, albumService);
|
||||
|
||||
|
@ -59,8 +59,6 @@ class DraggableScrollbar extends StatefulWidget {
|
||||
|
||||
final Function(bool scrolling) scrollStateListener;
|
||||
|
||||
final double viewPortHeight;
|
||||
|
||||
DraggableScrollbar.semicircle({
|
||||
super.key,
|
||||
Key? scrollThumbKey,
|
||||
@ -69,7 +67,6 @@ class DraggableScrollbar extends StatefulWidget {
|
||||
required this.controller,
|
||||
required this.itemPositionsListener,
|
||||
required this.scrollStateListener,
|
||||
required this.viewPortHeight,
|
||||
this.heightScrollThumb = 48.0,
|
||||
this.backgroundColor = Colors.white,
|
||||
this.padding,
|
||||
@ -254,7 +251,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
|
||||
}
|
||||
|
||||
double get barMaxScrollExtent =>
|
||||
widget.viewPortHeight -
|
||||
(context.size?.height ?? 0) -
|
||||
widget.heightScrollThumb -
|
||||
(widget.heightOffset ?? 0);
|
||||
|
||||
@ -340,8 +337,8 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
|
||||
_thumbAnimationController.forward();
|
||||
}
|
||||
|
||||
if (itemPos < maxItemCount) {
|
||||
_currentItem = itemPos;
|
||||
if (itemPosition < maxItemCount) {
|
||||
_currentItem = itemPosition;
|
||||
}
|
||||
|
||||
_fadeoutTimer?.cancel();
|
||||
@ -365,25 +362,35 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
|
||||
widget.scrollStateListener(true);
|
||||
}
|
||||
|
||||
int get itemPos {
|
||||
int get itemPosition {
|
||||
int numberOfItems = widget.child.itemCount;
|
||||
return ((_barOffset / barMaxScrollExtent) * numberOfItems).toInt();
|
||||
}
|
||||
|
||||
void _jumpToBarPos() {
|
||||
if (itemPos > maxItemCount - 1) {
|
||||
void _jumpToBarPosition() {
|
||||
if (itemPosition > maxItemCount - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_currentItem = itemPos;
|
||||
_currentItem = itemPosition;
|
||||
|
||||
/// If the bar is at the bottom but the item position is still smaller than the max item count (due to rounding error)
|
||||
/// jump to the end of the list
|
||||
if (barMaxScrollExtent - _barOffset < 10 && itemPosition < maxItemCount) {
|
||||
widget.controller.jumpTo(
|
||||
index: maxItemCount,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
widget.controller.jumpTo(
|
||||
index: itemPos,
|
||||
index: itemPosition,
|
||||
);
|
||||
}
|
||||
|
||||
Timer? dragHaltTimer;
|
||||
int lastTimerPos = 0;
|
||||
int lastTimerPosition = 0;
|
||||
|
||||
void _onVerticalDragUpdate(DragUpdateDetails details) {
|
||||
setState(() {
|
||||
@ -400,8 +407,8 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
|
||||
_barOffset = barMaxScrollExtent;
|
||||
}
|
||||
|
||||
if (itemPos != lastTimerPos) {
|
||||
lastTimerPos = itemPos;
|
||||
if (itemPosition != lastTimerPosition) {
|
||||
lastTimerPosition = itemPosition;
|
||||
dragHaltTimer?.cancel();
|
||||
widget.scrollStateListener(true);
|
||||
|
||||
@ -413,7 +420,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
|
||||
);
|
||||
}
|
||||
|
||||
_jumpToBarPos();
|
||||
_jumpToBarPosition();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -426,7 +433,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_jumpToBarPos();
|
||||
_jumpToBarPosition();
|
||||
_isDragInProcess = false;
|
||||
});
|
||||
|
||||
|
@ -264,7 +264,6 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
|
||||
|
||||
final child = (useDragScrolling && ModalRoute.of(context) != null)
|
||||
? DraggableScrollbar.semicircle(
|
||||
viewPortHeight: context.height,
|
||||
scrollStateListener: dragScrolling,
|
||||
itemPositionsListener: _itemPositionsListener,
|
||||
controller: _itemScrollController,
|
||||
|
@ -237,35 +237,40 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
return Dialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
alignment: Alignment.topCenter,
|
||||
insetPadding: EdgeInsets.only(
|
||||
top: isHorizontal ? 20 : 40,
|
||||
left: horizontalPadding,
|
||||
right: horizontalPadding,
|
||||
bottom: isHorizontal ? 20 : 100,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: SizedBox(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: buildTopRow(),
|
||||
),
|
||||
const AppBarProfileInfoBox(),
|
||||
buildStorageInformation(),
|
||||
const AppBarServerInfo(),
|
||||
buildAppLogButton(),
|
||||
buildSettingButton(),
|
||||
buildSignOutButton(),
|
||||
buildFooter(),
|
||||
],
|
||||
return Dismissible(
|
||||
direction: DismissDirection.down,
|
||||
onDismissed: (_) => Navigator.of(context).pop(),
|
||||
key: const Key('app_bar_dialog'),
|
||||
child: Dialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
alignment: Alignment.topCenter,
|
||||
insetPadding: EdgeInsets.only(
|
||||
top: isHorizontal ? 20 : 40,
|
||||
left: horizontalPadding,
|
||||
right: horizontalPadding,
|
||||
bottom: isHorizontal ? 20 : 100,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: SizedBox(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: buildTopRow(),
|
||||
),
|
||||
const AppBarProfileInfoBox(),
|
||||
buildStorageInformation(),
|
||||
const AppBarServerInfo(),
|
||||
buildAppLogButton(),
|
||||
buildSettingButton(),
|
||||
buildSignOutButton(),
|
||||
buildFooter(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
5
mobile/openapi/README.md
generated
5
mobile/openapi/README.md
generated
@ -3,7 +3,7 @@ Immich API
|
||||
|
||||
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||
|
||||
- API version: 1.114.0
|
||||
- API version: 1.115.0
|
||||
- Generator version: 7.8.0
|
||||
- Build package: org.openapitools.codegen.languages.DartClientCodegen
|
||||
|
||||
@ -124,6 +124,7 @@ Class | Method | HTTP request | Description
|
||||
*FileReportsApi* | [**fixAuditFiles**](doc//FileReportsApi.md#fixauditfiles) | **POST** /reports/fix |
|
||||
*FileReportsApi* | [**getAuditFiles**](doc//FileReportsApi.md#getauditfiles) | **GET** /reports |
|
||||
*FileReportsApi* | [**getFileChecksums**](doc//FileReportsApi.md#getfilechecksums) | **POST** /reports/checksum |
|
||||
*JobsApi* | [**createJob**](doc//JobsApi.md#createjob) | **POST** /jobs |
|
||||
*JobsApi* | [**getAllJobsStatus**](doc//JobsApi.md#getalljobsstatus) | **GET** /jobs |
|
||||
*JobsApi* | [**sendJobCommand**](doc//JobsApi.md#sendjobcommand) | **PUT** /jobs/{id} |
|
||||
*LibrariesApi* | [**createLibrary**](doc//LibrariesApi.md#createlibrary) | **POST** /libraries |
|
||||
@ -330,6 +331,7 @@ Class | Method | HTTP request | Description
|
||||
- [JobCommand](doc//JobCommand.md)
|
||||
- [JobCommandDto](doc//JobCommandDto.md)
|
||||
- [JobCountsDto](doc//JobCountsDto.md)
|
||||
- [JobCreateDto](doc//JobCreateDto.md)
|
||||
- [JobName](doc//JobName.md)
|
||||
- [JobSettingsDto](doc//JobSettingsDto.md)
|
||||
- [JobStatusDto](doc//JobStatusDto.md)
|
||||
@ -341,6 +343,7 @@ Class | Method | HTTP request | Description
|
||||
- [LoginCredentialDto](doc//LoginCredentialDto.md)
|
||||
- [LoginResponseDto](doc//LoginResponseDto.md)
|
||||
- [LogoutResponseDto](doc//LogoutResponseDto.md)
|
||||
- [ManualJobName](doc//ManualJobName.md)
|
||||
- [MapMarkerResponseDto](doc//MapMarkerResponseDto.md)
|
||||
- [MapReverseGeocodeResponseDto](doc//MapReverseGeocodeResponseDto.md)
|
||||
- [MapTheme](doc//MapTheme.md)
|
||||
|
2
mobile/openapi/lib/api.dart
generated
2
mobile/openapi/lib/api.dart
generated
@ -144,6 +144,7 @@ part 'model/image_format.dart';
|
||||
part 'model/job_command.dart';
|
||||
part 'model/job_command_dto.dart';
|
||||
part 'model/job_counts_dto.dart';
|
||||
part 'model/job_create_dto.dart';
|
||||
part 'model/job_name.dart';
|
||||
part 'model/job_settings_dto.dart';
|
||||
part 'model/job_status_dto.dart';
|
||||
@ -155,6 +156,7 @@ part 'model/log_level.dart';
|
||||
part 'model/login_credential_dto.dart';
|
||||
part 'model/login_response_dto.dart';
|
||||
part 'model/logout_response_dto.dart';
|
||||
part 'model/manual_job_name.dart';
|
||||
part 'model/map_marker_response_dto.dart';
|
||||
part 'model/map_reverse_geocode_response_dto.dart';
|
||||
part 'model/map_theme.dart';
|
||||
|
39
mobile/openapi/lib/api/jobs_api.dart
generated
39
mobile/openapi/lib/api/jobs_api.dart
generated
@ -16,6 +16,45 @@ class JobsApi {
|
||||
|
||||
final ApiClient apiClient;
|
||||
|
||||
/// Performs an HTTP 'POST /jobs' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [JobCreateDto] jobCreateDto (required):
|
||||
Future<Response> createJobWithHttpInfo(JobCreateDto jobCreateDto,) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/jobs';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody = jobCreateDto;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
const contentTypes = <String>['application/json'];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [JobCreateDto] jobCreateDto (required):
|
||||
Future<void> createJob(JobCreateDto jobCreateDto,) async {
|
||||
final response = await createJobWithHttpInfo(jobCreateDto,);
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'GET /jobs' operation and returns the [Response].
|
||||
Future<Response> getAllJobsStatusWithHttpInfo() async {
|
||||
// ignore: prefer_const_declarations
|
||||
|
4
mobile/openapi/lib/api_client.dart
generated
4
mobile/openapi/lib/api_client.dart
generated
@ -343,6 +343,8 @@ class ApiClient {
|
||||
return JobCommandDto.fromJson(value);
|
||||
case 'JobCountsDto':
|
||||
return JobCountsDto.fromJson(value);
|
||||
case 'JobCreateDto':
|
||||
return JobCreateDto.fromJson(value);
|
||||
case 'JobName':
|
||||
return JobNameTypeTransformer().decode(value);
|
||||
case 'JobSettingsDto':
|
||||
@ -365,6 +367,8 @@ class ApiClient {
|
||||
return LoginResponseDto.fromJson(value);
|
||||
case 'LogoutResponseDto':
|
||||
return LogoutResponseDto.fromJson(value);
|
||||
case 'ManualJobName':
|
||||
return ManualJobNameTypeTransformer().decode(value);
|
||||
case 'MapMarkerResponseDto':
|
||||
return MapMarkerResponseDto.fromJson(value);
|
||||
case 'MapReverseGeocodeResponseDto':
|
||||
|
3
mobile/openapi/lib/api_helper.dart
generated
3
mobile/openapi/lib/api_helper.dart
generated
@ -97,6 +97,9 @@ String parameterToString(dynamic value) {
|
||||
if (value is LogLevel) {
|
||||
return LogLevelTypeTransformer().encode(value).toString();
|
||||
}
|
||||
if (value is ManualJobName) {
|
||||
return ManualJobNameTypeTransformer().encode(value).toString();
|
||||
}
|
||||
if (value is MapTheme) {
|
||||
return MapThemeTypeTransformer().encode(value).toString();
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ class AssetBulkUploadCheckResult {
|
||||
required this.action,
|
||||
this.assetId,
|
||||
required this.id,
|
||||
this.isTrashed,
|
||||
this.reason,
|
||||
});
|
||||
|
||||
@ -31,6 +32,14 @@ class AssetBulkUploadCheckResult {
|
||||
|
||||
String id;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isTrashed;
|
||||
|
||||
AssetBulkUploadCheckResultReasonEnum? reason;
|
||||
|
||||
@override
|
||||
@ -38,6 +47,7 @@ class AssetBulkUploadCheckResult {
|
||||
other.action == action &&
|
||||
other.assetId == assetId &&
|
||||
other.id == id &&
|
||||
other.isTrashed == isTrashed &&
|
||||
other.reason == reason;
|
||||
|
||||
@override
|
||||
@ -46,10 +56,11 @@ class AssetBulkUploadCheckResult {
|
||||
(action.hashCode) +
|
||||
(assetId == null ? 0 : assetId!.hashCode) +
|
||||
(id.hashCode) +
|
||||
(isTrashed == null ? 0 : isTrashed!.hashCode) +
|
||||
(reason == null ? 0 : reason!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'AssetBulkUploadCheckResult[action=$action, assetId=$assetId, id=$id, reason=$reason]';
|
||||
String toString() => 'AssetBulkUploadCheckResult[action=$action, assetId=$assetId, id=$id, isTrashed=$isTrashed, reason=$reason]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@ -60,6 +71,11 @@ class AssetBulkUploadCheckResult {
|
||||
// json[r'assetId'] = null;
|
||||
}
|
||||
json[r'id'] = this.id;
|
||||
if (this.isTrashed != null) {
|
||||
json[r'isTrashed'] = this.isTrashed;
|
||||
} else {
|
||||
// json[r'isTrashed'] = null;
|
||||
}
|
||||
if (this.reason != null) {
|
||||
json[r'reason'] = this.reason;
|
||||
} else {
|
||||
@ -79,6 +95,7 @@ class AssetBulkUploadCheckResult {
|
||||
action: AssetBulkUploadCheckResultActionEnum.fromJson(json[r'action'])!,
|
||||
assetId: mapValueOfType<String>(json, r'assetId'),
|
||||
id: mapValueOfType<String>(json, r'id')!,
|
||||
isTrashed: mapValueOfType<bool>(json, r'isTrashed'),
|
||||
reason: AssetBulkUploadCheckResultReasonEnum.fromJson(json[r'reason']),
|
||||
);
|
||||
}
|
||||
|
@ -13,30 +13,36 @@ part of openapi.api;
|
||||
class CreateProfileImageResponseDto {
|
||||
/// Returns a new [CreateProfileImageResponseDto] instance.
|
||||
CreateProfileImageResponseDto({
|
||||
required this.profileChangedAt,
|
||||
required this.profileImagePath,
|
||||
required this.userId,
|
||||
});
|
||||
|
||||
DateTime profileChangedAt;
|
||||
|
||||
String profileImagePath;
|
||||
|
||||
String userId;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is CreateProfileImageResponseDto &&
|
||||
other.profileChangedAt == profileChangedAt &&
|
||||
other.profileImagePath == profileImagePath &&
|
||||
other.userId == userId;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(profileChangedAt.hashCode) +
|
||||
(profileImagePath.hashCode) +
|
||||
(userId.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'CreateProfileImageResponseDto[profileImagePath=$profileImagePath, userId=$userId]';
|
||||
String toString() => 'CreateProfileImageResponseDto[profileChangedAt=$profileChangedAt, profileImagePath=$profileImagePath, userId=$userId]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String();
|
||||
json[r'profileImagePath'] = this.profileImagePath;
|
||||
json[r'userId'] = this.userId;
|
||||
return json;
|
||||
@ -50,6 +56,7 @@ class CreateProfileImageResponseDto {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return CreateProfileImageResponseDto(
|
||||
profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!,
|
||||
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
|
||||
userId: mapValueOfType<String>(json, r'userId')!,
|
||||
);
|
||||
@ -99,6 +106,7 @@ class CreateProfileImageResponseDto {
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'profileChangedAt',
|
||||
'profileImagePath',
|
||||
'userId',
|
||||
};
|
||||
|
98
mobile/openapi/lib/model/job_create_dto.dart
generated
Normal file
98
mobile/openapi/lib/model/job_create_dto.dart
generated
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class JobCreateDto {
|
||||
/// Returns a new [JobCreateDto] instance.
|
||||
JobCreateDto({
|
||||
required this.name,
|
||||
});
|
||||
|
||||
ManualJobName name;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is JobCreateDto &&
|
||||
other.name == name;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(name.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'JobCreateDto[name=$name]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'name'] = this.name;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [JobCreateDto] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static JobCreateDto? fromJson(dynamic value) {
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return JobCreateDto(
|
||||
name: ManualJobName.fromJson(json[r'name'])!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<JobCreateDto> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <JobCreateDto>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = JobCreateDto.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, JobCreateDto> mapFromJson(dynamic json) {
|
||||
final map = <String, JobCreateDto>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = JobCreateDto.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of JobCreateDto-objects as value to a dart map
|
||||
static Map<String, List<JobCreateDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<JobCreateDto>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = JobCreateDto.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'name',
|
||||
};
|
||||
}
|
||||
|
88
mobile/openapi/lib/model/manual_job_name.dart
generated
Normal file
88
mobile/openapi/lib/model/manual_job_name.dart
generated
Normal file
@ -0,0 +1,88 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
|
||||
class ManualJobName {
|
||||
/// Instantiate a new enum with the provided [value].
|
||||
const ManualJobName._(this.value);
|
||||
|
||||
/// The underlying value of this enum member.
|
||||
final String value;
|
||||
|
||||
@override
|
||||
String toString() => value;
|
||||
|
||||
String toJson() => value;
|
||||
|
||||
static const personCleanup = ManualJobName._(r'person-cleanup');
|
||||
static const tagCleanup = ManualJobName._(r'tag-cleanup');
|
||||
static const userCleanup = ManualJobName._(r'user-cleanup');
|
||||
|
||||
/// List of all possible values in this [enum][ManualJobName].
|
||||
static const values = <ManualJobName>[
|
||||
personCleanup,
|
||||
tagCleanup,
|
||||
userCleanup,
|
||||
];
|
||||
|
||||
static ManualJobName? fromJson(dynamic value) => ManualJobNameTypeTransformer().decode(value);
|
||||
|
||||
static List<ManualJobName> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <ManualJobName>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = ManualJobName.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
}
|
||||
|
||||
/// Transformation class that can [encode] an instance of [ManualJobName] to String,
|
||||
/// and [decode] dynamic data back to [ManualJobName].
|
||||
class ManualJobNameTypeTransformer {
|
||||
factory ManualJobNameTypeTransformer() => _instance ??= const ManualJobNameTypeTransformer._();
|
||||
|
||||
const ManualJobNameTypeTransformer._();
|
||||
|
||||
String encode(ManualJobName data) => data.value;
|
||||
|
||||
/// Decodes a [dynamic value][data] to a ManualJobName.
|
||||
///
|
||||
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
|
||||
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
|
||||
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
|
||||
///
|
||||
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
|
||||
/// and users are still using an old app with the old code.
|
||||
ManualJobName? decode(dynamic data, {bool allowNull = true}) {
|
||||
if (data != null) {
|
||||
switch (data) {
|
||||
case r'person-cleanup': return ManualJobName.personCleanup;
|
||||
case r'tag-cleanup': return ManualJobName.tagCleanup;
|
||||
case r'user-cleanup': return ManualJobName.userCleanup;
|
||||
default:
|
||||
if (!allowNull) {
|
||||
throw ArgumentError('Unknown enum value to decode: $data');
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Singleton [ManualJobNameTypeTransformer] instance.
|
||||
static ManualJobNameTypeTransformer? _instance;
|
||||
}
|
||||
|
10
mobile/openapi/lib/model/partner_response_dto.dart
generated
10
mobile/openapi/lib/model/partner_response_dto.dart
generated
@ -18,6 +18,7 @@ class PartnerResponseDto {
|
||||
required this.id,
|
||||
this.inTimeline,
|
||||
required this.name,
|
||||
required this.profileChangedAt,
|
||||
required this.profileImagePath,
|
||||
});
|
||||
|
||||
@ -37,6 +38,8 @@ class PartnerResponseDto {
|
||||
|
||||
String name;
|
||||
|
||||
DateTime profileChangedAt;
|
||||
|
||||
String profileImagePath;
|
||||
|
||||
@override
|
||||
@ -46,6 +49,7 @@ class PartnerResponseDto {
|
||||
other.id == id &&
|
||||
other.inTimeline == inTimeline &&
|
||||
other.name == name &&
|
||||
other.profileChangedAt == profileChangedAt &&
|
||||
other.profileImagePath == profileImagePath;
|
||||
|
||||
@override
|
||||
@ -56,10 +60,11 @@ class PartnerResponseDto {
|
||||
(id.hashCode) +
|
||||
(inTimeline == null ? 0 : inTimeline!.hashCode) +
|
||||
(name.hashCode) +
|
||||
(profileChangedAt.hashCode) +
|
||||
(profileImagePath.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'PartnerResponseDto[avatarColor=$avatarColor, email=$email, id=$id, inTimeline=$inTimeline, name=$name, profileImagePath=$profileImagePath]';
|
||||
String toString() => 'PartnerResponseDto[avatarColor=$avatarColor, email=$email, id=$id, inTimeline=$inTimeline, name=$name, profileChangedAt=$profileChangedAt, profileImagePath=$profileImagePath]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@ -72,6 +77,7 @@ class PartnerResponseDto {
|
||||
// json[r'inTimeline'] = null;
|
||||
}
|
||||
json[r'name'] = this.name;
|
||||
json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String();
|
||||
json[r'profileImagePath'] = this.profileImagePath;
|
||||
return json;
|
||||
}
|
||||
@ -89,6 +95,7 @@ class PartnerResponseDto {
|
||||
id: mapValueOfType<String>(json, r'id')!,
|
||||
inTimeline: mapValueOfType<bool>(json, r'inTimeline'),
|
||||
name: mapValueOfType<String>(json, r'name')!,
|
||||
profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!,
|
||||
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
|
||||
);
|
||||
}
|
||||
@ -141,6 +148,7 @@ class PartnerResponseDto {
|
||||
'email',
|
||||
'id',
|
||||
'name',
|
||||
'profileChangedAt',
|
||||
'profileImagePath',
|
||||
};
|
||||
}
|
||||
|
13
mobile/openapi/lib/model/update_asset_dto.dart
generated
13
mobile/openapi/lib/model/update_asset_dto.dart
generated
@ -18,6 +18,7 @@ class UpdateAssetDto {
|
||||
this.isArchived,
|
||||
this.isFavorite,
|
||||
this.latitude,
|
||||
this.livePhotoVideoId,
|
||||
this.longitude,
|
||||
this.rating,
|
||||
});
|
||||
@ -62,6 +63,8 @@ class UpdateAssetDto {
|
||||
///
|
||||
num? latitude;
|
||||
|
||||
String? livePhotoVideoId;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
@ -87,6 +90,7 @@ class UpdateAssetDto {
|
||||
other.isArchived == isArchived &&
|
||||
other.isFavorite == isFavorite &&
|
||||
other.latitude == latitude &&
|
||||
other.livePhotoVideoId == livePhotoVideoId &&
|
||||
other.longitude == longitude &&
|
||||
other.rating == rating;
|
||||
|
||||
@ -98,11 +102,12 @@ class UpdateAssetDto {
|
||||
(isArchived == null ? 0 : isArchived!.hashCode) +
|
||||
(isFavorite == null ? 0 : isFavorite!.hashCode) +
|
||||
(latitude == null ? 0 : latitude!.hashCode) +
|
||||
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
|
||||
(longitude == null ? 0 : longitude!.hashCode) +
|
||||
(rating == null ? 0 : rating!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'UpdateAssetDto[dateTimeOriginal=$dateTimeOriginal, description=$description, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, rating=$rating]';
|
||||
String toString() => 'UpdateAssetDto[dateTimeOriginal=$dateTimeOriginal, description=$description, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, livePhotoVideoId=$livePhotoVideoId, longitude=$longitude, rating=$rating]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@ -131,6 +136,11 @@ class UpdateAssetDto {
|
||||
} else {
|
||||
// json[r'latitude'] = null;
|
||||
}
|
||||
if (this.livePhotoVideoId != null) {
|
||||
json[r'livePhotoVideoId'] = this.livePhotoVideoId;
|
||||
} else {
|
||||
// json[r'livePhotoVideoId'] = null;
|
||||
}
|
||||
if (this.longitude != null) {
|
||||
json[r'longitude'] = this.longitude;
|
||||
} else {
|
||||
@ -157,6 +167,7 @@ class UpdateAssetDto {
|
||||
isArchived: mapValueOfType<bool>(json, r'isArchived'),
|
||||
isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
|
||||
latitude: num.parse('${json[r'latitude']}'),
|
||||
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
|
||||
longitude: num.parse('${json[r'longitude']}'),
|
||||
rating: num.parse('${json[r'rating']}'),
|
||||
);
|
||||
|
@ -22,6 +22,7 @@ class UserAdminResponseDto {
|
||||
required this.license,
|
||||
required this.name,
|
||||
required this.oauthId,
|
||||
required this.profileChangedAt,
|
||||
required this.profileImagePath,
|
||||
required this.quotaSizeInBytes,
|
||||
required this.quotaUsageInBytes,
|
||||
@ -49,6 +50,8 @@ class UserAdminResponseDto {
|
||||
|
||||
String oauthId;
|
||||
|
||||
DateTime profileChangedAt;
|
||||
|
||||
String profileImagePath;
|
||||
|
||||
int? quotaSizeInBytes;
|
||||
@ -74,6 +77,7 @@ class UserAdminResponseDto {
|
||||
other.license == license &&
|
||||
other.name == name &&
|
||||
other.oauthId == oauthId &&
|
||||
other.profileChangedAt == profileChangedAt &&
|
||||
other.profileImagePath == profileImagePath &&
|
||||
other.quotaSizeInBytes == quotaSizeInBytes &&
|
||||
other.quotaUsageInBytes == quotaUsageInBytes &&
|
||||
@ -94,6 +98,7 @@ class UserAdminResponseDto {
|
||||
(license == null ? 0 : license!.hashCode) +
|
||||
(name.hashCode) +
|
||||
(oauthId.hashCode) +
|
||||
(profileChangedAt.hashCode) +
|
||||
(profileImagePath.hashCode) +
|
||||
(quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) +
|
||||
(quotaUsageInBytes == null ? 0 : quotaUsageInBytes!.hashCode) +
|
||||
@ -103,7 +108,7 @@ class UserAdminResponseDto {
|
||||
(updatedAt.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'UserAdminResponseDto[avatarColor=$avatarColor, createdAt=$createdAt, deletedAt=$deletedAt, email=$email, id=$id, isAdmin=$isAdmin, license=$license, name=$name, oauthId=$oauthId, profileImagePath=$profileImagePath, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, shouldChangePassword=$shouldChangePassword, status=$status, storageLabel=$storageLabel, updatedAt=$updatedAt]';
|
||||
String toString() => 'UserAdminResponseDto[avatarColor=$avatarColor, createdAt=$createdAt, deletedAt=$deletedAt, email=$email, id=$id, isAdmin=$isAdmin, license=$license, name=$name, oauthId=$oauthId, profileChangedAt=$profileChangedAt, profileImagePath=$profileImagePath, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, shouldChangePassword=$shouldChangePassword, status=$status, storageLabel=$storageLabel, updatedAt=$updatedAt]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@ -124,6 +129,7 @@ class UserAdminResponseDto {
|
||||
}
|
||||
json[r'name'] = this.name;
|
||||
json[r'oauthId'] = this.oauthId;
|
||||
json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String();
|
||||
json[r'profileImagePath'] = this.profileImagePath;
|
||||
if (this.quotaSizeInBytes != null) {
|
||||
json[r'quotaSizeInBytes'] = this.quotaSizeInBytes;
|
||||
@ -163,6 +169,7 @@ class UserAdminResponseDto {
|
||||
license: UserLicense.fromJson(json[r'license']),
|
||||
name: mapValueOfType<String>(json, r'name')!,
|
||||
oauthId: mapValueOfType<String>(json, r'oauthId')!,
|
||||
profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!,
|
||||
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
|
||||
quotaSizeInBytes: mapValueOfType<int>(json, r'quotaSizeInBytes'),
|
||||
quotaUsageInBytes: mapValueOfType<int>(json, r'quotaUsageInBytes'),
|
||||
@ -226,6 +233,7 @@ class UserAdminResponseDto {
|
||||
'license',
|
||||
'name',
|
||||
'oauthId',
|
||||
'profileChangedAt',
|
||||
'profileImagePath',
|
||||
'quotaSizeInBytes',
|
||||
'quotaUsageInBytes',
|
||||
|
10
mobile/openapi/lib/model/user_response_dto.dart
generated
10
mobile/openapi/lib/model/user_response_dto.dart
generated
@ -17,6 +17,7 @@ class UserResponseDto {
|
||||
required this.email,
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.profileChangedAt,
|
||||
required this.profileImagePath,
|
||||
});
|
||||
|
||||
@ -28,6 +29,8 @@ class UserResponseDto {
|
||||
|
||||
String name;
|
||||
|
||||
DateTime profileChangedAt;
|
||||
|
||||
String profileImagePath;
|
||||
|
||||
@override
|
||||
@ -36,6 +39,7 @@ class UserResponseDto {
|
||||
other.email == email &&
|
||||
other.id == id &&
|
||||
other.name == name &&
|
||||
other.profileChangedAt == profileChangedAt &&
|
||||
other.profileImagePath == profileImagePath;
|
||||
|
||||
@override
|
||||
@ -45,10 +49,11 @@ class UserResponseDto {
|
||||
(email.hashCode) +
|
||||
(id.hashCode) +
|
||||
(name.hashCode) +
|
||||
(profileChangedAt.hashCode) +
|
||||
(profileImagePath.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'UserResponseDto[avatarColor=$avatarColor, email=$email, id=$id, name=$name, profileImagePath=$profileImagePath]';
|
||||
String toString() => 'UserResponseDto[avatarColor=$avatarColor, email=$email, id=$id, name=$name, profileChangedAt=$profileChangedAt, profileImagePath=$profileImagePath]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@ -56,6 +61,7 @@ class UserResponseDto {
|
||||
json[r'email'] = this.email;
|
||||
json[r'id'] = this.id;
|
||||
json[r'name'] = this.name;
|
||||
json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String();
|
||||
json[r'profileImagePath'] = this.profileImagePath;
|
||||
return json;
|
||||
}
|
||||
@ -72,6 +78,7 @@ class UserResponseDto {
|
||||
email: mapValueOfType<String>(json, r'email')!,
|
||||
id: mapValueOfType<String>(json, r'id')!,
|
||||
name: mapValueOfType<String>(json, r'name')!,
|
||||
profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!,
|
||||
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
|
||||
);
|
||||
}
|
||||
@ -124,6 +131,7 @@ class UserResponseDto {
|
||||
'email',
|
||||
'id',
|
||||
'name',
|
||||
'profileChangedAt',
|
||||
'profileImagePath',
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ name: immich_mobile
|
||||
description: Immich - selfhosted backup media file on mobile phone
|
||||
|
||||
publish_to: 'none'
|
||||
version: 1.114.0+158
|
||||
version: 1.115.0+159
|
||||
|
||||
environment:
|
||||
sdk: '>=3.3.0 <4.0.0'
|
||||
|
6
mobile/scripts/fdroid_build_isar.sh
Normal file → Executable file
6
mobile/scripts/fdroid_build_isar.sh
Normal file → Executable file
@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
cd .isar || exit
|
||||
test -d .isar || exit
|
||||
cp .isar-cargo.lock .isar/Cargo.lock
|
||||
(cd .isar || exit
|
||||
bash tool/build_android.sh x86
|
||||
bash tool/build_android.sh x64
|
||||
bash tool/build_android.sh armv7
|
||||
@ -13,4 +15,4 @@ mv libisar_android_x64.so libisar.so
|
||||
mv libisar.so ../.pub-cache/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86_64/
|
||||
mv libisar_android_x86.so libisar.so
|
||||
mv libisar.so ../.pub-cache/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86/
|
||||
cd ..
|
||||
)
|
14
mobile/scripts/fdroid_update_isar.sh
Executable file
14
mobile/scripts/fdroid_update_isar.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
isar_version="$(awk '/isar: /{gsub(/\^/, "", $2); print $2}' pubspec.yaml)"
|
||||
checked_out_version="$(git -C .isar describe --tags)"
|
||||
|
||||
if [ "$isar_version" = "$checked_out_version" ]; then
|
||||
echo "isar is up-to-date."
|
||||
exit 0
|
||||
fi
|
||||
echo "Updating from version $checked_out_version to $isar_version."
|
||||
|
||||
git -C .isar checkout "$isar_version"
|
||||
cargo generate-lockfile --manifest-path .isar/Cargo.toml
|
||||
mv .isar/Cargo.lock .isar-cargo.lock
|
13
mobile/test/repository.mocks.dart
Normal file
13
mobile/test/repository.mocks.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:immich_mobile/interfaces/album.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/backup.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockAlbumRepository extends Mock implements IAlbumRepository {}
|
||||
|
||||
class MockAssetRepository extends Mock implements IAssetRepository {}
|
||||
|
||||
class MockUserRepository extends Mock implements IUserRepository {}
|
||||
|
||||
class MockBackupRepository extends Mock implements IBackupRepository {}
|
10
mobile/test/service.mocks.dart
Normal file
10
mobile/test/service.mocks.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/sync.service.dart';
|
||||
import 'package:immich_mobile/services/user.service.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockApiService extends Mock implements ApiService {}
|
||||
|
||||
class MockUserService extends Mock implements UserService {}
|
||||
|
||||
class MockSyncService extends Mock implements SyncService {}
|
52
mobile/test/services/album.service.test.dart
Normal file
52
mobile/test/services/album.service.test.dart
Normal file
@ -0,0 +1,52 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||
import 'package:immich_mobile/services/album.service.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import '../repository.mocks.dart';
|
||||
import '../service.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late AlbumService sut;
|
||||
late MockApiService apiService;
|
||||
late MockUserService userService;
|
||||
late MockSyncService syncService;
|
||||
late MockAlbumRepository albumRepository;
|
||||
late MockAssetRepository assetRepository;
|
||||
late MockUserRepository userRepository;
|
||||
late MockBackupRepository backupRepository;
|
||||
|
||||
setUp(() {
|
||||
apiService = MockApiService();
|
||||
userService = MockUserService();
|
||||
syncService = MockSyncService();
|
||||
albumRepository = MockAlbumRepository();
|
||||
assetRepository = MockAssetRepository();
|
||||
userRepository = MockUserRepository();
|
||||
backupRepository = MockBackupRepository();
|
||||
|
||||
sut = AlbumService(
|
||||
apiService,
|
||||
userService,
|
||||
syncService,
|
||||
albumRepository,
|
||||
assetRepository,
|
||||
userRepository,
|
||||
backupRepository,
|
||||
);
|
||||
});
|
||||
|
||||
group('refreshDeviceAlbums', () {
|
||||
test('empty selection with one album in db', () async {
|
||||
when(() => backupRepository.getIdsBySelection(BackupSelection.exclude))
|
||||
.thenAnswer((_) async => []);
|
||||
when(() => backupRepository.getIdsBySelection(BackupSelection.select))
|
||||
.thenAnswer((_) async => []);
|
||||
when(() => albumRepository.count(local: true)).thenAnswer((_) async => 1);
|
||||
when(() => syncService.removeAllLocalAlbumsAndAssets())
|
||||
.thenAnswer((_) async => true);
|
||||
final result = await sut.refreshDeviceAlbums();
|
||||
expect(result, false);
|
||||
verify(() => syncService.removeAllLocalAlbumsAndAssets());
|
||||
});
|
||||
});
|
||||
}
|
@ -2561,6 +2561,39 @@
|
||||
"tags": [
|
||||
"Jobs"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"operationId": "createJob",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/JobCreateDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Jobs"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/jobs/{id}": {
|
||||
@ -7394,7 +7427,7 @@
|
||||
"info": {
|
||||
"title": "Immich",
|
||||
"description": "Immich API",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [],
|
||||
@ -7928,6 +7961,9 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"isTrashed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"reason": {
|
||||
"enum": [
|
||||
"duplicate",
|
||||
@ -8743,6 +8779,10 @@
|
||||
},
|
||||
"CreateProfileImageResponseDto": {
|
||||
"properties": {
|
||||
"profileChangedAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"profileImagePath": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -8751,6 +8791,7 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"profileChangedAt",
|
||||
"profileImagePath",
|
||||
"userId"
|
||||
],
|
||||
@ -9266,6 +9307,17 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"JobCreateDto": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/components/schemas/ManualJobName"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"JobName": {
|
||||
"enum": [
|
||||
"thumbnailGeneration",
|
||||
@ -9508,6 +9560,14 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ManualJobName": {
|
||||
"enum": [
|
||||
"person-cleanup",
|
||||
"tag-cleanup",
|
||||
"user-cleanup"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MapMarkerResponseDto": {
|
||||
"properties": {
|
||||
"city": {
|
||||
@ -9960,6 +10020,10 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"profileChangedAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"profileImagePath": {
|
||||
"type": "string"
|
||||
}
|
||||
@ -9969,6 +10033,7 @@
|
||||
"email",
|
||||
"id",
|
||||
"name",
|
||||
"profileChangedAt",
|
||||
"profileImagePath"
|
||||
],
|
||||
"type": "object"
|
||||
@ -12238,6 +12303,11 @@
|
||||
"latitude": {
|
||||
"type": "number"
|
||||
},
|
||||
"livePhotoVideoId": {
|
||||
"format": "uuid",
|
||||
"nullable": true,
|
||||
"type": "string"
|
||||
},
|
||||
"longitude": {
|
||||
"type": "number"
|
||||
},
|
||||
@ -12394,6 +12464,10 @@
|
||||
"oauthId": {
|
||||
"type": "string"
|
||||
},
|
||||
"profileChangedAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"profileImagePath": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -12432,6 +12506,7 @@
|
||||
"license",
|
||||
"name",
|
||||
"oauthId",
|
||||
"profileChangedAt",
|
||||
"profileImagePath",
|
||||
"quotaSizeInBytes",
|
||||
"quotaUsageInBytes",
|
||||
@ -12593,6 +12668,10 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"profileChangedAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"profileImagePath": {
|
||||
"type": "string"
|
||||
}
|
||||
@ -12602,6 +12681,7 @@
|
||||
"email",
|
||||
"id",
|
||||
"name",
|
||||
"profileChangedAt",
|
||||
"profileImagePath"
|
||||
],
|
||||
"type": "object"
|
||||
|
12
open-api/typescript-sdk/package-lock.json
generated
12
open-api/typescript-sdk/package-lock.json
generated
@ -1,18 +1,18 @@
|
||||
{
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -22,9 +22,9 @@
|
||||
"integrity": "sha512-8tKiYffhwTGHSHYGnZ3oneLGCjX0po/XAXQ5Ng9fqKkvIdl/xz8+Vh8i+6xjzZqvZ2pLVpUcuSfnvNI/x67L0g=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.3.tgz",
|
||||
"integrity": "sha512-/wdGiWRkMOm53gAsSyFMXFZHbVg7C6CbkrzHNpaHoYfsUWPg7m6ZRKtvQjgvQ9i8WT540a3ydRlRQbxjY30XxQ==",
|
||||
"version": "20.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
|
||||
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"description": "Auto-generated TypeScript SDK for the Immich API",
|
||||
"type": "module",
|
||||
"main": "./build/index.js",
|
||||
@ -19,7 +19,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Immich
|
||||
* 1.114.0
|
||||
* 1.115.0
|
||||
* DO NOT MODIFY - This file has been generated using oazapfts.
|
||||
* See https://www.npmjs.com/package/oazapfts
|
||||
*/
|
||||
@ -19,6 +19,7 @@ export type UserResponseDto = {
|
||||
email: string;
|
||||
id: string;
|
||||
name: string;
|
||||
profileChangedAt: string;
|
||||
profileImagePath: string;
|
||||
};
|
||||
export type ActivityResponseDto = {
|
||||
@ -53,6 +54,7 @@ export type UserAdminResponseDto = {
|
||||
license: (UserLicense) | null;
|
||||
name: string;
|
||||
oauthId: string;
|
||||
profileChangedAt: string;
|
||||
profileImagePath: string;
|
||||
quotaSizeInBytes: number | null;
|
||||
quotaUsageInBytes: number | null;
|
||||
@ -395,6 +397,7 @@ export type AssetBulkUploadCheckResult = {
|
||||
action: Action;
|
||||
assetId?: string;
|
||||
id: string;
|
||||
isTrashed?: boolean;
|
||||
reason?: Reason;
|
||||
};
|
||||
export type AssetBulkUploadCheckResponseDto = {
|
||||
@ -426,6 +429,7 @@ export type UpdateAssetDto = {
|
||||
isArchived?: boolean;
|
||||
isFavorite?: boolean;
|
||||
latitude?: number;
|
||||
livePhotoVideoId?: string | null;
|
||||
longitude?: number;
|
||||
rating?: number;
|
||||
};
|
||||
@ -546,6 +550,9 @@ export type AllJobStatusResponseDto = {
|
||||
thumbnailGeneration: JobStatusDto;
|
||||
videoConversion: JobStatusDto;
|
||||
};
|
||||
export type JobCreateDto = {
|
||||
name: ManualJobName;
|
||||
};
|
||||
export type JobCommandDto = {
|
||||
command: JobCommand;
|
||||
force: boolean;
|
||||
@ -664,6 +671,7 @@ export type PartnerResponseDto = {
|
||||
id: string;
|
||||
inTimeline?: boolean;
|
||||
name: string;
|
||||
profileChangedAt: string;
|
||||
profileImagePath: string;
|
||||
};
|
||||
export type UpdatePartnerDto = {
|
||||
@ -1247,6 +1255,7 @@ export type CreateProfileImageDto = {
|
||||
file: Blob;
|
||||
};
|
||||
export type CreateProfileImageResponseDto = {
|
||||
profileChangedAt: string;
|
||||
profileImagePath: string;
|
||||
userId: string;
|
||||
};
|
||||
@ -1939,6 +1948,15 @@ export function getAllJobsStatus(opts?: Oazapfts.RequestOpts) {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
export function createJob({ jobCreateDto }: {
|
||||
jobCreateDto: JobCreateDto;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchText("/jobs", oazapfts.json({
|
||||
...opts,
|
||||
method: "POST",
|
||||
body: jobCreateDto
|
||||
})));
|
||||
}
|
||||
export function sendJobCommand({ id, jobCommandDto }: {
|
||||
id: JobName;
|
||||
jobCommandDto: JobCommandDto;
|
||||
@ -3362,6 +3380,11 @@ export enum EntityType {
|
||||
Asset = "ASSET",
|
||||
Album = "ALBUM"
|
||||
}
|
||||
export enum ManualJobName {
|
||||
PersonCleanup = "person-cleanup",
|
||||
TagCleanup = "tag-cleanup",
|
||||
UserCleanup = "user-cleanup"
|
||||
}
|
||||
export enum JobName {
|
||||
ThumbnailGeneration = "thumbnailGeneration",
|
||||
MetadataExtraction = "metadataExtraction",
|
||||
|
@ -57,7 +57,7 @@
|
||||
- [路线图](https://immich.app/roadmap)
|
||||
- [在线演示](#示例)
|
||||
- [功能特性](#功能特性)
|
||||
- [多语言](https://immich.app/docs/developer/tranlations)
|
||||
- [多语言](https://immich.app/docs/developer/translations)
|
||||
- [贡献者](https://immich.app/docs/overview/support-the-project)
|
||||
|
||||
## 示例
|
||||
@ -95,7 +95,7 @@
|
||||
| 实况照片备份和查看 | 是 | 是 |
|
||||
| 支持360度全景图显示 | 否 | 是 |
|
||||
| 用户自定义存储结构 | 是 | 是 |
|
||||
| 公共分享 | 否 | 是 |
|
||||
| 公共分享 | 是 | 是 |
|
||||
| 归档与收藏功能 | 是 | 是 |
|
||||
| 足迹地图 | 是 | 是 |
|
||||
| 好友分享 | 是 | 是 |
|
||||
|
@ -1,5 +1,5 @@
|
||||
# dev build
|
||||
FROM ghcr.io/immich-app/base-server-dev:20240903@sha256:ca18e2805ec8ddcf0ac7734a6eaf6d9a08bd3a14218bf0dbdbe865d83117190f AS dev
|
||||
FROM ghcr.io/immich-app/base-server-dev:20240917@sha256:3d92952d37cd68f5bf641aa80e5cc034e0d11f3774147f5db8db93138cfa5b3b AS dev
|
||||
|
||||
RUN apt-get install --no-install-recommends -yqq tini
|
||||
WORKDIR /usr/src/app
|
||||
@ -25,7 +25,7 @@ COPY --from=dev /usr/src/app/node_modules/@img ./node_modules/@img
|
||||
COPY --from=dev /usr/src/app/node_modules/exiftool-vendored.pl ./node_modules/exiftool-vendored.pl
|
||||
|
||||
# web build
|
||||
FROM node:20.17.0-alpine3.20@sha256:1a526b97cace6b4006256570efa1a29cd1fe4b96a5301f8d48e87c5139438a45 AS web
|
||||
FROM node:20.17.0-alpine3.20@sha256:2d07db07a2df6830718ae2a47db6fedce6745f5bcd174c398f2acdda90a11c03 AS web
|
||||
|
||||
WORKDIR /usr/src/open-api/typescript-sdk
|
||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||
@ -41,7 +41,7 @@ RUN npm run build
|
||||
|
||||
|
||||
# prod build
|
||||
FROM ghcr.io/immich-app/base-server-prod:20240903@sha256:d0d170ceeee7ef6c7b62b5d927820d74c14a9893f3e6285c1b9df45b33951b09
|
||||
FROM ghcr.io/immich-app/base-server-prod:20240917@sha256:67a40250f03812fe1e6f6b6345a3c7b71b3a9f24c65ed4862e82be8b3e53d23a
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
ENV NODE_ENV=production \
|
||||
|
18
server/package-lock.json
generated
18
server/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@nestjs/bullmq": "^10.0.1",
|
||||
@ -83,7 +83,7 @@
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/picomatch": "^3.0.0",
|
||||
"@types/react": "^18.3.4",
|
||||
@ -6151,9 +6151,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.3.tgz",
|
||||
"integrity": "sha512-/wdGiWRkMOm53gAsSyFMXFZHbVg7C6CbkrzHNpaHoYfsUWPg7m6ZRKtvQjgvQ9i8WT540a3ydRlRQbxjY30XxQ==",
|
||||
"version": "20.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
|
||||
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
@ -20027,9 +20027,9 @@
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.3.tgz",
|
||||
"integrity": "sha512-/wdGiWRkMOm53gAsSyFMXFZHbVg7C6CbkrzHNpaHoYfsUWPg7m6ZRKtvQjgvQ9i8WT540a3ydRlRQbxjY30XxQ==",
|
||||
"version": "20.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
|
||||
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
|
||||
"requires": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich",
|
||||
"version": "1.114.0",
|
||||
"version": "1.115.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
@ -109,7 +109,7 @@
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^20.16.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/picomatch": "^3.0.0",
|
||||
"@types/react": "^18.3.4",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Body, Controller, Get, Param, Put } from '@nestjs/common';
|
||||
import { Body, Controller, Get, Param, Post, Put } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { AllJobStatusResponseDto, JobCommandDto, JobIdParamDto, JobStatusDto } from 'src/dtos/job.dto';
|
||||
import { AllJobStatusResponseDto, JobCommandDto, JobCreateDto, JobIdParamDto, JobStatusDto } from 'src/dtos/job.dto';
|
||||
import { Authenticated } from 'src/middleware/auth.guard';
|
||||
import { JobService } from 'src/services/job.service';
|
||||
|
||||
@ -15,6 +15,12 @@ export class JobController {
|
||||
return this.service.getAllJobsStatus();
|
||||
}
|
||||
|
||||
@Post()
|
||||
@Authenticated({ admin: true })
|
||||
createJob(@Body() dto: JobCreateDto): Promise<void> {
|
||||
return this.service.create(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@Authenticated({ admin: true })
|
||||
sendJobCommand(@Param() { id }: JobIdParamDto, @Body() dto: JobCommandDto): Promise<JobStatusDto> {
|
||||
|
@ -301,7 +301,7 @@ export class StorageCore {
|
||||
return this.assetRepository.update({ id, sidecarPath: newPath });
|
||||
}
|
||||
case PersonPathType.FACE: {
|
||||
return this.personRepository.update([{ id, thumbnailPath: newPath }]);
|
||||
return this.personRepository.update({ id, thumbnailPath: newPath });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ export class AssetBulkUploadCheckResult {
|
||||
action!: AssetUploadAction;
|
||||
reason?: AssetRejectReason;
|
||||
assetId?: string;
|
||||
isTrashed?: boolean;
|
||||
}
|
||||
|
||||
export class AssetBulkUploadCheckResponseDto {
|
||||
|
@ -68,6 +68,9 @@ export class UpdateAssetDto extends UpdateAssetBase {
|
||||
@Optional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ValidateUUID({ optional: true, nullable: true })
|
||||
livePhotoVideoId?: string | null;
|
||||
}
|
||||
|
||||
export class RandomAssetsDto {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNotEmpty } from 'class-validator';
|
||||
import { ManualJobName } from 'src/enum';
|
||||
import { JobCommand, QueueName } from 'src/interfaces/job.interface';
|
||||
import { ValidateBoolean } from 'src/validation';
|
||||
|
||||
@ -20,6 +21,12 @@ export class JobCommandDto {
|
||||
force!: boolean;
|
||||
}
|
||||
|
||||
export class JobCreateDto {
|
||||
@IsEnum(ManualJobName)
|
||||
@ApiProperty({ type: 'string', enum: ManualJobName, enumName: 'ManualJobName' })
|
||||
name!: ManualJobName;
|
||||
}
|
||||
|
||||
export class JobCountsDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
active!: number;
|
||||
|
@ -8,12 +8,6 @@ export class CreateProfileImageDto {
|
||||
|
||||
export class CreateProfileImageResponseDto {
|
||||
userId!: string;
|
||||
profileChangedAt!: Date;
|
||||
profileImagePath!: string;
|
||||
}
|
||||
|
||||
export function mapCreateProfileImageResponse(userId: string, profileImagePath: string): CreateProfileImageResponseDto {
|
||||
return {
|
||||
userId,
|
||||
profileImagePath,
|
||||
};
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ export class UserResponseDto {
|
||||
profileImagePath!: string;
|
||||
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
||||
avatarColor!: UserAvatarColor;
|
||||
profileChangedAt!: Date;
|
||||
}
|
||||
|
||||
export class UserLicense {
|
||||
@ -47,6 +48,7 @@ export const mapUser = (entity: UserEntity): UserResponseDto => {
|
||||
name: entity.name,
|
||||
profileImagePath: entity.profileImagePath,
|
||||
avatarColor: getPreferences(entity).avatar.color,
|
||||
profileChangedAt: entity.profileChangedAt,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -67,4 +67,7 @@ export class UserEntity {
|
||||
|
||||
@OneToMany(() => UserMetadataEntity, (metadata) => metadata.user)
|
||||
metadata!: UserMetadataEntity[];
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
|
||||
profileChangedAt!: Date;
|
||||
}
|
||||
|
@ -186,3 +186,9 @@ export enum SourceType {
|
||||
MACHINE_LEARNING = 'machine-learning',
|
||||
EXIF = 'exif',
|
||||
}
|
||||
|
||||
export enum ManualJobName {
|
||||
PERSON_CLEANUP = 'person-cleanup',
|
||||
TAG_CLEANUP = 'tag-cleanup',
|
||||
USER_CLEANUP = 'user-cleanup',
|
||||
}
|
||||
|
@ -16,18 +16,15 @@ export interface AlbumInfoOptions {
|
||||
|
||||
export interface IAlbumRepository extends IBulkAsset {
|
||||
getById(id: string, options: AlbumInfoOptions): Promise<AlbumEntity | null>;
|
||||
getByIds(ids: string[]): Promise<AlbumEntity[]>;
|
||||
getByAssetId(ownerId: string, assetId: string): Promise<AlbumEntity[]>;
|
||||
removeAsset(assetId: string): Promise<void>;
|
||||
getMetadataForIds(ids: string[]): Promise<AlbumAssetCount[]>;
|
||||
getInvalidThumbnail(): Promise<string[]>;
|
||||
getOwned(ownerId: string): Promise<AlbumEntity[]>;
|
||||
getShared(ownerId: string): Promise<AlbumEntity[]>;
|
||||
getNotShared(ownerId: string): Promise<AlbumEntity[]>;
|
||||
restoreAll(userId: string): Promise<void>;
|
||||
softDeleteAll(userId: string): Promise<void>;
|
||||
deleteAll(userId: string): Promise<void>;
|
||||
getAll(): Promise<AlbumEntity[]>;
|
||||
create(album: Partial<AlbumEntity>): Promise<AlbumEntity>;
|
||||
update(album: Partial<AlbumEntity>): Promise<AlbumEntity>;
|
||||
delete(id: string): Promise<void>;
|
||||
|
@ -147,8 +147,6 @@ export type AssetPathEntity = Pick<AssetEntity, 'id' | 'originalPath' | 'isOffli
|
||||
export const IAssetRepository = 'IAssetRepository';
|
||||
|
||||
export interface IAssetRepository {
|
||||
getAssetsByOriginalPath(userId: string, partialPath: string): Promise<AssetEntity[]>;
|
||||
getUniqueOriginalPaths(userId: string): Promise<string[]>;
|
||||
create(asset: AssetCreate): Promise<AssetEntity>;
|
||||
getByIds(
|
||||
ids: string[],
|
||||
@ -175,8 +173,7 @@ export interface IAssetRepository {
|
||||
libraryId?: string,
|
||||
withDeleted?: boolean,
|
||||
): Paginated<AssetEntity>;
|
||||
getRandom(userId: string, count: number): Promise<AssetEntity[]>;
|
||||
getFirstAssetForAlbumId(albumId: string): Promise<AssetEntity | null>;
|
||||
getRandom(userIds: string[], count: number): Promise<AssetEntity[]>;
|
||||
getLastUpdatedAssetForAlbumId(albumId: string): Promise<AssetEntity | null>;
|
||||
getExternalLibraryAssetPaths(pagination: PaginationOptions, libraryId: string): Paginated<AssetPathEntity>;
|
||||
getByLibraryIdAndOriginalPath(libraryId: string, originalPath: string): Promise<AssetEntity | null>;
|
||||
|
@ -17,13 +17,29 @@ type EmitEventMap = {
|
||||
'album.update': [{ id: string; updatedBy: string }];
|
||||
'album.invite': [{ id: string; userId: string }];
|
||||
|
||||
// tag events
|
||||
// asset events
|
||||
'asset.tag': [{ assetId: string }];
|
||||
'asset.untag': [{ assetId: string }];
|
||||
'asset.hide': [{ assetId: string; userId: string }];
|
||||
'asset.show': [{ assetId: string; userId: string }];
|
||||
'asset.trash': [{ assetId: string; userId: string }];
|
||||
'asset.delete': [{ assetId: string; userId: string }];
|
||||
|
||||
// asset bulk events
|
||||
'assets.trash': [{ assetIds: string[]; userId: string }];
|
||||
'assets.restore': [{ assetIds: string[]; userId: string }];
|
||||
|
||||
// session events
|
||||
'session.delete': [{ sessionId: string }];
|
||||
|
||||
// stack events
|
||||
'stack.create': [{ stackId: string; userId: string }];
|
||||
'stack.update': [{ stackId: string; userId: string }];
|
||||
'stack.delete': [{ stackId: string; userId: string }];
|
||||
|
||||
// stack bulk events
|
||||
'stacks.delete': [{ stackIds: string[]; userId: string }];
|
||||
|
||||
// user events
|
||||
'user.signup': [{ notify: boolean; id: string; tempPassword?: string }];
|
||||
};
|
||||
|
@ -60,6 +60,9 @@ export enum JobName {
|
||||
STORAGE_TEMPLATE_MIGRATION = 'storage-template-migration',
|
||||
STORAGE_TEMPLATE_MIGRATION_SINGLE = 'storage-template-migration-single',
|
||||
|
||||
// tags
|
||||
TAG_CLEANUP = 'tag-cleanup',
|
||||
|
||||
// migration
|
||||
QUEUE_MIGRATION = 'queue-migration',
|
||||
MIGRATE_ASSET = 'migrate-asset',
|
||||
@ -120,6 +123,7 @@ export interface IBaseJob {
|
||||
export interface IEntityJob extends IBaseJob {
|
||||
id: string;
|
||||
source?: 'upload' | 'sidecar-write' | 'copy';
|
||||
notify?: boolean;
|
||||
}
|
||||
|
||||
export interface IAssetDeleteJob extends IEntityJob {
|
||||
@ -261,6 +265,9 @@ export type JobItem =
|
||||
| { name: JobName.CLEAN_OLD_AUDIT_LOGS; data?: IBaseJob }
|
||||
| { name: JobName.CLEAN_OLD_SESSION_TOKENS; data?: IBaseJob }
|
||||
|
||||
// Tags
|
||||
| { name: JobName.TAG_CLEANUP; data?: IBaseJob }
|
||||
|
||||
// Asset Deletion
|
||||
| { name: JobName.PERSON_CLEANUP; data?: IBaseJob }
|
||||
| { name: JobName.ASSET_DELETION; data: IAssetDeleteJob }
|
||||
@ -299,7 +306,6 @@ export interface IJobRepository {
|
||||
addHandler(queueName: QueueName, concurrency: number, handler: JobItemHandler): void;
|
||||
addCronJob(name: string, expression: string, onTick: () => void, start?: boolean): void;
|
||||
updateCronJob(name: string, expression?: string, start?: boolean): void;
|
||||
deleteCronJob(name: string): void;
|
||||
setConcurrency(queueName: QueueName, concurrency: number): void;
|
||||
queue(item: JobItem): Promise<void>;
|
||||
queueAll(items: JobItem[]): Promise<void>;
|
||||
|
@ -54,7 +54,8 @@ export interface IPersonRepository {
|
||||
|
||||
getAssets(personId: string): Promise<AssetEntity[]>;
|
||||
|
||||
create(entities: Partial<PersonEntity>[]): Promise<PersonEntity[]>;
|
||||
create(person: Partial<PersonEntity>): Promise<PersonEntity>;
|
||||
createAll(people: Partial<PersonEntity>[]): Promise<string[]>;
|
||||
createFaces(entities: Partial<AssetFaceEntity>[]): Promise<string[]>;
|
||||
delete(entities: PersonEntity[]): Promise<void>;
|
||||
deleteAll(): Promise<void>;
|
||||
@ -74,6 +75,7 @@ export interface IPersonRepository {
|
||||
reassignFace(assetFaceId: string, newPersonId: string): Promise<number>;
|
||||
getNumberOfPeople(userId: string): Promise<PeopleStatistics>;
|
||||
reassignFaces(data: UpdateFacesData): Promise<number>;
|
||||
update(entities: Partial<PersonEntity>[]): Promise<PersonEntity[]>;
|
||||
update(person: Partial<PersonEntity>): Promise<PersonEntity>;
|
||||
updateAll(people: Partial<PersonEntity>[]): Promise<void>;
|
||||
getLatestFaceDate(): Promise<string | undefined>;
|
||||
}
|
||||
|
@ -17,4 +17,5 @@ export interface ITagRepository extends IBulkAsset {
|
||||
|
||||
upsertAssetTags({ assetId, tagIds }: { assetId: string; tagIds: string[] }): Promise<void>;
|
||||
upsertAssetIds(items: AssetTagItem[]): Promise<AssetTagItem[]>;
|
||||
deleteEmptyTags(): Promise<void>;
|
||||
}
|
||||
|
8
server/src/interfaces/view.interface.ts
Normal file
8
server/src/interfaces/view.interface.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { AssetEntity } from 'src/entities/asset.entity';
|
||||
|
||||
export const IViewRepository = 'IViewRepository';
|
||||
|
||||
export interface IViewRepository {
|
||||
getAssetsByOriginalPath(userId: string, partialPath: string): Promise<AssetEntity[]>;
|
||||
getUniqueOriginalPaths(userId: string): Promise<string[]>;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user