mirror of
https://github.com/immich-app/immich.git
synced 2026-05-22 07:32:32 -04:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15d1186949 | |||
| 8a95ff03d2 | |||
| 7b9dab872b | |||
| 6413495fb8 | |||
| b414b3d32b | |||
| 20da7c4267 | |||
| 92b6778d2d | |||
| 5a61e589e8 | |||
| 85192bb110 | |||
| c7ae97fa2b | |||
| 8d02f3625d | |||
| a5a7380a26 | |||
| d9ce3d2046 | |||
| 815ff677fc | |||
| 915d865ce2 | |||
| c28e5f90b6 | |||
| 4383473ed6 | |||
| 77701dd5a3 |
@@ -91,7 +91,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -159,14 +159,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Comment APK download link on PR
|
- name: Comment APK download link on PR
|
||||||
if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork }}
|
if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork }}
|
||||||
uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3.11.0
|
uses: immich-app/devtools/actions/sticky-comment@0135acd12ad9f3369b94a2aa3c0ae8c835a4e926 # sticky-comment-action-v1.0.0
|
||||||
env:
|
env:
|
||||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
APK_URL: ${{ steps.upload-apk.outputs.artifact-url }}
|
APK_URL: ${{ steps.upload-apk.outputs.artifact-url }}
|
||||||
with:
|
with:
|
||||||
github-token: ${{ steps.token.outputs.token }}
|
id: mobile-android-apk
|
||||||
message-id: 'mobile-android-apk'
|
token: ${{ steps.token.outputs.token }}
|
||||||
message: |
|
body: |
|
||||||
📱 **Android release APK (universal)** — `${{ env.HEAD_SHA }}`
|
📱 **Android release APK (universal)** — `${{ env.HEAD_SHA }}`
|
||||||
|
|
||||||
Download: ${{ env.APK_URL }}
|
Download: ${{ env.APK_URL }}
|
||||||
@@ -216,7 +216,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ jobs:
|
|||||||
run: mise //mobile:codegen:pigeon
|
run: mise //mobile:codegen:pigeon
|
||||||
|
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
|
uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1.307.0
|
||||||
with:
|
with:
|
||||||
ruby-version: '3.3'
|
ruby-version: '3.3'
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
@@ -288,7 +288,6 @@ jobs:
|
|||||||
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
||||||
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
||||||
ENVIRONMENT: ${{ inputs.environment || 'development' }}
|
ENVIRONMENT: ${{ inputs.environment || 'development' }}
|
||||||
BUNDLE_ID_SUFFIX: ${{ inputs.environment == 'production' && '' || 'development' }}
|
|
||||||
GITHUB_REF: ${{ github.ref }}
|
GITHUB_REF: ${{ github.ref }}
|
||||||
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
|
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
|
||||||
FASTLANE_XCODEBUILD_SETTINGS_RETRIES: 6
|
FASTLANE_XCODEBUILD_SETTINGS_RETRIES: 6
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Check for breaking API changes
|
- name: Check for breaking API changes
|
||||||
uses: oasdiff/oasdiff-action/breaking@26ccb332c67a45ca649de9faf60552ef1b8260d9 # v0.0.46
|
uses: oasdiff/oasdiff-action/breaking@6147a58e5d1249a12f42fc864ab791d571a30015 # v0.0.47
|
||||||
with:
|
with:
|
||||||
base: https://raw.githubusercontent.com/${{ github.repository }}/main/open-api/immich-openapi-specs.json
|
base: https://raw.githubusercontent.com/${{ github.repository }}/main/open-api/immich-openapi-specs.json
|
||||||
revision: open-api/immich-openapi-specs.json
|
revision: open-api/immich-openapi-specs.json
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -83,6 +83,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
||||||
with:
|
with:
|
||||||
category: '/language:${{matrix.language}}'
|
category: '/language:${{matrix.language}}'
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -213,12 +213,11 @@ jobs:
|
|||||||
run: 'mise run //deployment:tf apply'
|
run: 'mise run //deployment:tf apply'
|
||||||
|
|
||||||
- name: Comment
|
- name: Comment
|
||||||
uses: actions-cool/maintain-one-comment@909842216bc8e8658364c572ec52100f4c2cc50a # v3.3.0
|
uses: immich-app/devtools/actions/sticky-comment@0135acd12ad9f3369b94a2aa3c0ae8c835a4e926 # sticky-comment-action-v1.0.0
|
||||||
if: ${{ steps.parameters.outputs.event == 'pr' }}
|
if: ${{ steps.parameters.outputs.event == 'pr' }}
|
||||||
with:
|
with:
|
||||||
|
id: docs-pr-url
|
||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }}
|
number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }}
|
||||||
body: |
|
body: |
|
||||||
📖 Documentation deployed to [${{ steps.docs-output.outputs.subdomain }}](https://${{ steps.docs-output.outputs.subdomain }})
|
📖 Documentation deployed to [${{ steps.docs-output.outputs.subdomain }}](https://${{ steps.docs-output.outputs.subdomain }})
|
||||||
emojis: 'rocket'
|
|
||||||
body-include: '<!-- Docs PR URL -->'
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -44,9 +44,8 @@ jobs:
|
|||||||
run: 'mise run //deployment:tf destroy -- -refresh=false'
|
run: 'mise run //deployment:tf destroy -- -refresh=false'
|
||||||
|
|
||||||
- name: Comment
|
- name: Comment
|
||||||
uses: actions-cool/maintain-one-comment@909842216bc8e8658364c572ec52100f4c2cc50a # v3.3.0
|
uses: immich-app/devtools/actions/sticky-comment@0135acd12ad9f3369b94a2aa3c0ae8c835a4e926 # sticky-comment-action-v1.0.0
|
||||||
with:
|
with:
|
||||||
|
id: docs-pr-url
|
||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
number: ${{ github.event.number }}
|
|
||||||
delete: true
|
delete: true
|
||||||
body-include: '<!-- Docs PR URL -->'
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate_token
|
id: generate_token
|
||||||
if: ${{ inputs.skip != true }}
|
if: ${{ inputs.skip != true }}
|
||||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
|
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
|
||||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ jobs:
|
|||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
security-events: write
|
security-events: write
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
ref: main
|
ref: main
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
|
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
|
||||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ jobs:
|
|||||||
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
|
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
|
||||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||||
|
|
||||||
- uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3.11.0
|
- uses: immich-app/devtools/actions/sticky-comment@0135acd12ad9f3369b94a2aa3c0ae8c835a4e926 # sticky-comment-action-v1.0.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{ steps.token.outputs.token }}
|
id: preview-status
|
||||||
message-id: 'preview-status'
|
token: ${{ steps.token.outputs.token }}
|
||||||
message: 'Deploying preview environment to https://pr-${{ github.event.pull_request.number }}.preview.internal.immich.build/'
|
body: 'Deploying preview environment to https://pr-${{ github.event.pull_request.number }}.preview.internal.immich.build/'
|
||||||
|
|
||||||
remove-label:
|
remove-label:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -48,16 +48,16 @@ jobs:
|
|||||||
name: 'preview'
|
name: 'preview'
|
||||||
})
|
})
|
||||||
|
|
||||||
- uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3.11.0
|
- uses: immich-app/devtools/actions/sticky-comment@0135acd12ad9f3369b94a2aa3c0ae8c835a4e926 # sticky-comment-action-v1.0.0
|
||||||
if: ${{ github.event.pull_request.head.repo.fork }}
|
if: ${{ github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
github-token: ${{ steps.token.outputs.token }}
|
id: preview-status
|
||||||
message-id: 'preview-status'
|
token: ${{ steps.token.outputs.token }}
|
||||||
message: 'PRs from forks cannot have preview environments.'
|
body: 'PRs from forks cannot have preview environments.'
|
||||||
|
|
||||||
- uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3.11.0
|
- uses: immich-app/devtools/actions/sticky-comment@0135acd12ad9f3369b94a2aa3c0ae8c835a4e926 # sticky-comment-action-v1.0.0
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
github-token: ${{ steps.token.outputs.token }}
|
id: preview-status
|
||||||
message-id: 'preview-status'
|
token: ${{ steps.token.outputs.token }}
|
||||||
message: 'Preview environment has been removed.'
|
body: 'Preview environment has been removed.'
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
+20
-13
@@ -30,25 +30,32 @@ jobs:
|
|||||||
filters: |
|
filters: |
|
||||||
i18n:
|
i18n:
|
||||||
- 'i18n/**'
|
- 'i18n/**'
|
||||||
|
- 'mise.toml'
|
||||||
web:
|
web:
|
||||||
- 'web/**'
|
- 'web/**'
|
||||||
- 'i18n/**'
|
- 'i18n/**'
|
||||||
- 'packages/sdk/**'
|
- 'packages/sdk/**'
|
||||||
- 'pnpm-lock.yaml'
|
- 'pnpm-lock.yaml'
|
||||||
|
- 'mise.toml'
|
||||||
server:
|
server:
|
||||||
- 'server/**'
|
- 'server/**'
|
||||||
- 'pnpm-lock.yaml'
|
- 'pnpm-lock.yaml'
|
||||||
|
- 'mise.toml'
|
||||||
cli:
|
cli:
|
||||||
- 'packages/cli/**'
|
- 'packages/cli/**'
|
||||||
- 'packages/sdk/**'
|
- 'packages/sdk/**'
|
||||||
- 'pnpm-lock.yaml'
|
- 'pnpm-lock.yaml'
|
||||||
|
- 'mise.toml'
|
||||||
e2e:
|
e2e:
|
||||||
- 'e2e/**'
|
- 'e2e/**'
|
||||||
- 'pnpm-lock.yaml'
|
- 'pnpm-lock.yaml'
|
||||||
|
- 'mise.toml'
|
||||||
mobile:
|
mobile:
|
||||||
- 'mobile/**'
|
- 'mobile/**'
|
||||||
|
- 'mise.toml'
|
||||||
machine-learning:
|
machine-learning:
|
||||||
- 'machine-learning/**'
|
- 'machine-learning/**'
|
||||||
|
- 'mise.toml'
|
||||||
.github:
|
.github:
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
force-filters: |
|
force-filters: |
|
||||||
@@ -76,7 +83,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -107,7 +114,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -138,7 +145,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -182,7 +189,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -220,7 +227,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -248,7 +255,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -298,7 +305,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -331,7 +338,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -550,7 +557,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -587,7 +594,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -618,7 +625,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -669,7 +676,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
@@ -727,7 +734,7 @@ jobs:
|
|||||||
token: ${{ steps.token.outputs.token }}
|
token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Mise
|
- name: Setup Mise
|
||||||
uses: immich-app/devtools/actions/use-mise@cf6e190bacde3d7bda59372a786b36ac7d01536a # use-mise-action-v2.0.1
|
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ steps.token.outputs.token }}
|
github_token: ${{ steps.token.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html
|
||||||
|
|
||||||
|
[[tools.opentofu]]
|
||||||
|
version = "1.11.6"
|
||||||
|
backend = "aqua:opentofu/opentofu"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:d4f2ab15776925864b049bb329d69682851de6f5204f256e9fa86d07a0308850"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:d4f2ab15776925864b049bb329d69682851de6f5204f256e9fa86d07a0308850"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:02800fafa2753a9f50c38483e2fdf5bc353fd62895eb9e25eec9a5145df3a69e"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:02800fafa2753a9f50c38483e2fdf5bc353fd62895eb9e25eec9a5145df3a69e"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:62d7fa8539e13b444827aa0a3b90c5972da5c47e8f8882d9dcf2e430e78840c1"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_darwin_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:1408cdef1c380f914565e6b4bb70794c6b163f195fcb233357f3d6c5745906b6"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_darwin_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:27323f70c875b8251bfd7e61a4cffc3ebff4e56ed1e611b955016f0c7077367e"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_windows_amd64.tar.gz"
|
||||||
|
|
||||||
|
[[tools.terragrunt]]
|
||||||
|
version = "1.0.3"
|
||||||
|
backend = "aqua:gruntwork-io/terragrunt"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:e5b60ab05b5214db694e6bc215d8124fb626e277cdb56b86f6147ae110d510fe"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:e5b60ab05b5214db694e6bc215d8124fb626e277cdb56b86f6147ae110d510fe"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:6d48049baf82e0bf9c804368dc85cbfeadc10955e33777e9e8de3e020b94b073"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:6d48049baf82e0bf9c804368dc85cbfeadc10955e33777e9e8de3e020b94b073"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:aacb5be2ca5475300cbce246dfbd8a45eb47510fbaa70fab8561c49ef5db03aa"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_darwin_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:3133c2251e191aede8e3dd2a5b3aee2e91c5f08f88f117aee40eed9a24c8ef6b"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_darwin_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:183b2745b4e04980a6bfa4450ff81956a12596ca22d70f7aaa793980f5b036db"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_windows_amd64.exe.tar.gz"
|
||||||
@@ -10,7 +10,6 @@ const config = {
|
|||||||
url: 'https://docs.immich.app',
|
url: 'https://docs.immich.app',
|
||||||
baseUrl: '/',
|
baseUrl: '/',
|
||||||
onBrokenLinks: 'throw',
|
onBrokenLinks: 'throw',
|
||||||
onBrokenMarkdownLinks: 'warn',
|
|
||||||
favicon: 'img/favicon.png',
|
favicon: 'img/favicon.png',
|
||||||
|
|
||||||
// GitHub pages deployment config.
|
// GitHub pages deployment config.
|
||||||
@@ -29,6 +28,9 @@ const config = {
|
|||||||
// Mermaid diagrams
|
// Mermaid diagrams
|
||||||
markdown: {
|
markdown: {
|
||||||
mermaid: true,
|
mermaid: true,
|
||||||
|
hooks: {
|
||||||
|
onBrokenMarkdownLinks: 'warn',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
themes: ['@docusaurus/theme-mermaid'],
|
themes: ['@docusaurus/theme-mermaid'],
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html
|
||||||
|
|
||||||
|
[[tools.wrangler]]
|
||||||
|
version = "4.66.0"
|
||||||
|
backend = "npm:wrangler"
|
||||||
+1
-1
@@ -28,4 +28,4 @@ run = "prettier --write ."
|
|||||||
run = "wrangler pages deploy build --project-name=${PROJECT_NAME} --branch=${BRANCH_NAME}"
|
run = "wrangler pages deploy build --project-name=${PROJECT_NAME} --branch=${BRANCH_NAME}"
|
||||||
|
|
||||||
[tools]
|
[tools]
|
||||||
wrangler = "4.66.0"
|
wrangler = "4.91.0"
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@
|
|||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@socket.io/component-emitter": "^3.1.2",
|
"@socket.io/component-emitter": "^3.1.2",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^24.12.2",
|
"@types/node": "^24.12.4",
|
||||||
"@types/pg": "^8.15.1",
|
"@types/pg": "^8.15.1",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
"@types/supertest": "^7.0.0",
|
"@types/supertest": "^7.0.0",
|
||||||
|
|||||||
@@ -399,6 +399,10 @@
|
|||||||
"transcoding_preferred_hardware_device_description": "Applies only to VAAPI and QSV. Sets the dri node used for hardware transcoding.",
|
"transcoding_preferred_hardware_device_description": "Applies only to VAAPI and QSV. Sets the dri node used for hardware transcoding.",
|
||||||
"transcoding_preset_preset": "Preset (-preset)",
|
"transcoding_preset_preset": "Preset (-preset)",
|
||||||
"transcoding_preset_preset_description": "Compression speed. Slower presets produce smaller files, and increase quality when targeting a certain bitrate. VP9 ignores speeds above 'faster'.",
|
"transcoding_preset_preset_description": "Compression speed. Slower presets produce smaller files, and increase quality when targeting a certain bitrate. VP9 ignores speeds above 'faster'.",
|
||||||
|
"transcoding_realtime": "Real-time Transcoding [EXPERIMENTAL]",
|
||||||
|
"transcoding_realtime_description": "Allows transcoding to be performed in real-time as the video is being streamed. Enables quality switching, but may cause higher playback latency and stuttering depending on server capabilities.",
|
||||||
|
"transcoding_realtime_enabled": "Enable real-time transcoding",
|
||||||
|
"transcoding_realtime_enabled_description": "If disabled, the server will refuse to start new real-time transcoding sessions.",
|
||||||
"transcoding_reference_frames": "Reference frames",
|
"transcoding_reference_frames": "Reference frames",
|
||||||
"transcoding_reference_frames_description": "The number of frames to reference when compressing a given frame. Higher values improve compression efficiency, but slow down encoding. 0 sets this value automatically.",
|
"transcoding_reference_frames_description": "The number of frames to reference when compressing a given frame. Higher values improve compression efficiency, but slow down encoding. 0 sets this value automatically.",
|
||||||
"transcoding_required_description": "Only videos not in an accepted format",
|
"transcoding_required_description": "Only videos not in an accepted format",
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html
|
||||||
|
|
||||||
|
[[tools.python]]
|
||||||
|
version = "3.11.15"
|
||||||
|
backend = "core:python"
|
||||||
|
|
||||||
|
[tools.python."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:243f794278eff6adba96ed3677ec6877175df84c25f140e17f09f9be82d0f12a"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[tools.python."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:52b4c52094ff8b383a45c694acf4c5c0e883152be6d5229a35a8186ce907c6eb"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-aarch64-unknown-linux-musl-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[tools.python."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:171dffd8c0f66e8a0725364a7428015b22fc18dd298b24f541392e17dd0e561f"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[tools.python."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:2ac90fef8917ebd14826a6d667593a06cf0ae5f745ba9b1147dc086dd35f5284"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-x86_64-unknown-linux-musl-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[tools.python."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:fdfc363b538662eb7441a14e06f72c4a992c56af7f401f5730ea5081f8f8ad6e"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-aarch64-apple-darwin-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[tools.python."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:5f1eb247cbca2c0ad5ccbf6d299a4f54b31b5c63b492d74c3531dc4344a42f88"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-x86_64-apple-darwin-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[tools.python."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:756d7f148498b8822f6aedf44a020613576f09983161f346ad36dcef6238cdc3"
|
||||||
|
url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260510/cpython-3.11.15+20260510-x86_64-pc-windows-msvc-install_only_stripped.tar.gz"
|
||||||
|
provenance = "github-attestations"
|
||||||
|
|
||||||
|
[[tools.uv]]
|
||||||
|
version = "0.8.15"
|
||||||
|
backend = "aqua:astral-sh/uv"
|
||||||
|
|
||||||
|
[tools.uv."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:23ea21a05c62c4c307ce691f29bff2f15c94c4f07f2b83d9b356f0664bc8b3a2"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-aarch64-unknown-linux-musl.tar.gz"
|
||||||
|
|
||||||
|
[tools.uv."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:23ea21a05c62c4c307ce691f29bff2f15c94c4f07f2b83d9b356f0664bc8b3a2"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-aarch64-unknown-linux-musl.tar.gz"
|
||||||
|
|
||||||
|
[tools.uv."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:d0fec58f3124e05e0a1af0f6541abfce4333253cdaf23c7b6bb2e6128bf138ea"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-x86_64-unknown-linux-musl.tar.gz"
|
||||||
|
|
||||||
|
[tools.uv."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:d0fec58f3124e05e0a1af0f6541abfce4333253cdaf23c7b6bb2e6128bf138ea"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-x86_64-unknown-linux-musl.tar.gz"
|
||||||
|
|
||||||
|
[tools.uv."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:103367962c5cb00bf7370d84cbaa3fec5a9807be9cc833ea9d8eea400c119fa2"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-aarch64-apple-darwin.tar.gz"
|
||||||
|
|
||||||
|
[tools.uv."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:2bbef70982e97dfc36454de173f35ec1a5e83ae11e3885df6a50db3fd76171cb"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-x86_64-apple-darwin.tar.gz"
|
||||||
|
|
||||||
|
[tools.uv."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:459d95892a5cc5c21779532f4f41b9238594b79e312a5142da2148ecfa10e705"
|
||||||
|
url = "https://github.com/astral-sh/uv/releases/download/0.8.15/uv-x86_64-pc-windows-msvc.zip"
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html
|
||||||
|
|
||||||
|
[[tools."aqua:flutter/flutter"]]
|
||||||
|
version = "3.41.9"
|
||||||
|
backend = "aqua:flutter/flutter"
|
||||||
|
|
||||||
|
[[tools.flutter]]
|
||||||
|
version = "3.41.9-stable"
|
||||||
|
backend = "asdf:flutter"
|
||||||
|
|
||||||
|
[[tools."github:CQLabs/homebrew-dcm"]]
|
||||||
|
version = "1.37.0"
|
||||||
|
backend = "github:CQLabs/homebrew-dcm"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:253da2512b149913dfe345bf9a62a79acb2d730f66e71162ba4a92dfc4224b82"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-linux-arm-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543838"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:253da2512b149913dfe345bf9a62a79acb2d730f66e71162ba4a92dfc4224b82"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-linux-arm-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543838"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:477e086d4099c12f21e5ccd83b005d5fb945dd4cac4fd127fd9a08d7649af1cf"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-linux-x64-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543797"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:477e086d4099c12f21e5ccd83b005d5fb945dd4cac4fd127fd9a08d7649af1cf"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-linux-x64-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543797"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:30bede64367d09067093cc57af6ec9496d7717898138ded5cb98a16ac8dd9d93"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-macos-arm-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543757"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:e56cb99872be7445a4de1d37e5438ca70e3bcd83be7a2b9b385e3538881f8068"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-macos-x64-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543727"
|
||||||
|
|
||||||
|
[tools."github:CQLabs/homebrew-dcm"."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:f133470daa3fb0427f039b424392af7e917d7e7db6b556aa2a968ab0e31587da"
|
||||||
|
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.37.0/dcm-windows-release.zip"
|
||||||
|
url_api = "https://api.github.com/repos/CQLabs/homebrew-dcm/releases/assets/404543660"
|
||||||
|
|
||||||
|
[[tools."github:extism/cli"]]
|
||||||
|
version = "1.6.3"
|
||||||
|
backend = "github:extism/cli"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:d92f830c9be39637569feacb04e9750c28848df6d9a219db94152a9b4eb9452b"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-linux-arm64.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694030"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:d92f830c9be39637569feacb04e9750c28848df6d9a219db94152a9b4eb9452b"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-linux-arm64.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694030"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:34e7ae9bfded6e2c32dee83f70a4e50d34f9d3e80d1762b09625fe82e214d02d"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-linux-amd64.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694025"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:34e7ae9bfded6e2c32dee83f70a4e50d34f9d3e80d1762b09625fe82e214d02d"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-linux-amd64.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694025"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:b4ddbc575b5ac000115247f781723f9b9f284ed87b29c600539d72161b5b29fc"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-darwin-arm64.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694029"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:9a2f71b6e6009685a622cc3084e52d2a1a8e23c98d29ffa72e666e9dc699855f"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-darwin-amd64.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694026"
|
||||||
|
|
||||||
|
[tools."github:extism/cli"."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:47e4ed2782445b2b08a4d1ac127211588f8b4d1fc25fd6481d4cb65151b5213c"
|
||||||
|
url = "https://github.com/extism/cli/releases/download/v1.6.3/extism-v1.6.3-windows-amd64.zip"
|
||||||
|
url_api = "https://api.github.com/repos/extism/cli/releases/assets/275694035"
|
||||||
|
|
||||||
|
[[tools."github:extism/js-pdk"]]
|
||||||
|
version = "1.6.0"
|
||||||
|
backend = "github:extism/js-pdk"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:15a186250e68d6bff4ec839fff275d45a90e383a69209dcc1239eb9e3aee6e1b"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-aarch64-linux-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353223214"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:15a186250e68d6bff4ec839fff275d45a90e383a69209dcc1239eb9e3aee6e1b"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-aarch64-linux-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353223214"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:4ded271ccf465031ccd0dc35e7a140e134d7f30721671cc4a8e1ff805d4aad68"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-x86_64-linux-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353223119"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:4ded271ccf465031ccd0dc35e7a140e134d7f30721671cc4a8e1ff805d4aad68"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-x86_64-linux-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353223119"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:548e25bda3971a07c32d78a249135cf8cb7b3eede101e878e06e53e01ac2e0ce"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-aarch64-macos-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353223215"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:d85a875c2a071f0c29fe572764c52c3a499f157ab7f9efac8939a4364390e29b"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-x86_64-macos-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353223239"
|
||||||
|
|
||||||
|
[tools."github:extism/js-pdk"."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:97b7b746141e4777e1ca2b76febdeb16dc9d314ff6a4257df05a476b67228acc"
|
||||||
|
url = "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js-x86_64-windows-v1.6.0.gz"
|
||||||
|
url_api = "https://api.github.com/repos/extism/js-pdk/releases/assets/353224133"
|
||||||
|
|
||||||
|
[[tools."github:jellyfin/jellyfin-ffmpeg"]]
|
||||||
|
version = "7.1.3-6"
|
||||||
|
backend = "github:jellyfin/jellyfin-ffmpeg"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:bea03c670e8cc5bfe9edc0c5d624d4735421610cef5e808db93e7d8596952886"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_linuxarm64-gpl.tar.xz"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/409048876"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:bea03c670e8cc5bfe9edc0c5d624d4735421610cef5e808db93e7d8596952886"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_linuxarm64-gpl.tar.xz"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/409048876"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:39e99a7927468a6abec5f65d00f55010e8ff2ae3c2605294f179c94f6ae21af2"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_linux64-gpl.tar.xz"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/409048879"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:39e99a7927468a6abec5f65d00f55010e8ff2ae3c2605294f179c94f6ae21af2"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_linux64-gpl.tar.xz"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/409048879"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:e024d5e78d5414e75f0181036cd21373fafb9270c72894dfd7dbda2572439820"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_macarm64-gpl.tar.xz"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/408995838"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:066ede9774aaae97a18098aaeea8b7e0d286653eb8618f640476e99c59a536c2"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_mac64-gpl.tar.xz"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/408995889"
|
||||||
|
|
||||||
|
[tools."github:jellyfin/jellyfin-ffmpeg"."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:7b7168149689610296f3a187c717056ce0786cc125a31caf28056737e9ba1cc1"
|
||||||
|
url = "https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v7.1.3-6/jellyfin-ffmpeg_7.1.3-6_portable_win64-clang-gpl.zip"
|
||||||
|
url_api = "https://api.github.com/repos/jellyfin/jellyfin-ffmpeg/releases/assets/409036094"
|
||||||
|
|
||||||
|
[[tools."github:webassembly/binaryen"]]
|
||||||
|
version = "version_124"
|
||||||
|
backend = "github:webassembly/binaryen"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:6291bd9a57d8e046f3bc099a4db386c147433a87f71c783a901c5b1792e38de3"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-aarch64-linux.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288927659"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:6291bd9a57d8e046f3bc099a4db386c147433a87f71c783a901c5b1792e38de3"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-aarch64-linux.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288927659"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:0290c3779fedf592b8da0ded3032ff55c41a2b7bfa2d6bf7b7bac6f0e6e28963"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-x86_64-linux.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288926769"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:0290c3779fedf592b8da0ded3032ff55c41a2b7bfa2d6bf7b7bac6f0e6e28963"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-x86_64-linux.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288926769"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:86a2c960ff62c6d2ea6009d1f89745c22c70100d394a095eab45eb941bdaa24c"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-arm64-macos.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288926134"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:b389bb0731758d86c3cb266d01d28a12725c23bd3cabc3df34faa162af0887e9"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-x86_64-macos.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288926135"
|
||||||
|
|
||||||
|
[tools."github:webassembly/binaryen"."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:b5e1d2a1ad3c03229ddc89823848f4a1c11f9c6402a51fa26f0aaa5f1d7a2203"
|
||||||
|
url = "https://github.com/WebAssembly/binaryen/releases/download/version_124/binaryen-version_124-x86_64-windows.tar.gz"
|
||||||
|
url_api = "https://api.github.com/repos/WebAssembly/binaryen/releases/assets/288925833"
|
||||||
|
|
||||||
|
[[tools.java]]
|
||||||
|
version = "21.0.2"
|
||||||
|
backend = "core:java"
|
||||||
|
|
||||||
|
[tools.java."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:08db1392a48d4eb5ea5315cf8f18b89dbaf36cda663ba882cf03c704c9257ec2"
|
||||||
|
url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_linux-aarch64_bin.tar.gz"
|
||||||
|
|
||||||
|
[tools.java."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:a2def047a73941e01a73739f92755f86b895811afb1f91243db214cff5bdac3f"
|
||||||
|
url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_linux-x64_bin.tar.gz"
|
||||||
|
|
||||||
|
[tools.java."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:b3d588e16ec1e0ef9805d8a696591bd518a5cea62567da8f53b5ce32d11d22e4"
|
||||||
|
url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_macos-aarch64_bin.tar.gz"
|
||||||
|
|
||||||
|
[tools.java."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:8fd09e15dc406387a0aba70bf5d99692874e999bf9cd9208b452b5d76ac922d3"
|
||||||
|
url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_macos-x64_bin.tar.gz"
|
||||||
|
|
||||||
|
[tools.java."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:b6c17e747ae78cdd6de4d7532b3164b277daee97c007d3eaa2b39cca99882664"
|
||||||
|
url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_windows-x64_bin.zip"
|
||||||
|
|
||||||
|
[[tools.node]]
|
||||||
|
version = "24.15.0"
|
||||||
|
backend = "core:node"
|
||||||
|
|
||||||
|
[tools.node."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:73afc234d558c24919875f51c2d1ea002a2ada4ea6f83601a383869fefa64eed"
|
||||||
|
url = "https://nodejs.org/dist/v24.15.0/node-v24.15.0-linux-arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.node."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:31e98aa960a067da91edffd5d93bc46657b5d2a8029612c359f5f2ac0060152a"
|
||||||
|
url = "https://unofficial-builds.nodejs.org/download/release/v24.15.0/node-v24.15.0-linux-arm64-musl.tar.gz"
|
||||||
|
|
||||||
|
[tools.node."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89"
|
||||||
|
url = "https://nodejs.org/dist/v24.15.0/node-v24.15.0-linux-x64.tar.gz"
|
||||||
|
|
||||||
|
[tools.node."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:f55af5bd489c5347b113ca6594cae00a54b30ba57ac5875324311bfc6f4762e3"
|
||||||
|
url = "https://unofficial-builds.nodejs.org/download/release/v24.15.0/node-v24.15.0-linux-x64-musl.tar.gz"
|
||||||
|
|
||||||
|
[tools.node."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:372331b969779ab5d15b949884fc6eaf88d5afe87bde8ba881d6400b9100ffc4"
|
||||||
|
url = "https://nodejs.org/dist/v24.15.0/node-v24.15.0-darwin-arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.node."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:ffd5ee293467927f3ee731a553eb88fd1f48cf74eebc2d74a6babe4af228673b"
|
||||||
|
url = "https://nodejs.org/dist/v24.15.0/node-v24.15.0-darwin-x64.tar.gz"
|
||||||
|
|
||||||
|
[tools.node."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:cc5149eabd53779ce1e7bdc5401643622d0c7e6800ade18928a767e940bb0e62"
|
||||||
|
url = "https://nodejs.org/dist/v24.15.0/node-v24.15.0-win-x64.zip"
|
||||||
|
|
||||||
|
[[tools."npm:oazapfts"]]
|
||||||
|
version = "7.5.0"
|
||||||
|
backend = "npm:oazapfts"
|
||||||
|
|
||||||
|
[[tools.opentofu]]
|
||||||
|
version = "1.11.6"
|
||||||
|
backend = "aqua:opentofu/opentofu"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:d4f2ab15776925864b049bb329d69682851de6f5204f256e9fa86d07a0308850"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:d4f2ab15776925864b049bb329d69682851de6f5204f256e9fa86d07a0308850"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:02800fafa2753a9f50c38483e2fdf5bc353fd62895eb9e25eec9a5145df3a69e"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:02800fafa2753a9f50c38483e2fdf5bc353fd62895eb9e25eec9a5145df3a69e"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:62d7fa8539e13b444827aa0a3b90c5972da5c47e8f8882d9dcf2e430e78840c1"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_darwin_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:1408cdef1c380f914565e6b4bb70794c6b163f195fcb233357f3d6c5745906b6"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_darwin_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.opentofu."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:27323f70c875b8251bfd7e61a4cffc3ebff4e56ed1e611b955016f0c7077367e"
|
||||||
|
url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.6_windows_amd64.tar.gz"
|
||||||
|
|
||||||
|
[[tools.pnpm]]
|
||||||
|
version = "10.33.4"
|
||||||
|
backend = "aqua:pnpm/pnpm"
|
||||||
|
|
||||||
|
[[tools.terragrunt]]
|
||||||
|
version = "1.0.3"
|
||||||
|
backend = "aqua:gruntwork-io/terragrunt"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-arm64"]
|
||||||
|
checksum = "sha256:e5b60ab05b5214db694e6bc215d8124fb626e277cdb56b86f6147ae110d510fe"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-arm64-musl"]
|
||||||
|
checksum = "sha256:e5b60ab05b5214db694e6bc215d8124fb626e277cdb56b86f6147ae110d510fe"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-x64"]
|
||||||
|
checksum = "sha256:6d48049baf82e0bf9c804368dc85cbfeadc10955e33777e9e8de3e020b94b073"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.linux-x64-musl"]
|
||||||
|
checksum = "sha256:6d48049baf82e0bf9c804368dc85cbfeadc10955e33777e9e8de3e020b94b073"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.macos-arm64"]
|
||||||
|
checksum = "sha256:aacb5be2ca5475300cbce246dfbd8a45eb47510fbaa70fab8561c49ef5db03aa"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_darwin_arm64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.macos-x64"]
|
||||||
|
checksum = "sha256:3133c2251e191aede8e3dd2a5b3aee2e91c5f08f88f117aee40eed9a24c8ef6b"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_darwin_amd64.tar.gz"
|
||||||
|
|
||||||
|
[tools.terragrunt."platforms.windows-x64"]
|
||||||
|
checksum = "sha256:183b2745b4e04980a6bfa4450ff81956a12596ca22d70f7aaa793980f5b036db"
|
||||||
|
url = "https://github.com/gruntwork-io/terragrunt/releases/download/v1.0.3/terragrunt_windows_amd64.exe.tar.gz"
|
||||||
@@ -16,8 +16,8 @@ config_roots = [
|
|||||||
|
|
||||||
[tools]
|
[tools]
|
||||||
node = "24.15.0"
|
node = "24.15.0"
|
||||||
flutter = "3.41.9"
|
"aqua:flutter/flutter" = "3.41.9"
|
||||||
pnpm = "10.33.1"
|
pnpm = "10.33.4"
|
||||||
terragrunt = "1.0.3"
|
terragrunt = "1.0.3"
|
||||||
opentofu = "1.11.6"
|
opentofu = "1.11.6"
|
||||||
java = "21.0.2"
|
java = "21.0.2"
|
||||||
@@ -50,11 +50,12 @@ macos-arm64 = { asset_pattern = "jellyfin-ffmpeg_*_portable_macarm64-gpl.tar.xz"
|
|||||||
[settings]
|
[settings]
|
||||||
experimental = true
|
experimental = true
|
||||||
pin = true
|
pin = true
|
||||||
|
lockfile = true
|
||||||
|
|
||||||
[tasks.plugins]
|
[tasks.plugins]
|
||||||
run = [
|
run = [
|
||||||
"pnpm --filter @immich/plugin-sdk --filter @immich/plugin-core install --frozen-lockfile",
|
"pnpm --filter @immich/plugin-sdk --filter @immich/plugin-core install --frozen-lockfile",
|
||||||
"pnpm --filter @immich/plugin-sdk --filter @immich/plugin-core build"
|
"pnpm --filter @immich/plugin-sdk --filter @immich/plugin-core build",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tasks.open-api-typescript]
|
[tasks.open-api-typescript]
|
||||||
@@ -76,8 +77,8 @@ run = [
|
|||||||
{ task = "//server:install" },
|
{ task = "//server:install" },
|
||||||
{ task = "//server:build" },
|
{ task = "//server:build" },
|
||||||
{ task = "//server:sync-open-api" },
|
{ task = "//server:sync-open-api" },
|
||||||
{ task = ":open-api-typescript"},
|
{ task = ":open-api-typescript" },
|
||||||
{ task = ":open-api-dart"},
|
{ task = ":open-api-dart" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[tasks.sql]
|
[tasks.sql]
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ flutter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
constraints {
|
||||||
|
implementation("androidx.glance:glance-appwidget") {
|
||||||
|
version { strictly libs.versions.glance.get() }
|
||||||
|
because 'home_widget requests 1.+ which can resolve to pre-releases incompatible with our compileSdk/AGP'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
implementation libs.okhttp
|
implementation libs.okhttp
|
||||||
implementation libs.cronet.embedded
|
implementation libs.cronet.embedded
|
||||||
implementation libs.media3.datasource.okhttp
|
implementation libs.media3.datasource.okhttp
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ interface NetworkApi {
|
|||||||
fun hasCertificate(): Boolean
|
fun hasCertificate(): Boolean
|
||||||
fun getClientPointer(): Long
|
fun getClientPointer(): Long
|
||||||
fun setRequestHeaders(headers: Map<String, String>, serverUrls: List<String>, token: String?)
|
fun setRequestHeaders(headers: Map<String, String>, serverUrls: List<String>, token: String?)
|
||||||
|
fun getAppGroupId(): String
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/** The codec used by NetworkApi. */
|
/** The codec used by NetworkApi. */
|
||||||
@@ -430,6 +431,21 @@ interface NetworkApi {
|
|||||||
channel.setMessageHandler(null)
|
channel.setMessageHandler(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
run {
|
||||||
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.NetworkApi.getAppGroupId$separatedMessageChannelSuffix", codec)
|
||||||
|
if (api != null) {
|
||||||
|
channel.setMessageHandler { _, reply ->
|
||||||
|
val wrapped: List<Any?> = try {
|
||||||
|
listOf(api.getAppGroupId())
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
NetworkPigeonUtils.wrapError(exception)
|
||||||
|
}
|
||||||
|
reply.reply(wrapped)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channel.setMessageHandler(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class NetworkApiPlugin : FlutterPlugin, ActivityAware {
|
|||||||
private var networkApi: NetworkApiImpl? = null
|
private var networkApi: NetworkApiImpl? = null
|
||||||
|
|
||||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
networkApi = NetworkApiImpl()
|
networkApi = NetworkApiImpl(binding.applicationContext)
|
||||||
NetworkApi.setUp(binding.binaryMessenger, networkApi)
|
NetworkApi.setUp(binding.binaryMessenger, networkApi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,9 +39,11 @@ class NetworkApiPlugin : FlutterPlugin, ActivityAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NetworkApiImpl : NetworkApi {
|
private class NetworkApiImpl(private val context: Context) : NetworkApi {
|
||||||
var activity: Activity? = null
|
var activity: Activity? = null
|
||||||
|
|
||||||
|
override fun getAppGroupId(): String = context.packageName
|
||||||
|
|
||||||
override fun addCertificate(clientData: ClientCertData, callback: (Result<Unit>) -> Unit) {
|
override fun addCertificate(clientData: ClientCertData, callback: (Result<Unit>) -> Unit) {
|
||||||
try {
|
try {
|
||||||
HttpClientManager.setKeyEntry(clientData.data, clientData.password.toCharArray())
|
HttpClientManager.setKeyEntry(clientData.data, clientData.password.toCharArray())
|
||||||
|
|||||||
@@ -718,6 +718,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share.profile;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
@@ -750,7 +751,6 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 240;
|
CURRENT_PROJECT_VERSION = 240;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
|
||||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -801,6 +801,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share.debug;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
@@ -860,6 +861,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
@@ -894,7 +896,6 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 240;
|
CURRENT_PROJECT_VERSION = 240;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
|
||||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -924,7 +925,6 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 240;
|
CURRENT_PROJECT_VERSION = 240;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
|
||||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -1080,7 +1080,6 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 240;
|
CURRENT_PROJECT_VERSION = 240;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
|
||||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -1124,7 +1123,6 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 240;
|
CURRENT_PROJECT_VERSION = 240;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
|
||||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -1165,7 +1163,6 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 240;
|
CURRENT_PROJECT_VERSION = 240;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
|
||||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
|||||||
Generated
+14
@@ -288,6 +288,7 @@ protocol NetworkApi {
|
|||||||
func hasCertificate() throws -> Bool
|
func hasCertificate() throws -> Bool
|
||||||
func getClientPointer() throws -> Int64
|
func getClientPointer() throws -> Int64
|
||||||
func setRequestHeaders(headers: [String: String], serverUrls: [String], token: String?) throws
|
func setRequestHeaders(headers: [String: String], serverUrls: [String], token: String?) throws
|
||||||
|
func getAppGroupId() throws -> String
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
|
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
|
||||||
@@ -388,5 +389,18 @@ class NetworkApiSetup {
|
|||||||
} else {
|
} else {
|
||||||
setRequestHeadersChannel.setMessageHandler(nil)
|
setRequestHeadersChannel.setMessageHandler(nil)
|
||||||
}
|
}
|
||||||
|
let getAppGroupIdChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NetworkApi.getAppGroupId\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
|
||||||
|
if let api = api {
|
||||||
|
getAppGroupIdChannel.setMessageHandler { _, reply in
|
||||||
|
do {
|
||||||
|
let result = try api.getAppGroupId()
|
||||||
|
reply(wrapResult(result))
|
||||||
|
} catch {
|
||||||
|
reply(wrapError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getAppGroupIdChannel.setMessageHandler(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ class NetworkApiImpl: NetworkApi {
|
|||||||
return Int64(Int(bitPattern: pointer))
|
return Int64(Int(bitPattern: pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAppGroupId() throws -> String {
|
||||||
|
return Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as! String
|
||||||
|
}
|
||||||
|
|
||||||
func setRequestHeaders(headers: [String : String], serverUrls: [String], token: String?) throws {
|
func setRequestHeaders(headers: [String : String], serverUrls: [String], token: String?) throws {
|
||||||
URLSessionManager.setServerUrls(serverUrls)
|
URLSessionManager.setServerUrls(serverUrls)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import native_video_player
|
|||||||
let CLIENT_CERT_LABEL = "app.alextran.immich.client_identity"
|
let CLIENT_CERT_LABEL = "app.alextran.immich.client_identity"
|
||||||
let HEADERS_KEY = "immich.request_headers"
|
let HEADERS_KEY = "immich.request_headers"
|
||||||
let SERVER_URLS_KEY = "immich.server_urls"
|
let SERVER_URLS_KEY = "immich.server_urls"
|
||||||
let APP_GROUP = "group.app.immich.share"
|
let APP_GROUP = Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as! String
|
||||||
let COOKIE_EXPIRY_DAYS: TimeInterval = 400
|
let COOKIE_EXPIRY_DAYS: TimeInterval = 400
|
||||||
|
|
||||||
enum AuthCookie: CaseIterable {
|
enum AuthCookie: CaseIterable {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.app.immich.share</string>
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.app.immich.share</string>
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.app.immich.share</string>
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -2,7 +2,7 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
|
||||||
let IMMICH_SHARE_GROUP = "group.app.immich.share"
|
let IMMICH_SHARE_GROUP = Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as! String
|
||||||
|
|
||||||
enum WidgetError: Error, Codable {
|
enum WidgetError: Error, Codable {
|
||||||
case noLogin
|
case noLogin
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>AppGroupId</key>
|
||||||
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.app.immich.share</string>
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -21,6 +21,7 @@ platform :ios do
|
|||||||
CODE_SIGN_IDENTITY = "Apple Distribution: FUTO Holdings, Inc. (#{TEAM_ID})"
|
CODE_SIGN_IDENTITY = "Apple Distribution: FUTO Holdings, Inc. (#{TEAM_ID})"
|
||||||
BASE_BUNDLE_ID = "app.alextran.immich"
|
BASE_BUNDLE_ID = "app.alextran.immich"
|
||||||
DEV_BUNDLE_ID = "tech.futo.immich.testflight"
|
DEV_BUNDLE_ID = "tech.futo.immich.testflight"
|
||||||
|
DEV_GROUP_ID = "group.app.immich.share.testflight"
|
||||||
|
|
||||||
# Helper method to get App Store Connect API key
|
# Helper method to get App Store Connect API key
|
||||||
def get_api_key
|
def get_api_key
|
||||||
@@ -33,6 +34,13 @@ platform :ios do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Helper method to assemble xcargs with optional CUSTOM_GROUP_ID override
|
||||||
|
def build_xcargs(group_id: nil)
|
||||||
|
args = "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual"
|
||||||
|
args += " CUSTOM_GROUP_ID='#{group_id}'" if group_id
|
||||||
|
args
|
||||||
|
end
|
||||||
|
|
||||||
# Helper method to get version from pubspec.yaml
|
# Helper method to get version from pubspec.yaml
|
||||||
def get_version_from_pubspec
|
def get_version_from_pubspec
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
@@ -89,7 +97,8 @@ end
|
|||||||
version_number: nil,
|
version_number: nil,
|
||||||
profile_name_main:,
|
profile_name_main:,
|
||||||
profile_name_share:,
|
profile_name_share:,
|
||||||
profile_name_widget:
|
profile_name_widget:,
|
||||||
|
group_id: nil
|
||||||
)
|
)
|
||||||
app_identifier = base_bundle_id
|
app_identifier = base_bundle_id
|
||||||
|
|
||||||
@@ -113,7 +122,7 @@ end
|
|||||||
workspace: "Runner.xcworkspace",
|
workspace: "Runner.xcworkspace",
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
export_method: "app-store",
|
export_method: "app-store",
|
||||||
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
xcargs: build_xcargs(group_id: group_id),
|
||||||
export_options: {
|
export_options: {
|
||||||
provisioningProfiles: {
|
provisioningProfiles: {
|
||||||
"#{app_identifier}" => profile_name_main,
|
"#{app_identifier}" => profile_name_main,
|
||||||
@@ -165,7 +174,8 @@ end
|
|||||||
distribute_external: false,
|
distribute_external: false,
|
||||||
profile_name_main: main_profile_name,
|
profile_name_main: main_profile_name,
|
||||||
profile_name_share: share_profile_name,
|
profile_name_share: share_profile_name,
|
||||||
profile_name_widget: widget_profile_name
|
profile_name_widget: widget_profile_name,
|
||||||
|
group_id: DEV_GROUP_ID
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -274,7 +284,7 @@ end
|
|||||||
configuration: "Release",
|
configuration: "Release",
|
||||||
export_method: "app-store",
|
export_method: "app-store",
|
||||||
skip_package_ipa: true,
|
skip_package_ipa: true,
|
||||||
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
xcargs: build_xcargs(group_id: DEV_GROUP_ID),
|
||||||
export_options: {
|
export_options: {
|
||||||
provisioningProfiles: {
|
provisioningProfiles: {
|
||||||
DEV_BUNDLE_ID => main_profile_name,
|
DEV_BUNDLE_ID => main_profile_name,
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ const int kTimelineAssetLoadBatchSize = 1024;
|
|||||||
const int kTimelineAssetLoadOppositeSize = 64;
|
const int kTimelineAssetLoadOppositeSize = 64;
|
||||||
|
|
||||||
// Widget keys
|
// Widget keys
|
||||||
const String appShareGroupId = "group.app.immich.share";
|
|
||||||
const String kWidgetAuthToken = "widget_auth_token";
|
const String kWidgetAuthToken = "widget_auth_token";
|
||||||
const String kWidgetServerEndpoint = "widget_server_url";
|
const String kWidgetServerEndpoint = "widget_server_url";
|
||||||
const String kWidgetCustomHeaders = "widget_custom_headers";
|
const String kWidgetCustomHeaders = "widget_custom_headers";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:immich_mobile/domain/models/config/album_config.dart';
|
import 'package:immich_mobile/domain/models/config/album_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/backup_config.dart';
|
||||||
import 'package:immich_mobile/domain/models/config/cleanup_config.dart';
|
import 'package:immich_mobile/domain/models/config/cleanup_config.dart';
|
||||||
import 'package:immich_mobile/domain/models/config/image_config.dart';
|
import 'package:immich_mobile/domain/models/config/image_config.dart';
|
||||||
import 'package:immich_mobile/domain/models/config/map_config.dart';
|
import 'package:immich_mobile/domain/models/config/map_config.dart';
|
||||||
@@ -16,6 +17,7 @@ class AppConfig {
|
|||||||
final ViewerConfig viewer;
|
final ViewerConfig viewer;
|
||||||
final SlideshowConfig slideshow;
|
final SlideshowConfig slideshow;
|
||||||
final AlbumConfig album;
|
final AlbumConfig album;
|
||||||
|
final BackupConfig backup;
|
||||||
|
|
||||||
const AppConfig({
|
const AppConfig({
|
||||||
this.theme = const .new(),
|
this.theme = const .new(),
|
||||||
@@ -26,6 +28,7 @@ class AppConfig {
|
|||||||
this.viewer = const .new(),
|
this.viewer = const .new(),
|
||||||
this.slideshow = const .new(),
|
this.slideshow = const .new(),
|
||||||
this.album = const .new(),
|
this.album = const .new(),
|
||||||
|
this.backup = const .new(),
|
||||||
});
|
});
|
||||||
|
|
||||||
AppConfig copyWith({
|
AppConfig copyWith({
|
||||||
@@ -37,6 +40,7 @@ class AppConfig {
|
|||||||
ViewerConfig? viewer,
|
ViewerConfig? viewer,
|
||||||
SlideshowConfig? slideshow,
|
SlideshowConfig? slideshow,
|
||||||
AlbumConfig? album,
|
AlbumConfig? album,
|
||||||
|
BackupConfig? backup,
|
||||||
}) => .new(
|
}) => .new(
|
||||||
theme: theme ?? this.theme,
|
theme: theme ?? this.theme,
|
||||||
cleanup: cleanup ?? this.cleanup,
|
cleanup: cleanup ?? this.cleanup,
|
||||||
@@ -46,6 +50,7 @@ class AppConfig {
|
|||||||
viewer: viewer ?? this.viewer,
|
viewer: viewer ?? this.viewer,
|
||||||
slideshow: slideshow ?? this.slideshow,
|
slideshow: slideshow ?? this.slideshow,
|
||||||
album: album ?? this.album,
|
album: album ?? this.album,
|
||||||
|
backup: backup ?? this.backup,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -59,12 +64,13 @@ class AppConfig {
|
|||||||
other.image == image &&
|
other.image == image &&
|
||||||
other.viewer == viewer &&
|
other.viewer == viewer &&
|
||||||
other.slideshow == slideshow &&
|
other.slideshow == slideshow &&
|
||||||
other.album == album);
|
other.album == album &&
|
||||||
|
other.backup == backup);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(theme, cleanup, map, timeline, image, viewer, slideshow, album);
|
int get hashCode => Object.hash(theme, cleanup, map, timeline, image, viewer, slideshow, album, backup);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
'AppConfig(theme: $theme, cleanup: $cleanup, map: $map, timeline: $timeline, image: $image, viewer: $viewer, slideshow: $slideshow, album: $album)';
|
'AppConfig(theme: $theme, cleanup: $cleanup, map: $map, timeline: $timeline, image: $image, viewer: $viewer, slideshow: $slideshow, album: $album, backup: $backup)';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
class BackupConfig {
|
||||||
|
final bool enabled;
|
||||||
|
final bool useCellularForVideos;
|
||||||
|
final bool useCellularForPhotos;
|
||||||
|
final bool requireCharging;
|
||||||
|
final int triggerDelay;
|
||||||
|
final bool syncAlbums;
|
||||||
|
|
||||||
|
const BackupConfig({
|
||||||
|
this.enabled = false,
|
||||||
|
this.useCellularForVideos = false,
|
||||||
|
this.useCellularForPhotos = false,
|
||||||
|
this.requireCharging = false,
|
||||||
|
this.triggerDelay = 30,
|
||||||
|
this.syncAlbums = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
BackupConfig copyWith({
|
||||||
|
bool? enabled,
|
||||||
|
bool? useCellularForVideos,
|
||||||
|
bool? useCellularForPhotos,
|
||||||
|
bool? requireCharging,
|
||||||
|
int? triggerDelay,
|
||||||
|
bool? syncAlbums,
|
||||||
|
}) => BackupConfig(
|
||||||
|
enabled: enabled ?? this.enabled,
|
||||||
|
useCellularForVideos: useCellularForVideos ?? this.useCellularForVideos,
|
||||||
|
useCellularForPhotos: useCellularForPhotos ?? this.useCellularForPhotos,
|
||||||
|
requireCharging: requireCharging ?? this.requireCharging,
|
||||||
|
triggerDelay: triggerDelay ?? this.triggerDelay,
|
||||||
|
syncAlbums: syncAlbums ?? this.syncAlbums,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is BackupConfig &&
|
||||||
|
other.enabled == enabled &&
|
||||||
|
other.useCellularForVideos == useCellularForVideos &&
|
||||||
|
other.useCellularForPhotos == useCellularForPhotos &&
|
||||||
|
other.requireCharging == requireCharging &&
|
||||||
|
other.triggerDelay == triggerDelay &&
|
||||||
|
other.syncAlbums == syncAlbums);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
Object.hash(enabled, useCellularForVideos, useCellularForPhotos, requireCharging, triggerDelay, syncAlbums);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'BackupConfig(enabled: $enabled, useCellularForVideos: $useCellularForVideos, useCellularForPhotos: $useCellularForPhotos, requireCharging: $requireCharging, triggerDelay: $triggerDelay, syncAlbums: $syncAlbums)';
|
||||||
|
}
|
||||||
@@ -62,6 +62,14 @@ enum MetadataKey<T extends Object> {
|
|||||||
albumIsReverse<bool>(.appConfig, 'album.isReverse', true),
|
albumIsReverse<bool>(.appConfig, 'album.isReverse', true),
|
||||||
albumIsGrid<bool>(.appConfig, 'album.isGrid', false),
|
albumIsGrid<bool>(.appConfig, 'album.isGrid', false),
|
||||||
|
|
||||||
|
// Backup
|
||||||
|
backupEnabled<bool>(.appConfig, 'backup.enabled', false),
|
||||||
|
backupUseCellularForVideos<bool>(.appConfig, 'backup.useCellularForVideos', false),
|
||||||
|
backupUseCellularForPhotos<bool>(.appConfig, 'backup.useCellularForPhotos', false),
|
||||||
|
backupRequireCharging<bool>(.appConfig, 'backup.requireCharging', false),
|
||||||
|
backupTriggerDelay<int>(.appConfig, 'backup.triggerDelay', 30),
|
||||||
|
backupSyncAlbums<bool>(.appConfig, 'backup.syncAlbums', false),
|
||||||
|
|
||||||
// Timeline
|
// Timeline
|
||||||
timelineTilesPerRow<int>(.appConfig, 'timeline.tilesPerRow', 4),
|
timelineTilesPerRow<int>(.appConfig, 'timeline.tilesPerRow', 4),
|
||||||
timelineGroupAssetsBy<GroupAssetsBy>(
|
timelineGroupAssetsBy<GroupAssetsBy>(
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
|
|
||||||
enum Setting<T> {
|
enum Setting<T> {
|
||||||
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, false),
|
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, false);
|
||||||
enableBackup<bool>(StoreKey.enableBackup, false);
|
|
||||||
|
|
||||||
const Setting(this.storeKey, this.defaultValue);
|
const Setting(this.storeKey, this.defaultValue);
|
||||||
|
|
||||||
|
|||||||
@@ -6,26 +6,25 @@ enum StoreKey<T> {
|
|||||||
version<int>._(0),
|
version<int>._(0),
|
||||||
currentUser<UserDto>._(2),
|
currentUser<UserDto>._(2),
|
||||||
deviceId<String>._(4),
|
deviceId<String>._(4),
|
||||||
backupRequireCharging<bool>._(7),
|
|
||||||
backupTriggerDelay<int>._(8),
|
|
||||||
serverUrl<String>._(10),
|
serverUrl<String>._(10),
|
||||||
accessToken<String>._(11),
|
accessToken<String>._(11),
|
||||||
serverEndpoint<String>._(12),
|
serverEndpoint<String>._(12),
|
||||||
advancedTroubleshooting<bool>._(114),
|
advancedTroubleshooting<bool>._(114),
|
||||||
enableHapticFeedback<bool>._(126),
|
enableHapticFeedback<bool>._(126),
|
||||||
syncAlbums<bool>._(131),
|
|
||||||
|
|
||||||
manageLocalMediaAndroid<bool>._(137),
|
manageLocalMediaAndroid<bool>._(137),
|
||||||
// Read-only Mode settings
|
// Read-only Mode settings
|
||||||
readonlyModeEnabled<bool>._(138),
|
readonlyModeEnabled<bool>._(138),
|
||||||
|
|
||||||
// Experimental stuff
|
|
||||||
enableBackup<bool>._(1003),
|
|
||||||
useWifiForUploadVideos<bool>._(1004),
|
|
||||||
useWifiForUploadPhotos<bool>._(1005),
|
|
||||||
syncMigrationStatus<String>._(1013),
|
syncMigrationStatus<String>._(1013),
|
||||||
|
|
||||||
// Legacy keys that have been migrated to the new metadata store
|
// Legacy keys that have been migrated to the new metadata store
|
||||||
|
legacyBackupRequireCharging<bool>._(7),
|
||||||
|
legacyBackupTriggerDelay<int>._(8),
|
||||||
|
legacySyncAlbums<bool>._(131),
|
||||||
|
legacyEnableBackup<bool>._(1003),
|
||||||
|
legacyUseWifiForUploadVideos<bool>._(1004),
|
||||||
|
legacyUseWifiForUploadPhotos<bool>._(1005),
|
||||||
legacySelectedAlbumSortOrder<int>._(113),
|
legacySelectedAlbumSortOrder<int>._(113),
|
||||||
legacySelectedAlbumSortReverse<bool>._(123),
|
legacySelectedAlbumSortReverse<bool>._(123),
|
||||||
legacyAlbumGridView<bool>._(140),
|
legacyAlbumGridView<bool>._(140),
|
||||||
|
|||||||
@@ -11,15 +11,14 @@ import 'package:immich_mobile/entities/store.entity.dart';
|
|||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/platform/background_worker_api.g.dart';
|
import 'package:immich_mobile/platform/background_worker_api.g.dart';
|
||||||
import 'package:immich_mobile/platform/background_worker_lock_api.g.dart';
|
import 'package:immich_mobile/platform/background_worker_lock_api.g.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart' show nativeSyncApiProvider;
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart' show nativeSyncApiProvider;
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/services/auth.service.dart';
|
import 'package:immich_mobile/services/auth.service.dart';
|
||||||
import 'package:immich_mobile/services/foreground_upload.service.dart';
|
import 'package:immich_mobile/services/foreground_upload.service.dart';
|
||||||
import 'package:immich_mobile/services/localization.service.dart';
|
import 'package:immich_mobile/services/localization.service.dart';
|
||||||
@@ -39,16 +38,15 @@ class BackgroundWorkerFgService {
|
|||||||
Future<void> saveNotificationMessage(String title, String body) =>
|
Future<void> saveNotificationMessage(String title, String body) =>
|
||||||
_foregroundHostApi.saveNotificationMessage(title, body);
|
_foregroundHostApi.saveNotificationMessage(title, body);
|
||||||
|
|
||||||
Future<void> configure({int? minimumDelaySeconds, bool? requireCharging}) => _foregroundHostApi.configure(
|
Future<void> configure({int? minimumDelaySeconds, bool? requireCharging}) {
|
||||||
BackgroundWorkerSettings(
|
final backup = MetadataRepository.instance.appConfig.backup;
|
||||||
minimumDelaySeconds:
|
return _foregroundHostApi.configure(
|
||||||
minimumDelaySeconds ??
|
BackgroundWorkerSettings(
|
||||||
Store.get(AppSettingsEnum.backupTriggerDelay.storeKey, AppSettingsEnum.backupTriggerDelay.defaultValue),
|
minimumDelaySeconds: minimumDelaySeconds ?? backup.triggerDelay,
|
||||||
requiresCharging:
|
requiresCharging: requireCharging ?? backup.requireCharging,
|
||||||
requireCharging ??
|
),
|
||||||
Store.get(AppSettingsEnum.backupRequireCharging.storeKey, AppSettingsEnum.backupRequireCharging.defaultValue),
|
);
|
||||||
),
|
}
|
||||||
);
|
|
||||||
|
|
||||||
Future<void> disable() => _foregroundHostApi.disable();
|
Future<void> disable() => _foregroundHostApi.disable();
|
||||||
}
|
}
|
||||||
@@ -71,7 +69,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
|
|||||||
BackgroundWorkerFlutterApi.setUp(this);
|
BackgroundWorkerFlutterApi.setUp(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get _isBackupEnabled => _ref?.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup) ?? false;
|
bool get _isBackupEnabled => MetadataRepository.instance.appConfig.backup.enabled;
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -152,6 +152,14 @@ extension<T extends Object> on MetadataDomain<T> {
|
|||||||
isReverse: repo._read(.albumIsReverse),
|
isReverse: repo._read(.albumIsReverse),
|
||||||
isGrid: repo._read(.albumIsGrid),
|
isGrid: repo._read(.albumIsGrid),
|
||||||
),
|
),
|
||||||
|
backup: .new(
|
||||||
|
enabled: repo._read(.backupEnabled),
|
||||||
|
useCellularForVideos: repo._read(.backupUseCellularForVideos),
|
||||||
|
useCellularForPhotos: repo._read(.backupUseCellularForPhotos),
|
||||||
|
requireCharging: repo._read(.backupRequireCharging),
|
||||||
|
triggerDelay: repo._read(.backupTriggerDelay),
|
||||||
|
syncAlbums: repo._read(.backupSyncAlbums),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
case .systemConfig:
|
case .systemConfig:
|
||||||
repo._systemConfig = .new(
|
repo._systemConfig = .new(
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
|||||||
import 'package:immich_mobile/domain/services/sync_linked_album.service.dart';
|
import 'package:immich_mobile/domain/services/sync_linked_album.service.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/backup_album.provider.dart';
|
import 'package:immich_mobile/providers/backup/backup_album.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/widgets/backup/drift_album_info_list_tile.dart';
|
import 'package:immich_mobile/widgets/backup/drift_album_info_list_tile.dart';
|
||||||
import 'package:immich_mobile/widgets/common/search_field.dart';
|
import 'package:immich_mobile/widgets/common/search_field.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@@ -43,7 +43,7 @@ class _DriftBackupAlbumSelectionPageState extends ConsumerState<DriftBackupAlbum
|
|||||||
_searchController = TextEditingController();
|
_searchController = TextEditingController();
|
||||||
_searchFocusNode = FocusNode();
|
_searchFocusNode = FocusNode();
|
||||||
|
|
||||||
_enableSyncUploadAlbum.value = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums);
|
_enableSyncUploadAlbum.value = ref.read(metadataProvider).appConfig.backup.syncAlbums;
|
||||||
ref.read(backupAlbumProvider.notifier).getAll();
|
ref.read(backupAlbumProvider.notifier).getAll();
|
||||||
|
|
||||||
_initialTotalAssetCount = ref.read(driftBackupProvider.select((p) => p.totalCount));
|
_initialTotalAssetCount = ref.read(driftBackupProvider.select((p) => p.totalCount));
|
||||||
@@ -55,7 +55,7 @@ class _DriftBackupAlbumSelectionPageState extends ConsumerState<DriftBackupAlbum
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final enableSyncUploadAlbum = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums);
|
final enableSyncUploadAlbum = ref.read(metadataProvider).appConfig.backup.syncAlbums;
|
||||||
final selectedAlbums = ref
|
final selectedAlbums = ref
|
||||||
.read(backupAlbumProvider)
|
.read(backupAlbumProvider)
|
||||||
.where((a) => a.backupSelection == BackupSelection.selected)
|
.where((a) => a.backupSelection == BackupSelection.selected)
|
||||||
@@ -103,7 +103,7 @@ class _DriftBackupAlbumSelectionPageState extends ConsumerState<DriftBackupAlbum
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final isBackupEnabled = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup);
|
final isBackupEnabled = MetadataRepository.instance.appConfig.backup.enabled;
|
||||||
await ref.read(driftBackupProvider.notifier).getBackupStatus(user.id);
|
await ref.read(driftBackupProvider.notifier).getBackupStatus(user.id);
|
||||||
final currentTotalAssetCount = ref.read(driftBackupProvider.select((p) => p.totalCount));
|
final currentTotalAssetCount = ref.read(driftBackupProvider.select((p) => p.totalCount));
|
||||||
final totalChanged = currentTotalAssetCount != _initialTotalAssetCount;
|
final totalChanged = currentTotalAssetCount != _initialTotalAssetCount;
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ import 'dart:async';
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/widgets/settings/backup_settings/drift_backup_settings.dart';
|
import 'package:immich_mobile/widgets/settings/backup_settings/drift_backup_settings.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
@@ -21,18 +19,20 @@ class DriftBackupOptionsPage extends ConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
bool hasPopped = false;
|
bool hasPopped = false;
|
||||||
final previousWifiReqForVideos = Store.tryGet(StoreKey.useWifiForUploadVideos) ?? false;
|
final previousBackup = ref.read(metadataProvider).appConfig.backup;
|
||||||
final previousWifiReqForPhotos = Store.tryGet(StoreKey.useWifiForUploadPhotos) ?? false;
|
final previousCellularForVideos = previousBackup.useCellularForVideos;
|
||||||
|
final previousCellularForPhotos = previousBackup.useCellularForPhotos;
|
||||||
return PopScope(
|
return PopScope(
|
||||||
onPopInvokedWithResult: (didPop, result) async {
|
onPopInvokedWithResult: (didPop, result) async {
|
||||||
// There is an issue with Flutter where the pop event
|
// There is an issue with Flutter where the pop event
|
||||||
// can be triggered multiple times, so we guard it with _hasPopped
|
// can be triggered multiple times, so we guard it with _hasPopped
|
||||||
|
|
||||||
final currentWifiReqForVideos = Store.tryGet(StoreKey.useWifiForUploadVideos) ?? false;
|
final currentBackup = ref.read(metadataProvider).appConfig.backup;
|
||||||
final currentWifiReqForPhotos = Store.tryGet(StoreKey.useWifiForUploadPhotos) ?? false;
|
final currentCellularForVideos = currentBackup.useCellularForVideos;
|
||||||
|
final currentCellularForPhotos = currentBackup.useCellularForPhotos;
|
||||||
|
|
||||||
if (currentWifiReqForVideos == previousWifiReqForVideos &&
|
if (currentCellularForVideos == previousCellularForVideos &&
|
||||||
currentWifiReqForPhotos == previousWifiReqForPhotos) {
|
currentCellularForPhotos == previousCellularForPhotos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ class DriftBackupOptionsPage extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id);
|
await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id);
|
||||||
final isBackupEnabled = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup);
|
final isBackupEnabled = MetadataRepository.instance.appConfig.backup.enabled;
|
||||||
if (!isBackupEnabled) {
|
if (!isBackupEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
|||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
||||||
import 'package:immich_mobile/generated/translations.g.dart';
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
@@ -340,7 +341,7 @@ class SplashScreenPageState extends ConsumerState<SplashScreenPage> {
|
|||||||
await backgroundManager.hashAssets();
|
await backgroundManager.hashAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Store.get(StoreKey.syncAlbums, false)) {
|
if (MetadataRepository.instance.appConfig.backup.syncAlbums) {
|
||||||
await backgroundManager.syncLinkedAlbum();
|
await backgroundManager.syncLinkedAlbum();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -369,7 +370,7 @@ class SplashScreenPageState extends ConsumerState<SplashScreenPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _resumeBackup(DriftBackupNotifier notifier) async {
|
Future<void> _resumeBackup(DriftBackupNotifier notifier) async {
|
||||||
final isEnableBackup = Store.get(StoreKey.enableBackup, false);
|
final isEnableBackup = MetadataRepository.instance.appConfig.backup.enabled;
|
||||||
|
|
||||||
if (isEnableBackup) {
|
if (isEnableBackup) {
|
||||||
final currentUser = Store.tryGet(StoreKey.currentUser);
|
final currentUser = Store.tryGet(StoreKey.currentUser);
|
||||||
|
|||||||
Generated
+19
@@ -309,4 +309,23 @@ class NetworkApi {
|
|||||||
|
|
||||||
_extractReplyValueOrThrow(pigeonVar_replyList, pigeonVar_channelName, isNullValid: true);
|
_extractReplyValueOrThrow(pigeonVar_replyList, pigeonVar_channelName, isNullValid: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> getAppGroupId() async {
|
||||||
|
final pigeonVar_channelName =
|
||||||
|
'dev.flutter.pigeon.immich_mobile.NetworkApi.getAppGroupId$pigeonVar_messageChannelSuffix';
|
||||||
|
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||||
|
pigeonVar_channelName,
|
||||||
|
pigeonChannelCodec,
|
||||||
|
binaryMessenger: pigeonVar_binaryMessenger,
|
||||||
|
);
|
||||||
|
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||||
|
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||||
|
|
||||||
|
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
|
||||||
|
pigeonVar_replyList,
|
||||||
|
pigeonVar_channelName,
|
||||||
|
isNullValid: false,
|
||||||
|
);
|
||||||
|
return pigeonVar_replyValue! as String;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_key.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
|
|
||||||
class BackupToggleButton extends ConsumerStatefulWidget {
|
class BackupToggleButton extends ConsumerStatefulWidget {
|
||||||
final VoidCallback onStart;
|
final VoidCallback onStart;
|
||||||
@@ -31,7 +31,7 @@ class BackupToggleButtonState extends ConsumerState<BackupToggleButton> with Sin
|
|||||||
end: 1,
|
end: 1,
|
||||||
).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
|
).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
|
||||||
|
|
||||||
_isEnabled = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup);
|
_isEnabled = ref.read(metadataProvider).appConfig.backup.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -41,7 +41,7 @@ class BackupToggleButtonState extends ConsumerState<BackupToggleButton> with Sin
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onToggle(bool value) async {
|
Future<void> _onToggle(bool value) async {
|
||||||
await ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.enableBackup, value);
|
await ref.read(metadataProvider).write(MetadataKey.backupEnabled, value);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isEnabled = value;
|
_isEnabled = value;
|
||||||
|
|||||||
@@ -5,16 +5,15 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
|||||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
import 'package:immich_mobile/providers/notification_permission.provider.dart';
|
import 'package:immich_mobile/providers/notification_permission.provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/providers/websocket.provider.dart';
|
import 'package:immich_mobile/providers/websocket.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
enum AppLifeCycleEnum { active, inactive, paused, resumed, detached, hidden }
|
enum AppLifeCycleEnum { active, inactive, paused, resumed, detached, hidden }
|
||||||
@@ -108,7 +107,7 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
|||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
|
||||||
final backgroundManager = _ref.read(backgroundSyncProvider);
|
final backgroundManager = _ref.read(backgroundSyncProvider);
|
||||||
final isAlbumLinkedSyncEnable = _ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums);
|
final isAlbumLinkedSyncEnable = _ref.read(metadataProvider).appConfig.backup.syncAlbums;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bool syncSuccess = false;
|
bool syncSuccess = false;
|
||||||
@@ -138,7 +137,7 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _resumeBackup() async {
|
Future<void> _resumeBackup() async {
|
||||||
final isEnableBackup = _ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup);
|
final isEnableBackup = _ref.read(metadataProvider).appConfig.backup.enabled;
|
||||||
|
|
||||||
if (isEnableBackup) {
|
if (isEnableBackup) {
|
||||||
final currentUser = Store.tryGet(StoreKey.currentUser);
|
final currentUser = Store.tryGet(StoreKey.currentUser);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:immich_mobile/infrastructure/repositories/network.repository.dar
|
|||||||
import 'package:immich_mobile/models/server_info/server_version.model.dart';
|
import 'package:immich_mobile/models/server_info/server_version.model.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/utils/debounce.dart';
|
import 'package:immich_mobile/utils/debounce.dart';
|
||||||
import 'package:immich_mobile/utils/debug_print.dart';
|
import 'package:immich_mobile/utils/debug_print.dart';
|
||||||
@@ -192,7 +193,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final isSyncAlbumEnabled = Store.get(StoreKey.syncAlbums, false);
|
final isSyncAlbumEnabled = _ref.read(metadataProvider).appConfig.backup.syncAlbums;
|
||||||
try {
|
try {
|
||||||
unawaited(
|
unawaited(
|
||||||
_ref.read(backgroundSyncProvider).syncWebsocketBatchV1(_batchedAssetUploadReady.toList()).then((_) {
|
_ref.read(backgroundSyncProvider).syncWebsocketBatchV1(_batchedAssetUploadReady.toList()).then((_) {
|
||||||
@@ -213,7 +214,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final isSyncAlbumEnabled = Store.get(StoreKey.syncAlbums, false);
|
final isSyncAlbumEnabled = _ref.read(metadataProvider).appConfig.backup.syncAlbums;
|
||||||
try {
|
try {
|
||||||
unawaited(
|
unawaited(
|
||||||
_ref.read(backgroundSyncProvider).syncWebsocketBatchV2(_batchedAssetUploadReady.toList()).then((_) {
|
_ref.read(backgroundSyncProvider).syncWebsocketBatchV2(_batchedAssetUploadReady.toList()).then((_) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:home_widget/home_widget.dart';
|
import 'package:home_widget/home_widget.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
|
|
||||||
final widgetRepositoryProvider = Provider((_) => const WidgetRepository());
|
final widgetRepositoryProvider = Provider((_) => const WidgetRepository());
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ class WidgetRepository {
|
|||||||
await HomeWidget.updateWidget(iOSName: iosName, qualifiedAndroidName: androidName);
|
await HomeWidget.updateWidget(iOSName: iosName, qualifiedAndroidName: androidName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setAppGroupId(String appGroupId) async {
|
Future<void> setAppGroupId() async {
|
||||||
await HomeWidget.setAppGroupId(appGroupId);
|
await HomeWidget.setAppGroupId(await networkApi.getAppGroupId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,7 @@ enum AppSettingsEnum<T> {
|
|||||||
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),
|
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),
|
||||||
manageLocalMediaAndroid<bool>(StoreKey.manageLocalMediaAndroid, null, false),
|
manageLocalMediaAndroid<bool>(StoreKey.manageLocalMediaAndroid, null, false),
|
||||||
enableHapticFeedback<bool>(StoreKey.enableHapticFeedback, null, true),
|
enableHapticFeedback<bool>(StoreKey.enableHapticFeedback, null, true),
|
||||||
syncAlbums<bool>(StoreKey.syncAlbums, null, false),
|
readonlyModeEnabled<bool>(StoreKey.readonlyModeEnabled, "readonlyModeEnabled", false);
|
||||||
enableBackup<bool>(StoreKey.enableBackup, null, false),
|
|
||||||
useCellularForUploadVideos<bool>(StoreKey.useWifiForUploadVideos, null, false),
|
|
||||||
useCellularForUploadPhotos<bool>(StoreKey.useWifiForUploadPhotos, null, false),
|
|
||||||
readonlyModeEnabled<bool>(StoreKey.readonlyModeEnabled, "readonlyModeEnabled", false),
|
|
||||||
backupRequireCharging<bool>(StoreKey.backupRequireCharging, null, false),
|
|
||||||
backupTriggerDelay<int>(StoreKey.backupTriggerDelay, null, 30);
|
|
||||||
|
|
||||||
const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue);
|
const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue);
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_key.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/utils/background_sync.dart';
|
import 'package:immich_mobile/domain/utils/background_sync.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
||||||
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
|
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
|
||||||
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/auth.repository.dart';
|
import 'package:immich_mobile/repositories/auth.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/auth_api.repository.dart';
|
import 'package:immich_mobile/repositories/auth_api.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/services/network.service.dart';
|
import 'package:immich_mobile/services/network.service.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
@@ -25,7 +25,6 @@ final authServiceProvider = Provider(
|
|||||||
ref.watch(apiServiceProvider),
|
ref.watch(apiServiceProvider),
|
||||||
ref.watch(networkServiceProvider),
|
ref.watch(networkServiceProvider),
|
||||||
ref.watch(backgroundSyncProvider),
|
ref.watch(backgroundSyncProvider),
|
||||||
ref.watch(appSettingsServiceProvider),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ class AuthService {
|
|||||||
final ApiService _apiService;
|
final ApiService _apiService;
|
||||||
final NetworkService _networkService;
|
final NetworkService _networkService;
|
||||||
final BackgroundSyncManager _backgroundSyncManager;
|
final BackgroundSyncManager _backgroundSyncManager;
|
||||||
final AppSettingsService _appSettingsService;
|
|
||||||
final _log = Logger("AuthService");
|
final _log = Logger("AuthService");
|
||||||
|
|
||||||
AuthService(
|
AuthService(
|
||||||
@@ -44,7 +42,6 @@ class AuthService {
|
|||||||
this._apiService,
|
this._apiService,
|
||||||
this._networkService,
|
this._networkService,
|
||||||
this._backgroundSyncManager,
|
this._backgroundSyncManager,
|
||||||
this._appSettingsService,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Validates the provided server URL by resolving and setting the endpoint.
|
/// Validates the provided server URL by resolving and setting the endpoint.
|
||||||
@@ -103,7 +100,7 @@ class AuthService {
|
|||||||
_log.severe("Error clearing local data", error, stackTrace);
|
_log.severe("Error clearing local data", error, stackTrace);
|
||||||
});
|
});
|
||||||
|
|
||||||
await _appSettingsService.setSetting(AppSettingsEnum.enableBackup, false);
|
await MetadataRepository.instance.write(MetadataKey.backupEnabled, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,13 @@ import 'package:immich_mobile/entities/store.entity.dart';
|
|||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/upload.repository.dart';
|
import 'package:immich_mobile/repositories/upload.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/utils/debug_print.dart';
|
import 'package:immich_mobile/utils/debug_print.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
@@ -31,7 +30,6 @@ final backgroundUploadServiceProvider = Provider((ref) {
|
|||||||
ref.watch(storageRepositoryProvider),
|
ref.watch(storageRepositoryProvider),
|
||||||
ref.watch(localAssetRepository),
|
ref.watch(localAssetRepository),
|
||||||
ref.watch(backupRepositoryProvider),
|
ref.watch(backupRepositoryProvider),
|
||||||
ref.watch(appSettingsServiceProvider),
|
|
||||||
ref.watch(assetMediaRepositoryProvider),
|
ref.watch(assetMediaRepositoryProvider),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -105,7 +103,6 @@ class BackgroundUploadService {
|
|||||||
this._storageRepository,
|
this._storageRepository,
|
||||||
this._localAssetRepository,
|
this._localAssetRepository,
|
||||||
this._backupRepository,
|
this._backupRepository,
|
||||||
this._appSettingsService,
|
|
||||||
this._assetMediaRepository,
|
this._assetMediaRepository,
|
||||||
) {
|
) {
|
||||||
_uploadRepository.onUploadStatus = _onUploadCallback;
|
_uploadRepository.onUploadStatus = _onUploadCallback;
|
||||||
@@ -116,7 +113,6 @@ class BackgroundUploadService {
|
|||||||
final StorageRepository _storageRepository;
|
final StorageRepository _storageRepository;
|
||||||
final DriftLocalAssetRepository _localAssetRepository;
|
final DriftLocalAssetRepository _localAssetRepository;
|
||||||
final DriftBackupRepository _backupRepository;
|
final DriftBackupRepository _backupRepository;
|
||||||
final AppSettingsService _appSettingsService;
|
|
||||||
final AssetMediaRepository _assetMediaRepository;
|
final AssetMediaRepository _assetMediaRepository;
|
||||||
final Logger _logger = Logger('BackgroundUploadService');
|
final Logger _logger = Logger('BackgroundUploadService');
|
||||||
|
|
||||||
@@ -363,15 +359,14 @@ class BackgroundUploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool _shouldRequireWiFi(LocalAsset asset) {
|
bool _shouldRequireWiFi(LocalAsset asset) {
|
||||||
bool requiresWiFi = true;
|
final backup = MetadataRepository.instance.appConfig.backup;
|
||||||
|
if (asset.isVideo && backup.useCellularForVideos) {
|
||||||
if (asset.isVideo && _appSettingsService.getSetting(AppSettingsEnum.useCellularForUploadVideos)) {
|
return false;
|
||||||
requiresWiFi = false;
|
|
||||||
} else if (!asset.isVideo && _appSettingsService.getSetting(AppSettingsEnum.useCellularForUploadPhotos)) {
|
|
||||||
requiresWiFi = false;
|
|
||||||
}
|
}
|
||||||
|
if (!asset.isVideo && backup.useCellularForPhotos) {
|
||||||
return requiresWiFi;
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<UploadTask> buildUploadTask(
|
Future<UploadTask> buildUploadTask(
|
||||||
|
|||||||
@@ -7,18 +7,17 @@ import 'package:immich_mobile/domain/models/asset/asset_metadata.model.dart';
|
|||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
|
||||||
import 'package:immich_mobile/extensions/network_capability_extensions.dart';
|
import 'package:immich_mobile/extensions/network_capability_extensions.dart';
|
||||||
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
||||||
import 'package:immich_mobile/platform/connectivity_api.g.dart';
|
import 'package:immich_mobile/platform/connectivity_api.g.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/upload.repository.dart';
|
import 'package:immich_mobile/repositories/upload.repository.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:photo_manager/photo_manager.dart' show PMProgressHandler;
|
import 'package:photo_manager/photo_manager.dart' show PMProgressHandler;
|
||||||
@@ -39,7 +38,6 @@ final foregroundUploadServiceProvider = Provider((ref) {
|
|||||||
ref.watch(storageRepositoryProvider),
|
ref.watch(storageRepositoryProvider),
|
||||||
ref.watch(backupRepositoryProvider),
|
ref.watch(backupRepositoryProvider),
|
||||||
ref.watch(connectivityApiProvider),
|
ref.watch(connectivityApiProvider),
|
||||||
ref.watch(appSettingsServiceProvider),
|
|
||||||
ref.watch(assetMediaRepositoryProvider),
|
ref.watch(assetMediaRepositoryProvider),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -55,7 +53,6 @@ class ForegroundUploadService {
|
|||||||
this._storageRepository,
|
this._storageRepository,
|
||||||
this._backupRepository,
|
this._backupRepository,
|
||||||
this._connectivityApi,
|
this._connectivityApi,
|
||||||
this._appSettingsService,
|
|
||||||
this._assetMediaRepository,
|
this._assetMediaRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -63,7 +60,6 @@ class ForegroundUploadService {
|
|||||||
final StorageRepository _storageRepository;
|
final StorageRepository _storageRepository;
|
||||||
final DriftBackupRepository _backupRepository;
|
final DriftBackupRepository _backupRepository;
|
||||||
final ConnectivityApi _connectivityApi;
|
final ConnectivityApi _connectivityApi;
|
||||||
final AppSettingsService _appSettingsService;
|
|
||||||
final AssetMediaRepository _assetMediaRepository;
|
final AssetMediaRepository _assetMediaRepository;
|
||||||
final Logger _logger = Logger('ForegroundUploadService');
|
final Logger _logger = Logger('ForegroundUploadService');
|
||||||
|
|
||||||
@@ -455,14 +451,13 @@ class ForegroundUploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool _shouldRequireWiFi(LocalAsset asset) {
|
bool _shouldRequireWiFi(LocalAsset asset) {
|
||||||
bool requiresWiFi = true;
|
final backup = MetadataRepository.instance.appConfig.backup;
|
||||||
|
if (asset.isVideo && backup.useCellularForVideos) {
|
||||||
if (asset.isVideo && _appSettingsService.getSetting(AppSettingsEnum.useCellularForUploadVideos)) {
|
return false;
|
||||||
requiresWiFi = false;
|
|
||||||
} else if (!asset.isVideo && _appSettingsService.getSetting(AppSettingsEnum.useCellularForUploadPhotos)) {
|
|
||||||
requiresWiFi = false;
|
|
||||||
}
|
}
|
||||||
|
if (!asset.isVideo && backup.useCellularForPhotos) {
|
||||||
return requiresWiFi;
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class WidgetService {
|
|||||||
const WidgetService(this._repository);
|
const WidgetService(this._repository);
|
||||||
|
|
||||||
Future<void> writeCredentials(String serverURL, String sessionKey, String? customHeaders) async {
|
Future<void> writeCredentials(String serverURL, String sessionKey, String? customHeaders) async {
|
||||||
await _repository.setAppGroupId(appShareGroupId);
|
await _repository.setAppGroupId();
|
||||||
await _repository.saveData(kWidgetServerEndpoint, serverURL);
|
await _repository.saveData(kWidgetServerEndpoint, serverURL);
|
||||||
await _repository.saveData(kWidgetAuthToken, sessionKey);
|
await _repository.saveData(kWidgetAuthToken, sessionKey);
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ class WidgetService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clearCredentials() async {
|
Future<void> clearCredentials() async {
|
||||||
await _repository.setAppGroupId(appShareGroupId);
|
await _repository.setAppGroupId();
|
||||||
await _repository.saveData(kWidgetServerEndpoint, "");
|
await _repository.saveData(kWidgetServerEndpoint, "");
|
||||||
await _repository.saveData(kWidgetAuthToken, "");
|
await _repository.saveData(kWidgetAuthToken, "");
|
||||||
await _repository.saveData(kWidgetCustomHeaders, "");
|
await _repository.saveData(kWidgetCustomHeaders, "");
|
||||||
|
|||||||
@@ -124,6 +124,13 @@ Future<void> _migrateTo26(Drift drift) async {
|
|||||||
await _migrateAlbumSortMode(migrator);
|
await _migrateAlbumSortMode(migrator);
|
||||||
await migrator.migrateBool(StoreKey.legacySelectedAlbumSortReverse, MetadataKey.albumIsReverse);
|
await migrator.migrateBool(StoreKey.legacySelectedAlbumSortReverse, MetadataKey.albumIsReverse);
|
||||||
await migrator.migrateBool(StoreKey.legacyAlbumGridView, MetadataKey.albumIsGrid);
|
await migrator.migrateBool(StoreKey.legacyAlbumGridView, MetadataKey.albumIsGrid);
|
||||||
|
// Backup
|
||||||
|
await migrator.migrateBool(StoreKey.legacyEnableBackup, MetadataKey.backupEnabled);
|
||||||
|
await migrator.migrateBool(StoreKey.legacyUseWifiForUploadVideos, MetadataKey.backupUseCellularForVideos);
|
||||||
|
await migrator.migrateBool(StoreKey.legacyUseWifiForUploadPhotos, MetadataKey.backupUseCellularForPhotos);
|
||||||
|
await migrator.migrateBool(StoreKey.legacyBackupRequireCharging, MetadataKey.backupRequireCharging);
|
||||||
|
await migrator.migrateInt(StoreKey.legacyBackupTriggerDelay, MetadataKey.backupTriggerDelay);
|
||||||
|
await migrator.migrateBool(StoreKey.legacySyncAlbums, MetadataKey.backupSyncAlbums);
|
||||||
await migrator.complete();
|
await migrator.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/setting.model.dart';
|
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/cast.provider.dart';
|
import 'package:immich_mobile/providers/cast.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/providers/sync_status.provider.dart';
|
import 'package:immich_mobile/providers/sync_status.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
@@ -193,64 +192,51 @@ class _BackupIndicator extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget? _getBackupBadgeIcon(BuildContext context, WidgetRef ref) {
|
Widget? _getBackupBadgeIcon(BuildContext context, WidgetRef ref) {
|
||||||
final backupStateStream = ref.watch(settingsProvider).watch(Setting.enableBackup);
|
final backupEnabled = ref.watch(appConfigProvider.select((c) => c.backup.enabled));
|
||||||
final hasError = ref.watch(driftBackupProvider.select((state) => state.error != BackupError.none));
|
final hasError = ref.watch(driftBackupProvider.select((state) => state.error != BackupError.none));
|
||||||
final isDarkTheme = context.isDarkTheme;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
final iconColor = isDarkTheme ? Colors.white : Colors.black;
|
final iconColor = isDarkTheme ? Colors.white : Colors.black;
|
||||||
final isUploading = ref.watch(driftBackupProvider.select((state) => state.uploadItems.isNotEmpty));
|
final isUploading = ref.watch(driftBackupProvider.select((state) => state.uploadItems.isNotEmpty));
|
||||||
|
|
||||||
return StreamBuilder(
|
if (!backupEnabled) {
|
||||||
stream: backupStateStream,
|
return _BadgeLabel(
|
||||||
initialData: false,
|
Icon(Icons.cloud_off_rounded, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr()),
|
||||||
builder: (ctx, snapshot) {
|
);
|
||||||
final backupEnabled = snapshot.data ?? false;
|
}
|
||||||
|
|
||||||
if (!backupEnabled) {
|
if (hasError) {
|
||||||
return _BadgeLabel(
|
return _BadgeLabel(
|
||||||
Icon(
|
Icon(
|
||||||
Icons.cloud_off_rounded,
|
Icons.warning_rounded,
|
||||||
size: 9,
|
size: 12,
|
||||||
color: iconColor,
|
color: context.colorScheme.error,
|
||||||
semanticLabel: 'backup_controller_page_backup'.tr(),
|
semanticLabel: 'backup_controller_page_backup'.tr(),
|
||||||
|
),
|
||||||
|
backgroundColor: context.colorScheme.errorContainer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUploading) {
|
||||||
|
return _BadgeLabel(
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(3.5),
|
||||||
|
child: Theme(
|
||||||
|
data: context.themeData.copyWith(
|
||||||
|
progressIndicatorTheme: context.themeData.progressIndicatorTheme.copyWith(year2023: true),
|
||||||
),
|
),
|
||||||
);
|
child: CircularProgressIndicator(
|
||||||
}
|
strokeWidth: 2,
|
||||||
|
strokeCap: StrokeCap.round,
|
||||||
if (hasError) {
|
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
|
||||||
return _BadgeLabel(
|
semanticsLabel: 'backup_controller_page_backup'.tr(),
|
||||||
Icon(
|
|
||||||
Icons.warning_rounded,
|
|
||||||
size: 12,
|
|
||||||
color: context.colorScheme.error,
|
|
||||||
semanticLabel: 'backup_controller_page_backup'.tr(),
|
|
||||||
),
|
),
|
||||||
backgroundColor: context.colorScheme.errorContainer,
|
),
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isUploading) {
|
return _BadgeLabel(
|
||||||
return _BadgeLabel(
|
Icon(Icons.check_outlined, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr()),
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(3.5),
|
|
||||||
child: Theme(
|
|
||||||
data: context.themeData.copyWith(
|
|
||||||
progressIndicatorTheme: context.themeData.progressIndicatorTheme.copyWith(year2023: true),
|
|
||||||
),
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2,
|
|
||||||
strokeCap: StrokeCap.round,
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
|
|
||||||
semanticsLabel: 'backup_controller_page_backup'.tr(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _BadgeLabel(
|
|
||||||
Icon(Icons.check_outlined, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr()),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
|||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||||
@@ -186,7 +187,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
await backgroundManager.syncRemote();
|
await backgroundManager.syncRemote();
|
||||||
await backgroundManager.hashAssets();
|
await backgroundManager.hashAssets();
|
||||||
|
|
||||||
if (Store.get(StoreKey.syncAlbums, false)) {
|
if (MetadataRepository.instance.appConfig.backup.syncAlbums) {
|
||||||
await backgroundManager.syncLinkedAlbum();
|
await backgroundManager.syncLinkedAlbum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,17 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/config/app_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_key.dart';
|
||||||
import 'package:immich_mobile/domain/services/sync_linked_album.service.dart';
|
import 'package:immich_mobile/domain/services/sync_linked_album.service.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/backup_album.provider.dart';
|
import 'package:immich_mobile/providers/backup/backup_album.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
|
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/setting_list_tile.dart';
|
import 'package:immich_mobile/widgets/settings/setting_list_tile.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
||||||
@@ -31,8 +30,8 @@ class DriftBackupSettings extends ConsumerWidget {
|
|||||||
title: "network_requirements".t(context: context),
|
title: "network_requirements".t(context: context),
|
||||||
icon: Icons.cell_tower,
|
icon: Icons.cell_tower,
|
||||||
),
|
),
|
||||||
const _UseWifiForUploadVideosButton(),
|
const _UseCellularForVideosButton(),
|
||||||
const _UseWifiForUploadPhotosButton(),
|
const _UseCellularForPhotosButton(),
|
||||||
if (CurrentPlatform.isAndroid) ...[
|
if (CurrentPlatform.isAndroid) ...[
|
||||||
const Divider(),
|
const Divider(),
|
||||||
SettingGroupTitle(
|
SettingGroupTitle(
|
||||||
@@ -99,64 +98,58 @@ class _AlbumSyncActionButtonState extends ConsumerState<_AlbumSyncActionButton>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final albumSyncEnable = ref.watch(appConfigProvider.select((c) => c.backup.syncAlbums));
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 8.0),
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
StreamBuilder(
|
Column(
|
||||||
stream: Store.watch(StoreKey.syncAlbums),
|
children: [
|
||||||
initialData: Store.tryGet(StoreKey.syncAlbums) ?? false,
|
SettingListTile(
|
||||||
builder: (context, snapshot) {
|
title: "sync_albums".t(context: context),
|
||||||
final albumSyncEnable = snapshot.data ?? false;
|
subtitle: "sync_upload_album_setting_subtitle".t(context: context),
|
||||||
return Column(
|
trailing: Switch(
|
||||||
children: [
|
value: albumSyncEnable,
|
||||||
SettingListTile(
|
onChanged: (bool newValue) async {
|
||||||
title: "sync_albums".t(context: context),
|
await ref.read(metadataProvider).write(MetadataKey.backupSyncAlbums, newValue);
|
||||||
subtitle: "sync_upload_album_setting_subtitle".t(context: context),
|
|
||||||
trailing: Switch(
|
|
||||||
value: albumSyncEnable,
|
|
||||||
onChanged: (bool newValue) async {
|
|
||||||
await ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.syncAlbums, newValue);
|
|
||||||
|
|
||||||
if (newValue == true) {
|
if (newValue == true) {
|
||||||
await _manageLinkedAlbums();
|
await _manageLinkedAlbums();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
AnimatedSize(
|
AnimatedSize(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
opacity: albumSyncEnable ? 1.0 : 0.0,
|
opacity: albumSyncEnable ? 1.0 : 0.0,
|
||||||
child: albumSyncEnable
|
child: albumSyncEnable
|
||||||
? SettingListTile(
|
? SettingListTile(
|
||||||
onTap: _manualSyncAlbums,
|
onTap: _manualSyncAlbums,
|
||||||
contentPadding: const EdgeInsets.only(left: 32, right: 16),
|
contentPadding: const EdgeInsets.only(left: 32, right: 16),
|
||||||
title: "organize_into_albums".t(context: context),
|
title: "organize_into_albums".t(context: context),
|
||||||
subtitle: "organize_into_albums_description".t(context: context),
|
subtitle: "organize_into_albums_description".t(context: context),
|
||||||
trailing: isAlbumSyncInProgress
|
trailing: isAlbumSyncInProgress
|
||||||
? const SizedBox(
|
? const SizedBox(
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||||
)
|
)
|
||||||
: IconButton(
|
: IconButton(
|
||||||
onPressed: _manualSyncAlbums,
|
onPressed: _manualSyncAlbums,
|
||||||
icon: const Icon(Icons.sync_rounded),
|
icon: const Icon(Icons.sync_rounded),
|
||||||
color: context.colorScheme.onSurface.withValues(alpha: 0.7),
|
color: context.colorScheme.onSurface.withValues(alpha: 0.7),
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
|
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -164,60 +157,34 @@ class _AlbumSyncActionButtonState extends ConsumerState<_AlbumSyncActionButton>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsSwitchTile extends ConsumerStatefulWidget {
|
class _BackupSwitchTile extends ConsumerWidget {
|
||||||
final AppSettingsEnum<bool> appSettingsEnum;
|
final MetadataKey<bool> metadataKey;
|
||||||
|
final bool Function(AppConfig) selector;
|
||||||
final String titleKey;
|
final String titleKey;
|
||||||
final String subtitleKey;
|
final String subtitleKey;
|
||||||
final void Function(bool?)? onChanged;
|
final void Function(bool)? onChanged;
|
||||||
|
|
||||||
const _SettingsSwitchTile({
|
const _BackupSwitchTile({
|
||||||
required this.appSettingsEnum,
|
required this.metadataKey,
|
||||||
|
required this.selector,
|
||||||
required this.titleKey,
|
required this.titleKey,
|
||||||
required this.subtitleKey,
|
required this.subtitleKey,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState createState() => _SettingsSwitchTileState();
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
}
|
final value = ref.watch(appConfigProvider.select(selector));
|
||||||
|
|
||||||
class _SettingsSwitchTileState extends ConsumerState<_SettingsSwitchTile> {
|
|
||||||
late final Stream<bool?> valueStream;
|
|
||||||
late final StreamSubscription<bool?> subscription;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
valueStream = Store.watch(widget.appSettingsEnum.storeKey).asBroadcastStream();
|
|
||||||
subscription = valueStream.listen((value) {
|
|
||||||
widget.onChanged?.call(value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
subscription.cancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 8.0),
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
child: SettingListTile(
|
child: SettingListTile(
|
||||||
title: widget.titleKey.t(context: context),
|
title: titleKey.t(context: context),
|
||||||
subtitle: widget.subtitleKey.t(context: context),
|
subtitle: subtitleKey.t(context: context),
|
||||||
trailing: StreamBuilder(
|
trailing: Switch(
|
||||||
stream: valueStream,
|
value: value,
|
||||||
initialData: Store.tryGet(widget.appSettingsEnum.storeKey) ?? widget.appSettingsEnum.defaultValue,
|
onChanged: (bool newValue) async {
|
||||||
builder: (context, snapshot) {
|
await ref.read(metadataProvider).write(metadataKey, newValue);
|
||||||
final value = snapshot.data ?? false;
|
onChanged?.call(newValue);
|
||||||
return Switch(
|
|
||||||
value: value,
|
|
||||||
onChanged: (bool newValue) async {
|
|
||||||
await ref.read(appSettingsServiceProvider).setSetting(widget.appSettingsEnum, newValue);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -225,26 +192,28 @@ class _SettingsSwitchTileState extends ConsumerState<_SettingsSwitchTile> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UseWifiForUploadVideosButton extends ConsumerWidget {
|
class _UseCellularForVideosButton extends StatelessWidget {
|
||||||
const _UseWifiForUploadVideosButton();
|
const _UseCellularForVideosButton();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context) {
|
||||||
return const _SettingsSwitchTile(
|
return _BackupSwitchTile(
|
||||||
appSettingsEnum: AppSettingsEnum.useCellularForUploadVideos,
|
metadataKey: MetadataKey.backupUseCellularForVideos,
|
||||||
|
selector: (c) => c.backup.useCellularForVideos,
|
||||||
titleKey: "videos",
|
titleKey: "videos",
|
||||||
subtitleKey: "network_requirement_videos_upload",
|
subtitleKey: "network_requirement_videos_upload",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UseWifiForUploadPhotosButton extends ConsumerWidget {
|
class _UseCellularForPhotosButton extends StatelessWidget {
|
||||||
const _UseWifiForUploadPhotosButton();
|
const _UseCellularForPhotosButton();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context) {
|
||||||
return const _SettingsSwitchTile(
|
return _BackupSwitchTile(
|
||||||
appSettingsEnum: AppSettingsEnum.useCellularForUploadPhotos,
|
metadataKey: MetadataKey.backupUseCellularForPhotos,
|
||||||
|
selector: (c) => c.backup.useCellularForPhotos,
|
||||||
titleKey: "photos",
|
titleKey: "photos",
|
||||||
subtitleKey: "network_requirement_photos_upload",
|
subtitleKey: "network_requirement_photos_upload",
|
||||||
);
|
);
|
||||||
@@ -256,29 +225,22 @@ class _BackupOnlyWhenChargingButton extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return _SettingsSwitchTile(
|
final fgService = ref.read(backgroundWorkerFgServiceProvider);
|
||||||
appSettingsEnum: AppSettingsEnum.backupRequireCharging,
|
return _BackupSwitchTile(
|
||||||
|
metadataKey: MetadataKey.backupRequireCharging,
|
||||||
|
selector: (c) => c.backup.requireCharging,
|
||||||
titleKey: "charging",
|
titleKey: "charging",
|
||||||
subtitleKey: "charging_requirement_mobile_backup",
|
subtitleKey: "charging_requirement_mobile_backup",
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
ref.read(backgroundWorkerFgServiceProvider).configure(requireCharging: value ?? false);
|
fgService.configure(requireCharging: value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BackupDelaySlider extends ConsumerStatefulWidget {
|
class _BackupDelaySlider extends ConsumerWidget {
|
||||||
const _BackupDelaySlider();
|
const _BackupDelaySlider();
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<_BackupDelaySlider> createState() => _BackupDelaySliderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BackupDelaySliderState extends ConsumerState<_BackupDelaySlider> {
|
|
||||||
late final Stream<int?> valueStream;
|
|
||||||
late final StreamSubscription<int?> subscription;
|
|
||||||
late int currentValue;
|
|
||||||
|
|
||||||
static int backupDelayToSliderValue(int ms) => switch (ms) {
|
static int backupDelayToSliderValue(int ms) => switch (ms) {
|
||||||
5 => 0,
|
5 => 0,
|
||||||
30 => 1,
|
30 => 1,
|
||||||
@@ -301,30 +263,9 @@ class _BackupDelaySliderState extends ConsumerState<_BackupDelaySlider> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
super.initState();
|
final triggerDelay = ref.watch(appConfigProvider.select((c) => c.backup.triggerDelay));
|
||||||
final initialValue =
|
final currentValue = backupDelayToSliderValue(triggerDelay);
|
||||||
Store.tryGet(AppSettingsEnum.backupTriggerDelay.storeKey) ?? AppSettingsEnum.backupTriggerDelay.defaultValue;
|
|
||||||
currentValue = backupDelayToSliderValue(initialValue);
|
|
||||||
|
|
||||||
valueStream = Store.watch(AppSettingsEnum.backupTriggerDelay.storeKey).asBroadcastStream();
|
|
||||||
subscription = valueStream.listen((value) {
|
|
||||||
if (mounted && value != null) {
|
|
||||||
setState(() {
|
|
||||||
currentValue = backupDelayToSliderValue(value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
subscription.cancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -339,14 +280,13 @@ class _BackupDelaySliderState extends ConsumerState<_BackupDelaySlider> {
|
|||||||
),
|
),
|
||||||
Slider(
|
Slider(
|
||||||
value: currentValue.toDouble(),
|
value: currentValue.toDouble(),
|
||||||
onChanged: (double v) {
|
onChanged: (double v) async {
|
||||||
setState(() {
|
final seconds = backupDelayToSeconds(v.toInt());
|
||||||
currentValue = v.toInt();
|
await ref.read(metadataProvider).write(MetadataKey.backupTriggerDelay, seconds);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
onChangeEnd: (double v) async {
|
onChangeEnd: (double v) async {
|
||||||
final milliseconds = backupDelayToSeconds(v.toInt());
|
final seconds = backupDelayToSeconds(v.toInt());
|
||||||
await ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.backupTriggerDelay, milliseconds);
|
await ref.read(metadataProvider).write(MetadataKey.backupTriggerDelay, seconds);
|
||||||
},
|
},
|
||||||
max: 3.0,
|
max: 3.0,
|
||||||
min: 0.0,
|
min: 0.0,
|
||||||
|
|||||||
+8
-8
@@ -1,26 +1,26 @@
|
|||||||
.PHONY: build watch create_app_icon create_splash build_release_android pigeon test analyze format migration translation
|
.PHONY: build watch create_app_icon create_splash build_release_android pigeon test analyze format migration translation
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@printf "This command has been removed. Please use:\n\n mise codegen # or mise //:mobile:codegen:dart from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise codegen # or mise //mobile:codegen:dart from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
pigeon:
|
pigeon:
|
||||||
@printf "This command has been removed. Please use:\n\n mise pigeon # or mise //:mobile:codegen:pigeon from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise pigeon # or mise //mobile:codegen:pigeon from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
|
|
||||||
build_release_android:
|
build_release_android:
|
||||||
@printf "This command has been removed. Please use:\n\n mise run build:android # or mise //:mobile:build:android from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise run build:android # or mise //mobile:build:android from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
migration:
|
migration:
|
||||||
@printf "This command has been removed. Please use:\n\n mise migration # or mise //:mobile:drift:migration from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise migration # or mise //mobile:drift:migration from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
translation:
|
translation:
|
||||||
@printf "This command has been removed. Please use:\n\n mise translation # or mise //:mobile:codegen:translation from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise translation # or mise //mobile:codegen:translation from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
analyze:
|
analyze:
|
||||||
@printf "This command has been removed. Please use:\n\n mise analyze # or mise //:mobile:lint from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise analyze # or mise //mobile:lint from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@printf "This command has been removed. Please use:\n\n mise format # or mise //:mobile:format from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise format # or mise //mobile:format from another directory\n\n" >&2 && exit 1
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@printf "This command has been removed. Please use:\n\n mise test # or mise //:mobile:test from another directory\n\n" >&2 && exit 1
|
@printf "This command has been removed. Please use:\n\n mise test # or mise //mobile:test from another directory\n\n" >&2 && exit 1
|
||||||
|
|||||||
Generated
+5
@@ -103,12 +103,16 @@ Class | Method | HTTP request | Description
|
|||||||
*AssetsApi* | [**deleteBulkAssetMetadata**](doc//AssetsApi.md#deletebulkassetmetadata) | **DELETE** /assets/metadata | Delete asset metadata
|
*AssetsApi* | [**deleteBulkAssetMetadata**](doc//AssetsApi.md#deletebulkassetmetadata) | **DELETE** /assets/metadata | Delete asset metadata
|
||||||
*AssetsApi* | [**downloadAsset**](doc//AssetsApi.md#downloadasset) | **GET** /assets/{id}/original | Download original asset
|
*AssetsApi* | [**downloadAsset**](doc//AssetsApi.md#downloadasset) | **GET** /assets/{id}/original | Download original asset
|
||||||
*AssetsApi* | [**editAsset**](doc//AssetsApi.md#editasset) | **PUT** /assets/{id}/edits | Apply edits to an existing asset
|
*AssetsApi* | [**editAsset**](doc//AssetsApi.md#editasset) | **PUT** /assets/{id}/edits | Apply edits to an existing asset
|
||||||
|
*AssetsApi* | [**endSession**](doc//AssetsApi.md#endsession) | **DELETE** /assets/{id}/video/stream/{sessionId} | End HLS streaming session
|
||||||
*AssetsApi* | [**getAssetEdits**](doc//AssetsApi.md#getassetedits) | **GET** /assets/{id}/edits | Retrieve edits for an existing asset
|
*AssetsApi* | [**getAssetEdits**](doc//AssetsApi.md#getassetedits) | **GET** /assets/{id}/edits | Retrieve edits for an existing asset
|
||||||
*AssetsApi* | [**getAssetInfo**](doc//AssetsApi.md#getassetinfo) | **GET** /assets/{id} | Retrieve an asset
|
*AssetsApi* | [**getAssetInfo**](doc//AssetsApi.md#getassetinfo) | **GET** /assets/{id} | Retrieve an asset
|
||||||
*AssetsApi* | [**getAssetMetadata**](doc//AssetsApi.md#getassetmetadata) | **GET** /assets/{id}/metadata | Get asset metadata
|
*AssetsApi* | [**getAssetMetadata**](doc//AssetsApi.md#getassetmetadata) | **GET** /assets/{id}/metadata | Get asset metadata
|
||||||
*AssetsApi* | [**getAssetMetadataByKey**](doc//AssetsApi.md#getassetmetadatabykey) | **GET** /assets/{id}/metadata/{key} | Retrieve asset metadata by key
|
*AssetsApi* | [**getAssetMetadataByKey**](doc//AssetsApi.md#getassetmetadatabykey) | **GET** /assets/{id}/metadata/{key} | Retrieve asset metadata by key
|
||||||
*AssetsApi* | [**getAssetOcr**](doc//AssetsApi.md#getassetocr) | **GET** /assets/{id}/ocr | Retrieve asset OCR data
|
*AssetsApi* | [**getAssetOcr**](doc//AssetsApi.md#getassetocr) | **GET** /assets/{id}/ocr | Retrieve asset OCR data
|
||||||
*AssetsApi* | [**getAssetStatistics**](doc//AssetsApi.md#getassetstatistics) | **GET** /assets/statistics | Get asset statistics
|
*AssetsApi* | [**getAssetStatistics**](doc//AssetsApi.md#getassetstatistics) | **GET** /assets/statistics | Get asset statistics
|
||||||
|
*AssetsApi* | [**getMainPlaylist**](doc//AssetsApi.md#getmainplaylist) | **GET** /assets/{id}/video/stream/main.m3u8 | Get HLS main playlist
|
||||||
|
*AssetsApi* | [**getMediaPlaylist**](doc//AssetsApi.md#getmediaplaylist) | **GET** /assets/{id}/video/stream/{sessionId}/{variantIndex}/playlist.m3u8 | Get HLS media playlist
|
||||||
|
*AssetsApi* | [**getSegment**](doc//AssetsApi.md#getsegment) | **GET** /assets/{id}/video/stream/{sessionId}/{variantIndex}/{filename} | Get HLS segment or init file
|
||||||
*AssetsApi* | [**playAssetVideo**](doc//AssetsApi.md#playassetvideo) | **GET** /assets/{id}/video/playback | Play asset video
|
*AssetsApi* | [**playAssetVideo**](doc//AssetsApi.md#playassetvideo) | **GET** /assets/{id}/video/playback | Play asset video
|
||||||
*AssetsApi* | [**removeAssetEdits**](doc//AssetsApi.md#removeassetedits) | **DELETE** /assets/{id}/edits | Remove edits from an existing asset
|
*AssetsApi* | [**removeAssetEdits**](doc//AssetsApi.md#removeassetedits) | **DELETE** /assets/{id}/edits | Remove edits from an existing asset
|
||||||
*AssetsApi* | [**runAssetJobs**](doc//AssetsApi.md#runassetjobs) | **POST** /assets/jobs | Run an asset job
|
*AssetsApi* | [**runAssetJobs**](doc//AssetsApi.md#runassetjobs) | **POST** /assets/jobs | Run an asset job
|
||||||
@@ -594,6 +598,7 @@ Class | Method | HTTP request | Description
|
|||||||
- [SystemConfigBackupsDto](doc//SystemConfigBackupsDto.md)
|
- [SystemConfigBackupsDto](doc//SystemConfigBackupsDto.md)
|
||||||
- [SystemConfigDto](doc//SystemConfigDto.md)
|
- [SystemConfigDto](doc//SystemConfigDto.md)
|
||||||
- [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md)
|
- [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md)
|
||||||
|
- [SystemConfigFFmpegRealtimeDto](doc//SystemConfigFFmpegRealtimeDto.md)
|
||||||
- [SystemConfigFacesDto](doc//SystemConfigFacesDto.md)
|
- [SystemConfigFacesDto](doc//SystemConfigFacesDto.md)
|
||||||
- [SystemConfigGeneratedFullsizeImageDto](doc//SystemConfigGeneratedFullsizeImageDto.md)
|
- [SystemConfigGeneratedFullsizeImageDto](doc//SystemConfigGeneratedFullsizeImageDto.md)
|
||||||
- [SystemConfigGeneratedImageDto](doc//SystemConfigGeneratedImageDto.md)
|
- [SystemConfigGeneratedImageDto](doc//SystemConfigGeneratedImageDto.md)
|
||||||
|
|||||||
Generated
+1
@@ -340,6 +340,7 @@ part 'model/sync_user_v1.dart';
|
|||||||
part 'model/system_config_backups_dto.dart';
|
part 'model/system_config_backups_dto.dart';
|
||||||
part 'model/system_config_dto.dart';
|
part 'model/system_config_dto.dart';
|
||||||
part 'model/system_config_f_fmpeg_dto.dart';
|
part 'model/system_config_f_fmpeg_dto.dart';
|
||||||
|
part 'model/system_config_f_fmpeg_realtime_dto.dart';
|
||||||
part 'model/system_config_faces_dto.dart';
|
part 'model/system_config_faces_dto.dart';
|
||||||
part 'model/system_config_generated_fullsize_image_dto.dart';
|
part 'model/system_config_generated_fullsize_image_dto.dart';
|
||||||
part 'model/system_config_generated_image_dto.dart';
|
part 'model/system_config_generated_image_dto.dart';
|
||||||
|
|||||||
Generated
+310
@@ -416,6 +416,75 @@ class AssetsApi {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// End HLS streaming session
|
||||||
|
///
|
||||||
|
/// Releases server resources for the streaming session.
|
||||||
|
///
|
||||||
|
/// Note: This method returns the HTTP [Response].
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] sessionId (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<Response> endSessionWithHttpInfo(String id, String sessionId, { String? key, String? slug, }) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final apiPath = r'/assets/{id}/video/stream/{sessionId}'
|
||||||
|
.replaceAll('{id}', id)
|
||||||
|
.replaceAll('{sessionId}', sessionId);
|
||||||
|
|
||||||
|
// ignore: prefer_final_locals
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
if (key != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'key', key));
|
||||||
|
}
|
||||||
|
if (slug != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'slug', slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
apiPath,
|
||||||
|
'DELETE',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// End HLS streaming session
|
||||||
|
///
|
||||||
|
/// Releases server resources for the streaming session.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] sessionId (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<void> endSession(String id, String sessionId, { String? key, String? slug, }) async {
|
||||||
|
final response = await endSessionWithHttpInfo(id, sessionId, key: key, slug: slug, );
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve edits for an existing asset
|
/// Retrieve edits for an existing asset
|
||||||
///
|
///
|
||||||
/// Retrieve a series of edit actions (crop, rotate, mirror) associated with the specified asset.
|
/// Retrieve a series of edit actions (crop, rotate, mirror) associated with the specified asset.
|
||||||
@@ -809,6 +878,247 @@ class AssetsApi {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get HLS main playlist
|
||||||
|
///
|
||||||
|
/// Returns an HLS main playlist with all available variants for the asset.
|
||||||
|
///
|
||||||
|
/// Note: This method returns the HTTP [Response].
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<Response> getMainPlaylistWithHttpInfo(String id, { String? key, String? slug, }) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final apiPath = r'/assets/{id}/video/stream/main.m3u8'
|
||||||
|
.replaceAll('{id}', id);
|
||||||
|
|
||||||
|
// ignore: prefer_final_locals
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
if (key != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'key', key));
|
||||||
|
}
|
||||||
|
if (slug != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'slug', slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
apiPath,
|
||||||
|
'GET',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get HLS main playlist
|
||||||
|
///
|
||||||
|
/// Returns an HLS main playlist with all available variants for the asset.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<String?> getMainPlaylist(String id, { String? key, String? slug, }) async {
|
||||||
|
final response = await getMainPlaylistWithHttpInfo(id, key: key, slug: slug, );
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
// When a remote server returns no body with a status of 204, we shall not decode it.
|
||||||
|
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
||||||
|
// FormatException when trying to decode an empty string.
|
||||||
|
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'String',) as String;
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get HLS media playlist
|
||||||
|
///
|
||||||
|
/// Returns an HLS media playlist for one variant of the streaming session.
|
||||||
|
///
|
||||||
|
/// Note: This method returns the HTTP [Response].
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] sessionId (required):
|
||||||
|
///
|
||||||
|
/// * [int] variantIndex (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<Response> getMediaPlaylistWithHttpInfo(String id, String sessionId, int variantIndex, { String? key, String? slug, }) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final apiPath = r'/assets/{id}/video/stream/{sessionId}/{variantIndex}/playlist.m3u8'
|
||||||
|
.replaceAll('{id}', id)
|
||||||
|
.replaceAll('{sessionId}', sessionId)
|
||||||
|
.replaceAll('{variantIndex}', variantIndex.toString());
|
||||||
|
|
||||||
|
// ignore: prefer_final_locals
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
if (key != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'key', key));
|
||||||
|
}
|
||||||
|
if (slug != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'slug', slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
apiPath,
|
||||||
|
'GET',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get HLS media playlist
|
||||||
|
///
|
||||||
|
/// Returns an HLS media playlist for one variant of the streaming session.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] sessionId (required):
|
||||||
|
///
|
||||||
|
/// * [int] variantIndex (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<String?> getMediaPlaylist(String id, String sessionId, int variantIndex, { String? key, String? slug, }) async {
|
||||||
|
final response = await getMediaPlaylistWithHttpInfo(id, sessionId, variantIndex, key: key, slug: slug, );
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
// When a remote server returns no body with a status of 204, we shall not decode it.
|
||||||
|
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
||||||
|
// FormatException when trying to decode an empty string.
|
||||||
|
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'String',) as String;
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get HLS segment or init file
|
||||||
|
///
|
||||||
|
/// Streams an HLS init segment (init.mp4) or media segment (seg_N.m4s).
|
||||||
|
///
|
||||||
|
/// Note: This method returns the HTTP [Response].
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] filename (required):
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] sessionId (required):
|
||||||
|
///
|
||||||
|
/// * [int] variantIndex (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<Response> getSegmentWithHttpInfo(String filename, String id, String sessionId, int variantIndex, { String? key, String? slug, }) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final apiPath = r'/assets/{id}/video/stream/{sessionId}/{variantIndex}/{filename}'
|
||||||
|
.replaceAll('{filename}', filename)
|
||||||
|
.replaceAll('{id}', id)
|
||||||
|
.replaceAll('{sessionId}', sessionId)
|
||||||
|
.replaceAll('{variantIndex}', variantIndex.toString());
|
||||||
|
|
||||||
|
// ignore: prefer_final_locals
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
if (key != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'key', key));
|
||||||
|
}
|
||||||
|
if (slug != null) {
|
||||||
|
queryParams.addAll(_queryParams('', 'slug', slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
apiPath,
|
||||||
|
'GET',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get HLS segment or init file
|
||||||
|
///
|
||||||
|
/// Streams an HLS init segment (init.mp4) or media segment (seg_N.m4s).
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] filename (required):
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
///
|
||||||
|
/// * [String] sessionId (required):
|
||||||
|
///
|
||||||
|
/// * [int] variantIndex (required):
|
||||||
|
///
|
||||||
|
/// * [String] key:
|
||||||
|
///
|
||||||
|
/// * [String] slug:
|
||||||
|
Future<MultipartFile?> getSegment(String filename, String id, String sessionId, int variantIndex, { String? key, String? slug, }) async {
|
||||||
|
final response = await getSegmentWithHttpInfo(filename, id, sessionId, variantIndex, key: key, slug: slug, );
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
// When a remote server returns no body with a status of 204, we shall not decode it.
|
||||||
|
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
||||||
|
// FormatException when trying to decode an empty string.
|
||||||
|
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'MultipartFile',) as MultipartFile;
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Play asset video
|
/// Play asset video
|
||||||
///
|
///
|
||||||
/// Streams the video file for the specified asset. This endpoint also supports byte range requests.
|
/// Streams the video file for the specified asset. This endpoint also supports byte range requests.
|
||||||
|
|||||||
Generated
+2
@@ -726,6 +726,8 @@ class ApiClient {
|
|||||||
return SystemConfigDto.fromJson(value);
|
return SystemConfigDto.fromJson(value);
|
||||||
case 'SystemConfigFFmpegDto':
|
case 'SystemConfigFFmpegDto':
|
||||||
return SystemConfigFFmpegDto.fromJson(value);
|
return SystemConfigFFmpegDto.fromJson(value);
|
||||||
|
case 'SystemConfigFFmpegRealtimeDto':
|
||||||
|
return SystemConfigFFmpegRealtimeDto.fromJson(value);
|
||||||
case 'SystemConfigFacesDto':
|
case 'SystemConfigFacesDto':
|
||||||
return SystemConfigFacesDto.fromJson(value);
|
return SystemConfigFacesDto.fromJson(value);
|
||||||
case 'SystemConfigGeneratedFullsizeImageDto':
|
case 'SystemConfigGeneratedFullsizeImageDto':
|
||||||
|
|||||||
Generated
+3
@@ -52,6 +52,7 @@ class JobName {
|
|||||||
static const librarySyncFilesQueueAll = JobName._(r'LibrarySyncFilesQueueAll');
|
static const librarySyncFilesQueueAll = JobName._(r'LibrarySyncFilesQueueAll');
|
||||||
static const librarySyncFiles = JobName._(r'LibrarySyncFiles');
|
static const librarySyncFiles = JobName._(r'LibrarySyncFiles');
|
||||||
static const libraryScanQueueAll = JobName._(r'LibraryScanQueueAll');
|
static const libraryScanQueueAll = JobName._(r'LibraryScanQueueAll');
|
||||||
|
static const hlsSessionCleanup = JobName._(r'HlsSessionCleanup');
|
||||||
static const memoryCleanup = JobName._(r'MemoryCleanup');
|
static const memoryCleanup = JobName._(r'MemoryCleanup');
|
||||||
static const memoryGenerate = JobName._(r'MemoryGenerate');
|
static const memoryGenerate = JobName._(r'MemoryGenerate');
|
||||||
static const notificationsCleanup = JobName._(r'NotificationsCleanup');
|
static const notificationsCleanup = JobName._(r'NotificationsCleanup');
|
||||||
@@ -110,6 +111,7 @@ class JobName {
|
|||||||
librarySyncFilesQueueAll,
|
librarySyncFilesQueueAll,
|
||||||
librarySyncFiles,
|
librarySyncFiles,
|
||||||
libraryScanQueueAll,
|
libraryScanQueueAll,
|
||||||
|
hlsSessionCleanup,
|
||||||
memoryCleanup,
|
memoryCleanup,
|
||||||
memoryGenerate,
|
memoryGenerate,
|
||||||
notificationsCleanup,
|
notificationsCleanup,
|
||||||
@@ -203,6 +205,7 @@ class JobNameTypeTransformer {
|
|||||||
case r'LibrarySyncFilesQueueAll': return JobName.librarySyncFilesQueueAll;
|
case r'LibrarySyncFilesQueueAll': return JobName.librarySyncFilesQueueAll;
|
||||||
case r'LibrarySyncFiles': return JobName.librarySyncFiles;
|
case r'LibrarySyncFiles': return JobName.librarySyncFiles;
|
||||||
case r'LibraryScanQueueAll': return JobName.libraryScanQueueAll;
|
case r'LibraryScanQueueAll': return JobName.libraryScanQueueAll;
|
||||||
|
case r'HlsSessionCleanup': return JobName.hlsSessionCleanup;
|
||||||
case r'MemoryCleanup': return JobName.memoryCleanup;
|
case r'MemoryCleanup': return JobName.memoryCleanup;
|
||||||
case r'MemoryGenerate': return JobName.memoryGenerate;
|
case r'MemoryGenerate': return JobName.memoryGenerate;
|
||||||
case r'NotificationsCleanup': return JobName.notificationsCleanup;
|
case r'NotificationsCleanup': return JobName.notificationsCleanup;
|
||||||
|
|||||||
+9
-1
@@ -25,6 +25,7 @@ class SystemConfigFFmpegDto {
|
|||||||
required this.maxBitrate,
|
required this.maxBitrate,
|
||||||
required this.preferredHwDevice,
|
required this.preferredHwDevice,
|
||||||
required this.preset,
|
required this.preset,
|
||||||
|
required this.realtime,
|
||||||
required this.refs,
|
required this.refs,
|
||||||
required this.targetAudioCodec,
|
required this.targetAudioCodec,
|
||||||
required this.targetResolution,
|
required this.targetResolution,
|
||||||
@@ -79,6 +80,8 @@ class SystemConfigFFmpegDto {
|
|||||||
/// Preset
|
/// Preset
|
||||||
String preset;
|
String preset;
|
||||||
|
|
||||||
|
SystemConfigFFmpegRealtimeDto realtime;
|
||||||
|
|
||||||
/// References
|
/// References
|
||||||
///
|
///
|
||||||
/// Minimum value: 0
|
/// Minimum value: 0
|
||||||
@@ -122,6 +125,7 @@ class SystemConfigFFmpegDto {
|
|||||||
other.maxBitrate == maxBitrate &&
|
other.maxBitrate == maxBitrate &&
|
||||||
other.preferredHwDevice == preferredHwDevice &&
|
other.preferredHwDevice == preferredHwDevice &&
|
||||||
other.preset == preset &&
|
other.preset == preset &&
|
||||||
|
other.realtime == realtime &&
|
||||||
other.refs == refs &&
|
other.refs == refs &&
|
||||||
other.targetAudioCodec == targetAudioCodec &&
|
other.targetAudioCodec == targetAudioCodec &&
|
||||||
other.targetResolution == targetResolution &&
|
other.targetResolution == targetResolution &&
|
||||||
@@ -147,6 +151,7 @@ class SystemConfigFFmpegDto {
|
|||||||
(maxBitrate.hashCode) +
|
(maxBitrate.hashCode) +
|
||||||
(preferredHwDevice.hashCode) +
|
(preferredHwDevice.hashCode) +
|
||||||
(preset.hashCode) +
|
(preset.hashCode) +
|
||||||
|
(realtime.hashCode) +
|
||||||
(refs.hashCode) +
|
(refs.hashCode) +
|
||||||
(targetAudioCodec.hashCode) +
|
(targetAudioCodec.hashCode) +
|
||||||
(targetResolution.hashCode) +
|
(targetResolution.hashCode) +
|
||||||
@@ -158,7 +163,7 @@ class SystemConfigFFmpegDto {
|
|||||||
(twoPass.hashCode);
|
(twoPass.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'SystemConfigFFmpegDto[accel=$accel, accelDecode=$accelDecode, acceptedAudioCodecs=$acceptedAudioCodecs, acceptedContainers=$acceptedContainers, acceptedVideoCodecs=$acceptedVideoCodecs, bframes=$bframes, cqMode=$cqMode, crf=$crf, gopSize=$gopSize, maxBitrate=$maxBitrate, preferredHwDevice=$preferredHwDevice, preset=$preset, refs=$refs, targetAudioCodec=$targetAudioCodec, targetResolution=$targetResolution, targetVideoCodec=$targetVideoCodec, temporalAQ=$temporalAQ, threads=$threads, tonemap=$tonemap, transcode=$transcode, twoPass=$twoPass]';
|
String toString() => 'SystemConfigFFmpegDto[accel=$accel, accelDecode=$accelDecode, acceptedAudioCodecs=$acceptedAudioCodecs, acceptedContainers=$acceptedContainers, acceptedVideoCodecs=$acceptedVideoCodecs, bframes=$bframes, cqMode=$cqMode, crf=$crf, gopSize=$gopSize, maxBitrate=$maxBitrate, preferredHwDevice=$preferredHwDevice, preset=$preset, realtime=$realtime, refs=$refs, targetAudioCodec=$targetAudioCodec, targetResolution=$targetResolution, targetVideoCodec=$targetVideoCodec, temporalAQ=$temporalAQ, threads=$threads, tonemap=$tonemap, transcode=$transcode, twoPass=$twoPass]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@@ -174,6 +179,7 @@ class SystemConfigFFmpegDto {
|
|||||||
json[r'maxBitrate'] = this.maxBitrate;
|
json[r'maxBitrate'] = this.maxBitrate;
|
||||||
json[r'preferredHwDevice'] = this.preferredHwDevice;
|
json[r'preferredHwDevice'] = this.preferredHwDevice;
|
||||||
json[r'preset'] = this.preset;
|
json[r'preset'] = this.preset;
|
||||||
|
json[r'realtime'] = this.realtime;
|
||||||
json[r'refs'] = this.refs;
|
json[r'refs'] = this.refs;
|
||||||
json[r'targetAudioCodec'] = this.targetAudioCodec;
|
json[r'targetAudioCodec'] = this.targetAudioCodec;
|
||||||
json[r'targetResolution'] = this.targetResolution;
|
json[r'targetResolution'] = this.targetResolution;
|
||||||
@@ -207,6 +213,7 @@ class SystemConfigFFmpegDto {
|
|||||||
maxBitrate: mapValueOfType<String>(json, r'maxBitrate')!,
|
maxBitrate: mapValueOfType<String>(json, r'maxBitrate')!,
|
||||||
preferredHwDevice: mapValueOfType<String>(json, r'preferredHwDevice')!,
|
preferredHwDevice: mapValueOfType<String>(json, r'preferredHwDevice')!,
|
||||||
preset: mapValueOfType<String>(json, r'preset')!,
|
preset: mapValueOfType<String>(json, r'preset')!,
|
||||||
|
realtime: SystemConfigFFmpegRealtimeDto.fromJson(json[r'realtime'])!,
|
||||||
refs: mapValueOfType<int>(json, r'refs')!,
|
refs: mapValueOfType<int>(json, r'refs')!,
|
||||||
targetAudioCodec: AudioCodec.fromJson(json[r'targetAudioCodec'])!,
|
targetAudioCodec: AudioCodec.fromJson(json[r'targetAudioCodec'])!,
|
||||||
targetResolution: mapValueOfType<String>(json, r'targetResolution')!,
|
targetResolution: mapValueOfType<String>(json, r'targetResolution')!,
|
||||||
@@ -275,6 +282,7 @@ class SystemConfigFFmpegDto {
|
|||||||
'maxBitrate',
|
'maxBitrate',
|
||||||
'preferredHwDevice',
|
'preferredHwDevice',
|
||||||
'preset',
|
'preset',
|
||||||
|
'realtime',
|
||||||
'refs',
|
'refs',
|
||||||
'targetAudioCodec',
|
'targetAudioCodec',
|
||||||
'targetResolution',
|
'targetResolution',
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class SystemConfigFFmpegRealtimeDto {
|
||||||
|
/// Returns a new [SystemConfigFFmpegRealtimeDto] instance.
|
||||||
|
SystemConfigFFmpegRealtimeDto({
|
||||||
|
required this.enabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Enable real-time HLS transcoding (alpha)
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || other is SystemConfigFFmpegRealtimeDto &&
|
||||||
|
other.enabled == enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
// ignore: unnecessary_parenthesis
|
||||||
|
(enabled.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'SystemConfigFFmpegRealtimeDto[enabled=$enabled]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
json[r'enabled'] = this.enabled;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new [SystemConfigFFmpegRealtimeDto] instance and imports its values from
|
||||||
|
/// [value] if it's a [Map], null otherwise.
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static SystemConfigFFmpegRealtimeDto? fromJson(dynamic value) {
|
||||||
|
upgradeDto(value, "SystemConfigFFmpegRealtimeDto");
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
|
return SystemConfigFFmpegRealtimeDto(
|
||||||
|
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<SystemConfigFFmpegRealtimeDto> listFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final result = <SystemConfigFFmpegRealtimeDto>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = SystemConfigFFmpegRealtimeDto.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, SystemConfigFFmpegRealtimeDto> mapFromJson(dynamic json) {
|
||||||
|
final map = <String, SystemConfigFFmpegRealtimeDto>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
final value = SystemConfigFFmpegRealtimeDto.fromJson(entry.value);
|
||||||
|
if (value != null) {
|
||||||
|
map[entry.key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// maps a json object with a list of SystemConfigFFmpegRealtimeDto-objects as value to a dart map
|
||||||
|
static Map<String, List<SystemConfigFFmpegRealtimeDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final map = <String, List<SystemConfigFFmpegRealtimeDto>>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
map[entry.key] = SystemConfigFFmpegRealtimeDto.listFromJson(entry.value, growable: growable,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of required keys that must be present in a JSON.
|
||||||
|
static const requiredKeys = <String>{
|
||||||
|
'enabled',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.13.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -103,10 +103,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -124,10 +124,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.1"
|
version: "1.10.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -164,10 +164,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -180,10 +180,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.2"
|
version: "15.2.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.11.0 <4.0.0"
|
dart: ">=3.11.0 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.18.0-18.0.pre.54"
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.13.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -77,10 +77,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c
|
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.2.0"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -124,10 +124,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: "5540e4a3f416dd4a93458257b908eb88353cbd0fb5b0a3d1bd7d849ba1e88735"
|
sha256: "92d8cee7c57dff0a6c409c05597b460002434eccf7424a712283225b3962d03f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "17.2.1"
|
version: "17.2.3"
|
||||||
immich_ui:
|
immich_ui:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -211,10 +211,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -248,10 +248,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.1"
|
version: "1.10.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -312,10 +312,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -328,10 +328,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8
|
sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.5.2"
|
version: "4.5.3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -344,10 +344,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.2"
|
version: "15.2.0"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -44,4 +44,6 @@ abstract class NetworkApi {
|
|||||||
int getClientPointer();
|
int getClientPointer();
|
||||||
|
|
||||||
void setRequestHeaders(Map<String, String> headers, List<String> serverUrls, String? token);
|
void setRequestHeaders(Map<String, String> headers, List<String> serverUrls, String? token);
|
||||||
|
|
||||||
|
String getAppGroupId();
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-36
@@ -133,10 +133,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
sha256: aadd943f4f8cc946882c954c187e6115a84c98c81ad1d9c6cbf0895a8c85da9c
|
sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.5"
|
version: "4.0.6"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -157,10 +157,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "521daf8d189deb79ba474e43a696b41c49fb3987818dbacf3308f1e03673a75e"
|
sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.1"
|
version: "2.15.0"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -173,10 +173,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "0730c18c770d05636a8f945c32a4d7d81cb6e0f0148c8db4ad12e7748f7e49af"
|
sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.12.5"
|
version: "8.12.6"
|
||||||
cast:
|
cast:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -358,18 +358,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: drift
|
name: drift
|
||||||
sha256: "055c249d1f91be5a47fe447f88afc24c4ca6f4cd6c5ed66767b4797d48acc2e5"
|
sha256: "8033500116b24398fba0cca0369cc31678cd627c01e41753a61186911cea743e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.32.1"
|
version: "2.33.0"
|
||||||
drift_dev:
|
drift_dev:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: drift_dev
|
name: drift_dev
|
||||||
sha256: "88a9de3af8571518148a6d8a513b57779fd1e60a026d3ab8a481a878fba01d91"
|
sha256: b3dd5b75e30522a91da8abda9f5bb17230cb038097f6d15fa75d42bb563428aa
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.32.1"
|
version: "2.33.0"
|
||||||
drift_flutter:
|
drift_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -613,10 +613,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
sha256: "1ded017b39c8e15c8948ea855070a5ff8ff8b3d5e83f3446e02d6bb12add7ad9"
|
sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.4"
|
version: "2.3.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -772,10 +772,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hooks
|
name: hooks
|
||||||
sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388
|
sha256: "025f060e86d2d4c3c47b56e33caf7f93bf9283340f26d23424ebcfccf34f621e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.3"
|
||||||
hooks_riverpod:
|
hooks_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -844,18 +844,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: image_picker
|
name: image_picker
|
||||||
sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320"
|
sha256: "91c025426c2881c551100bce834e201c835a170151545f58d17da5180ca7d9ac"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.2"
|
||||||
image_picker_android:
|
image_picker_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_android
|
name: image_picker_android
|
||||||
sha256: "66810af8e99b2657ee98e5c6f02064f69bb63f7a70e343937f70946c5f8c6622"
|
sha256: d5b3e1774af29c9ab00103afb0d4614070f924d2e0057ac867ec98800114793f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.13+16"
|
version: "0.8.13+17"
|
||||||
image_picker_for_web:
|
image_picker_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -952,10 +952,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8
|
sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.11.0"
|
version: "4.12.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -984,10 +984,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: lean_builder
|
name: lean_builder
|
||||||
sha256: ee4117b03e93a4eb83e1a78c8e7a1dc22188d43bb142309982be48673a1b3a53
|
sha256: c16e95ddf7b2d49dd551357b7212fe2ce9f13ec7ad1b1e660c157184031e96c0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.7"
|
version: "0.1.10"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1429,6 +1429,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.0"
|
||||||
|
record_use:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: record_use
|
||||||
|
sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.0"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1607,10 +1615,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
sha256: "732792cfd197d2161a65bb029606a46e0a18ff30ef9e141a7a82172b05ea8ecd"
|
sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.2"
|
version: "4.2.3"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1647,10 +1655,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlparser
|
name: sqlparser
|
||||||
sha256: ab2b467425f1d4f3acfa5fd11a08226f7d6c26ff102c06be1807e1dff34e050b
|
sha256: ecdc06d4a7d79dcbc928d99afd2f7f5b0f98a637c46f89be83d911617f759978
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.44.3"
|
version: "0.44.4"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1807,10 +1815,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f
|
sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.4.3"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1831,10 +1839,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics
|
name: vector_graphics
|
||||||
sha256: "81da85e9ca8885ade47f9685b953cb098970d11be4821ac765580a6607ea4373"
|
sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.21"
|
version: "1.2.2"
|
||||||
vector_graphics_codec:
|
vector_graphics_codec:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1847,10 +1855,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_compiler
|
name: vector_graphics_compiler
|
||||||
sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74"
|
sha256: b9b3f391857781aa96acacef96066f2f49b4cd03cf9fce3ca4d8da2ef5ea129e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1863,10 +1871,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "046d3928e16fa4dc46e8350415661755ab759d9fc97fc21b5ab295f71e4f0499"
|
sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.1.0"
|
version: "15.2.0"
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1879,10 +1887,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus_platform_interface
|
name: wakelock_plus_platform_interface
|
||||||
sha256: "14b2e5b9e35c2631e656913c47adecdd71633ae92896a27a64c8f1fcfabc21cc"
|
sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.0"
|
version: "1.5.1"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import 'package:mocktail/mocktail.dart';
|
|||||||
import '../../infrastructure/repository.mock.dart';
|
import '../../infrastructure/repository.mock.dart';
|
||||||
|
|
||||||
const _kAccessToken = '#ThisIsAToken';
|
const _kAccessToken = '#ThisIsAToken';
|
||||||
const _kEnableBackup = false;
|
const _kAdvancedTroubleshooting = false;
|
||||||
const _kVersion = 2;
|
const _kVersion = 2;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@@ -22,13 +22,13 @@ void main() {
|
|||||||
mockDriftStoreRepo = MockDriftStoreRepository();
|
mockDriftStoreRepo = MockDriftStoreRepository();
|
||||||
// For generics, we need to provide fallback to each concrete type to avoid runtime errors
|
// For generics, we need to provide fallback to each concrete type to avoid runtime errors
|
||||||
registerFallbackValue(StoreKey.accessToken);
|
registerFallbackValue(StoreKey.accessToken);
|
||||||
registerFallbackValue(StoreKey.backupTriggerDelay);
|
registerFallbackValue(StoreKey.version);
|
||||||
registerFallbackValue(StoreKey.enableBackup);
|
registerFallbackValue(StoreKey.advancedTroubleshooting);
|
||||||
|
|
||||||
when(() => mockDriftStoreRepo.getAll()).thenAnswer(
|
when(() => mockDriftStoreRepo.getAll()).thenAnswer(
|
||||||
(_) async => [
|
(_) async => [
|
||||||
const StoreDto(StoreKey.accessToken, _kAccessToken),
|
const StoreDto(StoreKey.accessToken, _kAccessToken),
|
||||||
const StoreDto(StoreKey.enableBackup, _kEnableBackup),
|
const StoreDto(StoreKey.advancedTroubleshooting, _kAdvancedTroubleshooting),
|
||||||
const StoreDto(StoreKey.version, _kVersion),
|
const StoreDto(StoreKey.version, _kVersion),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -46,7 +46,7 @@ void main() {
|
|||||||
test('Populates the internal cache on init', () {
|
test('Populates the internal cache on init', () {
|
||||||
verify(() => mockDriftStoreRepo.getAll()).called(1);
|
verify(() => mockDriftStoreRepo.getAll()).called(1);
|
||||||
expect(sut.tryGet(StoreKey.accessToken), _kAccessToken);
|
expect(sut.tryGet(StoreKey.accessToken), _kAccessToken);
|
||||||
expect(sut.tryGet(StoreKey.enableBackup), _kEnableBackup);
|
expect(sut.tryGet(StoreKey.advancedTroubleshooting), _kAdvancedTroubleshooting);
|
||||||
expect(sut.tryGet(StoreKey.version), _kVersion);
|
expect(sut.tryGet(StoreKey.version), _kVersion);
|
||||||
// Other keys should be null
|
// Other keys should be null
|
||||||
expect(sut.tryGet(StoreKey.currentUser), isNull);
|
expect(sut.tryGet(StoreKey.currentUser), isNull);
|
||||||
@@ -147,7 +147,7 @@ void main() {
|
|||||||
await sut.clear();
|
await sut.clear();
|
||||||
verify(() => mockDriftStoreRepo.deleteAll()).called(1);
|
verify(() => mockDriftStoreRepo.deleteAll()).called(1);
|
||||||
expect(sut.tryGet(StoreKey.accessToken), isNull);
|
expect(sut.tryGet(StoreKey.accessToken), isNull);
|
||||||
expect(sut.tryGet(StoreKey.enableBackup), isNull);
|
expect(sut.tryGet(StoreKey.advancedTroubleshooting), isNull);
|
||||||
expect(sut.tryGet(StoreKey.version), isNull);
|
expect(sut.tryGet(StoreKey.version), isNull);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import '../../fixtures/user.stub.dart';
|
|||||||
|
|
||||||
const _kTestAccessToken = "#TestToken";
|
const _kTestAccessToken = "#TestToken";
|
||||||
const _kTestVersion = 10;
|
const _kTestVersion = 10;
|
||||||
const _kTestBackupRequireCharging = false;
|
const _kTestAdvancedTroubleshooting = false;
|
||||||
final _kTestUser = UserStub.admin;
|
final _kTestUser = UserStub.admin;
|
||||||
|
|
||||||
Future<void> _populateStore(Drift db) async {
|
Future<void> _populateStore(Drift db) async {
|
||||||
@@ -21,8 +21,8 @@ Future<void> _populateStore(Drift db) async {
|
|||||||
batch.insert(
|
batch.insert(
|
||||||
db.storeEntity,
|
db.storeEntity,
|
||||||
StoreEntityCompanion(
|
StoreEntityCompanion(
|
||||||
id: Value(StoreKey.backupRequireCharging.id),
|
id: Value(StoreKey.advancedTroubleshooting.id),
|
||||||
intValue: const Value(_kTestBackupRequireCharging ? 1 : 0),
|
intValue: const Value(_kTestAdvancedTroubleshooting ? 1 : 0),
|
||||||
stringValue: const Value(null),
|
stringValue: const Value(null),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -76,11 +76,11 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('converts bool', () async {
|
test('converts bool', () async {
|
||||||
bool? backupRequireCharging = await sut.tryGet(StoreKey.backupRequireCharging);
|
bool? advancedTroubleshooting = await sut.tryGet(StoreKey.advancedTroubleshooting);
|
||||||
expect(backupRequireCharging, isNull);
|
expect(advancedTroubleshooting, isNull);
|
||||||
await sut.upsert(StoreKey.backupRequireCharging, _kTestBackupRequireCharging);
|
await sut.upsert(StoreKey.advancedTroubleshooting, _kTestAdvancedTroubleshooting);
|
||||||
backupRequireCharging = await sut.tryGet(StoreKey.backupRequireCharging);
|
advancedTroubleshooting = await sut.tryGet(StoreKey.advancedTroubleshooting);
|
||||||
expect(backupRequireCharging, _kTestBackupRequireCharging);
|
expect(advancedTroubleshooting, _kTestAdvancedTroubleshooting);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('converts user', () async {
|
test('converts user', () async {
|
||||||
@@ -98,11 +98,11 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('delete()', () async {
|
test('delete()', () async {
|
||||||
bool? backupRequireCharging = await sut.tryGet(StoreKey.backupRequireCharging);
|
bool? advancedTroubleshooting = await sut.tryGet(StoreKey.advancedTroubleshooting);
|
||||||
expect(backupRequireCharging, isFalse);
|
expect(advancedTroubleshooting, isFalse);
|
||||||
await sut.delete(StoreKey.backupRequireCharging);
|
await sut.delete(StoreKey.advancedTroubleshooting);
|
||||||
backupRequireCharging = await sut.tryGet(StoreKey.backupRequireCharging);
|
advancedTroubleshooting = await sut.tryGet(StoreKey.advancedTroubleshooting);
|
||||||
expect(backupRequireCharging, isNull);
|
expect(advancedTroubleshooting, isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('deleteAll()', () async {
|
test('deleteAll()', () async {
|
||||||
@@ -147,13 +147,13 @@ void main() {
|
|||||||
emitsInOrder([
|
emitsInOrder([
|
||||||
[
|
[
|
||||||
const StoreDto<Object>(StoreKey.version, _kTestVersion),
|
const StoreDto<Object>(StoreKey.version, _kTestVersion),
|
||||||
const StoreDto<Object>(StoreKey.backupRequireCharging, _kTestBackupRequireCharging),
|
|
||||||
const StoreDto<Object>(StoreKey.accessToken, _kTestAccessToken),
|
const StoreDto<Object>(StoreKey.accessToken, _kTestAccessToken),
|
||||||
|
const StoreDto<Object>(StoreKey.advancedTroubleshooting, _kTestAdvancedTroubleshooting),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
const StoreDto<Object>(StoreKey.version, _kTestVersion + 10),
|
const StoreDto<Object>(StoreKey.version, _kTestVersion + 10),
|
||||||
const StoreDto<Object>(StoreKey.backupRequireCharging, _kTestBackupRequireCharging),
|
|
||||||
const StoreDto<Object>(StoreKey.accessToken, _kTestAccessToken),
|
const StoreDto<Object>(StoreKey.accessToken, _kTestAccessToken),
|
||||||
|
const StoreDto<Object>(StoreKey.advancedTroubleshooting, _kTestAdvancedTroubleshooting),
|
||||||
],
|
],
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ void main() {
|
|||||||
late MockApiService apiService;
|
late MockApiService apiService;
|
||||||
late MockNetworkService networkService;
|
late MockNetworkService networkService;
|
||||||
late MockBackgroundSyncManager backgroundSyncManager;
|
late MockBackgroundSyncManager backgroundSyncManager;
|
||||||
late MockAppSettingService appSettingsService;
|
|
||||||
late Drift db;
|
late Drift db;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
@@ -30,15 +29,12 @@ void main() {
|
|||||||
apiService = MockApiService();
|
apiService = MockApiService();
|
||||||
networkService = MockNetworkService();
|
networkService = MockNetworkService();
|
||||||
backgroundSyncManager = MockBackgroundSyncManager();
|
backgroundSyncManager = MockBackgroundSyncManager();
|
||||||
appSettingsService = MockAppSettingService();
|
|
||||||
|
|
||||||
sut = AuthService(
|
sut = AuthService(
|
||||||
authApiRepository,
|
authApiRepository,
|
||||||
authRepository,
|
authRepository,
|
||||||
apiService,
|
apiService,
|
||||||
networkService,
|
networkService,
|
||||||
backgroundSyncManager,
|
backgroundSyncManager,
|
||||||
appSettingsService,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
registerFallbackValue(Uri());
|
registerFallbackValue(Uri());
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ import 'package:immich_mobile/entities/store.entity.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/services/background_upload.service.dart';
|
import 'package:immich_mobile/services/background_upload.service.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
|
||||||
import '../domain/service.mock.dart';
|
|
||||||
import '../fixtures/asset.stub.dart';
|
import '../fixtures/asset.stub.dart';
|
||||||
import '../infrastructure/repository.mock.dart';
|
import '../infrastructure/repository.mock.dart';
|
||||||
import '../mocks/asset_entity.mock.dart';
|
import '../mocks/asset_entity.mock.dart';
|
||||||
@@ -29,13 +27,10 @@ void main() {
|
|||||||
late MockStorageRepository mockStorageRepository;
|
late MockStorageRepository mockStorageRepository;
|
||||||
late MockDriftLocalAssetRepository mockLocalAssetRepository;
|
late MockDriftLocalAssetRepository mockLocalAssetRepository;
|
||||||
late MockDriftBackupRepository mockBackupRepository;
|
late MockDriftBackupRepository mockBackupRepository;
|
||||||
late MockAppSettingsService mockAppSettingsService;
|
|
||||||
late MockAssetMediaRepository mockAssetMediaRepository;
|
late MockAssetMediaRepository mockAssetMediaRepository;
|
||||||
late Drift db;
|
late Drift db;
|
||||||
|
|
||||||
setUpAll(() async {
|
setUpAll(() async {
|
||||||
registerFallbackValue(AppSettingsEnum.useCellularForUploadPhotos);
|
|
||||||
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||||
const MethodChannel('plugins.flutter.io/path_provider'),
|
const MethodChannel('plugins.flutter.io/path_provider'),
|
||||||
@@ -54,18 +49,13 @@ void main() {
|
|||||||
mockStorageRepository = MockStorageRepository();
|
mockStorageRepository = MockStorageRepository();
|
||||||
mockLocalAssetRepository = MockDriftLocalAssetRepository();
|
mockLocalAssetRepository = MockDriftLocalAssetRepository();
|
||||||
mockBackupRepository = MockDriftBackupRepository();
|
mockBackupRepository = MockDriftBackupRepository();
|
||||||
mockAppSettingsService = MockAppSettingsService();
|
|
||||||
mockAssetMediaRepository = MockAssetMediaRepository();
|
mockAssetMediaRepository = MockAssetMediaRepository();
|
||||||
|
|
||||||
when(() => mockAppSettingsService.getSetting(AppSettingsEnum.useCellularForUploadVideos)).thenReturn(false);
|
|
||||||
when(() => mockAppSettingsService.getSetting(AppSettingsEnum.useCellularForUploadPhotos)).thenReturn(false);
|
|
||||||
|
|
||||||
sut = BackgroundUploadService(
|
sut = BackgroundUploadService(
|
||||||
mockUploadRepository,
|
mockUploadRepository,
|
||||||
mockStorageRepository,
|
mockStorageRepository,
|
||||||
mockLocalAssetRepository,
|
mockLocalAssetRepository,
|
||||||
mockBackupRepository,
|
mockBackupRepository,
|
||||||
mockAppSettingsService,
|
|
||||||
mockAssetMediaRepository,
|
mockAssetMediaRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -181,7 +171,6 @@ void main() {
|
|||||||
mockStorageRepository,
|
mockStorageRepository,
|
||||||
mockLocalAssetRepository,
|
mockLocalAssetRepository,
|
||||||
mockBackupRepository,
|
mockBackupRepository,
|
||||||
mockAppSettingsService,
|
|
||||||
mockAssetMediaRepository,
|
mockAssetMediaRepository,
|
||||||
);
|
);
|
||||||
addTearDown(() => sutWithV24.dispose());
|
addTearDown(() => sutWithV24.dispose());
|
||||||
@@ -232,7 +221,6 @@ void main() {
|
|||||||
mockStorageRepository,
|
mockStorageRepository,
|
||||||
mockLocalAssetRepository,
|
mockLocalAssetRepository,
|
||||||
mockBackupRepository,
|
mockBackupRepository,
|
||||||
mockAppSettingsService,
|
|
||||||
mockAssetMediaRepository,
|
mockAssetMediaRepository,
|
||||||
);
|
);
|
||||||
addTearDown(() => sutAndroid.dispose());
|
addTearDown(() => sutAndroid.dispose());
|
||||||
@@ -273,7 +261,6 @@ void main() {
|
|||||||
mockStorageRepository,
|
mockStorageRepository,
|
||||||
mockLocalAssetRepository,
|
mockLocalAssetRepository,
|
||||||
mockBackupRepository,
|
mockBackupRepository,
|
||||||
mockAppSettingsService,
|
|
||||||
mockAssetMediaRepository,
|
mockAssetMediaRepository,
|
||||||
);
|
);
|
||||||
addTearDown(() => sutWithV24.dispose());
|
addTearDown(() => sutWithV24.dispose());
|
||||||
@@ -314,7 +301,6 @@ void main() {
|
|||||||
mockStorageRepository,
|
mockStorageRepository,
|
||||||
mockLocalAssetRepository,
|
mockLocalAssetRepository,
|
||||||
mockBackupRepository,
|
mockBackupRepository,
|
||||||
mockAppSettingsService,
|
|
||||||
mockAssetMediaRepository,
|
mockAssetMediaRepository,
|
||||||
);
|
);
|
||||||
addTearDown(() => sutWithV24.dispose());
|
addTearDown(() => sutWithV24.dispose());
|
||||||
|
|||||||
@@ -11,9 +11,6 @@
|
|||||||
"required": true,
|
"required": true,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"description": "Album ID",
|
"description": "Album ID",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity search"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
@@ -25,9 +22,6 @@
|
|||||||
"required": false,
|
"required": false,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"description": "Asset ID (if activity is for an asset)",
|
"description": "Asset ID (if activity is for an asset)",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity search"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
@@ -38,9 +32,6 @@
|
|||||||
"name": "level",
|
"name": "level",
|
||||||
"required": false,
|
"required": false,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity search"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ReactionLevel"
|
"$ref": "#/components/schemas/ReactionLevel"
|
||||||
}
|
}
|
||||||
@@ -49,9 +40,6 @@
|
|||||||
"name": "type",
|
"name": "type",
|
||||||
"required": false,
|
"required": false,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity search"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ReactionType"
|
"$ref": "#/components/schemas/ReactionType"
|
||||||
}
|
}
|
||||||
@@ -61,9 +49,6 @@
|
|||||||
"required": false,
|
"required": false,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"description": "Filter by user ID",
|
"description": "Filter by user ID",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity search"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
@@ -187,9 +172,6 @@
|
|||||||
"required": true,
|
"required": true,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"description": "Album ID",
|
"description": "Album ID",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
@@ -201,9 +183,6 @@
|
|||||||
"required": false,
|
"required": false,
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"description": "Asset ID (if activity is for an asset)",
|
"description": "Asset ID (if activity is for an asset)",
|
||||||
"x-nestjs_zod-parent-metadata": {
|
|
||||||
"description": "Activity"
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
@@ -4309,6 +4288,351 @@
|
|||||||
"x-immich-state": "Stable"
|
"x-immich-state": "Stable"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/assets/{id}/video/stream/main.m3u8": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns an HLS main playlist with all available variants for the asset.",
|
||||||
|
"operationId": "getMainPlaylist",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "slug",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/vnd.apple.mpegurl": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Get HLS main playlist",
|
||||||
|
"tags": [
|
||||||
|
"Assets"
|
||||||
|
],
|
||||||
|
"x-immich-history": [
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Added"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Alpha"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-immich-permission": "asset.view",
|
||||||
|
"x-immich-state": "Alpha"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/assets/{id}/video/stream/{sessionId}": {
|
||||||
|
"delete": {
|
||||||
|
"description": "Releases server resources for the streaming session.",
|
||||||
|
"operationId": "endSession",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sessionId",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "slug",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "End HLS streaming session",
|
||||||
|
"tags": [
|
||||||
|
"Assets"
|
||||||
|
],
|
||||||
|
"x-immich-history": [
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Added"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Alpha"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-immich-permission": "asset.view",
|
||||||
|
"x-immich-state": "Alpha"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/assets/{id}/video/stream/{sessionId}/{variantIndex}/playlist.m3u8": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns an HLS media playlist for one variant of the streaming session.",
|
||||||
|
"operationId": "getMediaPlaylist",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sessionId",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "slug",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "variantIndex",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 9007199254740991,
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/vnd.apple.mpegurl": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Get HLS media playlist",
|
||||||
|
"tags": [
|
||||||
|
"Assets"
|
||||||
|
],
|
||||||
|
"x-immich-history": [
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Added"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Alpha"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-immich-permission": "asset.view",
|
||||||
|
"x-immich-state": "Alpha"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/assets/{id}/video/stream/{sessionId}/{variantIndex}/{filename}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Streams an HLS init segment (init.mp4) or media segment (seg_N.m4s).",
|
||||||
|
"operationId": "getSegment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "filename",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"pattern": "^(init\\.mp4|seg_\\d+\\.m4s)$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sessionId",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"format": "uuid",
|
||||||
|
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "slug",
|
||||||
|
"required": false,
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "variantIndex",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 9007199254740991,
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/octet-stream": {
|
||||||
|
"schema": {
|
||||||
|
"format": "binary",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Get HLS segment or init file",
|
||||||
|
"tags": [
|
||||||
|
"Assets"
|
||||||
|
],
|
||||||
|
"x-immich-history": [
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Added"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v3",
|
||||||
|
"state": "Alpha"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-immich-permission": "asset.view",
|
||||||
|
"x-immich-state": "Alpha"
|
||||||
|
}
|
||||||
|
},
|
||||||
"/auth/admin-sign-up": {
|
"/auth/admin-sign-up": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "Create the first admin user in the system.",
|
"description": "Create the first admin user in the system.",
|
||||||
@@ -18103,6 +18427,7 @@
|
|||||||
"LibrarySyncFilesQueueAll",
|
"LibrarySyncFilesQueueAll",
|
||||||
"LibrarySyncFiles",
|
"LibrarySyncFiles",
|
||||||
"LibraryScanQueueAll",
|
"LibraryScanQueueAll",
|
||||||
|
"HlsSessionCleanup",
|
||||||
"MemoryCleanup",
|
"MemoryCleanup",
|
||||||
"MemoryGenerate",
|
"MemoryGenerate",
|
||||||
"NotificationsCleanup",
|
"NotificationsCleanup",
|
||||||
@@ -24061,6 +24386,9 @@
|
|||||||
"description": "Preset",
|
"description": "Preset",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"realtime": {
|
||||||
|
"$ref": "#/components/schemas/SystemConfigFFmpegRealtimeDto"
|
||||||
|
},
|
||||||
"refs": {
|
"refs": {
|
||||||
"description": "References",
|
"description": "References",
|
||||||
"maximum": 6,
|
"maximum": 6,
|
||||||
@@ -24111,6 +24439,7 @@
|
|||||||
"maxBitrate",
|
"maxBitrate",
|
||||||
"preferredHwDevice",
|
"preferredHwDevice",
|
||||||
"preset",
|
"preset",
|
||||||
|
"realtime",
|
||||||
"refs",
|
"refs",
|
||||||
"targetAudioCodec",
|
"targetAudioCodec",
|
||||||
"targetResolution",
|
"targetResolution",
|
||||||
@@ -24123,6 +24452,18 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"SystemConfigFFmpegRealtimeDto": {
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"description": "Enable real-time HLS transcoding (alpha)",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"enabled"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"SystemConfigFacesDto": {
|
"SystemConfigFacesDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"import": {
|
"import": {
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
"format": "prettier --cache --check i18n/",
|
"format": "prettier --cache --check i18n/",
|
||||||
"format:fix": "prettier --cache --write --list-different i18n"
|
"format:fix": "prettier --cache --write --list-different i18n"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.33.1+sha512.05ba3c1d5d1c18f68df06470d74055e62d41fc110a0c660db1b2dfb2785327f04cf0f68345d4609bc52089e7fa0343c31593b2f9594e2c5d5da426230acc9820",
|
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800",
|
||||||
"engines": {
|
"engines": {
|
||||||
"pnpm": ">=10.0.0"
|
"pnpm": ">=10.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^24.12.2",
|
"@types/node": "^24.12.4",
|
||||||
"@vitest/coverage-v8": "^4.0.0",
|
"@vitest/coverage-v8": "^4.0.0",
|
||||||
"byte-size": "^9.0.0",
|
"byte-size": "^9.0.0",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
|
|||||||
@@ -13,5 +13,5 @@
|
|||||||
"oidc-provider": "^9.0.0",
|
"oidc-provider": "^9.0.0",
|
||||||
"tsx": "^4.20.6"
|
"tsx": "^4.20.6"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.33.1"
|
"packageManager": "pnpm@10.33.4"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"packageManager": "pnpm@10.30.3",
|
"packageManager": "pnpm@10.33.4",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@extism/js-pdk": "^1.1.1",
|
"@extism/js-pdk": "^1.1.1",
|
||||||
"@types/node": "^24.11.0",
|
"@types/node": "^24.12.4",
|
||||||
"esbuild": "^0.27.3",
|
"esbuild": "^0.28.0",
|
||||||
"tsc-alias": "^1.8.16",
|
"tsc-alias": "^1.8.16",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.12.2",
|
"@types/node": "^24.12.4",
|
||||||
"typescript": "^6.0.0"
|
"typescript": "^6.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2227,6 +2227,10 @@ export type DatabaseBackupConfig = {
|
|||||||
export type SystemConfigBackupsDto = {
|
export type SystemConfigBackupsDto = {
|
||||||
database: DatabaseBackupConfig;
|
database: DatabaseBackupConfig;
|
||||||
};
|
};
|
||||||
|
export type SystemConfigFFmpegRealtimeDto = {
|
||||||
|
/** Enable real-time HLS transcoding (alpha) */
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
export type SystemConfigFFmpegDto = {
|
export type SystemConfigFFmpegDto = {
|
||||||
accel: TranscodeHWAccel;
|
accel: TranscodeHWAccel;
|
||||||
/** Accelerated decode */
|
/** Accelerated decode */
|
||||||
@@ -2250,6 +2254,7 @@ export type SystemConfigFFmpegDto = {
|
|||||||
preferredHwDevice: string;
|
preferredHwDevice: string;
|
||||||
/** Preset */
|
/** Preset */
|
||||||
preset: string;
|
preset: string;
|
||||||
|
realtime: SystemConfigFFmpegRealtimeDto;
|
||||||
/** References */
|
/** References */
|
||||||
refs: number;
|
refs: number;
|
||||||
targetAudioCodec: AudioCodec;
|
targetAudioCodec: AudioCodec;
|
||||||
@@ -4184,6 +4189,82 @@ export function playAssetVideo({ id, key, slug }: {
|
|||||||
...opts
|
...opts
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Get HLS main playlist
|
||||||
|
*/
|
||||||
|
export function getMainPlaylist({ id, key, slug }: {
|
||||||
|
id: string;
|
||||||
|
key?: string;
|
||||||
|
slug?: string;
|
||||||
|
}, opts?: Oazapfts.RequestOpts) {
|
||||||
|
return oazapfts.ok(oazapfts.fetchBlob<{
|
||||||
|
status: 200;
|
||||||
|
data: string;
|
||||||
|
}>(`/assets/${encodeURIComponent(id)}/video/stream/main.m3u8${QS.query(QS.explode({
|
||||||
|
key,
|
||||||
|
slug
|
||||||
|
}))}`, {
|
||||||
|
...opts
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* End HLS streaming session
|
||||||
|
*/
|
||||||
|
export function endSession({ id, key, sessionId, slug }: {
|
||||||
|
id: string;
|
||||||
|
key?: string;
|
||||||
|
sessionId: string;
|
||||||
|
slug?: string;
|
||||||
|
}, opts?: Oazapfts.RequestOpts) {
|
||||||
|
return oazapfts.ok(oazapfts.fetchText(`/assets/${encodeURIComponent(id)}/video/stream/${encodeURIComponent(sessionId)}${QS.query(QS.explode({
|
||||||
|
key,
|
||||||
|
slug
|
||||||
|
}))}`, {
|
||||||
|
...opts,
|
||||||
|
method: "DELETE"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get HLS media playlist
|
||||||
|
*/
|
||||||
|
export function getMediaPlaylist({ id, key, sessionId, slug, variantIndex }: {
|
||||||
|
id: string;
|
||||||
|
key?: string;
|
||||||
|
sessionId: string;
|
||||||
|
slug?: string;
|
||||||
|
variantIndex: number;
|
||||||
|
}, opts?: Oazapfts.RequestOpts) {
|
||||||
|
return oazapfts.ok(oazapfts.fetchBlob<{
|
||||||
|
status: 200;
|
||||||
|
data: string;
|
||||||
|
}>(`/assets/${encodeURIComponent(id)}/video/stream/${encodeURIComponent(sessionId)}/${encodeURIComponent(variantIndex)}/playlist.m3u8${QS.query(QS.explode({
|
||||||
|
key,
|
||||||
|
slug
|
||||||
|
}))}`, {
|
||||||
|
...opts
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get HLS segment or init file
|
||||||
|
*/
|
||||||
|
export function getSegment({ filename, id, key, sessionId, slug, variantIndex }: {
|
||||||
|
filename: string;
|
||||||
|
id: string;
|
||||||
|
key?: string;
|
||||||
|
sessionId: string;
|
||||||
|
slug?: string;
|
||||||
|
variantIndex: number;
|
||||||
|
}, opts?: Oazapfts.RequestOpts) {
|
||||||
|
return oazapfts.ok(oazapfts.fetchBlob<{
|
||||||
|
status: 200;
|
||||||
|
data: Blob;
|
||||||
|
}>(`/assets/${encodeURIComponent(id)}/video/stream/${encodeURIComponent(sessionId)}/${encodeURIComponent(variantIndex)}/${encodeURIComponent(filename)}${QS.query(QS.explode({
|
||||||
|
key,
|
||||||
|
slug
|
||||||
|
}))}`, {
|
||||||
|
...opts
|
||||||
|
}));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Register admin
|
* Register admin
|
||||||
*/
|
*/
|
||||||
@@ -7082,6 +7163,7 @@ export enum JobName {
|
|||||||
LibrarySyncFilesQueueAll = "LibrarySyncFilesQueueAll",
|
LibrarySyncFilesQueueAll = "LibrarySyncFilesQueueAll",
|
||||||
LibrarySyncFiles = "LibrarySyncFiles",
|
LibrarySyncFiles = "LibrarySyncFiles",
|
||||||
LibraryScanQueueAll = "LibraryScanQueueAll",
|
LibraryScanQueueAll = "LibraryScanQueueAll",
|
||||||
|
HlsSessionCleanup = "HlsSessionCleanup",
|
||||||
MemoryCleanup = "MemoryCleanup",
|
MemoryCleanup = "MemoryCleanup",
|
||||||
MemoryGenerate = "MemoryGenerate",
|
MemoryGenerate = "MemoryGenerate",
|
||||||
NotificationsCleanup = "NotificationsCleanup",
|
NotificationsCleanup = "NotificationsCleanup",
|
||||||
|
|||||||
Generated
+4449
-4093
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -55,7 +55,7 @@ FROM builder AS plugins
|
|||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
COPY --from=ghcr.io/jdx/mise:2026.3.12@sha256:0210678cbf58413806531a27adb2c7daf1c37238e56e8f7ea381d73521571775 /usr/local/bin/mise /usr/local/bin/mise
|
COPY --from=ghcr.io/jdx/mise:2026.5.11@sha256:2ba959e4827f845fe0c4cfb4814089e790dc513040ef74f9e14925f446412a51 /usr/local/bin/mise /usr/local/bin/mise
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./mise.toml ./mise.toml
|
COPY ./mise.toml ./mise.toml
|
||||||
|
|||||||
+8
-8
@@ -49,14 +49,14 @@
|
|||||||
"@nestjs/websockets": "^11.0.4",
|
"@nestjs/websockets": "^11.0.4",
|
||||||
"@opentelemetry/api": "^1.9.0",
|
"@opentelemetry/api": "^1.9.0",
|
||||||
"@opentelemetry/context-async-hooks": "^2.0.0",
|
"@opentelemetry/context-async-hooks": "^2.0.0",
|
||||||
"@opentelemetry/exporter-prometheus": "^0.217.0",
|
"@opentelemetry/exporter-prometheus": "^0.218.0",
|
||||||
"@opentelemetry/instrumentation-http": "^0.215.0",
|
"@opentelemetry/instrumentation-http": "^0.218.0",
|
||||||
"@opentelemetry/instrumentation-ioredis": "^0.63.0",
|
"@opentelemetry/instrumentation-ioredis": "^0.66.0",
|
||||||
"@opentelemetry/instrumentation-nestjs-core": "^0.61.0",
|
"@opentelemetry/instrumentation-nestjs-core": "^0.64.0",
|
||||||
"@opentelemetry/instrumentation-pg": "^0.67.0",
|
"@opentelemetry/instrumentation-pg": "^0.70.0",
|
||||||
"@opentelemetry/resources": "^2.0.1",
|
"@opentelemetry/resources": "^2.0.1",
|
||||||
"@opentelemetry/sdk-metrics": "^2.0.1",
|
"@opentelemetry/sdk-metrics": "^2.0.1",
|
||||||
"@opentelemetry/sdk-node": "^0.217.0",
|
"@opentelemetry/sdk-node": "^0.218.0",
|
||||||
"@opentelemetry/semantic-conventions": "^1.34.0",
|
"@opentelemetry/semantic-conventions": "^1.34.0",
|
||||||
"@react-email/components": "^1.0.0",
|
"@react-email/components": "^1.0.0",
|
||||||
"@react-email/render": "^2.0.0",
|
"@react-email/render": "^2.0.0",
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
"ua-parser-js": "^2.0.0",
|
"ua-parser-js": "^2.0.0",
|
||||||
"uuid": "^14.0.0",
|
"uuid": "^14.0.0",
|
||||||
"validator": "^13.12.0",
|
"validator": "^13.12.0",
|
||||||
"zod": "^4.3.6"
|
"zod": "4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.0",
|
"@eslint/js": "^10.0.0",
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
"@types/luxon": "^3.6.2",
|
"@types/luxon": "^3.6.2",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/multer": "^2.0.0",
|
"@types/multer": "^2.0.0",
|
||||||
"@types/node": "^24.12.2",
|
"@types/node": "^24.12.4",
|
||||||
"@types/nodemailer": "^8.0.0",
|
"@types/nodemailer": "^8.0.0",
|
||||||
"@types/picomatch": "^4.0.0",
|
"@types/picomatch": "^4.0.0",
|
||||||
"@types/pngjs": "^6.0.5",
|
"@types/pngjs": "^6.0.5",
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ export type SystemConfig = {
|
|||||||
accel: TranscodeHardwareAcceleration;
|
accel: TranscodeHardwareAcceleration;
|
||||||
accelDecode: boolean;
|
accelDecode: boolean;
|
||||||
tonemap: ToneMapping;
|
tonemap: ToneMapping;
|
||||||
|
realtime: {
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
job: Record<ConcurrentQueueName, { concurrency: number }>;
|
job: Record<ConcurrentQueueName, { concurrency: number }>;
|
||||||
logging: {
|
logging: {
|
||||||
@@ -224,6 +227,9 @@ export const defaults = Object.freeze<SystemConfig>({
|
|||||||
tonemap: ToneMapping.Hable,
|
tonemap: ToneMapping.Hable,
|
||||||
accel: TranscodeHardwareAcceleration.Disabled,
|
accel: TranscodeHardwareAcceleration.Disabled,
|
||||||
accelDecode: true,
|
accelDecode: true,
|
||||||
|
realtime: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
job: {
|
job: {
|
||||||
[QueueName.BackgroundTask]: { concurrency: 5 },
|
[QueueName.BackgroundTask]: { concurrency: 5 },
|
||||||
|
|||||||
+38
-1
@@ -1,7 +1,15 @@
|
|||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { dirname, join } from 'node:path';
|
import { dirname, join } from 'node:path';
|
||||||
import { SemVer } from 'semver';
|
import { SemVer } from 'semver';
|
||||||
import { ApiTag, AudioCodec, DatabaseExtension, ExifOrientation, VectorIndex } from 'src/enum';
|
import {
|
||||||
|
ApiTag,
|
||||||
|
AudioCodec,
|
||||||
|
DatabaseExtension,
|
||||||
|
ExifOrientation,
|
||||||
|
TranscodeHardwareAcceleration,
|
||||||
|
VectorIndex,
|
||||||
|
VideoCodec,
|
||||||
|
} from 'src/enum';
|
||||||
|
|
||||||
export const IMMICH_SERVER_START = 'Immich Server is listening';
|
export const IMMICH_SERVER_START = 'Immich Server is listening';
|
||||||
|
|
||||||
@@ -202,3 +210,32 @@ export const AUDIO_ENCODER: Record<AudioCodec, string> = {
|
|||||||
[AudioCodec.Opus]: 'libopus',
|
[AudioCodec.Opus]: 'libopus',
|
||||||
[AudioCodec.PcmS16le]: 'pcm_s16le',
|
[AudioCodec.PcmS16le]: 'pcm_s16le',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SUPPORTED_HWA_CODECS: Record<TranscodeHardwareAcceleration, VideoCodec[]> = {
|
||||||
|
[TranscodeHardwareAcceleration.Nvenc]: [VideoCodec.H264, VideoCodec.Hevc, VideoCodec.Av1],
|
||||||
|
[TranscodeHardwareAcceleration.Qsv]: [VideoCodec.H264, VideoCodec.Hevc, VideoCodec.Vp9, VideoCodec.Av1],
|
||||||
|
[TranscodeHardwareAcceleration.Vaapi]: [VideoCodec.H264, VideoCodec.Hevc, VideoCodec.Vp9, VideoCodec.Av1],
|
||||||
|
[TranscodeHardwareAcceleration.Rkmpp]: [VideoCodec.H264, VideoCodec.Hevc],
|
||||||
|
[TranscodeHardwareAcceleration.Disabled]: [VideoCodec.H264, VideoCodec.Hevc, VideoCodec.Vp9, VideoCodec.Av1],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HLS_BACKPRESSURE_PAUSE_SEGMENTS = 30;
|
||||||
|
export const HLS_BACKPRESSURE_RESUME_SEGMENTS = 15;
|
||||||
|
export const HLS_CLEANUP_INTERVAL_MS = 60 * 1000;
|
||||||
|
export const HLS_INACTIVITY_TIMEOUT_MS = 5 * 60 * 1000;
|
||||||
|
export const HLS_LEASE_DURATION_MS = 30 * 60 * 1000;
|
||||||
|
export const HLS_PLAYLIST_CONTENT_TYPE = 'application/vnd.apple.mpegurl';
|
||||||
|
export const HLS_SEGMENT_DURATION = 2;
|
||||||
|
export const HLS_SEGMENT_FILENAME_REGEX = /^seg_(\d+)\.m4s$/;
|
||||||
|
export const HLS_VARIANTS = [
|
||||||
|
{ resolution: 480, codec: VideoCodec.Av1, bitrate: 1_000_000, codecString: 'av01.0.04M.08' },
|
||||||
|
{ resolution: 480, codec: VideoCodec.Hevc, bitrate: 1_200_000, codecString: 'hvc1.1.6.L90.B0' },
|
||||||
|
{ resolution: 480, codec: VideoCodec.H264, bitrate: 2_500_000, codecString: 'avc1.64001e' },
|
||||||
|
{ resolution: 720, codec: VideoCodec.Av1, bitrate: 2_000_000, codecString: 'av01.0.08M.08' },
|
||||||
|
{ resolution: 720, codec: VideoCodec.Hevc, bitrate: 2_500_000, codecString: 'hvc1.1.6.L93.B0' },
|
||||||
|
{ resolution: 720, codec: VideoCodec.H264, bitrate: 5_000_000, codecString: 'avc1.64001f' },
|
||||||
|
{ resolution: 1080, codec: VideoCodec.Av1, bitrate: 4_000_000, codecString: 'av01.0.09M.08' },
|
||||||
|
{ resolution: 1080, codec: VideoCodec.Hevc, bitrate: 4_500_000, codecString: 'hvc1.1.6.L120.B0' },
|
||||||
|
{ resolution: 1080, codec: VideoCodec.H264, bitrate: 8_000_000, codecString: 'avc1.640028' },
|
||||||
|
];
|
||||||
|
export const HLS_VERSION = 7;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import { TimelineController } from 'src/controllers/timeline.controller';
|
|||||||
import { TrashController } from 'src/controllers/trash.controller';
|
import { TrashController } from 'src/controllers/trash.controller';
|
||||||
import { UserAdminController } from 'src/controllers/user-admin.controller';
|
import { UserAdminController } from 'src/controllers/user-admin.controller';
|
||||||
import { UserController } from 'src/controllers/user.controller';
|
import { UserController } from 'src/controllers/user.controller';
|
||||||
|
import { VideoStreamController } from 'src/controllers/video-stream.controller';
|
||||||
import { ViewController } from 'src/controllers/view.controller';
|
import { ViewController } from 'src/controllers/view.controller';
|
||||||
import { WorkflowController } from 'src/controllers/workflow.controller';
|
import { WorkflowController } from 'src/controllers/workflow.controller';
|
||||||
|
|
||||||
@@ -76,6 +77,7 @@ export const controllers = [
|
|||||||
TrashController,
|
TrashController,
|
||||||
UserAdminController,
|
UserAdminController,
|
||||||
UserController,
|
UserController,
|
||||||
|
VideoStreamController,
|
||||||
ViewController,
|
ViewController,
|
||||||
WorkflowController,
|
WorkflowController,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { Controller, Delete, Get, Header, HttpCode, HttpStatus, Next, Param, Res } from '@nestjs/common';
|
||||||
|
import { ApiProduces, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { NextFunction, Response } from 'express';
|
||||||
|
import { HLS_PLAYLIST_CONTENT_TYPE } from 'src/constants';
|
||||||
|
import { Endpoint, HistoryBuilder } from 'src/decorators';
|
||||||
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
|
import { HlsSegmentParamDto, HlsSessionParamDto, HlsVariantParamDto } from 'src/dtos/streaming.dto';
|
||||||
|
import { ApiTag, Permission, RouteKey } from 'src/enum';
|
||||||
|
import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard';
|
||||||
|
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||||
|
import { HlsService } from 'src/services/hls.service';
|
||||||
|
import { sendFile } from 'src/utils/file';
|
||||||
|
import { UUIDParamDto } from 'src/validation';
|
||||||
|
|
||||||
|
@ApiTags(ApiTag.Assets)
|
||||||
|
@Controller(RouteKey.Asset)
|
||||||
|
export class VideoStreamController {
|
||||||
|
constructor(
|
||||||
|
private logger: LoggingRepository,
|
||||||
|
private service: HlsService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Get(':id/video/stream/main.m3u8')
|
||||||
|
@Authenticated({ permission: Permission.AssetView, sharedLink: true })
|
||||||
|
@Header('Cache-Control', 'no-cache')
|
||||||
|
@Header('Content-Type', HLS_PLAYLIST_CONTENT_TYPE)
|
||||||
|
@ApiProduces(HLS_PLAYLIST_CONTENT_TYPE)
|
||||||
|
@Endpoint({
|
||||||
|
summary: 'Get HLS main playlist',
|
||||||
|
description: 'Returns an HLS main playlist with all available variants for the asset.',
|
||||||
|
history: new HistoryBuilder().added('v3').alpha('v3'),
|
||||||
|
})
|
||||||
|
getMainPlaylist(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto) {
|
||||||
|
return this.service.getMainPlaylist(auth, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id/video/stream/:sessionId/:variantIndex/playlist.m3u8')
|
||||||
|
@Authenticated({ permission: Permission.AssetView, sharedLink: true })
|
||||||
|
@Header('Cache-Control', 'no-cache')
|
||||||
|
@Header('Content-Type', HLS_PLAYLIST_CONTENT_TYPE)
|
||||||
|
@ApiProduces(HLS_PLAYLIST_CONTENT_TYPE)
|
||||||
|
@Endpoint({
|
||||||
|
summary: 'Get HLS media playlist',
|
||||||
|
description: 'Returns an HLS media playlist for one variant of the streaming session.',
|
||||||
|
history: new HistoryBuilder().added('v3').alpha('v3'),
|
||||||
|
})
|
||||||
|
getMediaPlaylist(@Auth() auth: AuthDto, @Param() { id, sessionId }: HlsVariantParamDto) {
|
||||||
|
return this.service.getMediaPlaylist(auth, id, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id/video/stream/:sessionId/:variantIndex/:filename')
|
||||||
|
@FileResponse()
|
||||||
|
@Authenticated({ permission: Permission.AssetView, sharedLink: true })
|
||||||
|
@Endpoint({
|
||||||
|
summary: 'Get HLS segment or init file',
|
||||||
|
description: 'Streams an HLS init segment (init.mp4) or media segment (seg_N.m4s).',
|
||||||
|
history: new HistoryBuilder().added('v3').alpha('v3'),
|
||||||
|
})
|
||||||
|
async getSegment(
|
||||||
|
@Auth() auth: AuthDto,
|
||||||
|
@Param() { id, sessionId, variantIndex, filename }: HlsSegmentParamDto,
|
||||||
|
@Res() res: Response,
|
||||||
|
@Next() next: NextFunction,
|
||||||
|
) {
|
||||||
|
await sendFile(res, next, () => this.service.getSegment(auth, id, sessionId, variantIndex, filename), this.logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id/video/stream/:sessionId')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
@Authenticated({ permission: Permission.AssetView, sharedLink: true })
|
||||||
|
@Endpoint({
|
||||||
|
summary: 'End HLS streaming session',
|
||||||
|
description: 'Releases server resources for the streaming session.',
|
||||||
|
history: new HistoryBuilder().added('v3').alpha('v3'),
|
||||||
|
})
|
||||||
|
async endSession(@Auth() auth: AuthDto, @Param() { id, sessionId }: HlsSessionParamDto) {
|
||||||
|
await this.service.endSession(auth, id, sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,10 @@ export interface MoveRequest {
|
|||||||
|
|
||||||
export type ThumbnailPathEntity = { id: string; ownerId: string };
|
export type ThumbnailPathEntity = { id: string; ownerId: string };
|
||||||
|
|
||||||
|
export type HlsSessionFolder = { ownerId: string; sessionId: string };
|
||||||
|
|
||||||
|
export type HlsVariantFolder = { ownerId: string; sessionId: string; variantIndex: number };
|
||||||
|
|
||||||
export type ImagePathOptions = { fileType: AssetFileType; format: ImageFormat | RawExtractedFormat; isEdited: boolean };
|
export type ImagePathOptions = { fileType: AssetFileType; format: ImageFormat | RawExtractedFormat; isEdited: boolean };
|
||||||
|
|
||||||
let instance: StorageCore | null;
|
let instance: StorageCore | null;
|
||||||
@@ -125,6 +129,14 @@ export class StorageCore {
|
|||||||
return StorageCore.getNestedPath(StorageFolder.EncodedVideo, asset.ownerId, `${asset.id}.mp4`);
|
return StorageCore.getNestedPath(StorageFolder.EncodedVideo, asset.ownerId, `${asset.id}.mp4`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getHlsSessionFolder({ ownerId, sessionId }: HlsSessionFolder) {
|
||||||
|
return StorageCore.getNestedPath(StorageFolder.EncodedVideo, ownerId, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getHlsVariantFolder({ ownerId, sessionId, variantIndex }: HlsVariantFolder) {
|
||||||
|
return join(StorageCore.getHlsSessionFolder({ ownerId, sessionId }), variantIndex.toString());
|
||||||
|
}
|
||||||
|
|
||||||
static getAndroidMotionPath(asset: ThumbnailPathEntity, uuid: string) {
|
static getAndroidMotionPath(asset: ThumbnailPathEntity, uuid: string) {
|
||||||
return StorageCore.getNestedPath(StorageFolder.EncodedVideo, asset.ownerId, `${uuid}-MP.mp4`);
|
return StorageCore.getNestedPath(StorageFolder.EncodedVideo, asset.ownerId, `${uuid}-MP.mp4`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,18 +36,16 @@ const ActivityStatisticsResponseSchema = z
|
|||||||
})
|
})
|
||||||
.meta({ id: 'ActivityStatisticsResponseDto' });
|
.meta({ id: 'ActivityStatisticsResponseDto' });
|
||||||
|
|
||||||
const ActivitySchema = z
|
const ActivitySchema = z.object({
|
||||||
.object({
|
albumId: z.uuidv4().describe('Album ID'),
|
||||||
albumId: z.uuidv4().describe('Album ID'),
|
assetId: z.uuidv4().optional().describe('Asset ID (if activity is for an asset)'),
|
||||||
assetId: z.uuidv4().optional().describe('Asset ID (if activity is for an asset)'),
|
});
|
||||||
})
|
|
||||||
.describe('Activity');
|
|
||||||
|
|
||||||
const ActivitySearchSchema = ActivitySchema.extend({
|
const ActivitySearchSchema = ActivitySchema.extend({
|
||||||
type: ReactionTypeSchema.optional(),
|
type: ReactionTypeSchema.optional(),
|
||||||
level: ReactionLevelSchema.optional(),
|
level: ReactionLevelSchema.optional(),
|
||||||
userId: z.uuidv4().optional().describe('Filter by user ID'),
|
userId: z.uuidv4().optional().describe('Filter by user ID'),
|
||||||
}).describe('Activity search');
|
});
|
||||||
|
|
||||||
const ActivityCreateSchema = ActivitySchema.extend({
|
const ActivityCreateSchema = ActivitySchema.extend({
|
||||||
type: ReactionTypeSchema,
|
type: ReactionTypeSchema,
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { createZodDto } from 'nestjs-zod';
|
||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
const HlsSessionParamSchema = z.object({
|
||||||
|
id: z.uuidv4(),
|
||||||
|
sessionId: z.uuidv4(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export class HlsSessionParamDto extends createZodDto(HlsSessionParamSchema) {}
|
||||||
|
|
||||||
|
const HlsVariantParamSchema = z.object({
|
||||||
|
id: z.uuidv4(),
|
||||||
|
sessionId: z.uuidv4(),
|
||||||
|
variantIndex: z.coerce.number().int().min(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
export class HlsVariantParamDto extends createZodDto(HlsVariantParamSchema) {}
|
||||||
|
|
||||||
|
const HlsSegmentParamSchema = z.object({
|
||||||
|
id: z.uuidv4(),
|
||||||
|
sessionId: z.uuidv4(),
|
||||||
|
variantIndex: z.coerce.number().int().min(0),
|
||||||
|
filename: z.string().regex(/^(init\.mp4|seg_\d+\.m4s)$/, { error: 'Invalid HLS segment filename' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
export class HlsSegmentParamDto extends createZodDto(HlsSegmentParamSchema) {}
|
||||||
@@ -79,6 +79,11 @@ const SystemConfigFFmpegSchema = z
|
|||||||
accel: TranscodeHardwareAccelerationSchema,
|
accel: TranscodeHardwareAccelerationSchema,
|
||||||
accelDecode: configBool.describe('Accelerated decode'),
|
accelDecode: configBool.describe('Accelerated decode'),
|
||||||
tonemap: ToneMappingSchema,
|
tonemap: ToneMappingSchema,
|
||||||
|
realtime: z
|
||||||
|
.object({
|
||||||
|
enabled: configBool.describe('Enable real-time HLS transcoding (alpha)'),
|
||||||
|
})
|
||||||
|
.meta({ id: 'SystemConfigFFmpegRealtimeDto' }),
|
||||||
})
|
})
|
||||||
.meta({ id: 'SystemConfigFFmpegDto' });
|
.meta({ id: 'SystemConfigFFmpegDto' });
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -452,11 +452,7 @@ export enum VideoCodec {
|
|||||||
|
|
||||||
export const VideoCodecSchema = z.enum(VideoCodec).describe('Target video codec').meta({ id: 'VideoCodec' });
|
export const VideoCodecSchema = z.enum(VideoCodec).describe('Target video codec').meta({ id: 'VideoCodec' });
|
||||||
|
|
||||||
export enum VideoSegmentCodec {
|
export type VideoSegmentCodec = VideoCodec.Av1 | VideoCodec.Hevc | VideoCodec.H264;
|
||||||
Av1 = 'av1',
|
|
||||||
Hevc = 'hevc',
|
|
||||||
H264 = 'h264',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum AudioCodec {
|
export enum AudioCodec {
|
||||||
Mp3 = 'mp3',
|
Mp3 = 'mp3',
|
||||||
@@ -826,6 +822,8 @@ export enum JobName {
|
|||||||
LibrarySyncFiles = 'LibrarySyncFiles',
|
LibrarySyncFiles = 'LibrarySyncFiles',
|
||||||
LibraryScanQueueAll = 'LibraryScanQueueAll',
|
LibraryScanQueueAll = 'LibraryScanQueueAll',
|
||||||
|
|
||||||
|
HlsSessionCleanup = 'HlsSessionCleanup',
|
||||||
|
|
||||||
MemoryCleanup = 'MemoryCleanup',
|
MemoryCleanup = 'MemoryCleanup',
|
||||||
MemoryGenerate = 'MemoryGenerate',
|
MemoryGenerate = 'MemoryGenerate',
|
||||||
|
|
||||||
@@ -919,6 +917,7 @@ export enum DatabaseLock {
|
|||||||
MaintenanceOperation = 621,
|
MaintenanceOperation = 621,
|
||||||
MemoryCreation = 777,
|
MemoryCreation = 777,
|
||||||
VersionCheck = 800,
|
VersionCheck = 800,
|
||||||
|
HlsSessionCleanup = 850,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MaintenanceAction {
|
export enum MaintenanceAction {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from
|
|||||||
"video_stream_session"
|
"video_stream_session"
|
||||||
where
|
where
|
||||||
"id" = $1
|
"id" = $1
|
||||||
|
and "expiresAt" > $2
|
||||||
|
|
||||||
-- VideoStreamRepository.getVariant
|
-- VideoStreamRepository.getVariant
|
||||||
select
|
select
|
||||||
@@ -27,11 +28,13 @@ where
|
|||||||
|
|
||||||
-- VideoStreamRepository.getExpiredSessions
|
-- VideoStreamRepository.getExpiredSessions
|
||||||
select
|
select
|
||||||
"id"
|
"video_stream_session"."id",
|
||||||
|
"asset"."ownerId"
|
||||||
from
|
from
|
||||||
"video_stream_session"
|
"video_stream_session"
|
||||||
|
inner join "asset" on "asset"."id" = "video_stream_session"."assetId"
|
||||||
where
|
where
|
||||||
"expiresAt" <= $1
|
"video_stream_session"."expiresAt" <= $1
|
||||||
|
|
||||||
-- VideoStreamRepository.extendSession
|
-- VideoStreamRepository.extendSession
|
||||||
update "video_stream_session"
|
update "video_stream_session"
|
||||||
@@ -44,3 +47,253 @@ where
|
|||||||
delete from "video_stream_session"
|
delete from "video_stream_session"
|
||||||
where
|
where
|
||||||
"id" = $1
|
"id" = $1
|
||||||
|
|
||||||
|
-- VideoStreamRepository.getForMainPlaylist
|
||||||
|
select
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_video"."index",
|
||||||
|
"asset_video"."codecName",
|
||||||
|
"asset_video"."profile",
|
||||||
|
"asset_video"."level",
|
||||||
|
"asset_video"."bitrate",
|
||||||
|
"asset_exif"."exifImageWidth" as "width",
|
||||||
|
"asset_exif"."exifImageHeight" as "height",
|
||||||
|
"asset_video"."pixelFormat",
|
||||||
|
"asset_video"."frameCount",
|
||||||
|
"asset_exif"."fps" as "frameRate",
|
||||||
|
"asset_video"."timeBase",
|
||||||
|
case
|
||||||
|
when "asset_exif"."orientation" = '6' then -90
|
||||||
|
when "asset_exif"."orientation" = '8' then 90
|
||||||
|
when "asset_exif"."orientation" = '3' then 180
|
||||||
|
else 0
|
||||||
|
end as "rotation",
|
||||||
|
"asset_video"."colorPrimaries",
|
||||||
|
"asset_video"."colorMatrix",
|
||||||
|
"asset_video"."colorTransfer",
|
||||||
|
"asset_video"."dvProfile",
|
||||||
|
"asset_video"."dvLevel",
|
||||||
|
"asset_video"."dvBlSignalCompatibilityId"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_video"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "videoStream",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_keyframe"."pts" as "keyframePts",
|
||||||
|
"asset_keyframe"."accDuration" as "keyframeAccDuration",
|
||||||
|
"asset_keyframe"."ownDuration" as "keyframeOwnDuration",
|
||||||
|
"asset_keyframe"."totalDuration",
|
||||||
|
"asset_keyframe"."packetCount",
|
||||||
|
"asset_keyframe"."outputFrames"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_keyframe"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "packets"
|
||||||
|
from
|
||||||
|
"asset"
|
||||||
|
inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
|
||||||
|
inner join "asset_video" on "asset"."id" = "asset_video"."assetId"
|
||||||
|
inner join "asset_keyframe" on "asset"."id" = "asset_keyframe"."assetId"
|
||||||
|
where
|
||||||
|
"asset"."id" = $1
|
||||||
|
|
||||||
|
-- VideoStreamRepository.getForMediaPlaylist
|
||||||
|
select
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_video"."index",
|
||||||
|
"asset_video"."codecName",
|
||||||
|
"asset_video"."profile",
|
||||||
|
"asset_video"."level",
|
||||||
|
"asset_video"."bitrate",
|
||||||
|
"asset_exif"."exifImageWidth" as "width",
|
||||||
|
"asset_exif"."exifImageHeight" as "height",
|
||||||
|
"asset_video"."pixelFormat",
|
||||||
|
"asset_video"."frameCount",
|
||||||
|
"asset_exif"."fps" as "frameRate",
|
||||||
|
"asset_video"."timeBase",
|
||||||
|
case
|
||||||
|
when "asset_exif"."orientation" = '6' then -90
|
||||||
|
when "asset_exif"."orientation" = '8' then 90
|
||||||
|
when "asset_exif"."orientation" = '3' then 180
|
||||||
|
else 0
|
||||||
|
end as "rotation",
|
||||||
|
"asset_video"."colorPrimaries",
|
||||||
|
"asset_video"."colorMatrix",
|
||||||
|
"asset_video"."colorTransfer",
|
||||||
|
"asset_video"."dvProfile",
|
||||||
|
"asset_video"."dvLevel",
|
||||||
|
"asset_video"."dvBlSignalCompatibilityId"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_video"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "videoStream",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_keyframe"."pts" as "keyframePts",
|
||||||
|
"asset_keyframe"."accDuration" as "keyframeAccDuration",
|
||||||
|
"asset_keyframe"."ownDuration" as "keyframeOwnDuration",
|
||||||
|
"asset_keyframe"."totalDuration",
|
||||||
|
"asset_keyframe"."packetCount",
|
||||||
|
"asset_keyframe"."outputFrames"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_keyframe"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "packets"
|
||||||
|
from
|
||||||
|
"asset"
|
||||||
|
inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
|
||||||
|
inner join "video_stream_session" on "asset"."id" = "video_stream_session"."assetId"
|
||||||
|
inner join "asset_video" on "asset"."id" = "asset_video"."assetId"
|
||||||
|
inner join "asset_keyframe" on "asset"."id" = "asset_keyframe"."assetId"
|
||||||
|
where
|
||||||
|
"asset"."id" = $1
|
||||||
|
and "video_stream_session"."id" = $2
|
||||||
|
and "video_stream_session"."expiresAt" > $3
|
||||||
|
|
||||||
|
-- VideoStreamRepository.getForTranscoding
|
||||||
|
select
|
||||||
|
"asset"."originalPath",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_audio"."index",
|
||||||
|
"asset_audio"."codecName",
|
||||||
|
"asset_audio"."profile",
|
||||||
|
"asset_audio"."bitrate"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_audio"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "audioStream",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_video"."index",
|
||||||
|
"asset_video"."codecName",
|
||||||
|
"asset_video"."profile",
|
||||||
|
"asset_video"."level",
|
||||||
|
"asset_video"."bitrate",
|
||||||
|
"asset_exif"."exifImageWidth" as "width",
|
||||||
|
"asset_exif"."exifImageHeight" as "height",
|
||||||
|
"asset_video"."pixelFormat",
|
||||||
|
"asset_video"."frameCount",
|
||||||
|
"asset_exif"."fps" as "frameRate",
|
||||||
|
"asset_video"."timeBase",
|
||||||
|
case
|
||||||
|
when "asset_exif"."orientation" = '6' then -90
|
||||||
|
when "asset_exif"."orientation" = '8' then 90
|
||||||
|
when "asset_exif"."orientation" = '3' then 180
|
||||||
|
else 0
|
||||||
|
end as "rotation",
|
||||||
|
"asset_video"."colorPrimaries",
|
||||||
|
"asset_video"."colorMatrix",
|
||||||
|
"asset_video"."colorTransfer",
|
||||||
|
"asset_video"."dvProfile",
|
||||||
|
"asset_video"."dvLevel",
|
||||||
|
"asset_video"."dvBlSignalCompatibilityId"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_video"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "videoStream",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_video"."formatName",
|
||||||
|
"asset_video"."formatLongName",
|
||||||
|
"asset"."duration",
|
||||||
|
"asset_video"."bitrate"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_video"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "format",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"asset_keyframe"."pts" as "keyframePts",
|
||||||
|
"asset_keyframe"."accDuration" as "keyframeAccDuration",
|
||||||
|
"asset_keyframe"."ownDuration" as "keyframeOwnDuration",
|
||||||
|
"asset_keyframe"."totalDuration",
|
||||||
|
"asset_keyframe"."packetCount",
|
||||||
|
"asset_keyframe"."outputFrames"
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
1
|
||||||
|
) as "dummy"
|
||||||
|
where
|
||||||
|
"asset_keyframe"."assetId" is not null
|
||||||
|
) as obj
|
||||||
|
) as "packets"
|
||||||
|
from
|
||||||
|
"asset"
|
||||||
|
inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
|
||||||
|
left join "asset_audio" on "asset"."id" = "asset_audio"."assetId"
|
||||||
|
inner join "asset_video" on "asset"."id" = "asset_video"."assetId"
|
||||||
|
inner join "asset_keyframe" on "asset"."id" = "asset_keyframe"."assetId"
|
||||||
|
where
|
||||||
|
"asset"."id" = $1
|
||||||
|
|||||||
@@ -92,6 +92,14 @@ type EventMap = {
|
|||||||
|
|
||||||
AuthChangePassword: [{ userId: string; currentSessionId?: string; invalidateSessions?: boolean }];
|
AuthChangePassword: [{ userId: string; currentSessionId?: string; invalidateSessions?: boolean }];
|
||||||
|
|
||||||
|
// hls streaming events
|
||||||
|
HlsSegmentRequest: [{ sessionId: string; assetId: string; variantIndex: number; segmentIndex: number }];
|
||||||
|
HlsSegmentResult: [{ sessionId: string; variantIndex: number; segmentIndex: number; error?: string }];
|
||||||
|
HlsHeartbeat: [{ sessionId: string; variantIndex?: number; segmentIndex?: number }];
|
||||||
|
HlsSessionRequest: [{ sessionId: string; assetId: string; ownerId: string }];
|
||||||
|
HlsSessionResult: [{ sessionId: string; error?: string }];
|
||||||
|
HlsSessionEnd: [{ sessionId: string }];
|
||||||
|
|
||||||
// websocket events
|
// websocket events
|
||||||
WebsocketConnect: [{ userId: string }];
|
WebsocketConnect: [{ userId: string }];
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user