Compare commits
69 Commits
v1.105.0
...
feat/backg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a156b813e | ||
|
|
4907916345 | ||
|
|
a3489d604b | ||
|
|
00b5ad3421 | ||
|
|
2ada4a8426 | ||
|
|
924e9f08cd | ||
|
|
91b835cfeb | ||
|
|
bb79df655d | ||
|
|
02e755bd92 | ||
|
|
0963a32a95 | ||
|
|
6119618ae2 | ||
|
|
4d044658a0 | ||
|
|
67fa598f44 | ||
|
|
9222b9d130 | ||
|
|
d6757fc2dd | ||
|
|
4f838eabbe | ||
|
|
143b9d6828 | ||
|
|
1df7be8436 | ||
|
|
5f25f28c42 | ||
|
|
ae92422df7 | ||
|
|
84d824d6a7 | ||
|
|
4353153fe6 | ||
|
|
c37bf9d5d0 | ||
|
|
5c8c0b2f5b | ||
|
|
39129721fa | ||
|
|
451416ec88 | ||
|
|
e39ee8a16f | ||
|
|
1e56352b04 | ||
|
|
470c95d614 | ||
|
|
1ad04f0b17 | ||
|
|
60427f18ce | ||
|
|
9aed736911 | ||
|
|
6b369e84fc | ||
|
|
136bb69bd0 | ||
|
|
975f2351ec | ||
|
|
2e62c7b417 | ||
|
|
2689178a35 | ||
|
|
d61418886f | ||
|
|
c03981ac1d | ||
|
|
4807fc40a6 | ||
|
|
101bc290f9 | ||
|
|
df42352f84 | ||
|
|
c8aa6a62c2 | ||
|
|
85aca2bb54 | ||
|
|
ff52300624 | ||
|
|
936a46b4ed | ||
|
|
d8eca168ca | ||
|
|
64636c0618 | ||
|
|
673e97e71d | ||
|
|
984aa8fb41 | ||
|
|
7f0f016f2e | ||
|
|
0589575154 | ||
|
|
73bf8f343a | ||
|
|
581b467b4b | ||
|
|
efb844c6cd | ||
|
|
88d4338348 | ||
|
|
ce7bbe88f9 | ||
|
|
d62e90424e | ||
|
|
0f129cae4a | ||
|
|
5583635947 | ||
|
|
b7715305b3 | ||
|
|
6c008176c9 | ||
|
|
72b1d582ba | ||
|
|
7b1112f3e3 | ||
|
|
42d0fc85ca | ||
|
|
d32b621750 | ||
|
|
d551003311 | ||
|
|
dd64379a4e | ||
|
|
c1cdda0ac4 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -2,8 +2,6 @@ mobile/openapi/**/*.md -diff -merge
|
||||
mobile/openapi/**/*.md linguist-generated=true
|
||||
mobile/openapi/**/*.dart -diff -merge
|
||||
mobile/openapi/**/*.dart linguist-generated=true
|
||||
mobile/openapi/.openapi-generator/FILES -diff -merge
|
||||
mobile/openapi/.openapi-generator/FILES linguist-generated=true
|
||||
|
||||
mobile/lib/**/*.g.dart -diff -merge
|
||||
mobile/lib/**/*.g.dart linguist-generated=true
|
||||
|
||||
2
.github/workflows/build-mobile.yml
vendored
2
.github/workflows/build-mobile.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version: '3.19.3'
|
||||
flutter-version: '3.22.0'
|
||||
cache: true
|
||||
|
||||
- name: Create the Keystore
|
||||
|
||||
15
.github/workflows/pr-require-conventional-commit.yml
vendored
Normal file
15
.github/workflows/pr-require-conventional-commit.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: PR Conventional Commit Validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
|
||||
jobs:
|
||||
validate-pr-title:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: PR Conventional Commit Validation
|
||||
uses: ytanikin/PRConventionalCommits@1.1.0
|
||||
with:
|
||||
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
|
||||
add_label: 'false'
|
||||
4
.github/workflows/static_analysis.yml
vendored
4
.github/workflows/static_analysis.yml
vendored
@@ -22,8 +22,8 @@ jobs:
|
||||
- name: Setup Flutter SDK
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: "3.19.3"
|
||||
channel: 'stable'
|
||||
flutter-version: '3.22.0'
|
||||
|
||||
- name: Install dependencies
|
||||
run: dart pub get
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -208,7 +208,7 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version: '3.19.3'
|
||||
flutter-version: '3.22.0'
|
||||
- name: Run tests
|
||||
working-directory: ./mobile
|
||||
run: flutter test -j 1
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -14,7 +14,10 @@ mobile/gradle.properties
|
||||
mobile/openapi/pubspec.lock
|
||||
mobile/*.jks
|
||||
mobile/libisar.dylib
|
||||
mobile/openapi/test
|
||||
mobile/openapi/doc
|
||||
mobile/openapi/.openapi-generator/FILES
|
||||
|
||||
open-api/typescript-sdk/build
|
||||
mobile/android/fastlane/report.xml
|
||||
mobile/ios/fastlane/report.xml
|
||||
mobile/ios/fastlane/report.xml
|
||||
|
||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@@ -1,6 +1,16 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"[javascript][typescript][css]": {
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.tabSize": 2,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.tabSize": 2,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.tabSize": 2,
|
||||
"editor.formatOnSave": true
|
||||
@@ -31,4 +41,4 @@
|
||||
"explorer.fileNesting.patterns": {
|
||||
"*.ts": "${capture}.spec.ts,${capture}.mock.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
272
cli/package-lock.json
generated
272
cli/package-lock.json
generated
@@ -31,7 +31,7 @@
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^52.0.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
@@ -47,14 +47,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.105.0",
|
||||
"version": "1.105.1",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.0",
|
||||
"@types/node": "^20.12.12",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -174,9 +174,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
|
||||
"integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1113,12 +1113,6 @@
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz",
|
||||
@@ -1144,10 +1138,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz",
|
||||
"integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==",
|
||||
"version": "20.12.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz",
|
||||
"integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
@@ -1158,28 +1153,21 @@
|
||||
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz",
|
||||
"integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz",
|
||||
"integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/type-utils": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"@typescript-eslint/scope-manager": "7.9.0",
|
||||
"@typescript-eslint/type-utils": "7.9.0",
|
||||
"@typescript-eslint/utils": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1200,15 +1188,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz",
|
||||
"integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz",
|
||||
"integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"@typescript-eslint/scope-manager": "7.9.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/typescript-estree": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1228,13 +1217,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz",
|
||||
"integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz",
|
||||
"integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0"
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1245,13 +1235,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz",
|
||||
"integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz",
|
||||
"integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.9.0",
|
||||
"@typescript-eslint/utils": "7.9.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
@@ -1272,10 +1263,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz",
|
||||
"integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz",
|
||||
"integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
@@ -1285,13 +1277,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz",
|
||||
"integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz",
|
||||
"integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -1313,18 +1306,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz",
|
||||
"integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz",
|
||||
"integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"semver": "^7.6.0"
|
||||
"@typescript-eslint/scope-manager": "7.9.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/typescript-estree": "7.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1338,12 +1329,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz",
|
||||
"integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz",
|
||||
"integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1564,6 +1556,7 @@
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -1588,6 +1581,7 @@
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
@@ -1822,12 +1816,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.36.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz",
|
||||
"integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==",
|
||||
"version": "3.37.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz",
|
||||
"integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.3"
|
||||
"browserslist": "^4.23.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -1897,6 +1891,7 @@
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-type": "^4.0.0"
|
||||
},
|
||||
@@ -2094,17 +2089,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn": {
|
||||
"version": "52.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz",
|
||||
"integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==",
|
||||
"version": "53.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz",
|
||||
"integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-validator-identifier": "^7.24.5",
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/eslintrc": "^3.0.2",
|
||||
"ci-info": "^4.0.0",
|
||||
"clean-regexp": "^1.0.0",
|
||||
"core-js-compat": "^3.34.0",
|
||||
"core-js-compat": "^3.37.0",
|
||||
"esquery": "^1.5.0",
|
||||
"indent-string": "^4.0.0",
|
||||
"is-builtin-module": "^3.2.1",
|
||||
@@ -2113,11 +2108,11 @@
|
||||
"read-pkg-up": "^7.0.1",
|
||||
"regexp-tree": "^0.1.27",
|
||||
"regjsparser": "^0.10.0",
|
||||
"semver": "^7.5.4",
|
||||
"semver": "^7.6.1",
|
||||
"strip-indent": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18.18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1"
|
||||
@@ -2126,6 +2121,92 @@
|
||||
"eslint": ">=8.56.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz",
|
||||
"integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^10.0.1",
|
||||
"globals": "^14.0.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/eslint-visitor-keys": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
||||
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/espree": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
|
||||
"integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.3",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
|
||||
@@ -2466,6 +2547,7 @@
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
@@ -2969,6 +3051,7 @@
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
@@ -3232,6 +3315,7 @@
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -3711,13 +3795,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"version": "7.6.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
||||
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
@@ -3725,18 +3806,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/semver/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -3781,6 +3850,7 @@
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4407,12 +4477,6 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^52.0.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defaults, getMyUserInfo, isHttpError } from '@immich/sdk';
|
||||
import { getMyUserInfo, init, isHttpError } from '@immich/sdk';
|
||||
import { glob } from 'fast-glob';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { createReadStream } from 'node:fs';
|
||||
@@ -46,8 +46,7 @@ export const connect = async (url: string, key: string) => {
|
||||
// noop
|
||||
}
|
||||
|
||||
defaults.baseUrl = url;
|
||||
defaults.headers = { 'x-api-key': key };
|
||||
init({ baseUrl: url, apiKey: key });
|
||||
|
||||
const [error] = await withError(getMyUserInfo());
|
||||
if (isHttpError(error)) {
|
||||
|
||||
@@ -4,32 +4,29 @@
|
||||
|
||||
name: immich-dev
|
||||
|
||||
x-server-build: &server-common
|
||||
image: immich-server-dev:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
target: dev
|
||||
restart: always
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
- ../open-api:/usr/src/open-api
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload
|
||||
- /usr/src/app/node_modules
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 1048576
|
||||
hard: 1048576
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
command: ['/usr/src/app/bin/immich-dev', 'immich']
|
||||
<<: *server-common
|
||||
command: ['/usr/src/app/bin/immich-dev']
|
||||
image: immich-server-dev:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
target: dev
|
||||
restart: always
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
- ../open-api:/usr/src/open-api
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload
|
||||
- /usr/src/app/node_modules
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 1048576
|
||||
hard: 1048576
|
||||
ports:
|
||||
- 3001:3001
|
||||
- 9230:9230
|
||||
@@ -37,19 +34,6 @@ services:
|
||||
- redis
|
||||
- database
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
command: ['/usr/src/app/bin/immich-dev', 'microservices']
|
||||
<<: *server-common
|
||||
# extends:
|
||||
# file: hwaccel.transcoding.yml
|
||||
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
||||
ports:
|
||||
- 9231:9230
|
||||
depends_on:
|
||||
- database
|
||||
- immich-server
|
||||
|
||||
immich-web:
|
||||
container_name: immich_web
|
||||
image: immich-web-dev:latest
|
||||
@@ -97,7 +81,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672
|
||||
image: redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
|
||||
@@ -1,40 +1,24 @@
|
||||
name: immich-prod
|
||||
|
||||
x-server-build: &server-common
|
||||
image: immich-server:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
command: ['start.sh', 'immich']
|
||||
<<: *server-common
|
||||
image: immich-server:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
ports:
|
||||
- 2283:3001
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
command: ['start.sh', 'microservices']
|
||||
<<: *server-common
|
||||
# extends:
|
||||
# file: hwaccel.transcoding.yml
|
||||
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
- immich-server
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
image: immich-machine-learning:latest
|
||||
@@ -54,7 +38,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672
|
||||
image: redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
|
||||
restart: always
|
||||
|
||||
database:
|
||||
@@ -90,7 +74,7 @@ services:
|
||||
command: ['./run.sh', '-disable-reporting']
|
||||
ports:
|
||||
- 3000:3000
|
||||
image: grafana/grafana:10.4.2-ubuntu@sha256:4f55071b556fb03f12b41423c98a185ed6695ed9ff2558e35805f0dd765fd958
|
||||
image: grafana/grafana:11.0.0-ubuntu@sha256:02e99d1ee0b52dc9d3000c7b5314e7a07e0dfd69cc49bb3f8ce323491ed3406b
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||
command: ['start.sh', 'immich']
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
@@ -25,23 +24,6 @@ services:
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/hardware-transcoding
|
||||
# file: hwaccel.transcoding.yml
|
||||
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
||||
command: ['start.sh', 'microservices']
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
|
||||
@@ -58,12 +40,12 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: registry.hub.docker.com/library/redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672
|
||||
image: docker.io/redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
|
||||
restart: always
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
||||
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
version: "3.8"
|
||||
|
||||
# Configurations for hardware-accelerated machine learning
|
||||
|
||||
# If using Unraid or another platform that doesn't allow multiple Compose files,
|
||||
# you can inline the config for a backend by copying its contents
|
||||
# you can inline the config for a backend by copying its contents
|
||||
# into the immich-machine-learning service in the docker-compose.yml file.
|
||||
|
||||
# See https://immich.app/docs/features/ml-hardware-acceleration for info on usage.
|
||||
@@ -30,7 +28,7 @@ services:
|
||||
|
||||
openvino:
|
||||
device_cgroup_rules:
|
||||
- "c 189:* rmw"
|
||||
- 'c 189:* rmw'
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
volumes:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
version: "3.8"
|
||||
|
||||
# Configurations for hardware-accelerated transcoding
|
||||
|
||||
# If using Unraid or another platform that doesn't allow multiple Compose files,
|
||||
|
||||
@@ -5,13 +5,13 @@ This website is built using [Docusaurus](https://docusaurus.io/), a modern stati
|
||||
### Installation
|
||||
|
||||
```
|
||||
$ yarn
|
||||
$ npm install
|
||||
```
|
||||
|
||||
### Local Development
|
||||
|
||||
```
|
||||
$ yarn start
|
||||
$ npm run start
|
||||
```
|
||||
|
||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||
@@ -19,7 +19,7 @@ This command starts a local development server and opens up a browser window. Mo
|
||||
### Build
|
||||
|
||||
```
|
||||
$ yarn build
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
||||
@@ -29,13 +29,13 @@ This command generates static content into the `build` directory and can be serv
|
||||
Using SSH:
|
||||
|
||||
```
|
||||
$ USE_SSH=true yarn deploy
|
||||
$ USE_SSH=true npm run deploy
|
||||
```
|
||||
|
||||
Not using SSH:
|
||||
|
||||
```
|
||||
$ GIT_USER=<Your GitHub username> yarn deploy
|
||||
$ GIT_USER=<Your GitHub username> npm run deploy
|
||||
```
|
||||
|
||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
||||
|
||||
@@ -18,7 +18,7 @@ In any other situation, there are 3 different options that can appear:
|
||||
|
||||
- MATCHES - These files are matched by their checksums.
|
||||
|
||||
- OFFLINE PATHS - These files are the result of manually deleting files in the upload library or a failed file move in the past (losing track of a file).
|
||||
- OFFLINE PATHS - These files are the result of manually deleting files from immich or a failed file move in the past (losing track of a file).
|
||||
|
||||
- UNTRACKED FILES - These files are not tracked by the application. They can be the result of failed moves, interrupted uploads, or left behind due to a bug.
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ You do not need to redo any transcoding jobs after enabling hardware acceleratio
|
||||
- WSL2 does not support Quick Sync.
|
||||
- Raspberry Pi is currently not supported.
|
||||
- Two-pass mode is only supported for NVENC. Other APIs will ignore this setting.
|
||||
- Only encoding is currently hardware accelerated, so the CPU is still used for software decoding and tone-mapping.
|
||||
- By default, only encoding is currently hardware accelerated. This means the CPU is still used for software decoding and tone-mapping.
|
||||
- NVENC and RKMPP can be fully accelerated by enabling hardware decoding in the video transcoding settings.
|
||||
- Hardware dependent
|
||||
- Codec support varies, but H.264 and HEVC are usually supported.
|
||||
- Notably, NVIDIA and AMD GPUs do not support VP9 encoding.
|
||||
@@ -65,6 +66,7 @@ For RKMPP to work:
|
||||
|
||||
3. Redeploy the `immich-microservices` container with these updated settings.
|
||||
4. In the Admin page under `Video transcoding settings`, change the hardware acceleration setting to the appropriate option and save.
|
||||
5. (Optional) If using a compatible backend, you may enable hardware decoding for optimal performance.
|
||||
|
||||
#### Single Compose File
|
||||
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
|
||||
Immich supports the creation of libraries which is a top-level asset container. Currently, there are two types of libraries: traditional upload libraries that can sync with a mobile device, and external libraries, that keeps up to date with files on disk. Libraries are different from albums in that an asset can belong to multiple albums but only one library, and deleting a library deletes all assets contained within. As of August 2023, this is a new feature and libraries have a lot of potential for future development beyond what is documented here. This document attempts to describe the current state of libraries.
|
||||
|
||||
## The Upload Library
|
||||
|
||||
Immich comes preconfigured with an upload library for each user. All assets uploaded to Immich are added to this library. This library can be renamed, but not deleted. The upload library is the only library that can be synced with a mobile device. No items in an upload library is allowed to have the same sha1 hash as another item in the same library in order to prevent duplicates.
|
||||
|
||||
## External Libraries
|
||||
|
||||
External libraries tracks assets stored outside of Immich, i.e. in the file system. When the external library is scanned, Immich will read the metadata from the file and create an asset in the library for each image or video file. These items will then be shown in the main timeline, and they will look and behave like any other asset, including viewing on the map, adding to albums, etc.
|
||||
|
||||
@@ -95,7 +95,7 @@ immich-machine-learning:
|
||||
Once this is done, you can redeploy the `immich-machine-learning` container.
|
||||
|
||||
:::info
|
||||
You can confirm the device is being recognized and used by checking its utilization (via `nvtop` for CUDA, `intel_gpu_top` for OpenVINO, etc.). You can also enable debug logging by setting `LOG_LEVEL=debug` in the `.env` file and restarting the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, you should see a log for `Available ORT providers` containing the relevant provider. In the case of ARM NN, the absence of a `Could not load ANN shared libraries` log entry means it loaded successfully.
|
||||
You can confirm the device is being recognized and used by checking its utilization (via `nvtop` for CUDA, `intel_gpu_top` for OpenVINO, etc.). You can also enable debug logging by setting `IMMICH_LOG_LEVEL=debug` in the `.env` file and restarting the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, you should see a log for `Available ORT providers` containing the relevant provider. In the case of ARM NN, the absence of a `Could not load ANN shared libraries` log entry means it loaded successfully.
|
||||
:::
|
||||
|
||||
[hw-file]: https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml
|
||||
|
||||
@@ -2,48 +2,52 @@
|
||||
|
||||
A short guide on connecting [pgAdmin](https://www.pgadmin.org/) to Immich.
|
||||
|
||||
:::note
|
||||
|
||||
In order to connect to the database the immich_postgres container **must be running**.
|
||||
|
||||
The passwords and usernames used below match the ones specified in the example `.env` file. If changed, please use actual values instead.
|
||||
|
||||
**Optional:** To connect to the database **outside** of your Docker's network:
|
||||
|
||||
- Expose port 5432 in your `docker-compose.yml` file.
|
||||
- Edit the PostgreSQL [`pg_hba.conf`](https://www.postgresql.org/docs/current/auth-pg-hba-conf.html) file.
|
||||
- Make sure your firewall does not block access to port 5432.
|
||||
Note that exposing the database port increases the risk of getting attacked by hackers.
|
||||
Make sure to remove the binding port after finishing the database's tasks.
|
||||
|
||||
:::
|
||||
|
||||
## 1. Install pgAdmin
|
||||
|
||||
Download and install [pgAdmin](https://www.pgadmin.org/download/) following the official documentation.
|
||||
Add a file `docker-compose-pgadmin.yml` next to your `docker-compose.yml` with the following content:
|
||||
|
||||
```
|
||||
name: immich
|
||||
|
||||
services:
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4
|
||||
container_name: pgadmin4_container
|
||||
restart: always
|
||||
ports:
|
||||
- "8888:80"
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: user-name@domain-name.com
|
||||
PGADMIN_DEFAULT_PASSWORD: strong-password
|
||||
volumes:
|
||||
- pgadmin-data:/var/lib/pgadmin
|
||||
|
||||
volumes:
|
||||
pgadmin-data:
|
||||
```
|
||||
|
||||
Change the values of `PGADMIN_DEFAULT_EMAIL` and `PGADMIN_DEFAULT_PASSWORD` in this file.
|
||||
|
||||
Run `docker compose -f docker-compose.yml -f docker-compose-pgadmin.yml up` to start immich along with `pgAdmin`.
|
||||
|
||||
## 2. Add a Server
|
||||
|
||||
Open pgAdmin and click "Add New Server".
|
||||
Open [localhost:8888](http://localhost:8888) and login with the default credentials from above.
|
||||
|
||||
<img src={require('./img/add-new-server-option.png').default} width="50%" title="new server option" />
|
||||
Right click on `Servers` and click on `Register >> Server..` then enter the values below in the `Connection` tab.
|
||||
|
||||
## 3. Enter Connection Details
|
||||
<img src={require('./img/pgadmin-add-new-server.png').default} width="50%" title="new server option" />
|
||||
|
||||
| Name | Value |
|
||||
| -------------------- | ----------- |
|
||||
| Host name/address | `localhost` |
|
||||
| Port | `5432` |
|
||||
| Maintenance database | `immich` |
|
||||
| Username | `postgres` |
|
||||
| Password | `postgres` |
|
||||
:::note
|
||||
The parameters used here match those specified in the example `.env` file. If you have changed your `.env` file, you'll need to adjust accordingly.
|
||||
:::
|
||||
|
||||
<img src={require('./img/Connection-Pgadmin.png').default} width="75%" title="Connection" />
|
||||
|
||||
## 4. Save Connection
|
||||
| Name | Value |
|
||||
| -------------------- | ----------------- |
|
||||
| Host name/address | `immich_postgres` |
|
||||
| Port | `5432` |
|
||||
| Maintenance database | `immich` |
|
||||
| Username | `postgres` |
|
||||
| Password | `postgres` |
|
||||
|
||||
Click on "Save" to connect to the Immich database.
|
||||
|
||||
:::tip
|
||||
View [Database Queries](/docs/guides/database-queries/) for common database queries.
|
||||
:::
|
||||
|
||||
@@ -96,7 +96,7 @@ SELECT * FROM "users";
|
||||
## System Config
|
||||
|
||||
```sql title="Custom settings"
|
||||
SELECT "key", "value" FROM "system_config";
|
||||
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
|
||||
```
|
||||
|
||||
(Only used when not using the [config file](/docs/install/config-file))
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 39 KiB |
BIN
docs/docs/guides/img/pgadmin-add-new-server.png
Normal file
BIN
docs/docs/guides/img/pgadmin-add-new-server.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
@@ -77,6 +77,10 @@ The default configuration looks like this:
|
||||
"enabled": true,
|
||||
"modelName": "ViT-B-32__openai"
|
||||
},
|
||||
"duplicateDetection": {
|
||||
"enabled": false,
|
||||
"maxDistance": 0.03
|
||||
},
|
||||
"facialRecognition": {
|
||||
"enabled": true,
|
||||
"modelName": "buffalo_l",
|
||||
|
||||
@@ -41,8 +41,8 @@ Regardless of filesystem, it is not recommended to use a network share for your
|
||||
| Variable | Description | Default | Services |
|
||||
| :------------------------------ | :------------------------------------------- | :----------------------: | :-------------------------------------- |
|
||||
| `TZ` | Timezone | | microservices |
|
||||
| `NODE_ENV` | Environment (production, development) | `production` | server, microservices, machine learning |
|
||||
| `LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices, machine learning |
|
||||
| `IMMICH_ENV` | Environment (production, development) | `production` | server, microservices, machine learning |
|
||||
| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices, machine learning |
|
||||
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload`<sup>\*1</sup> | server, microservices |
|
||||
| `IMMICH_CONFIG_FILE` | Path to config file | | server, microservices |
|
||||
| `IMMICH_WEB_ROOT` | Path of root index.html | `/usr/src/app/www` | server |
|
||||
@@ -59,13 +59,10 @@ It only need to be set if the Immich deployment method is changing.
|
||||
|
||||
## Ports
|
||||
|
||||
| Variable | Description | Default | Services |
|
||||
| :---------------------- | :-------------------- | :-------: | :-------------------- |
|
||||
| `HOST` | Host | `0.0.0.0` | server, microservices |
|
||||
| `SERVER_PORT` | Server Port | `3001` | server |
|
||||
| `MICROSERVICES_PORT` | Microservices Port | `3002` | microservices |
|
||||
| `MACHINE_LEARNING_HOST` | Machine Learning Host | `0.0.0.0` | machine learning |
|
||||
| `MACHINE_LEARNING_PORT` | Machine Learning Port | `3003` | machine learning |
|
||||
| Variable | Description | Default |
|
||||
| :------------ | :------------- | :------------------------------------: |
|
||||
| `IMMICH_HOST` | Listening host | `0.0.0.0` |
|
||||
| `IMMICH_PORT` | Listening port | 3001 (server), 3003 (machine learning) |
|
||||
|
||||
## Database
|
||||
|
||||
|
||||
@@ -10,17 +10,17 @@ interface CommunityGuidesProps {
|
||||
const guides: CommunityGuidesProps[] = [
|
||||
{
|
||||
title: 'Cloudflare Tunnels with SSO/OAuth',
|
||||
description: `Setting up Cloudflare Tunnels and a SaaS App for immich.`,
|
||||
description: `Setting up Cloudflare Tunnels and a SaaS App for Immich.`,
|
||||
url: 'https://github.com/immich-app/immich/discussions/8299',
|
||||
},
|
||||
{
|
||||
title: 'Database backup in Truenas',
|
||||
description: `Create a database backup with pgAdmin in Truenas.`,
|
||||
title: 'Database backup in TrueNAS',
|
||||
description: `Create a database backup with pgAdmin in TrueNAS.`,
|
||||
url: 'https://github.com/immich-app/immich/discussions/8809',
|
||||
},
|
||||
{
|
||||
title: 'Unraid backup scripts',
|
||||
description: `Back up your assets in Unarid with a pre-prepared script.`,
|
||||
description: `Back up your assets in Unraid with a pre-prepared script.`,
|
||||
url: 'https://github.com/immich-app/immich/discussions/8416',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ interface CommunityProjectProps {
|
||||
const projects: CommunityProjectProps[] = [
|
||||
{
|
||||
title: 'immich-go',
|
||||
description: `An alternative to the immich-CLI command that doesn't depend on nodejs installation. It tries its best for importing google photos takeout archives.`,
|
||||
description: `An alternative to the immich-CLI that doesn't depend on nodejs. It specializes in importing Google Photos Takeout archives.`,
|
||||
url: 'https://github.com/simulot/immich-go',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,40 +2,32 @@ version: '3.8'
|
||||
|
||||
name: immich-e2e
|
||||
|
||||
x-server-build: &server-common
|
||||
image: immich-server:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
environment:
|
||||
- DB_HOSTNAME=database
|
||||
- DB_USERNAME=postgres
|
||||
- DB_PASSWORD=postgres
|
||||
- DB_DATABASE_NAME=immich
|
||||
- IMMICH_MACHINE_LEARNING_ENABLED=false
|
||||
- IMMICH_METRICS=true
|
||||
volumes:
|
||||
- upload:/usr/src/app/upload
|
||||
- ./test-assets:/test-assets
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich-e2e-server
|
||||
command: ['./start.sh', 'immich']
|
||||
<<: *server-common
|
||||
command: ['./start.sh']
|
||||
image: immich-server:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
environment:
|
||||
- DB_HOSTNAME=database
|
||||
- DB_USERNAME=postgres
|
||||
- DB_PASSWORD=postgres
|
||||
- DB_DATABASE_NAME=immich
|
||||
- IMMICH_MACHINE_LEARNING_ENABLED=false
|
||||
- IMMICH_METRICS=true
|
||||
volumes:
|
||||
- upload:/usr/src/app/upload
|
||||
- ./test-assets:/test-assets
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
ports:
|
||||
- 2283:3001
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich-e2e-microservices
|
||||
command: ['./start.sh', 'microservices']
|
||||
<<: *server-common
|
||||
|
||||
redis:
|
||||
image: redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672
|
||||
image: redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
|
||||
|
||||
database:
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
||||
|
||||
259
e2e/package-lock.json
generated
259
e2e/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.105.0",
|
||||
"version": "1.105.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich-e2e",
|
||||
"version": "1.105.0",
|
||||
"version": "1.105.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"devDependencies": {
|
||||
"@immich/cli": "file:../cli",
|
||||
@@ -23,7 +23,7 @@
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^52.0.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"exiftool-vendored": "^26.0.0",
|
||||
"luxon": "^3.4.4",
|
||||
"pg": "^8.11.3",
|
||||
@@ -65,7 +65,7 @@
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^52.0.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
@@ -81,14 +81,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.105.0",
|
||||
"version": "1.105.1",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.0",
|
||||
"@types/node": "^20.12.12",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -208,9 +208,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
|
||||
"integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1217,12 +1217,6 @@
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz",
|
||||
@@ -1236,10 +1230,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz",
|
||||
"integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==",
|
||||
"version": "20.12.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz",
|
||||
"integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
@@ -1327,12 +1322,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/superagent": {
|
||||
"version": "8.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.3.tgz",
|
||||
@@ -1355,21 +1344,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz",
|
||||
"integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz",
|
||||
"integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/type-utils": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"@typescript-eslint/scope-manager": "7.9.0",
|
||||
"@typescript-eslint/type-utils": "7.9.0",
|
||||
"@typescript-eslint/utils": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1390,15 +1378,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz",
|
||||
"integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz",
|
||||
"integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"@typescript-eslint/scope-manager": "7.9.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/typescript-estree": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1418,13 +1407,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz",
|
||||
"integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz",
|
||||
"integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0"
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1435,13 +1425,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz",
|
||||
"integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz",
|
||||
"integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.9.0",
|
||||
"@typescript-eslint/utils": "7.9.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
@@ -1462,10 +1453,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz",
|
||||
"integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz",
|
||||
"integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
@@ -1475,13 +1467,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz",
|
||||
"integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz",
|
||||
"integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/visitor-keys": "7.9.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -1507,6 +1500,7 @@
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
@@ -1516,6 +1510,7 @@
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
@@ -1527,18 +1522,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz",
|
||||
"integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz",
|
||||
"integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"semver": "^7.6.0"
|
||||
"@typescript-eslint/scope-manager": "7.9.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"@typescript-eslint/typescript-estree": "7.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1552,12 +1545,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz",
|
||||
"integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz",
|
||||
"integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/types": "7.9.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1785,6 +1779,7 @@
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -1840,6 +1835,7 @@
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
@@ -2121,12 +2117,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.36.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz",
|
||||
"integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==",
|
||||
"version": "3.37.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz",
|
||||
"integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.3"
|
||||
"browserslist": "^4.23.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -2247,6 +2243,7 @@
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-type": "^4.0.0"
|
||||
},
|
||||
@@ -2487,17 +2484,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn": {
|
||||
"version": "52.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz",
|
||||
"integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==",
|
||||
"version": "53.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz",
|
||||
"integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-validator-identifier": "^7.24.5",
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/eslintrc": "^3.0.2",
|
||||
"ci-info": "^4.0.0",
|
||||
"clean-regexp": "^1.0.0",
|
||||
"core-js-compat": "^3.34.0",
|
||||
"core-js-compat": "^3.37.0",
|
||||
"esquery": "^1.5.0",
|
||||
"indent-string": "^4.0.0",
|
||||
"is-builtin-module": "^3.2.1",
|
||||
@@ -2506,11 +2503,11 @@
|
||||
"read-pkg-up": "^7.0.1",
|
||||
"regexp-tree": "^0.1.27",
|
||||
"regjsparser": "^0.10.0",
|
||||
"semver": "^7.5.4",
|
||||
"semver": "^7.6.1",
|
||||
"strip-indent": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18.18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1"
|
||||
@@ -2519,6 +2516,70 @@
|
||||
"eslint": ">=8.56.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz",
|
||||
"integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^10.0.1",
|
||||
"globals": "^14.0.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/eslint-visitor-keys": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
||||
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/espree": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
|
||||
"integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.3",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
|
||||
@@ -2692,6 +2753,7 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
@@ -2708,6 +2770,7 @@
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
@@ -2759,6 +2822,7 @@
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@@ -3001,6 +3065,7 @@
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
@@ -3276,6 +3341,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
@@ -3491,18 +3557,6 @@
|
||||
"get-func-name": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz",
|
||||
@@ -3561,6 +3615,7 @@
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
@@ -3579,6 +3634,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
@@ -4047,6 +4103,7 @@
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4175,6 +4232,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
@@ -4710,13 +4768,10 @@
|
||||
]
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"version": "7.6.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
||||
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
@@ -4809,6 +4864,7 @@
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -5135,6 +5191,7 @@
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.105.0",
|
||||
"version": "1.105.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -33,7 +33,7 @@
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^52.0.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"exiftool-vendored": "^26.0.0",
|
||||
"luxon": "^3.4.4",
|
||||
"pg": "^8.11.3",
|
||||
|
||||
@@ -2,10 +2,8 @@ import {
|
||||
AssetFileUploadResponseDto,
|
||||
AssetResponseDto,
|
||||
AssetTypeEnum,
|
||||
LibraryResponseDto,
|
||||
LoginResponseDto,
|
||||
SharedLinkType,
|
||||
getAllLibraries,
|
||||
getAssetInfo,
|
||||
updateAssets,
|
||||
} from '@immich/sdk';
|
||||
@@ -819,25 +817,6 @@ describe('/asset', () => {
|
||||
expect(duplicate).toBe(true);
|
||||
});
|
||||
|
||||
it("should not upload to another user's library", async () => {
|
||||
const libraries = await getAllLibraries({}, { headers: asBearerAuth(admin.accessToken) });
|
||||
const library = libraries.find((library) => library.ownerId === user1.userId) as LibraryResponseDto;
|
||||
|
||||
const { body, status } = await request(app)
|
||||
.post('/asset/upload')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.field('libraryId', library.id)
|
||||
.field('deviceAssetId', 'example-image')
|
||||
.field('deviceId', 'e2e')
|
||||
.field('fileCreatedAt', new Date().toISOString())
|
||||
.field('fileModifiedAt', new Date().toISOString())
|
||||
.field('duration', '0:00:00.000000')
|
||||
.attach('assetData', makeRandomImage(), 'example.png');
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest('Not found or no asset.upload access'));
|
||||
});
|
||||
|
||||
it('should update the used quota', async () => {
|
||||
const { body, status } = await request(app)
|
||||
.post('/asset/upload')
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
LibraryResponseDto,
|
||||
LibraryType,
|
||||
LoginResponseDto,
|
||||
ScanLibraryDto,
|
||||
getAllLibraries,
|
||||
scanLibrary,
|
||||
} from '@immich/sdk';
|
||||
import { LibraryResponseDto, LoginResponseDto, ScanLibraryDto, getAllLibraries, scanLibrary } from '@immich/sdk';
|
||||
import { cpSync, existsSync } from 'node:fs';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { userDto, uuidDto } from 'src/fixtures';
|
||||
@@ -29,7 +22,7 @@ describe('/library', () => {
|
||||
admin = await utils.adminSetup();
|
||||
await utils.resetAdminConfig(admin.accessToken);
|
||||
user = await utils.userSetup(admin.accessToken, userDto.user1);
|
||||
library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, type: LibraryType.External });
|
||||
library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId });
|
||||
websocket = await utils.connectWebsocket(admin.accessToken);
|
||||
utils.createImageFile(`${testAssetDir}/temp/directoryA/assetA.png`);
|
||||
utils.createImageFile(`${testAssetDir}/temp/directoryB/assetB.png`);
|
||||
@@ -50,24 +43,6 @@ describe('/library', () => {
|
||||
expect(status).toBe(401);
|
||||
expect(body).toEqual(errorDto.unauthorized);
|
||||
});
|
||||
|
||||
it('should start with a default upload library', async () => {
|
||||
const { status, body } = await request(app).get('/library').set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.Upload,
|
||||
name: 'Default Library',
|
||||
refreshedAt: null,
|
||||
assetCount: 0,
|
||||
importPaths: [],
|
||||
exclusionPatterns: [],
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /library', () => {
|
||||
@@ -81,7 +56,7 @@ describe('/library', () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/library')
|
||||
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||
.send({ ownerId: admin.userId, type: LibraryType.External });
|
||||
.send({ ownerId: admin.userId });
|
||||
|
||||
expect(status).toBe(403);
|
||||
expect(body).toEqual(errorDto.forbidden);
|
||||
@@ -91,13 +66,12 @@ describe('/library', () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/library')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({ ownerId: admin.userId, type: LibraryType.External });
|
||||
.send({ ownerId: admin.userId });
|
||||
|
||||
expect(status).toBe(201);
|
||||
expect(body).toEqual(
|
||||
expect.objectContaining({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
name: 'New External Library',
|
||||
refreshedAt: null,
|
||||
assetCount: 0,
|
||||
@@ -113,7 +87,6 @@ describe('/library', () => {
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
name: 'My Awesome Library',
|
||||
importPaths: ['/path/to/import'],
|
||||
exclusionPatterns: ['**/Raw/**'],
|
||||
@@ -134,7 +107,6 @@ describe('/library', () => {
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
name: 'My Awesome Library',
|
||||
importPaths: ['/path', '/path'],
|
||||
exclusionPatterns: ['**/Raw/**'],
|
||||
@@ -150,7 +122,6 @@ describe('/library', () => {
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
name: 'My Awesome Library',
|
||||
importPaths: ['/path/to/import'],
|
||||
exclusionPatterns: ['**/Raw/**', '**/Raw/**'],
|
||||
@@ -159,60 +130,6 @@ describe('/library', () => {
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest(["All exclusionPatterns's elements must be unique"]));
|
||||
});
|
||||
|
||||
it('should create an upload library with defaults', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/library')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({ ownerId: admin.userId, type: LibraryType.Upload });
|
||||
|
||||
expect(status).toBe(201);
|
||||
expect(body).toEqual(
|
||||
expect.objectContaining({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.Upload,
|
||||
name: 'New Upload Library',
|
||||
refreshedAt: null,
|
||||
assetCount: 0,
|
||||
importPaths: [],
|
||||
exclusionPatterns: [],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should create an upload library with options', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/library')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({ ownerId: admin.userId, type: LibraryType.Upload, name: 'My Awesome Library' });
|
||||
|
||||
expect(status).toBe(201);
|
||||
expect(body).toEqual(
|
||||
expect.objectContaining({
|
||||
name: 'My Awesome Library',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not allow upload libraries to have import paths', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/library')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({ ownerId: admin.userId, type: LibraryType.Upload, importPaths: ['/path/to/import'] });
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest('Upload libraries cannot have import paths'));
|
||||
});
|
||||
|
||||
it('should not allow upload libraries to have exclusion patterns', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/library')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send({ ownerId: admin.userId, type: LibraryType.Upload, exclusionPatterns: ['**/Raw/**'] });
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest('Upload libraries cannot have exclusion patterns'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('PUT /library/:id', () => {
|
||||
@@ -332,10 +249,7 @@ describe('/library', () => {
|
||||
});
|
||||
|
||||
it('should get library by id', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
});
|
||||
const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId });
|
||||
|
||||
const { status, body } = await request(app)
|
||||
.get(`/library/${library.id}`)
|
||||
@@ -345,7 +259,6 @@ describe('/library', () => {
|
||||
expect(body).toEqual(
|
||||
expect.objectContaining({
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
name: 'New External Library',
|
||||
refreshedAt: null,
|
||||
assetCount: 0,
|
||||
@@ -373,24 +286,9 @@ describe('/library', () => {
|
||||
expect(body).toEqual(errorDto.unauthorized);
|
||||
});
|
||||
|
||||
it('should not scan an upload library', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.Upload,
|
||||
});
|
||||
|
||||
const { status, body } = await request(app)
|
||||
.post(`/library/${library.id}/scan`)
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest('Can only refresh external libraries'));
|
||||
});
|
||||
|
||||
it('should scan external library', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp/directoryA`],
|
||||
});
|
||||
|
||||
@@ -406,7 +304,6 @@ describe('/library', () => {
|
||||
it('should scan external library with exclusion pattern', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
exclusionPatterns: ['**/directoryA'],
|
||||
});
|
||||
@@ -423,7 +320,6 @@ describe('/library', () => {
|
||||
it('should scan multiple import paths', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp/directoryA`, `${testAssetDirInternal}/temp/directoryB`],
|
||||
});
|
||||
|
||||
@@ -440,7 +336,6 @@ describe('/library', () => {
|
||||
it('should pick up new files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -466,7 +361,6 @@ describe('/library', () => {
|
||||
utils.createImageFile(`${testAssetDir}/temp/directoryA/assetB.png`);
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -493,7 +387,6 @@ describe('/library', () => {
|
||||
it('should scan new files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -521,7 +414,6 @@ describe('/library', () => {
|
||||
it('should reimport modified files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -549,7 +441,6 @@ describe('/library', () => {
|
||||
it('should not reimport unmodified files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -579,7 +470,6 @@ describe('/library', () => {
|
||||
it('should reimport all files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -617,7 +507,6 @@ describe('/library', () => {
|
||||
it('should remove offline files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -658,7 +547,6 @@ describe('/library', () => {
|
||||
it('should not remove online files', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -737,37 +625,8 @@ describe('/library', () => {
|
||||
expect(body).toEqual(errorDto.unauthorized);
|
||||
});
|
||||
|
||||
it('should not delete the last upload library', async () => {
|
||||
const libraries = await getAllLibraries(
|
||||
{ $type: LibraryType.Upload },
|
||||
{ headers: asBearerAuth(admin.accessToken) },
|
||||
);
|
||||
|
||||
const adminLibraries = libraries.filter((library) => library.ownerId === admin.userId);
|
||||
expect(adminLibraries.length).toBeGreaterThanOrEqual(1);
|
||||
const lastLibrary = adminLibraries.pop() as LibraryResponseDto;
|
||||
|
||||
// delete all but the last upload library
|
||||
for (const library of adminLibraries) {
|
||||
const { status } = await request(app)
|
||||
.delete(`/library/${library.id}`)
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
expect(status).toBe(204);
|
||||
}
|
||||
|
||||
const { status, body } = await request(app)
|
||||
.delete(`/library/${lastLibrary.id}`)
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
|
||||
expect(body).toEqual(errorDto.noDeleteUploadLibrary);
|
||||
expect(status).toBe(400);
|
||||
});
|
||||
|
||||
it('should delete an external library', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
});
|
||||
const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId });
|
||||
|
||||
const { status, body } = await request(app)
|
||||
.delete(`/library/${library.id}`)
|
||||
@@ -776,7 +635,7 @@ describe('/library', () => {
|
||||
expect(status).toBe(204);
|
||||
expect(body).toEqual({});
|
||||
|
||||
const libraries = await getAllLibraries({}, { headers: asBearerAuth(admin.accessToken) });
|
||||
const libraries = await getAllLibraries({ headers: asBearerAuth(admin.accessToken) });
|
||||
expect(libraries).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
@@ -789,7 +648,6 @@ describe('/library', () => {
|
||||
it('should delete an external library with assets', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
type: LibraryType.External,
|
||||
importPaths: [`${testAssetDirInternal}/temp`],
|
||||
});
|
||||
|
||||
@@ -803,7 +661,7 @@ describe('/library', () => {
|
||||
expect(status).toBe(204);
|
||||
expect(body).toEqual({});
|
||||
|
||||
const libraries = await getAllLibraries({}, { headers: asBearerAuth(admin.accessToken) });
|
||||
const libraries = await getAllLibraries({ headers: asBearerAuth(admin.accessToken) });
|
||||
expect(libraries).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
|
||||
@@ -66,6 +66,7 @@ describe('/server-info', () => {
|
||||
expect(body).toEqual({
|
||||
smartSearch: false,
|
||||
configFile: false,
|
||||
duplicateDetection: false,
|
||||
facialRecognition: false,
|
||||
map: true,
|
||||
reverseGeocoding: true,
|
||||
|
||||
@@ -32,8 +32,7 @@ describe('/trash', () => {
|
||||
await utils.deleteAssets(admin.accessToken, [assetId]);
|
||||
|
||||
const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
||||
|
||||
expect(before.length).toBeGreaterThanOrEqual(1);
|
||||
expect(before).toStrictEqual([expect.objectContaining({ id: assetId, isTrashed: true })]);
|
||||
|
||||
const { status } = await request(app).post('/trash/empty').set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
expect(status).toBe(204);
|
||||
@@ -57,14 +56,14 @@ describe('/trash', () => {
|
||||
const { id: assetId } = await utils.createAsset(admin.accessToken);
|
||||
await utils.deleteAssets(admin.accessToken, [assetId]);
|
||||
|
||||
const before = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||
expect(before.isTrashed).toBe(true);
|
||||
const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
||||
expect(before).toStrictEqual([expect.objectContaining({ id: assetId, isTrashed: true })]);
|
||||
|
||||
const { status } = await request(app).post('/trash/restore').set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
expect(status).toBe(204);
|
||||
|
||||
const after = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||
expect(after.isTrashed).toBe(false);
|
||||
const after = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
|
||||
expect(after).toStrictEqual([expect.objectContaining({ id: assetId, isTrashed: false })]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -51,11 +51,6 @@ export const errorDto = {
|
||||
statusCode: 400,
|
||||
message: 'The server already has an admin',
|
||||
},
|
||||
noDeleteUploadLibrary: {
|
||||
error: 'Bad Request',
|
||||
statusCode: 400,
|
||||
message: 'Cannot delete the last upload library',
|
||||
},
|
||||
};
|
||||
|
||||
export const signupResponseDto = {
|
||||
|
||||
@@ -17,7 +17,7 @@ const setup = async () => {
|
||||
child.stdout.on('data', (data) => {
|
||||
const input = data.toString();
|
||||
console.log(input);
|
||||
if (input.includes('Immich Microservices is listening')) {
|
||||
if (input.includes('Immich Microservices is running')) {
|
||||
_resolve();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
createPerson,
|
||||
createSharedLink,
|
||||
createUser,
|
||||
defaults,
|
||||
deleteAssets,
|
||||
getAllAssets,
|
||||
getAllJobsStatus,
|
||||
@@ -24,6 +23,7 @@ import {
|
||||
getConfigDefaults,
|
||||
login,
|
||||
searchMetadata,
|
||||
setBaseUrl,
|
||||
signUpAdmin,
|
||||
updateAdminOnboarding,
|
||||
updateAlbumUser,
|
||||
@@ -145,7 +145,6 @@ export const utils = {
|
||||
'sessions',
|
||||
'users',
|
||||
'system_metadata',
|
||||
'system_config',
|
||||
];
|
||||
|
||||
const sql: string[] = [];
|
||||
@@ -256,8 +255,8 @@ export const utils = {
|
||||
});
|
||||
},
|
||||
|
||||
setApiEndpoint: () => {
|
||||
defaults.baseUrl = app;
|
||||
initSdk: () => {
|
||||
setBaseUrl(app);
|
||||
},
|
||||
|
||||
adminSetup: async (options?: AdminSetupOptions) => {
|
||||
@@ -463,7 +462,7 @@ export const utils = {
|
||||
},
|
||||
};
|
||||
|
||||
utils.setApiEndpoint();
|
||||
utils.initSdk();
|
||||
|
||||
if (!existsSync(`${testAssetDir}/albums`)) {
|
||||
throw new Error(
|
||||
|
||||
@@ -3,7 +3,7 @@ import { utils } from 'src/utils';
|
||||
|
||||
test.describe('Registration', () => {
|
||||
test.beforeAll(() => {
|
||||
utils.setApiEndpoint();
|
||||
utils.initSdk();
|
||||
});
|
||||
|
||||
test.beforeEach(async () => {
|
||||
|
||||
@@ -17,7 +17,7 @@ test.describe('Shared Links', () => {
|
||||
let sharedLinkPassword: SharedLinkResponseDto;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
utils.setApiEndpoint();
|
||||
utils.initSdk();
|
||||
await utils.resetDatabase();
|
||||
admin = await utils.adminSetup();
|
||||
asset = await utils.createAsset(admin.accessToken);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ARG DEVICE=cpu
|
||||
|
||||
FROM python:3.11-bookworm@sha256:9df8be5280f00f39931fc2168309e82ddf252a7f30cda6593b7990fb0f5f59f9 as builder-cpu
|
||||
FROM python:3.11-bookworm@sha256:96de1ea4821d73fd2c1853d1fdc3cf794ccfe2fae4c3f08579e846de51760a61 as builder-cpu
|
||||
|
||||
FROM openvino/ubuntu22_runtime:2023.3.0@sha256:176646df619032ea6c10faf842867119c393e7497b7f88b5e307e932a0fd5aa8 as builder-openvino
|
||||
USER root
|
||||
@@ -40,6 +40,9 @@ FROM python:3.11-slim-bookworm@sha256:fc39d2e68b554c3f0a5cb8a776280c0b3d73b4c04b
|
||||
|
||||
FROM openvino/ubuntu22_runtime:2023.3.0@sha256:176646df619032ea6c10faf842867119c393e7497b7f88b5e307e932a0fd5aa8 as prod-openvino
|
||||
USER root
|
||||
# TODO: remove this once the image has the fix for https://github.com/intel/compute-runtime/issues/710
|
||||
ENV NEOReadDebugKeys=1 \
|
||||
OverrideGpuAddressSpace=48
|
||||
|
||||
FROM nvidia/cuda:12.2.2-cudnn8-runtime-ubuntu22.04@sha256:2d913b09e6be8387e1a10976933642c73c840c0b735f0bf3c28d97fc9bc422e0 as prod-cuda
|
||||
|
||||
@@ -74,8 +77,7 @@ RUN apt-get update && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
ENV NODE_ENV=production \
|
||||
TRANSFORMERS_CACHE=/cache \
|
||||
ENV TRANSFORMERS_CACHE=/cache \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PATH="/opt/venv/bin:$PATH" \
|
||||
|
||||
@@ -41,7 +41,7 @@ class Settings(BaseSettings):
|
||||
|
||||
|
||||
class LogSettings(BaseSettings):
|
||||
log_level: str = "info"
|
||||
immich_log_level: str = "info"
|
||||
no_color: bool = False
|
||||
|
||||
class Config:
|
||||
@@ -77,7 +77,7 @@ LOG_LEVELS: dict[str, int] = {
|
||||
settings = Settings()
|
||||
log_settings = LogSettings()
|
||||
|
||||
LOG_LEVEL = LOG_LEVELS.get(log_settings.log_level.lower(), logging.INFO)
|
||||
LOG_LEVEL = LOG_LEVELS.get(log_settings.immich_log_level.lower(), logging.INFO)
|
||||
|
||||
|
||||
class CustomRichHandler(RichHandler):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
FROM mambaorg/micromamba:bookworm-slim@sha256:abcb3ae7e3521d08e1fdeaff63131765b34e4f29b6a8a2c28660036b53841569 as builder
|
||||
FROM mambaorg/micromamba:bookworm-slim@sha256:d5b82811074b396275ef69aadbf31098257dd8836e231371e9cdb393128e571c as builder
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
TRANSFORMERS_CACHE=/cache \
|
||||
ENV TRANSFORMERS_CACHE=/cache \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PATH="/opt/venv/bin:$PATH" \
|
||||
|
||||
12
machine-learning/poetry.lock
generated
12
machine-learning/poetry.lock
generated
@@ -738,13 +738,13 @@ dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
name = "flask-cors"
|
||||
version = "4.0.0"
|
||||
version = "4.0.1"
|
||||
description = "A Flask extension adding a decorator for CORS support"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "Flask-Cors-4.0.0.tar.gz", hash = "sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0"},
|
||||
{file = "Flask_Cors-4.0.0-py2.py3-none-any.whl", hash = "sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783"},
|
||||
{file = "Flask_Cors-4.0.1-py2.py3-none-any.whl", hash = "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677"},
|
||||
{file = "flask_cors-4.0.1.tar.gz", hash = "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1374,13 +1374,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.3"
|
||||
version = "3.1.4"
|
||||
description = "A very fast and expressive template engine."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"},
|
||||
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"},
|
||||
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
|
||||
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "machine-learning"
|
||||
version = "1.105.0"
|
||||
version = "1.105.1"
|
||||
description = ""
|
||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
|
||||
lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.2"
|
||||
# mimalloc seems to increase memory usage dramatically with openvino, need to investigate
|
||||
if ! [ "$DEVICE" = "openvino" ]; then
|
||||
if ! [ "$DEVICE" = "openvino" ]; then
|
||||
export LD_PRELOAD="$lib_path"
|
||||
export LD_BIND_NOW=1
|
||||
fi
|
||||
|
||||
: "${MACHINE_LEARNING_HOST:=[::]}"
|
||||
: "${MACHINE_LEARNING_PORT:=3003}"
|
||||
: "${IMMICH_HOST:=[::]}"
|
||||
: "${IMMICH_PORT:=3003}"
|
||||
: "${MACHINE_LEARNING_WORKERS:=1}"
|
||||
: "${MACHINE_LEARNING_WORKER_TIMEOUT:=120}"
|
||||
|
||||
gunicorn app.main:app \
|
||||
-k app.config.CustomUvicornWorker \
|
||||
-b "$IMMICH_HOST":"$IMMICH_PORT" \
|
||||
-w "$MACHINE_LEARNING_WORKERS" \
|
||||
-b "$MACHINE_LEARNING_HOST":"$MACHINE_LEARNING_PORT" \
|
||||
-t "$MACHINE_LEARNING_WORKER_TIMEOUT" \
|
||||
--log-config-json log_conf.json \
|
||||
--graceful-timeout 0
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"flutter": "3.19.6"
|
||||
"flutter": "3.22.0"
|
||||
}
|
||||
2
mobile/.vscode/settings.json
vendored
2
mobile/.vscode/settings.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dart.flutterSdkPath": ".fvm/versions/3.19.3",
|
||||
"dart.flutterSdkPath": ".fvm/versions/3.22.0",
|
||||
"search.exclude": {
|
||||
"**/.fvm": true
|
||||
},
|
||||
|
||||
@@ -10,16 +10,16 @@ GEM
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.925.0)
|
||||
aws-sdk-core (3.194.1)
|
||||
aws-partitions (1.931.0)
|
||||
aws-sdk-core (3.196.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.8)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.80.0)
|
||||
aws-sdk-kms (1.81.0)
|
||||
aws-sdk-core (~> 3, >= 3.193.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.149.1)
|
||||
aws-sdk-s3 (1.151.0)
|
||||
aws-sdk-core (~> 3, >= 3.194.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.8)
|
||||
@@ -155,7 +155,7 @@ GEM
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.0)
|
||||
multipart-post (2.4.1)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
nkf (0.2.0)
|
||||
@@ -169,7 +169,8 @@ GEM
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.2.6)
|
||||
rexml (3.2.8)
|
||||
strscan (>= 3.0.9)
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
@@ -182,6 +183,7 @@ GEM
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
strscan (3.1.0)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
|
||||
@@ -81,8 +81,8 @@ flutter {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
def kotlin_version = '1.9.23'
|
||||
def kotlin_coroutines_version = '1.8.0'
|
||||
def kotlin_version = '1.9.24'
|
||||
def kotlin_coroutines_version = '1.8.1'
|
||||
def work_version = '2.9.0'
|
||||
def concurrent_version = '1.1.0'
|
||||
def guava_version = '33.2.0-android'
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
allprojects {
|
||||
ext.kotlin_version = '1.9.24'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
||||
@@ -35,8 +35,8 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 139,
|
||||
"android.injected.version.name" => "1.105.0",
|
||||
"android.injected.version.code" => 140,
|
||||
"android.injected.version.name" => "1.105.1",
|
||||
}
|
||||
)
|
||||
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')
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000344">
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000374">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="52.933903">
|
||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="84.292464">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="31.026779">
|
||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="33.336934">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
BIN
mobile/android/kls_database.db
Normal file
BIN
mobile/android/kls_database.db
Normal file
Binary file not shown.
@@ -19,8 +19,8 @@ pluginManagement {
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "7.4.2" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.9.23" apply false
|
||||
id "org.jetbrains.kotlin.kapt" version "1.9.23" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.9.24" apply false
|
||||
id "org.jetbrains.kotlin.kapt" version "1.9.24" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
@@ -391,6 +391,7 @@
|
||||
"setting_image_viewer_original_title": "Original laden",
|
||||
"setting_image_viewer_preview_subtitle": "Aktivieren, um ein Bild mit mittlerer Auflösung zu laden. Deaktivieren, um entweder das Original direkt zu laden oder nur die Miniaturansicht zu verwenden.",
|
||||
"setting_image_viewer_preview_title": "Vorschaubild laden",
|
||||
"setting_image_viewer_title": "Bilder",
|
||||
"setting_languages_apply": "Anwenden",
|
||||
"setting_languages_title": "Sprachen",
|
||||
"setting_notifications_notify_failures_grace_period": "Benachrichtigung über Fehler bei der Hintergrundsicherung: {}",
|
||||
@@ -406,6 +407,9 @@
|
||||
"setting_notifications_total_progress_subtitle": "Gesamter Upload-Fortschritt (abgeschlossen/Anzahl Elemente)",
|
||||
"setting_notifications_total_progress_title": "Zeige Gesamtfortschritt bei der Hintergrundsicherung",
|
||||
"setting_pages_app_bar_settings": "Einstellungen",
|
||||
"setting_video_viewer_looping_subtitle": "Aktivieren, damit sich ein Video in der Detailansicht automatisch wiederholt.",
|
||||
"setting_video_viewer_looping_title": "Wiederholen",
|
||||
"setting_video_viewer_title": "Videos",
|
||||
"settings_require_restart": "Bitte starte Immich neu, um diese Einstellung anzuwenden.",
|
||||
"share_add": "Hinzufügen",
|
||||
"share_add_photos": "Fotos hinzufügen",
|
||||
|
||||
@@ -391,6 +391,7 @@
|
||||
"setting_image_viewer_original_title": "Load original image",
|
||||
"setting_image_viewer_preview_subtitle": "Enable to load a medium-resolution image. Disable to either directly load the original or only use the thumbnail.",
|
||||
"setting_image_viewer_preview_title": "Load preview image",
|
||||
"setting_image_viewer_title": "Images",
|
||||
"setting_languages_apply": "Apply",
|
||||
"setting_languages_title": "Languages",
|
||||
"setting_notifications_notify_failures_grace_period": "Notify background backup failures: {}",
|
||||
@@ -406,6 +407,9 @@
|
||||
"setting_notifications_total_progress_subtitle": "Overall upload progress (done/total assets)",
|
||||
"setting_notifications_total_progress_title": "Show background backup total progress",
|
||||
"setting_pages_app_bar_settings": "Settings",
|
||||
"setting_video_viewer_looping_subtitle": "Enable to automatically loop a video in the detail viewer.",
|
||||
"setting_video_viewer_looping_title": "Looping",
|
||||
"setting_video_viewer_title": "Videos",
|
||||
"settings_require_restart": "Please restart Immich to apply this setting",
|
||||
"share_add": "Add",
|
||||
"share_add_photos": "Add photos",
|
||||
|
||||
@@ -10,16 +10,16 @@ GEM
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.925.0)
|
||||
aws-sdk-core (3.194.1)
|
||||
aws-partitions (1.931.0)
|
||||
aws-sdk-core (3.196.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.8)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.80.0)
|
||||
aws-sdk-kms (1.81.0)
|
||||
aws-sdk-core (~> 3, >= 3.193.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.149.1)
|
||||
aws-sdk-s3 (1.151.0)
|
||||
aws-sdk-core (~> 3, >= 3.194.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.8)
|
||||
@@ -155,7 +155,7 @@ GEM
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.0)
|
||||
multipart-post (2.4.1)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
nkf (0.2.0)
|
||||
@@ -169,7 +169,8 @@ GEM
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.2.6)
|
||||
rexml (3.2.8)
|
||||
strscan (>= 3.0.9)
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
@@ -182,6 +183,7 @@ GEM
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
strscan (3.1.0)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
|
||||
@@ -159,7 +159,7 @@ SPEC CHECKSUMS:
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461
|
||||
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
|
||||
integration_test: 13825b8a9334a850581300559b8839134b124670
|
||||
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
|
||||
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
|
||||
MapLibre: 620fc933c1d6029b33738c905c1490d024e5d4ef
|
||||
maplibre_gl: a2efec727dd340e4c65e26d2b03b584f14881fd9
|
||||
|
||||
@@ -383,7 +383,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 156;
|
||||
CURRENT_PROJECT_VERSION = 157;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -525,7 +525,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 156;
|
||||
CURRENT_PROJECT_VERSION = 157;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -553,7 +553,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 156;
|
||||
CURRENT_PROJECT_VERSION = 157;
|
||||
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.104.0</string>
|
||||
<string>1.105.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>156</string>
|
||||
<string>157</string>
|
||||
<key>FLTEnableImpeller</key>
|
||||
<true />
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
|
||||
@@ -19,7 +19,7 @@ platform :ios do
|
||||
desc "iOS Beta"
|
||||
lane :beta do
|
||||
increment_version_number(
|
||||
version_number: "1.105.0"
|
||||
version_number: "1.105.1"
|
||||
)
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number + 1,
|
||||
|
||||
@@ -5,32 +5,32 @@
|
||||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000406">
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.020864">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="37.890919">
|
||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.917777">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="7.615129">
|
||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="5.283943">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.535245">
|
||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.944748">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="4: build_app" time="213.966277">
|
||||
<testcase classname="fastlane.lanes" name="4: build_app" time="215.971639">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="80.742201">
|
||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="76.674601">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ enum StoreKey<T> {
|
||||
advancedTroubleshooting<bool>(114, type: bool),
|
||||
logLevel<int>(115, type: int),
|
||||
preferRemoteImage<bool>(116, type: bool),
|
||||
loopVideo<bool>(117, type: bool),
|
||||
// map related settings
|
||||
mapShowFavoriteOnly<bool>(118, type: bool),
|
||||
mapRelativeDate<int>(119, type: int),
|
||||
|
||||
@@ -54,7 +54,7 @@ class AlbumPreviewPage extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -191,7 +191,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
title: const Text(
|
||||
|
||||
@@ -7,16 +7,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
||||
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
|
||||
import 'package:immich_mobile/providers/backup/ios_background_settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
|
||||
import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart';
|
||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/providers/websocket.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/widgets/backup/backup_info_card.dart';
|
||||
import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart';
|
||||
|
||||
@RoutePage()
|
||||
class BackupControllerPage extends HookConsumerWidget {
|
||||
@@ -260,7 +260,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
ref.watch(websocketProvider.notifier).listenUploadEvent();
|
||||
context.popRoute(true);
|
||||
context.maybePop(true);
|
||||
},
|
||||
splashRadius: 24,
|
||||
icon: const Icon(
|
||||
|
||||
@@ -13,7 +13,7 @@ class BackupOptionsPage extends StatelessWidget {
|
||||
elevation: 0,
|
||||
title: const Text("backup_options_page_title").tr(),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(true),
|
||||
onPressed: () => context.maybePop(true),
|
||||
splashRadius: 24,
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios_rounded,
|
||||
|
||||
@@ -23,7 +23,7 @@ class FailedBackupStatusPage extends HookConsumerWidget {
|
||||
),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
context.popRoute(true);
|
||||
context.maybePop(true);
|
||||
},
|
||||
splashRadius: 24,
|
||||
icon: const Icon(
|
||||
|
||||
@@ -26,7 +26,7 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget {
|
||||
final sharedUsersList = useState<Set<User>>({});
|
||||
|
||||
addNewUsersHandler() {
|
||||
context.popRoute(sharedUsersList.value.map((e) => e.id).toList());
|
||||
context.maybePop(sharedUsersList.value.map((e) => e.id).toList());
|
||||
}
|
||||
|
||||
buildTileIcon(User user) {
|
||||
@@ -55,10 +55,9 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget {
|
||||
child: Chip(
|
||||
backgroundColor: context.primaryColor.withOpacity(0.15),
|
||||
label: Text(
|
||||
user.email,
|
||||
user.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
@@ -88,13 +87,20 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget {
|
||||
itemBuilder: ((context, index) {
|
||||
return ListTile(
|
||||
leading: buildTileIcon(users[index]),
|
||||
dense: true,
|
||||
title: Text(
|
||||
users[index].email,
|
||||
users[index].name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
users[index].email,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (sharedUsersList.value.contains(users[index])) {
|
||||
sharedUsersList.value = sharedUsersList.value
|
||||
@@ -127,7 +133,7 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget {
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
onPressed: () {
|
||||
context.popRoute(null);
|
||||
context.maybePop(null);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
|
||||
@@ -184,7 +184,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||
onPressed: () => context.popRoute(null),
|
||||
onPressed: () => context.maybePop(null),
|
||||
),
|
||||
centerTitle: true,
|
||||
title: Text("translated_text_options".tr()),
|
||||
|
||||
@@ -36,7 +36,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget {
|
||||
await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||
// ref.watch(assetSelectionProvider.notifier).removeAll();
|
||||
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
||||
context.popRoute(true);
|
||||
context.maybePop(true);
|
||||
context
|
||||
.navigateTo(const TabControllerRoute(children: [SharingRoute()]));
|
||||
}
|
||||
@@ -152,7 +152,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget {
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
onPressed: () async {
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
|
||||
@@ -105,7 +105,7 @@ class AppLogPage extends HookConsumerWidget {
|
||||
],
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
|
||||
@@ -3,16 +3,16 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/album/album_title.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/widgets/album/album_action_outlined_button.dart';
|
||||
import 'package:immich_mobile/widgets/album/album_title_text_field.dart';
|
||||
import 'package:immich_mobile/widgets/album/shared_album_thumbnail_image.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/providers/asset.provider.dart';
|
||||
|
||||
@RoutePage()
|
||||
// ignore: must_be_immutable
|
||||
@@ -216,7 +216,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
selectedAssets.value = {};
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
},
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
),
|
||||
|
||||
@@ -2,32 +2,33 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/providers/image/immich_remote_image_provider.dart';
|
||||
import 'package:immich_mobile/pages/common/video_viewer.page.dart';
|
||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/asset_stack.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||
import 'package:immich_mobile/providers/image/immich_remote_image_provider.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/widgets/asset_viewer/advanced_bottom_sheet.dart';
|
||||
import 'package:immich_mobile/widgets/asset_viewer/bottom_gallery_bar.dart';
|
||||
import 'package:immich_mobile/widgets/asset_viewer/exif_sheet/exif_bottom_sheet.dart';
|
||||
import 'package:immich_mobile/widgets/asset_viewer/gallery_app_bar.dart';
|
||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/pages/common/video_viewer.page.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
|
||||
import 'package:immich_mobile/widgets/photo_view/photo_view_gallery.dart';
|
||||
import 'package:immich_mobile/widgets/photo_view/src/photo_view_computed_scale.dart';
|
||||
import 'package:immich_mobile/widgets/photo_view/src/photo_view_scale_state.dart';
|
||||
import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_hero_attributes.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:openapi/api.dart' show ThumbnailFormat;
|
||||
|
||||
@@ -59,6 +60,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
final settings = ref.watch(appSettingsServiceProvider);
|
||||
final isLoadPreview = useState(AppSettingsEnum.loadPreview.defaultValue);
|
||||
final isLoadOriginal = useState(AppSettingsEnum.loadOriginal.defaultValue);
|
||||
final shouldLoopVideo = useState(AppSettingsEnum.loopVideo.defaultValue);
|
||||
final isZoomed = useState(false);
|
||||
final isPlayingVideo = useState(false);
|
||||
final localPosition = useState<Offset?>(null);
|
||||
@@ -101,6 +103,8 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
settings.getSetting<bool>(AppSettingsEnum.loadPreview);
|
||||
isLoadOriginal.value =
|
||||
settings.getSetting<bool>(AppSettingsEnum.loadOriginal);
|
||||
shouldLoopVideo.value =
|
||||
settings.getSetting<bool>(AppSettingsEnum.loopVideo);
|
||||
return null;
|
||||
},
|
||||
[],
|
||||
@@ -174,7 +178,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
|
||||
final ratio = d.dy / max(d.dx.abs(), 1);
|
||||
if (d.dy > sensitivity && ratio > ratioThreshold) {
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
} else if (d.dy < -sensitivity && ratio < -ratioThreshold) {
|
||||
showInfo();
|
||||
}
|
||||
@@ -261,12 +265,9 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (_) {
|
||||
// Change immersive mode back to normal "edgeToEdge" mode
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||
context.pop();
|
||||
},
|
||||
// Change immersive mode back to normal "edgeToEdge" mode
|
||||
onPopInvoked: (_) =>
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge),
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: Stack(
|
||||
@@ -370,6 +371,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
key: ValueKey(a),
|
||||
asset: a,
|
||||
isMotionVideo: a.livePhotoVideoId != null,
|
||||
loopVideo: shouldLoopVideo.value,
|
||||
placeholder: Image(
|
||||
image: provider,
|
||||
fit: BoxFit.contain,
|
||||
|
||||
@@ -5,8 +5,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/widgets/settings/advanced_settings.dart';
|
||||
import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_settings.dart';
|
||||
import 'package:immich_mobile/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart';
|
||||
import 'package:immich_mobile/widgets/settings/backup_settings/backup_settings.dart';
|
||||
import 'package:immich_mobile/widgets/settings/image_viewer_quality_setting.dart';
|
||||
import 'package:immich_mobile/widgets/settings/language_settings.dart';
|
||||
import 'package:immich_mobile/widgets/settings/notification_setting.dart';
|
||||
import 'package:immich_mobile/widgets/settings/preference_settings/preference_setting.dart';
|
||||
@@ -33,7 +33,7 @@ enum SettingSection {
|
||||
SettingSection.preferences => const PreferenceSetting(),
|
||||
SettingSection.backup => const BackupSettings(),
|
||||
SettingSection.timeline => const AssetListSettings(),
|
||||
SettingSection.viewer => const ImageViewerQualitySetting(),
|
||||
SettingSection.viewer => const AssetViewerSettings(),
|
||||
SettingSection.advanced => const AdvancedSettings(),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_controller_provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
||||
import 'package:immich_mobile/widgets/asset_viewer/video_player.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
|
||||
@RoutePage()
|
||||
// ignore: must_be_immutable
|
||||
class VideoViewerPage extends HookConsumerWidget {
|
||||
final Asset asset;
|
||||
final bool isMotionVideo;
|
||||
@@ -20,6 +17,7 @@ class VideoViewerPage extends HookConsumerWidget {
|
||||
final Duration hideControlsTimer;
|
||||
final bool showControls;
|
||||
final bool showDownloadingIndicator;
|
||||
final bool loopVideo;
|
||||
|
||||
const VideoViewerPage({
|
||||
super.key,
|
||||
@@ -29,6 +27,7 @@ class VideoViewerPage extends HookConsumerWidget {
|
||||
this.showControls = true,
|
||||
this.hideControlsTimer = const Duration(seconds: 5),
|
||||
this.showDownloadingIndicator = true,
|
||||
this.loopVideo = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -76,7 +75,9 @@ class VideoViewerPage extends HookConsumerWidget {
|
||||
// Also sets the error if there is an error in the playback
|
||||
void updateVideoPlayback() {
|
||||
final videoPlayback = VideoPlaybackValue.fromController(controller);
|
||||
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
|
||||
if (!loopVideo) {
|
||||
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
|
||||
}
|
||||
final state = videoPlayback.state;
|
||||
|
||||
// Enable the WakeLock while the video is playing
|
||||
@@ -156,6 +157,7 @@ class VideoViewerPage extends HookConsumerWidget {
|
||||
hideControlsTimer: hideControlsTimer,
|
||||
showControls: showControls,
|
||||
showDownloadingIndicator: showDownloadingIndicator,
|
||||
loopVideo: loopVideo,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -17,7 +17,7 @@ class ArchivePage extends HookConsumerWidget {
|
||||
final count = archivedAssets.value?.totalAssets.toString() ?? "?";
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
centerTitle: true,
|
||||
|
||||
@@ -15,7 +15,7 @@ class FavoritesPage extends HookConsumerWidget {
|
||||
AppBar buildAppBar() {
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
centerTitle: true,
|
||||
|
||||
@@ -143,7 +143,7 @@ class TrashPage extends HookConsumerWidget {
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: !selectionEnabledHook.value
|
||||
? () => context.popRoute()
|
||||
? () => context.maybePop()
|
||||
: () {
|
||||
selectionEnabledHook.value = false;
|
||||
selection.value = {};
|
||||
|
||||
@@ -176,7 +176,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('permission_onboarding_back').tr(),
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -3,14 +3,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/models/memories/memory.model.dart';
|
||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
||||
import 'package:immich_mobile/widgets/memories/memory_bottom_info.dart';
|
||||
import 'package:immich_mobile/widgets/memories/memory_card.dart';
|
||||
import 'package:immich_mobile/widgets/memories/memory_epilogue.dart';
|
||||
import 'package:immich_mobile/widgets/memories/memory_progress_indicator.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
||||
|
||||
@RoutePage()
|
||||
class MemoryPage extends HookConsumerWidget {
|
||||
@@ -153,7 +153,7 @@ class MemoryPage extends HookConsumerWidget {
|
||||
final offset = notification.metrics.pixels;
|
||||
if (isEpiloguePage &&
|
||||
(offset > notification.metrics.maxScrollExtent + 150)) {
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -256,7 +256,7 @@ class MemoryPage extends HookConsumerWidget {
|
||||
// auto_route doesn't invoke pop scope, so
|
||||
// turn off full screen mode here
|
||||
// https://github.com/Milad-Akarie/auto_route_library/issues/1799
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
SystemChrome.setEnabledSystemUIMode(
|
||||
SystemUiMode.edgeToEdge,
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ class AllMotionPhotosPage extends HookConsumerWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text('motion_photos_page_title').tr(),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -21,7 +21,7 @@ class AllPeoplePage extends HookConsumerWidget {
|
||||
'all_people_page_title',
|
||||
).tr(),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -22,7 +22,7 @@ class AllPlacesPage extends HookConsumerWidget {
|
||||
'curated_location_page_title',
|
||||
).tr(),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -15,7 +15,7 @@ class AllVideosPage extends HookConsumerWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text('all_videos_page_title').tr(),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -41,7 +41,7 @@ class MapLocationPickerPage extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
void onClose([LatLng? selected]) {
|
||||
context.popRoute(selected);
|
||||
context.maybePop(selected);
|
||||
}
|
||||
|
||||
Future<void> getCurrentLocation() async {
|
||||
|
||||
@@ -102,7 +102,7 @@ class PersonResultPage extends HookConsumerWidget {
|
||||
appBar: AppBar(
|
||||
title: Text(name.value),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
actions: [
|
||||
|
||||
@@ -18,7 +18,7 @@ class RecentlyAddedPage extends HookConsumerWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text('recently_added_page_title').tr(),
|
||||
leading: IconButton(
|
||||
onPressed: () => context.popRoute(),
|
||||
onPressed: () => context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,9 +4,11 @@ import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||
import 'package:immich_mobile/providers/search/paginated_search.provider.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart';
|
||||
import 'package:immich_mobile/widgets/search/search_filter/camera_picker.dart';
|
||||
import 'package:immich_mobile/widgets/search/search_filter/display_option_picker.dart';
|
||||
import 'package:immich_mobile/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart';
|
||||
@@ -15,8 +17,6 @@ import 'package:immich_mobile/widgets/search/search_filter/media_type_picker.dar
|
||||
import 'package:immich_mobile/widgets/search/search_filter/people_picker.dart';
|
||||
import 'package:immich_mobile/widgets/search/search_filter/search_filter_chip.dart';
|
||||
import 'package:immich_mobile/widgets/search/search_filter/search_filter_utils.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
@RoutePage()
|
||||
@@ -480,9 +480,7 @@ class SearchInputPage extends HookConsumerWidget {
|
||||
],
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||
onPressed: () {
|
||||
context.router.pop();
|
||||
},
|
||||
onPressed: () => context.router.maybePop(),
|
||||
),
|
||||
title: TextField(
|
||||
controller: textSearchController,
|
||||
|
||||
@@ -328,7 +328,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
||||
alignment: Alignment.bottomRight,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
},
|
||||
child: const Text(
|
||||
"share_done",
|
||||
@@ -431,7 +431,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
||||
changeExpiry: changeExpiry,
|
||||
);
|
||||
ref.invalidate(sharedLinksStateProvider);
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
|
||||
@@ -1,35 +1,32 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/models/memories/memory.model.dart';
|
||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||
import 'package:immich_mobile/pages/common/activities.page.dart';
|
||||
import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart';
|
||||
import 'package:immich_mobile/pages/common/album_options.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_viewer.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_asset_selection.page.dart';
|
||||
import 'package:immich_mobile/pages/common/create_album.page.dart';
|
||||
import 'package:immich_mobile/models/shared_link/shared_link.model.dart';
|
||||
import 'package:immich_mobile/pages/common/album_additional_shared_user_selection.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_shared_user_selection.page.dart';
|
||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||
import 'package:immich_mobile/routing/auth_guard.dart';
|
||||
import 'package:immich_mobile/routing/custom_transition_builders.dart';
|
||||
import 'package:immich_mobile/routing/duplicate_guard.dart';
|
||||
import 'package:immich_mobile/routing/backup_permission_guard.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/logger_message.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/pages/common/app_log_detail.page.dart';
|
||||
import 'package:immich_mobile/pages/common/app_log.page.dart';
|
||||
import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart';
|
||||
import 'package:immich_mobile/models/memories/memory.model.dart';
|
||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||
import 'package:immich_mobile/models/shared_link/shared_link.model.dart';
|
||||
import 'package:immich_mobile/pages/backup/album_preview.page.dart';
|
||||
import 'package:immich_mobile/pages/backup/backup_album_selection.page.dart';
|
||||
import 'package:immich_mobile/pages/backup/backup_controller.page.dart';
|
||||
import 'package:immich_mobile/pages/backup/backup_options.page.dart';
|
||||
import 'package:immich_mobile/pages/backup/failed_backup_status.page.dart';
|
||||
import 'package:immich_mobile/pages/common/activities.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_additional_shared_user_selection.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_asset_selection.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_options.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_shared_user_selection.page.dart';
|
||||
import 'package:immich_mobile/pages/common/album_viewer.page.dart';
|
||||
import 'package:immich_mobile/pages/common/app_log.page.dart';
|
||||
import 'package:immich_mobile/pages/common/app_log_detail.page.dart';
|
||||
import 'package:immich_mobile/pages/common/create_album.page.dart';
|
||||
import 'package:immich_mobile/pages/common/gallery_viewer.page.dart';
|
||||
import 'package:immich_mobile/pages/common/settings.page.dart';
|
||||
import 'package:immich_mobile/pages/common/splash_screen.page.dart';
|
||||
import 'package:immich_mobile/pages/common/tab_controller.page.dart';
|
||||
import 'package:immich_mobile/pages/library/archive.page.dart';
|
||||
import 'package:immich_mobile/pages/library/favorite.page.dart';
|
||||
import 'package:immich_mobile/pages/library/library.page.dart';
|
||||
@@ -43,21 +40,23 @@ import 'package:immich_mobile/pages/search/all_motion_videos.page.dart';
|
||||
import 'package:immich_mobile/pages/search/all_people.page.dart';
|
||||
import 'package:immich_mobile/pages/search/all_places.page.dart';
|
||||
import 'package:immich_mobile/pages/search/all_videos.page.dart';
|
||||
import 'package:immich_mobile/pages/search/map/map_location_picker.page.dart';
|
||||
import 'package:immich_mobile/pages/search/map/map.page.dart';
|
||||
import 'package:immich_mobile/pages/search/map/map_location_picker.page.dart';
|
||||
import 'package:immich_mobile/pages/search/person_result.page.dart';
|
||||
import 'package:immich_mobile/pages/search/recently_added.page.dart';
|
||||
import 'package:immich_mobile/pages/search/search_input.page.dart';
|
||||
import 'package:immich_mobile/pages/search/search.page.dart';
|
||||
import 'package:immich_mobile/pages/common/settings.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/partner/partner_detail.page.dart';
|
||||
import 'package:immich_mobile/pages/search/search_input.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/partner/partner.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/shared_link/shared_link_edit.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/partner/partner_detail.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/shared_link/shared_link.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/shared_link/shared_link_edit.page.dart';
|
||||
import 'package:immich_mobile/pages/sharing/sharing.page.dart';
|
||||
import 'package:immich_mobile/pages/common/splash_screen.page.dart';
|
||||
import 'package:immich_mobile/pages/common/tab_controller.page.dart';
|
||||
import 'package:immich_mobile/pages/common/video_viewer.page.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||
import 'package:immich_mobile/routing/auth_guard.dart';
|
||||
import 'package:immich_mobile/routing/backup_permission_guard.dart';
|
||||
import 'package:immich_mobile/routing/custom_transition_builders.dart';
|
||||
import 'package:immich_mobile/routing/duplicate_guard.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
@@ -120,10 +119,6 @@ class AppRouter extends _$AppRouter {
|
||||
guards: [_authGuard, _duplicateGuard],
|
||||
transitionsBuilder: CustomTransitionsBuilders.zoomedPage,
|
||||
),
|
||||
AutoRoute(
|
||||
page: VideoViewerRoute.page,
|
||||
guards: [_authGuard, _duplicateGuard],
|
||||
),
|
||||
AutoRoute(
|
||||
page: BackupControllerRoute.page,
|
||||
guards: [_authGuard, _duplicateGuard, _backupPermissionGuard],
|
||||
|
||||
@@ -21,6 +21,29 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
child: const ActivitiesPage(),
|
||||
);
|
||||
},
|
||||
AlbumAdditionalSharedUserSelectionRoute.name: (routeData) {
|
||||
final args =
|
||||
routeData.argsAs<AlbumAdditionalSharedUserSelectionRouteArgs>();
|
||||
return AutoRoutePage<List<String>?>(
|
||||
routeData: routeData,
|
||||
child: AlbumAdditionalSharedUserSelectionPage(
|
||||
key: args.key,
|
||||
album: args.album,
|
||||
),
|
||||
);
|
||||
},
|
||||
AlbumAssetSelectionRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<AlbumAssetSelectionRouteArgs>();
|
||||
return AutoRoutePage<AssetSelectionPageResult?>(
|
||||
routeData: routeData,
|
||||
child: AlbumAssetSelectionPage(
|
||||
key: args.key,
|
||||
existingAssets: args.existingAssets,
|
||||
canDeselect: args.canDeselect,
|
||||
query: args.query,
|
||||
),
|
||||
);
|
||||
},
|
||||
AlbumOptionsRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<AlbumOptionsRouteArgs>();
|
||||
return AutoRoutePage<dynamic>(
|
||||
@@ -41,6 +64,16 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
),
|
||||
);
|
||||
},
|
||||
AlbumSharedUserSelectionRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<AlbumSharedUserSelectionRouteArgs>();
|
||||
return AutoRoutePage<List<String>>(
|
||||
routeData: routeData,
|
||||
child: AlbumSharedUserSelectionPage(
|
||||
key: args.key,
|
||||
assets: args.assets,
|
||||
),
|
||||
);
|
||||
},
|
||||
AlbumViewerRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<AlbumViewerRouteArgs>();
|
||||
return AutoRoutePage<dynamic>(
|
||||
@@ -97,18 +130,6 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
child: const ArchivePage(),
|
||||
);
|
||||
},
|
||||
AlbumAssetSelectionRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<AssetSelectionRouteArgs>();
|
||||
return AutoRoutePage<AssetSelectionPageResult?>(
|
||||
routeData: routeData,
|
||||
child: AlbumAssetSelectionPage(
|
||||
key: args.key,
|
||||
existingAssets: args.existingAssets,
|
||||
canDeselect: args.canDeselect,
|
||||
query: args.query,
|
||||
),
|
||||
);
|
||||
},
|
||||
BackupAlbumSelectionRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
@@ -170,12 +191,6 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
),
|
||||
);
|
||||
},
|
||||
PhotosRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
child: const PhotosPage(),
|
||||
);
|
||||
},
|
||||
LibraryRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
@@ -249,6 +264,12 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
),
|
||||
);
|
||||
},
|
||||
PhotosRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
child: const PhotosPage(),
|
||||
);
|
||||
},
|
||||
RecentlyAddedRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
@@ -272,26 +293,6 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
child: const SearchPage(),
|
||||
);
|
||||
},
|
||||
AlbumAdditionalSharedUserSelectionRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<SelectAdditionalUserForSharingRouteArgs>();
|
||||
return AutoRoutePage<List<String>?>(
|
||||
routeData: routeData,
|
||||
child: AlbumAdditionalSharedUserSelectionPage(
|
||||
key: args.key,
|
||||
album: args.album,
|
||||
),
|
||||
);
|
||||
},
|
||||
AlbumSharedUserSelectionRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<SelectUserForSharingRouteArgs>();
|
||||
return AutoRoutePage<List<String>>(
|
||||
routeData: routeData,
|
||||
child: AlbumSharedUserSelectionPage(
|
||||
key: args.key,
|
||||
assets: args.assets,
|
||||
),
|
||||
);
|
||||
},
|
||||
SettingsRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
@@ -351,21 +352,6 @@ abstract class _$AppRouter extends RootStackRouter {
|
||||
child: const TrashPage(),
|
||||
);
|
||||
},
|
||||
VideoViewerRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<VideoViewerRouteArgs>();
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
child: VideoViewerPage(
|
||||
key: args.key,
|
||||
asset: args.asset,
|
||||
isMotionVideo: args.isMotionVideo,
|
||||
placeholder: args.placeholder,
|
||||
showControls: args.showControls,
|
||||
hideControlsTimer: args.hideControlsTimer,
|
||||
showDownloadingIndicator: args.showDownloadingIndicator,
|
||||
),
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -383,6 +369,94 @@ class ActivitiesRoute extends PageRouteInfo<void> {
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumAdditionalSharedUserSelectionPage]
|
||||
class AlbumAdditionalSharedUserSelectionRoute
|
||||
extends PageRouteInfo<AlbumAdditionalSharedUserSelectionRouteArgs> {
|
||||
AlbumAdditionalSharedUserSelectionRoute({
|
||||
Key? key,
|
||||
required Album album,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AlbumAdditionalSharedUserSelectionRoute.name,
|
||||
args: AlbumAdditionalSharedUserSelectionRouteArgs(
|
||||
key: key,
|
||||
album: album,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AlbumAdditionalSharedUserSelectionRoute';
|
||||
|
||||
static const PageInfo<AlbumAdditionalSharedUserSelectionRouteArgs> page =
|
||||
PageInfo<AlbumAdditionalSharedUserSelectionRouteArgs>(name);
|
||||
}
|
||||
|
||||
class AlbumAdditionalSharedUserSelectionRouteArgs {
|
||||
const AlbumAdditionalSharedUserSelectionRouteArgs({
|
||||
this.key,
|
||||
required this.album,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Album album;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AlbumAdditionalSharedUserSelectionRouteArgs{key: $key, album: $album}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumAssetSelectionPage]
|
||||
class AlbumAssetSelectionRoute
|
||||
extends PageRouteInfo<AlbumAssetSelectionRouteArgs> {
|
||||
AlbumAssetSelectionRoute({
|
||||
Key? key,
|
||||
required Set<Asset> existingAssets,
|
||||
bool canDeselect = false,
|
||||
required QueryBuilder<Asset, Asset, QAfterSortBy>? query,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AlbumAssetSelectionRoute.name,
|
||||
args: AlbumAssetSelectionRouteArgs(
|
||||
key: key,
|
||||
existingAssets: existingAssets,
|
||||
canDeselect: canDeselect,
|
||||
query: query,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AlbumAssetSelectionRoute';
|
||||
|
||||
static const PageInfo<AlbumAssetSelectionRouteArgs> page =
|
||||
PageInfo<AlbumAssetSelectionRouteArgs>(name);
|
||||
}
|
||||
|
||||
class AlbumAssetSelectionRouteArgs {
|
||||
const AlbumAssetSelectionRouteArgs({
|
||||
this.key,
|
||||
required this.existingAssets,
|
||||
this.canDeselect = false,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Set<Asset> existingAssets;
|
||||
|
||||
final bool canDeselect;
|
||||
|
||||
final QueryBuilder<Asset, Asset, QAfterSortBy>? query;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AlbumAssetSelectionRouteArgs{key: $key, existingAssets: $existingAssets, canDeselect: $canDeselect, query: $query}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumOptionsPage]
|
||||
class AlbumOptionsRoute extends PageRouteInfo<AlbumOptionsRouteArgs> {
|
||||
@@ -459,6 +533,45 @@ class AlbumPreviewRouteArgs {
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumSharedUserSelectionPage]
|
||||
class AlbumSharedUserSelectionRoute
|
||||
extends PageRouteInfo<AlbumSharedUserSelectionRouteArgs> {
|
||||
AlbumSharedUserSelectionRoute({
|
||||
Key? key,
|
||||
required Set<Asset> assets,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AlbumSharedUserSelectionRoute.name,
|
||||
args: AlbumSharedUserSelectionRouteArgs(
|
||||
key: key,
|
||||
assets: assets,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AlbumSharedUserSelectionRoute';
|
||||
|
||||
static const PageInfo<AlbumSharedUserSelectionRouteArgs> page =
|
||||
PageInfo<AlbumSharedUserSelectionRouteArgs>(name);
|
||||
}
|
||||
|
||||
class AlbumSharedUserSelectionRouteArgs {
|
||||
const AlbumSharedUserSelectionRouteArgs({
|
||||
this.key,
|
||||
required this.assets,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Set<Asset> assets;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AlbumSharedUserSelectionRouteArgs{key: $key, assets: $assets}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumViewerPage]
|
||||
class AlbumViewerRoute extends PageRouteInfo<AlbumViewerRouteArgs> {
|
||||
@@ -619,54 +732,6 @@ class ArchiveRoute extends PageRouteInfo<void> {
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumAssetSelectionPage]
|
||||
class AlbumAssetSelectionRoute extends PageRouteInfo<AssetSelectionRouteArgs> {
|
||||
AlbumAssetSelectionRoute({
|
||||
Key? key,
|
||||
required Set<Asset> existingAssets,
|
||||
bool canDeselect = false,
|
||||
required QueryBuilder<Asset, Asset, QAfterSortBy>? query,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AlbumAssetSelectionRoute.name,
|
||||
args: AssetSelectionRouteArgs(
|
||||
key: key,
|
||||
existingAssets: existingAssets,
|
||||
canDeselect: canDeselect,
|
||||
query: query,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AlbumAssetSelectionRoute';
|
||||
|
||||
static const PageInfo<AssetSelectionRouteArgs> page =
|
||||
PageInfo<AssetSelectionRouteArgs>(name);
|
||||
}
|
||||
|
||||
class AssetSelectionRouteArgs {
|
||||
const AssetSelectionRouteArgs({
|
||||
this.key,
|
||||
required this.existingAssets,
|
||||
this.canDeselect = false,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Set<Asset> existingAssets;
|
||||
|
||||
final bool canDeselect;
|
||||
|
||||
final QueryBuilder<Asset, Asset, QAfterSortBy>? query;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AssetSelectionRouteArgs{key: $key, existingAssets: $existingAssets, canDeselect: $canDeselect, query: $query}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [BackupAlbumSelectionPage]
|
||||
class BackupAlbumSelectionRoute extends PageRouteInfo<void> {
|
||||
@@ -852,20 +917,6 @@ class GalleryViewerRouteArgs {
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [PhotosPage]
|
||||
class PhotosRoute extends PageRouteInfo<void> {
|
||||
const PhotosRoute({List<PageRouteInfo>? children})
|
||||
: super(
|
||||
PhotosRoute.name,
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'PhotosRoute';
|
||||
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [LibraryPage]
|
||||
class LibraryRoute extends PageRouteInfo<void> {
|
||||
@@ -1097,6 +1148,20 @@ class PersonResultRouteArgs {
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [PhotosPage]
|
||||
class PhotosRoute extends PageRouteInfo<void> {
|
||||
const PhotosRoute({List<PageRouteInfo>? children})
|
||||
: super(
|
||||
PhotosRoute.name,
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'PhotosRoute';
|
||||
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [RecentlyAddedPage]
|
||||
class RecentlyAddedRoute extends PageRouteInfo<void> {
|
||||
@@ -1163,84 +1228,6 @@ class SearchRoute extends PageRouteInfo<void> {
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumAdditionalSharedUserSelectionPage]
|
||||
class AlbumAdditionalSharedUserSelectionRoute
|
||||
extends PageRouteInfo<SelectAdditionalUserForSharingRouteArgs> {
|
||||
AlbumAdditionalSharedUserSelectionRoute({
|
||||
Key? key,
|
||||
required Album album,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AlbumAdditionalSharedUserSelectionRoute.name,
|
||||
args: SelectAdditionalUserForSharingRouteArgs(
|
||||
key: key,
|
||||
album: album,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AlbumAdditionalSharedUserSelectionRoute';
|
||||
|
||||
static const PageInfo<SelectAdditionalUserForSharingRouteArgs> page =
|
||||
PageInfo<SelectAdditionalUserForSharingRouteArgs>(name);
|
||||
}
|
||||
|
||||
class SelectAdditionalUserForSharingRouteArgs {
|
||||
const SelectAdditionalUserForSharingRouteArgs({
|
||||
this.key,
|
||||
required this.album,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Album album;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SelectAdditionalUserForSharingRouteArgs{key: $key, album: $album}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AlbumSharedUserSelectionPage]
|
||||
class AlbumSharedUserSelectionRoute
|
||||
extends PageRouteInfo<SelectUserForSharingRouteArgs> {
|
||||
AlbumSharedUserSelectionRoute({
|
||||
Key? key,
|
||||
required Set<Asset> assets,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AlbumSharedUserSelectionRoute.name,
|
||||
args: SelectUserForSharingRouteArgs(
|
||||
key: key,
|
||||
assets: assets,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AlbumSharedUserSelectionRoute';
|
||||
|
||||
static const PageInfo<SelectUserForSharingRouteArgs> page =
|
||||
PageInfo<SelectUserForSharingRouteArgs>(name);
|
||||
}
|
||||
|
||||
class SelectUserForSharingRouteArgs {
|
||||
const SelectUserForSharingRouteArgs({
|
||||
this.key,
|
||||
required this.assets,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Set<Asset> assets;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SelectUserForSharingRouteArgs{key: $key, assets: $assets}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [SettingsPage]
|
||||
class SettingsRoute extends PageRouteInfo<void> {
|
||||
@@ -1410,66 +1397,3 @@ class TrashRoute extends PageRouteInfo<void> {
|
||||
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [VideoViewerPage]
|
||||
class VideoViewerRoute extends PageRouteInfo<VideoViewerRouteArgs> {
|
||||
VideoViewerRoute({
|
||||
Key? key,
|
||||
required Asset asset,
|
||||
bool isMotionVideo = false,
|
||||
Widget? placeholder,
|
||||
bool showControls = true,
|
||||
Duration hideControlsTimer = const Duration(seconds: 5),
|
||||
bool showDownloadingIndicator = true,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
VideoViewerRoute.name,
|
||||
args: VideoViewerRouteArgs(
|
||||
key: key,
|
||||
asset: asset,
|
||||
isMotionVideo: isMotionVideo,
|
||||
placeholder: placeholder,
|
||||
showControls: showControls,
|
||||
hideControlsTimer: hideControlsTimer,
|
||||
showDownloadingIndicator: showDownloadingIndicator,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'VideoViewerRoute';
|
||||
|
||||
static const PageInfo<VideoViewerRouteArgs> page =
|
||||
PageInfo<VideoViewerRouteArgs>(name);
|
||||
}
|
||||
|
||||
class VideoViewerRouteArgs {
|
||||
const VideoViewerRouteArgs({
|
||||
this.key,
|
||||
required this.asset,
|
||||
this.isMotionVideo = false,
|
||||
this.placeholder,
|
||||
this.showControls = true,
|
||||
this.hideControlsTimer = const Duration(seconds: 5),
|
||||
this.showDownloadingIndicator = true,
|
||||
});
|
||||
|
||||
final Key? key;
|
||||
|
||||
final Asset asset;
|
||||
|
||||
final bool isMotionVideo;
|
||||
|
||||
final Widget? placeholder;
|
||||
|
||||
final bool showControls;
|
||||
|
||||
final Duration hideControlsTimer;
|
||||
|
||||
final bool showDownloadingIndicator;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VideoViewerRouteArgs{key: $key, asset: $asset, isMotionVideo: $isMotionVideo, placeholder: $placeholder, showControls: $showControls, hideControlsTimer: $hideControlsTimer, showDownloadingIndicator: $showDownloadingIndicator}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ enum AppSettingsEnum<T> {
|
||||
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),
|
||||
logLevel<int>(StoreKey.logLevel, null, 5), // Level.INFO = 5
|
||||
preferRemoteImage<bool>(StoreKey.preferRemoteImage, null, false),
|
||||
loopVideo<bool>(StoreKey.loopVideo, "loopVideo", true),
|
||||
mapThemeMode<int>(StoreKey.mapThemeMode, null, 0),
|
||||
mapShowFavoriteOnly<bool>(StoreKey.mapShowFavoriteOnly, null, false),
|
||||
mapIncludeArchived<bool>(StoreKey.mapIncludeArchived, null, false),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:background_downloader/background_downloader.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -21,7 +21,6 @@ import 'package:openapi/api.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:cancellation_token_http/http.dart' as http;
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
final backupServiceProvider = Provider(
|
||||
(ref) => BackupService(
|
||||
@@ -33,6 +32,7 @@ final backupServiceProvider = Provider(
|
||||
|
||||
class BackupService {
|
||||
final httpClient = http.Client();
|
||||
final _fileDownloader = FileDownloader();
|
||||
final ApiService _apiService;
|
||||
final Isar _db;
|
||||
final Logger _log = Logger("BackupService");
|
||||
@@ -242,121 +242,127 @@ class BackupService {
|
||||
)
|
||||
: assetList.toList();
|
||||
|
||||
final tasks = <UploadTask>[];
|
||||
for (var entity in assetsToUpload) {
|
||||
File? file;
|
||||
File? livePhotoFile;
|
||||
final isAvailableLocally =
|
||||
await entity.isLocallyAvailable(isOrigin: true);
|
||||
|
||||
try {
|
||||
final isAvailableLocally =
|
||||
await entity.isLocallyAvailable(isOrigin: true);
|
||||
|
||||
// Handle getting files from iCloud
|
||||
if (!isAvailableLocally && Platform.isIOS) {
|
||||
// Skip iCloud assets if the user has disabled this feature
|
||||
if (isIgnoreIcloudAssets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
setCurrentUploadAssetCb(
|
||||
CurrentUploadAsset(
|
||||
id: entity.id,
|
||||
fileCreatedAt: entity.createDateTime.year == 1970
|
||||
? entity.modifiedDateTime
|
||||
: entity.createDateTime,
|
||||
fileName: await entity.titleAsync,
|
||||
fileType: _getAssetType(entity.type),
|
||||
iCloudAsset: true,
|
||||
),
|
||||
);
|
||||
|
||||
file = await entity.loadFile(progressHandler: pmProgressHandler);
|
||||
livePhotoFile = await entity.loadFile(
|
||||
withSubtype: true,
|
||||
progressHandler: pmProgressHandler,
|
||||
);
|
||||
} else {
|
||||
if (entity.type == AssetType.video) {
|
||||
file = await entity.originFile;
|
||||
} else {
|
||||
file = await entity.originFile.timeout(const Duration(seconds: 5));
|
||||
if (entity.isLivePhoto) {
|
||||
livePhotoFile = await entity.originFileWithSubtype
|
||||
.timeout(const Duration(seconds: 5));
|
||||
}
|
||||
}
|
||||
// Handle getting files from iCloud
|
||||
if (!isAvailableLocally && Platform.isIOS) {
|
||||
// Skip iCloud assets if the user has disabled this feature
|
||||
if (isIgnoreIcloudAssets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
String originalFileName = await entity.titleAsync;
|
||||
var fileStream = file.openRead();
|
||||
var assetRawUploadData = http.MultipartFile(
|
||||
"assetData",
|
||||
fileStream,
|
||||
file.lengthSync(),
|
||||
filename: originalFileName,
|
||||
);
|
||||
setCurrentUploadAssetCb(
|
||||
CurrentUploadAsset(
|
||||
id: entity.id,
|
||||
fileCreatedAt: entity.createDateTime.year == 1970
|
||||
? entity.modifiedDateTime
|
||||
: entity.createDateTime,
|
||||
fileName: await entity.titleAsync,
|
||||
fileType: _getAssetType(entity.type),
|
||||
iCloudAsset: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
var req = MultipartRequest(
|
||||
'POST',
|
||||
Uri.parse('$savedEndpoint/asset/upload'),
|
||||
onProgress: ((bytes, totalBytes) =>
|
||||
uploadProgressCb(bytes, totalBytes)),
|
||||
);
|
||||
req.headers["x-immich-user-token"] = Store.get(StoreKey.accessToken);
|
||||
req.headers["Transfer-Encoding"] = "chunked";
|
||||
final files = [];
|
||||
// TODO: This is silly to have to load the file just to access the path
|
||||
// But there doesn't seem to be any other way to do it
|
||||
final fileName = (await entity.originFile)?.path;
|
||||
files.add(fileName);
|
||||
|
||||
req.fields['deviceAssetId'] = entity.id;
|
||||
req.fields['deviceId'] = deviceId;
|
||||
req.fields['fileCreatedAt'] =
|
||||
entity.createDateTime.toUtc().toIso8601String();
|
||||
req.fields['fileModifiedAt'] =
|
||||
entity.modifiedDateTime.toUtc().toIso8601String();
|
||||
req.fields['isFavorite'] = entity.isFavorite.toString();
|
||||
req.fields['duration'] = entity.videoDuration.toString();
|
||||
if (entity.isLivePhoto) {
|
||||
final livePhotoFileName = (await entity.originFileWithSubtype)?.path;
|
||||
if (livePhotoFileName != null) {
|
||||
files.add(livePhotoFileName);
|
||||
}
|
||||
}
|
||||
|
||||
req.files.add(assetRawUploadData);
|
||||
final url = '$savedEndpoint/asset/upload';
|
||||
final headers = {
|
||||
'x-immich-user-token': Store.get(StoreKey.accessToken),
|
||||
'Transfer-Encoding': 'chunked',
|
||||
};
|
||||
|
||||
var fileSize = file.lengthSync();
|
||||
final fields = {
|
||||
'deviceAssetId': entity.id,
|
||||
'deviceId': deviceId,
|
||||
'fileCreatedAt': entity.createDateTime.toUtc().toIso8601String(),
|
||||
'fileModifiedAt': entity.modifiedDateTime.toUtc().toIso8601String(),
|
||||
'isFavorite': entity.isFavorite.toString(),
|
||||
'duration': entity.videoDuration.toString(),
|
||||
};
|
||||
|
||||
if (entity.isLivePhoto) {
|
||||
if (livePhotoFile != null) {
|
||||
final livePhotoTitle = p.setExtension(
|
||||
originalFileName,
|
||||
p.extension(livePhotoFile.path),
|
||||
);
|
||||
final fileStream = livePhotoFile.openRead();
|
||||
final livePhotoRawUploadData = http.MultipartFile(
|
||||
"livePhotoData",
|
||||
fileStream,
|
||||
livePhotoFile.lengthSync(),
|
||||
filename: livePhotoTitle,
|
||||
);
|
||||
req.files.add(livePhotoRawUploadData);
|
||||
fileSize += livePhotoFile.lengthSync();
|
||||
} else {
|
||||
_log.warning(
|
||||
"Failed to obtain motion part of the livePhoto - $originalFileName",
|
||||
);
|
||||
}
|
||||
}
|
||||
for (final file in files) {
|
||||
final split = file.split('/');
|
||||
final name = split.last;
|
||||
final directory = split.take(split.length - 1).join('/');
|
||||
|
||||
setCurrentUploadAssetCb(
|
||||
CurrentUploadAsset(
|
||||
id: entity.id,
|
||||
fileCreatedAt: entity.createDateTime.year == 1970
|
||||
? entity.modifiedDateTime
|
||||
: entity.createDateTime,
|
||||
fileName: originalFileName,
|
||||
fileType: _getAssetType(entity.type),
|
||||
fileSize: fileSize,
|
||||
iCloudAsset: false,
|
||||
),
|
||||
);
|
||||
final task = UploadTask(
|
||||
url: url,
|
||||
group: 'backup',
|
||||
fileField: 'assetData',
|
||||
taskId: entity.id,
|
||||
fields: fields,
|
||||
headers: headers,
|
||||
updates: Updates.statusAndProgress,
|
||||
retries: 0,
|
||||
httpRequestMethod: 'POST',
|
||||
displayName: 'Immich',
|
||||
filename: name,
|
||||
directory: directory,
|
||||
baseDirectory: BaseDirectory.root,
|
||||
);
|
||||
tasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
var response =
|
||||
await httpClient.send(req, cancellationToken: cancelToken);
|
||||
final permission = await _fileDownloader.permissions
|
||||
.status(PermissionType.androidSharedStorage);
|
||||
print('has permission $permission');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
if (tasks.length == 1) {
|
||||
final result = await _fileDownloader.upload(
|
||||
tasks.first,
|
||||
onProgress: (percent) => print('${percent * 100} done'),
|
||||
onStatus: (status) => print('status $status'),
|
||||
onElapsedTime: (t) => print('time is $t'),
|
||||
elapsedTimeInterval: const Duration(seconds: 1),
|
||||
);
|
||||
|
||||
print('$result is done with ${result.status}');
|
||||
print('result ${result.responseBody}');
|
||||
print('result ${result.responseHeaders}');
|
||||
} else {
|
||||
final result = await _fileDownloader.uploadBatch(
|
||||
tasks,
|
||||
batchProgressCallback: (succeeded, failed) =>
|
||||
print('$succeeded succeeded, $failed failed'),
|
||||
taskStatusCallback: (status) => print('status $status'),
|
||||
taskProgressCallback: (update) => print('update $update'),
|
||||
onElapsedTime: (t) => print('time is $t'),
|
||||
elapsedTimeInterval: const Duration(seconds: 1),
|
||||
);
|
||||
|
||||
print(
|
||||
'$result is done with ${result.succeeded.length} succeeded and ${result.failed.length} failed',
|
||||
);
|
||||
|
||||
for (final task in result.succeeded) {
|
||||
final r = result.results[task];
|
||||
print('successful task $task with result $r');
|
||||
}
|
||||
|
||||
for (final task in result.failed) {
|
||||
final r = result.results[task];
|
||||
print('failed task $task with result $r');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (result.status == 200) {
|
||||
// asset is a duplicate (already exists on the server)
|
||||
duplicatedAssetIds.add(entity.id);
|
||||
uploadSuccessCb(entity.id, deviceId, true);
|
||||
@@ -409,6 +415,7 @@ class BackupService {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (duplicatedAssetIds.isNotEmpty) {
|
||||
await _saveDuplicatedAssetIds(duplicatedAssetIds);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ ChewieController useChewieController({
|
||||
bool allowFullScreen = false,
|
||||
bool allowedScreenSleep = false,
|
||||
bool showControls = true,
|
||||
bool loopVideo = false,
|
||||
Widget? customControls,
|
||||
Widget? placeholder,
|
||||
Duration hideControlsTimer = const Duration(seconds: 1),
|
||||
@@ -36,6 +37,7 @@ ChewieController useChewieController({
|
||||
hideControlsTimer: hideControlsTimer,
|
||||
showControlsOnInitialize: showControlsOnInitialize,
|
||||
showControls: showControls,
|
||||
loopVideo: loopVideo,
|
||||
allowedScreenSleep: allowedScreenSleep,
|
||||
onPlaying: onPlaying,
|
||||
onPaused: onPaused,
|
||||
@@ -53,6 +55,7 @@ class _ChewieControllerHook extends Hook<ChewieController> {
|
||||
final bool allowFullScreen;
|
||||
final bool allowedScreenSleep;
|
||||
final bool showControls;
|
||||
final bool loopVideo;
|
||||
final Widget? customControls;
|
||||
final Widget? placeholder;
|
||||
final Duration hideControlsTimer;
|
||||
@@ -71,6 +74,7 @@ class _ChewieControllerHook extends Hook<ChewieController> {
|
||||
this.allowFullScreen = false,
|
||||
this.allowedScreenSleep = false,
|
||||
this.showControls = true,
|
||||
this.loopVideo = false,
|
||||
this.customControls,
|
||||
this.placeholder,
|
||||
this.hideControlsTimer = const Duration(seconds: 3),
|
||||
@@ -94,6 +98,7 @@ class _ChewieControllerHookState
|
||||
allowFullScreen: hook.allowFullScreen,
|
||||
allowedScreenSleep: hook.allowedScreenSleep,
|
||||
showControls: hook.showControls,
|
||||
looping: hook.loopVideo,
|
||||
customControls: hook.customControls,
|
||||
placeholder: hook.placeholder,
|
||||
hideControlsTimer: hook.hideControlsTimer,
|
||||
|
||||
@@ -121,12 +121,12 @@ final ThemeData immichLightTheme = ThemeData(
|
||||
),
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
indicatorColor: Colors.indigo.withOpacity(0.15),
|
||||
iconTheme: MaterialStatePropertyAll(
|
||||
iconTheme: WidgetStatePropertyAll(
|
||||
IconThemeData(color: Colors.grey[700]),
|
||||
),
|
||||
backgroundColor: immichBackgroundColor,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
labelTextStyle: MaterialStatePropertyAll(
|
||||
labelTextStyle: WidgetStatePropertyAll(
|
||||
TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -249,12 +249,12 @@ final ThemeData immichDarkTheme = ThemeData(
|
||||
),
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
indicatorColor: immichDarkThemePrimaryColor.withOpacity(0.4),
|
||||
iconTheme: MaterialStatePropertyAll(
|
||||
iconTheme: WidgetStatePropertyAll(
|
||||
IconThemeData(color: Colors.grey[500]),
|
||||
),
|
||||
backgroundColor: Colors.grey[900],
|
||||
surfaceTintColor: Colors.transparent,
|
||||
labelTextStyle: MaterialStatePropertyAll(
|
||||
labelTextStyle: WidgetStatePropertyAll(
|
||||
TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
||||
@@ -275,7 +275,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
);
|
||||
} else {
|
||||
return IconButton(
|
||||
onPressed: () async => await context.popRoute(),
|
||||
onPressed: () async => await context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
splashRadius: 25,
|
||||
);
|
||||
|
||||
@@ -110,7 +110,7 @@ class BottomGalleryBar extends ConsumerWidget {
|
||||
if (isDeleted && isParent) {
|
||||
if (totalAssets == 1) {
|
||||
// Handle only one asset
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
} else {
|
||||
// Go to next page otherwise
|
||||
controller.nextPage(
|
||||
@@ -181,7 +181,7 @@ class BottomGalleryBar extends ConsumerWidget {
|
||||
stackElements.elementAt(stackIndex),
|
||||
);
|
||||
ctx.pop();
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
},
|
||||
title: const Text(
|
||||
"viewer_stack_use_as_main_asset",
|
||||
@@ -208,7 +208,7 @@ class BottomGalleryBar extends ConsumerWidget {
|
||||
childrenToRemove: [asset],
|
||||
);
|
||||
ctx.pop();
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
} else {
|
||||
await ref.read(assetStackServiceProvider).updateStack(
|
||||
asset,
|
||||
@@ -236,7 +236,7 @@ class BottomGalleryBar extends ConsumerWidget {
|
||||
childrenToRemove: stack,
|
||||
);
|
||||
ctx.pop();
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
},
|
||||
title: const Text(
|
||||
"viewer_unstack",
|
||||
@@ -267,7 +267,7 @@ class BottomGalleryBar extends ConsumerWidget {
|
||||
handleArchive() {
|
||||
ref.read(assetProvider.notifier).toggleArchive([asset]);
|
||||
if (isParent) {
|
||||
context.popRoute();
|
||||
context.maybePop();
|
||||
return;
|
||||
}
|
||||
removeAssetFromStack();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user