Compare commits
4 Commits
workflows
...
mobile/onb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5645f9982d | ||
|
|
90f893df66 | ||
|
|
9e99973c18 | ||
|
|
5818197c10 |
1
.github/workflows/pr-label-validation.yml
vendored
1
.github/workflows/pr-label-validation.yml
vendored
@@ -19,4 +19,3 @@ jobs:
|
|||||||
use_regex: true
|
use_regex: true
|
||||||
labels: "changelog:.*"
|
labels: "changelog:.*"
|
||||||
add_comment: true
|
add_comment: true
|
||||||
message: "Label error. Requires {{errorString}} {{count}} of: {{ provided }}. Found: {{ applied }}. A maintainer will add the required label."
|
|
||||||
|
|||||||
@@ -69,8 +69,7 @@ However, Immich will delete original files that have been trashed when the trash
|
|||||||
|
|
||||||
### Why do my file names appear as a random string in the file manager?
|
### Why do my file names appear as a random string in the file manager?
|
||||||
|
|
||||||
When Storage Template is off (default) Immich saves the file names in a random string (also known as random UUIDs) to prevent duplicate file names.
|
When Storage Template is off (default) Immich saves the file names in a random string (also known as random UUIDs) to prevent duplicate file names. To retrieve the original file names, you must enable the Storage Template and then run the STORAGE TEMPLATE MIGRATION job.
|
||||||
To retrieve the original file names, you must enable the Storage Template and then run the STORAGE TEMPLATE MIGRATION job.
|
|
||||||
It is recommended to read about [Storage Template](https://immich.app/docs/administration/storage-template) before activation.
|
It is recommended to read about [Storage Template](https://immich.app/docs/administration/storage-template) before activation.
|
||||||
|
|
||||||
### Can I add my existing photo library?
|
### Can I add my existing photo library?
|
||||||
@@ -83,20 +82,11 @@ Template changes will only apply to _new_ assets. To retroactively apply the tem
|
|||||||
|
|
||||||
### Why are only photos and not videos being uploaded to Immich?
|
### Why are only photos and not videos being uploaded to Immich?
|
||||||
|
|
||||||
This often happens when using a reverse proxy in front of Immich.
|
This often happens when using a reverse proxy (such as Nginx or Cloudflare tunnel) in front of Immich. Make sure to set your reverse proxy to allow large `POST` requests. In `nginx`, set `client_max_body_size 50000M;` or similar. Also, check the disk space of your reverse proxy. In some cases, proxies cache requests to disk before passing them on, and if disk space runs out, the request fails.
|
||||||
Make sure to [set your reverse proxy](/docs/administration/reverse-proxy/) to allow large requests.
|
|
||||||
Also, check the disk space of your reverse proxy.
|
|
||||||
In some cases, proxies cache requests to disk before passing them on, and if disk space runs out, the request fails.
|
|
||||||
|
|
||||||
If you are using Cloudflare Tunnel, please know that they set a maxiumum filesize of 100 MB that cannot be changed.
|
|
||||||
At times, files larger than this may work, potentially up to 1 GB. However, the official limit is 100 MB.
|
|
||||||
If you are having issues, we recommend switching to a different network deployment.
|
|
||||||
|
|
||||||
### Why are some photos stored in the file system with the wrong date?
|
### Why are some photos stored in the file system with the wrong date?
|
||||||
|
|
||||||
There are a few different scenarios that can lead to this situation. The solution is to rerun the storage migration job.
|
There are a few different scenarios that can lead to this situation. The solution is to rerun the storage migration job. The job is only automatically run once per asset after upload. If metadata extraction originally failed, the jobs were cleared/canceled, etc., the job may not have run automatically the first time.
|
||||||
The job is only automatically run once per asset after upload. If metadata extraction originally failed, the jobs were cleared/canceled, etc.,
|
|
||||||
the job may not have run automatically the first time.
|
|
||||||
|
|
||||||
### How can I hide photos from the timeline?
|
### How can I hide photos from the timeline?
|
||||||
|
|
||||||
@@ -126,8 +116,7 @@ Also, there are additional jobs for person (face) thumbnails.
|
|||||||
|
|
||||||
### Why do files from WhatsApp not appear with the correct date?
|
### Why do files from WhatsApp not appear with the correct date?
|
||||||
|
|
||||||
Files sent on WhatsApp are saved without metadata on the file. Therefore, Immich has no way of knowing the original date of the file when files are uploaded from WhatsApp,
|
Files sent on WhatsApp are saved without metadata on the file. Therefore, Immich has no way of knowing the original date of the file when files are uploaded from WhatsApp, not the order of arrival on the device. [See #3527](https://github.com/immich-app/immich/issues/3527).
|
||||||
not the order of arrival on the device. [See #9116](https://github.com/immich-app/immich/discussions/9116).
|
|
||||||
|
|
||||||
### What happens if an asset exists in more than one account?
|
### What happens if an asset exists in more than one account?
|
||||||
|
|
||||||
@@ -319,7 +308,7 @@ Do not exaggerate with the job concurrency because you're probably thoroughly ov
|
|||||||
|
|
||||||
### My server shows Server Status Offline | Version Unknown. What can I do?
|
### My server shows Server Status Offline | Version Unknown. What can I do?
|
||||||
|
|
||||||
You need to [enable WebSockets](/docs/administration/reverse-proxy/) on your reverse proxy.
|
You need to enable WebSockets on your reverse proxy.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -350,7 +339,7 @@ The non-root user/group needs read/write access to the volume mounts, including
|
|||||||
The Docker Compose top level volume element does not support non-root access, all of the above volumes must be local volume mounts.
|
The Docker Compose top level volume element does not support non-root access, all of the above volumes must be local volume mounts.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
For a further hardened system, you can add the following block to every container.
|
For a further hardened system, you can add the following block to every container except for `immich_postgres`.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>docker-compose.yml</summary>
|
<summary>docker-compose.yml</summary>
|
||||||
@@ -399,21 +388,22 @@ If the error says the worker is exiting, then this is normal. This is a feature
|
|||||||
|
|
||||||
There are a few reasons why this can happen.
|
There are a few reasons why this can happen.
|
||||||
|
|
||||||
If the error mentions SIGKILL or error code 137, it most likely means the service is running out of memory.
|
If the error mentions SIGKILL or error code 137, it most likely means the service is running out of memory. Consider either increasing the server's RAM or moving the service to a server with more RAM.
|
||||||
Consider either increasing the server's RAM or moving the service to a server with more RAM.
|
|
||||||
|
|
||||||
If it mentions SIGILL (note the lack of a K) or error code 132, it most likely means your server's CPU is incompatible with Immich.
|
If it mentions SIGILL (note the lack of a K) or error code 132, it most likely means your server's CPU is incompatible. This is unlikely to occur on version 1.92.0 or later. Consider upgrading if your version of Immich is below that.
|
||||||
|
|
||||||
|
If your version of Immich is below 1.92.0 and the crash occurs after logs about tracing or exporting a model, consider either upgrading or disabling the Tag Objects job.
|
||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
### Why am I getting database ownership errors?
|
### Why am I getting database ownership errors?
|
||||||
|
|
||||||
If you get database errors such as `FATAL: data directory "/var/lib/postgresql/data" has wrong ownership` upon database startup, this is likely due to an issue with your filesystem.
|
If you get database errors such as `FATAL: data directory "/var/lib/postgresql/data" has wrong ownership` upon database startup, this is likely due to an issue with your filesystem.
|
||||||
NTFS and ex/FAT/32 filesystems are not supported. See [here](/docs/install/requirements#special-requirements-for-windows-users) for more details.
|
NTFS and ex/FAT/32 filesystems are not supported. See [here](/docs/install/environment-variables#supported-filesystems) for more details.
|
||||||
|
|
||||||
### How can I verify the integrity of my database?
|
### How can I verify the integrity of my database?
|
||||||
|
|
||||||
Database checksums are enabled by default for new installations since v1.104.0. You can check if they are enabled by running the following command.
|
If you installed Immich using v1.104.0 or later, you likely have database checksums enabled by default. You can check this by running the following command.
|
||||||
A result of `on` means that checksums are enabled.
|
A result of `on` means that checksums are enabled.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@@ -429,7 +419,7 @@ docker exec -it immich_postgres psql --dbname=immich --username=<DB_USERNAME> --
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
If checksums are enabled, you can check the status of the database with the following command. A normal result is all `0`s.
|
If checksums are enabled, you can check the status of the database with the following command. A normal result is all zeroes.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Check for database corruption</summary>
|
<summary>Check for database corruption</summary>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LibraryResponseDto, LoginResponseDto, getAllLibraries, scanLibrary } from '@immich/sdk';
|
import { LibraryResponseDto, LoginResponseDto, getAllLibraries, scanLibrary } from '@immich/sdk';
|
||||||
import { cpSync, existsSync, rmSync, unlinkSync } from 'node:fs';
|
import { cpSync, existsSync } from 'node:fs';
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { userDto, uuidDto } from 'src/fixtures';
|
import { userDto, uuidDto } from 'src/fixtures';
|
||||||
import { errorDto } from 'src/responses';
|
import { errorDto } from 'src/responses';
|
||||||
@@ -403,157 +403,68 @@ describe('/libraries', () => {
|
|||||||
utils.removeImageFile(`${testAssetDir}/temp/folder} b/assetB.png`);
|
utils.removeImageFile(`${testAssetDir}/temp/folder} b/assetB.png`);
|
||||||
});
|
});
|
||||||
|
|
||||||
const annoyingChars = [
|
|
||||||
"'",
|
|
||||||
'"',
|
|
||||||
'`',
|
|
||||||
'*',
|
|
||||||
'{',
|
|
||||||
'}',
|
|
||||||
',',
|
|
||||||
'(',
|
|
||||||
')',
|
|
||||||
'[',
|
|
||||||
']',
|
|
||||||
'?',
|
|
||||||
'!',
|
|
||||||
'@',
|
|
||||||
'#',
|
|
||||||
'$',
|
|
||||||
'%',
|
|
||||||
'^',
|
|
||||||
'&',
|
|
||||||
'=',
|
|
||||||
'+',
|
|
||||||
'~',
|
|
||||||
'|',
|
|
||||||
'<',
|
|
||||||
'>',
|
|
||||||
';',
|
|
||||||
':',
|
|
||||||
'/', // We never got backslashes to work
|
|
||||||
];
|
|
||||||
|
|
||||||
it.each(annoyingChars)('should scan multiple import paths with %s', async (char) => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/folder${char}1`, `${testAssetDirInternal}/temp/folder${char}2`],
|
|
||||||
});
|
|
||||||
|
|
||||||
utils.createImageFile(`${testAssetDir}/temp/folder${char}1/asset1.png`);
|
|
||||||
utils.createImageFile(`${testAssetDir}/temp/folder${char}2/asset2.png`);
|
|
||||||
|
|
||||||
const { status } = await request(app)
|
|
||||||
.post(`/libraries/${library.id}/scan`)
|
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
|
||||||
.send();
|
|
||||||
expect(status).toBe(204);
|
|
||||||
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
|
|
||||||
const { assets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(assets.items).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.objectContaining({ originalPath: expect.stringContaining(`folder${char}1/asset1.png`) }),
|
|
||||||
expect.objectContaining({ originalPath: expect.stringContaining(`folder${char}2/asset2.png`) }),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
|
|
||||||
utils.removeImageFile(`${testAssetDir}/temp/folder${char}1/asset1.png`);
|
|
||||||
utils.removeImageFile(`${testAssetDir}/temp/folder${char}2/asset2.png`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reimport a modified file', async () => {
|
it('should reimport a modified file', async () => {
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
const library = await utils.createLibrary(admin.accessToken, {
|
||||||
ownerId: admin.userId,
|
ownerId: admin.userId,
|
||||||
importPaths: [`${testAssetDirInternal}/temp/reimport`],
|
importPaths: [`${testAssetDirInternal}/temp`],
|
||||||
});
|
});
|
||||||
|
|
||||||
utils.createImageFile(`${testAssetDir}/temp/reimport/asset.jpg`);
|
utils.createImageFile(`${testAssetDir}/temp/directoryA/assetB.jpg`);
|
||||||
await utimes(`${testAssetDir}/temp/reimport/asset.jpg`, 447_775_200_000);
|
await utimes(`${testAssetDir}/temp/directoryA/assetB.jpg`, 447_775_200_000);
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
await scan(admin.accessToken, library.id);
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/albums/nature/tanners_ridge.jpg`, `${testAssetDir}/temp/reimport/asset.jpg`);
|
cpSync(`${testAssetDir}/albums/nature/tanners_ridge.jpg`, `${testAssetDir}/temp/directoryA/assetB.jpg`);
|
||||||
await utimes(`${testAssetDir}/temp/reimport/asset.jpg`, 447_775_200_001);
|
await utimes(`${testAssetDir}/temp/directoryA/assetB.jpg`, 447_775_200_001);
|
||||||
|
|
||||||
const { status } = await request(app)
|
const { status } = await request(app)
|
||||||
.post(`/libraries/${library.id}/scan`)
|
.post(`/libraries/${library.id}/scan`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
.send();
|
.send({ refreshModifiedFiles: true });
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
||||||
|
utils.removeImageFile(`${testAssetDir}/temp/directoryA/assetB.jpg`);
|
||||||
|
|
||||||
const { assets } = await utils.searchAssets(admin.accessToken, {
|
const { assets } = await utils.searchAssets(admin.accessToken, {
|
||||||
libraryId: library.id,
|
libraryId: library.id,
|
||||||
|
model: 'NIKON D750',
|
||||||
});
|
});
|
||||||
|
expect(assets.count).toBe(1);
|
||||||
expect(assets.count).toEqual(1);
|
|
||||||
|
|
||||||
const asset = await utils.getAssetInfo(admin.accessToken, assets.items[0].id);
|
|
||||||
|
|
||||||
expect(asset).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'asset.jpg',
|
|
||||||
exifInfo: expect.objectContaining({
|
|
||||||
model: 'NIKON D750',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
utils.removeImageFile(`${testAssetDir}/temp/reimport/asset.jpg`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not reimport unmodified files', async () => {
|
it('should not reimport unmodified files', async () => {
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
const library = await utils.createLibrary(admin.accessToken, {
|
||||||
ownerId: admin.userId,
|
ownerId: admin.userId,
|
||||||
importPaths: [`${testAssetDirInternal}/temp/reimport`],
|
importPaths: [`${testAssetDirInternal}/temp`],
|
||||||
});
|
});
|
||||||
|
|
||||||
utils.createImageFile(`${testAssetDir}/temp/reimport/asset.jpg`);
|
utils.createImageFile(`${testAssetDir}/temp/directoryA/assetB.jpg`);
|
||||||
await utimes(`${testAssetDir}/temp/reimport/asset.jpg`, 447_775_200_000);
|
await utimes(`${testAssetDir}/temp/directoryA/assetB.jpg`, 447_775_200_000);
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
await scan(admin.accessToken, library.id);
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/albums/nature/tanners_ridge.jpg`, `${testAssetDir}/temp/reimport/asset.jpg`);
|
cpSync(`${testAssetDir}/albums/nature/tanners_ridge.jpg`, `${testAssetDir}/temp/directoryA/assetB.jpg`);
|
||||||
await utimes(`${testAssetDir}/temp/reimport/asset.jpg`, 447_775_200_000);
|
await utimes(`${testAssetDir}/temp/directoryA/assetB.jpg`, 447_775_200_000);
|
||||||
|
|
||||||
const { status } = await request(app)
|
const { status } = await request(app)
|
||||||
.post(`/libraries/${library.id}/scan`)
|
.post(`/libraries/${library.id}/scan`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
.send();
|
.send({ refreshModifiedFiles: true });
|
||||||
expect(status).toBe(204);
|
expect(status).toBe(204);
|
||||||
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
||||||
|
utils.removeImageFile(`${testAssetDir}/temp/directoryA/assetB.jpg`);
|
||||||
|
|
||||||
const { assets } = await utils.searchAssets(admin.accessToken, {
|
const { assets } = await utils.searchAssets(admin.accessToken, {
|
||||||
libraryId: library.id,
|
libraryId: library.id,
|
||||||
|
model: 'NIKON D750',
|
||||||
});
|
});
|
||||||
|
expect(assets.count).toBe(0);
|
||||||
expect(assets.count).toEqual(1);
|
|
||||||
|
|
||||||
const asset = await utils.getAssetInfo(admin.accessToken, assets.items[0].id);
|
|
||||||
|
|
||||||
expect(asset).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'asset.jpg',
|
|
||||||
exifInfo: expect.not.objectContaining({
|
|
||||||
model: 'NIKON D750',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
utils.removeImageFile(`${testAssetDir}/temp/reimport/asset.jpg`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set an asset offline if its file is missing', async () => {
|
it('should set an asset offline if its file is missing', async () => {
|
||||||
@@ -690,298 +601,6 @@ describe('/libraries', () => {
|
|||||||
|
|
||||||
expect(assets).toEqual(assetsBefore);
|
expect(assets).toEqual(assetsBefore);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('xmp metadata', async () => {
|
|
||||||
it('should import metadata from file.xmp', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2000-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import metadata from file.ext.xmp', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2000-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import metadata in file.ext.xmp before file.xmp if both exist', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2010.xmp`, `${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2000-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should switch from using file.xmp to file.ext.xmp when asset refreshes', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_000);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2010.xmp`, `${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
unlinkSync(`${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_001);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2010-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should switch from using file metadata to file.xmp metadata when asset refreshes', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_000);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_001);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2000-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should switch from using file metadata to file.xmp metadata when asset refreshes', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_000);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_001);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2000-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should switch from using file.ext.xmp to file.xmp when asset refreshes', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_000);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2010.xmp`, `${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
unlinkSync(`${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_001);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2010-09-27T12:35:33.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should switch from using file.ext.xmp to file metadata', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_000);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
unlinkSync(`${testAssetDir}/temp/xmp/glarus.nef.xmp`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_001);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2010-07-20T17:27:12.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should switch from using file.xmp to file metadata', async () => {
|
|
||||||
const library = await utils.createLibrary(admin.accessToken, {
|
|
||||||
ownerId: admin.userId,
|
|
||||||
importPaths: [`${testAssetDirInternal}/temp/xmp`],
|
|
||||||
});
|
|
||||||
|
|
||||||
cpSync(`${testAssetDir}/metadata/xmp/dates/2000.xmp`, `${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
cpSync(`${testAssetDir}/formats/raw/Nikon/D80/glarus.nef`, `${testAssetDir}/temp/xmp/glarus.nef`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_000);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
unlinkSync(`${testAssetDir}/temp/xmp/glarus.xmp`);
|
|
||||||
await utimes(`${testAssetDir}/temp/xmp/glarus.nef`, 447_775_200_001);
|
|
||||||
|
|
||||||
await scan(admin.accessToken, library.id);
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'sidecar');
|
|
||||||
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
|
|
||||||
|
|
||||||
const { assets: newAssets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
|
|
||||||
|
|
||||||
expect(newAssets.items).toEqual([
|
|
||||||
expect.objectContaining({
|
|
||||||
originalFileName: 'glarus.nef',
|
|
||||||
fileCreatedAt: '2010-07-20T17:27:12.000Z',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
rmSync(`${testAssetDir}/temp/xmp`, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /libraries/:id/validate', () => {
|
describe('POST /libraries/:id/validate', () => {
|
||||||
|
|||||||
Submodule e2e/test-assets updated: 9e3b964b08...99544a2004
@@ -1142,7 +1142,6 @@
|
|||||||
"set": "Set",
|
"set": "Set",
|
||||||
"set_as_album_cover": "Set as album cover",
|
"set_as_album_cover": "Set as album cover",
|
||||||
"set_as_profile_picture": "Set as profile picture",
|
"set_as_profile_picture": "Set as profile picture",
|
||||||
"set_as_featured_photo": "Set as featured photo",
|
|
||||||
"set_date_of_birth": "Set date of birth",
|
"set_date_of_birth": "Set date of birth",
|
||||||
"set_profile_picture": "Set profile picture",
|
"set_profile_picture": "Set profile picture",
|
||||||
"set_slideshow_to_fullscreen": "Set Slideshow to fullscreen",
|
"set_slideshow_to_fullscreen": "Set Slideshow to fullscreen",
|
||||||
@@ -1197,7 +1196,6 @@
|
|||||||
"sort_items": "Number of items",
|
"sort_items": "Number of items",
|
||||||
"sort_modified": "Date modified",
|
"sort_modified": "Date modified",
|
||||||
"sort_oldest": "Oldest photo",
|
"sort_oldest": "Oldest photo",
|
||||||
"sort_people_by_similarity": "Sort people by similarity",
|
|
||||||
"sort_recent": "Most recent photo",
|
"sort_recent": "Most recent photo",
|
||||||
"sort_title": "Title",
|
"sort_title": "Title",
|
||||||
"source": "Source",
|
"source": "Source",
|
||||||
@@ -1338,6 +1336,5 @@
|
|||||||
"years_ago": "{years, plural, one {# year} other {# years}} ago",
|
"years_ago": "{years, plural, one {# year} other {# years}} ago",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"you_dont_have_any_shared_links": "You don't have any shared links",
|
"you_dont_have_any_shared_links": "You don't have any shared links",
|
||||||
"zoom_image": "Zoom Image",
|
"zoom_image": "Zoom Image"
|
||||||
"workflows": "Workflows"
|
|
||||||
}
|
}
|
||||||
|
|||||||
246
machine-learning/poetry.lock
generated
246
machine-learning/poetry.lock
generated
@@ -1331,13 +1331,13 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "huggingface-hub"
|
name = "huggingface-hub"
|
||||||
version = "0.27.0"
|
version = "0.26.5"
|
||||||
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "huggingface_hub-0.27.0-py3-none-any.whl", hash = "sha256:8f2e834517f1f1ddf1ecc716f91b120d7333011b7485f665a9a412eacb1a2a81"},
|
{file = "huggingface_hub-0.26.5-py3-none-any.whl", hash = "sha256:fb7386090bbe892072e64b85f7c4479fd2d65eea5f2543327c970d5169e83924"},
|
||||||
{file = "huggingface_hub-0.27.0.tar.gz", hash = "sha256:902cce1a1be5739f5589e560198a65a8edcfd3b830b1666f36e4b961f0454fac"},
|
{file = "huggingface_hub-0.26.5.tar.gz", hash = "sha256:1008bd18f60bfb65e8dbc0a97249beeeaa8c99d3c2fa649354df9fa5a13ed83b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2492,18 +2492,18 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.10.4"
|
version = "2.10.3"
|
||||||
description = "Data validation using Python type hints"
|
description = "Data validation using Python type hints"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d"},
|
{file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"},
|
||||||
{file = "pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"},
|
{file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
annotated-types = ">=0.6.0"
|
annotated-types = ">=0.6.0"
|
||||||
pydantic-core = "2.27.2"
|
pydantic-core = "2.27.1"
|
||||||
typing-extensions = ">=4.12.2"
|
typing-extensions = ">=4.12.2"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@@ -2512,111 +2512,111 @@ timezone = ["tzdata"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic-core"
|
name = "pydantic-core"
|
||||||
version = "2.27.2"
|
version = "2.27.1"
|
||||||
description = "Core functionality for Pydantic validation and serialization"
|
description = "Core functionality for Pydantic validation and serialization"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"},
|
{file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"},
|
{file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"},
|
||||||
{file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"},
|
{file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"},
|
{file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"},
|
{file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"},
|
{file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"},
|
||||||
{file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"},
|
{file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"},
|
{file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"},
|
{file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"},
|
{file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"},
|
||||||
{file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"},
|
{file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"},
|
{file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"},
|
{file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"},
|
{file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"},
|
||||||
{file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"},
|
{file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"},
|
{file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"},
|
{file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"},
|
||||||
{file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"},
|
{file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"},
|
{file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"},
|
{file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"},
|
||||||
{file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"},
|
{file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"},
|
||||||
{file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"},
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"},
|
||||||
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"},
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"},
|
||||||
{file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"},
|
{file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2624,13 +2624,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic-settings"
|
name = "pydantic-settings"
|
||||||
version = "2.7.0"
|
version = "2.6.1"
|
||||||
description = "Settings management using Pydantic"
|
description = "Settings management using Pydantic"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic_settings-2.7.0-py3-none-any.whl", hash = "sha256:e00c05d5fa6cbbb227c84bd7487c5c1065084119b750df7c8c1a554aed236eb5"},
|
{file = "pydantic_settings-2.6.1-py3-none-any.whl", hash = "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87"},
|
||||||
{file = "pydantic_settings-2.7.0.tar.gz", hash = "sha256:ac4bfd4a36831a48dbf8b2d9325425b549a0a6f18cea118436d728eb4f1c4d66"},
|
{file = "pydantic_settings-2.6.1.tar.gz", hash = "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2706,20 +2706,20 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest-asyncio"
|
name = "pytest-asyncio"
|
||||||
version = "0.25.0"
|
version = "0.24.0"
|
||||||
description = "Pytest support for asyncio"
|
description = "Pytest support for asyncio"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3"},
|
{file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"},
|
||||||
{file = "pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609"},
|
{file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pytest = ">=8.2,<9"
|
pytest = ">=8.2,<9"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"]
|
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
||||||
testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
|
testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2787,13 +2787,13 @@ cli = ["click (>=5.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-multipart"
|
name = "python-multipart"
|
||||||
version = "0.0.20"
|
version = "0.0.19"
|
||||||
description = "A streaming multipart parser for Python"
|
description = "A streaming multipart parser for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"},
|
{file = "python_multipart-0.0.19-py3-none-any.whl", hash = "sha256:f8d5b0b9c618575bf9df01c684ded1d94a338839bdd8223838afacfb4bb2082d"},
|
||||||
{file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"},
|
{file = "python_multipart-0.0.19.tar.gz", hash = "sha256:905502ef39050557b7a6af411f454bc19526529ca46ae6831508438890ce12cc"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3393,13 +3393,13 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uvicorn"
|
name = "uvicorn"
|
||||||
version = "0.34.0"
|
version = "0.32.1"
|
||||||
description = "The lightning-fast ASGI server."
|
description = "The lightning-fast ASGI server."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"},
|
{file = "uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e"},
|
||||||
{file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"},
|
{file = "uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
|||||||
BIN
mobile/assets/onboarding-1-screenshot.jpeg
Normal file
BIN
mobile/assets/onboarding-1-screenshot.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 689 KiB |
@@ -127,29 +127,18 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
useSafeArea: true,
|
useSafeArea: true,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return DraggableScrollableSheet(
|
return FractionallySizedBox(
|
||||||
minChildSize: 0.5,
|
heightFactor: 0.75,
|
||||||
maxChildSize: 1,
|
child: Padding(
|
||||||
initialChildSize: 0.75,
|
padding: EdgeInsets.only(
|
||||||
expand: false,
|
bottom: context.viewInsets.bottom,
|
||||||
builder: (context, scrollController) {
|
),
|
||||||
return Padding(
|
child: ref
|
||||||
padding: EdgeInsets.only(
|
.watch(appSettingsServiceProvider)
|
||||||
bottom: context.viewInsets.bottom,
|
.getSetting<bool>(AppSettingsEnum.advancedTroubleshooting)
|
||||||
),
|
? AdvancedBottomSheet(assetDetail: asset)
|
||||||
child: ref.watch(appSettingsServiceProvider).getSetting<bool>(
|
: DetailPanel(asset: asset),
|
||||||
AppSettingsEnum.advancedTroubleshooting,
|
),
|
||||||
)
|
|
||||||
? AdvancedBottomSheet(
|
|
||||||
assetDetail: asset,
|
|
||||||
scrollController: scrollController,
|
|
||||||
)
|
|
||||||
: DetailPanel(
|
|
||||||
asset: asset,
|
|
||||||
scrollController: scrollController,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
383
mobile/lib/pages/onboarding/onboarding.page.dart
Normal file
383
mobile/lib/pages/onboarding/onboarding.page.dart
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class OnboardingPage extends HookConsumerWidget {
|
||||||
|
const OnboardingPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final pageController = usePageController(keepPage: false);
|
||||||
|
|
||||||
|
toNextPage() {
|
||||||
|
pageController.nextPage(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: SvgPicture.asset(
|
||||||
|
context.isDarkTheme
|
||||||
|
? 'assets/immich-logo-inline-dark.svg'
|
||||||
|
: 'assets/immich-logo-inline-light.svg',
|
||||||
|
height: 48,
|
||||||
|
),
|
||||||
|
centerTitle: false,
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: PageView(
|
||||||
|
controller: pageController,
|
||||||
|
// physics: const NeverScrollableScrollPhysics(),
|
||||||
|
children: [
|
||||||
|
OnboardingWelcome(
|
||||||
|
onNextPage: () => toNextPage(),
|
||||||
|
),
|
||||||
|
OnboardingGalleryPermission(
|
||||||
|
onNextPage: () => toNextPage(),
|
||||||
|
),
|
||||||
|
OnboardingLocationPermission(
|
||||||
|
onNextPage: () => toNextPage(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OnboardingWelcome extends StatelessWidget {
|
||||||
|
final VoidCallback onNextPage;
|
||||||
|
|
||||||
|
const OnboardingWelcome({super.key, required this.onNextPage});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(18.0),
|
||||||
|
child: ListView(
|
||||||
|
physics: const ClampingScrollPhysics(),
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
child: Card(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(32),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
child: AnimatedHeroImage(
|
||||||
|
imagePath: 'assets/onboarding-1-screenshot.jpeg',
|
||||||
|
color: context.colorScheme.primary.withOpacity(0.25),
|
||||||
|
colorBlendMode: BlendMode.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 32.0,
|
||||||
|
left: 8.0,
|
||||||
|
bottom: 8.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"WELCOME",
|
||||||
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
|
color: context.colorScheme.onSurface.withOpacity(0.6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: Text(
|
||||||
|
"Let’s get you setup with some permissions that the app needs",
|
||||||
|
style: context.textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0, top: 24.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
child: MaterialButton(
|
||||||
|
onPressed: onNextPage,
|
||||||
|
color: context.primaryColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
child: Icon(
|
||||||
|
Icons.chevron_right_rounded,
|
||||||
|
color: context.colorScheme.onPrimary,
|
||||||
|
size: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnimatedHeroImage extends StatefulWidget {
|
||||||
|
final String imagePath;
|
||||||
|
final Color color;
|
||||||
|
final BlendMode colorBlendMode;
|
||||||
|
|
||||||
|
const AnimatedHeroImage({
|
||||||
|
super.key,
|
||||||
|
required this.imagePath,
|
||||||
|
required this.color,
|
||||||
|
required this.colorBlendMode,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
AnimatedHeroImageState createState() => AnimatedHeroImageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnimatedHeroImageState extends State<AnimatedHeroImage>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _controller;
|
||||||
|
late Animation<double> _scaleAnimation;
|
||||||
|
late Animation<double> _rotationAnimation;
|
||||||
|
late Animation<Offset> _parallaxAnimation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = AnimationController(
|
||||||
|
duration: const Duration(seconds: 15),
|
||||||
|
vsync: this,
|
||||||
|
)..repeat(reverse: true);
|
||||||
|
|
||||||
|
_scaleAnimation = Tween<double>(begin: 1.0, end: 1.15).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
_rotationAnimation = Tween<double>(begin: 0.0, end: 0.025).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
_parallaxAnimation =
|
||||||
|
Tween<Offset>(begin: Offset.zero, end: const Offset(0.05, 0.05))
|
||||||
|
.animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: _controller,
|
||||||
|
child: Image(
|
||||||
|
image: AssetImage(widget.imagePath),
|
||||||
|
filterQuality: FilterQuality.high,
|
||||||
|
isAntiAlias: true,
|
||||||
|
// color: widget.color,
|
||||||
|
// colorBlendMode: widget.colorBlendMode,
|
||||||
|
),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Transform.scale(
|
||||||
|
scale: _scaleAnimation.value,
|
||||||
|
child: Transform.rotate(
|
||||||
|
angle: _rotationAnimation.value,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: _parallaxAnimation.value,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OnboardingGalleryPermission extends StatelessWidget {
|
||||||
|
final VoidCallback onNextPage;
|
||||||
|
|
||||||
|
const OnboardingGalleryPermission({super.key, required this.onNextPage});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(24.0),
|
||||||
|
child: PermissionInfoTemplate(
|
||||||
|
icon: Icons.perm_media_outlined,
|
||||||
|
title: "Gallery Permission",
|
||||||
|
subtitle:
|
||||||
|
"We use the read and write permission of the media gallery for the following actions",
|
||||||
|
descriptionList: [
|
||||||
|
'Display the local videos and images',
|
||||||
|
'Read the file content to upload to your Immich instance',
|
||||||
|
'Remove media from the device on your request',
|
||||||
|
],
|
||||||
|
onConfirm: onNextPage,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OnboardingLocationPermission extends StatelessWidget {
|
||||||
|
final VoidCallback onNextPage;
|
||||||
|
|
||||||
|
const OnboardingLocationPermission({super.key, required this.onNextPage});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(24.0),
|
||||||
|
child: PermissionInfoTemplate(
|
||||||
|
icon: Icons.location_on_outlined,
|
||||||
|
title: "Location Permission",
|
||||||
|
subtitle:
|
||||||
|
"We use the always on, precise location access for the following actions",
|
||||||
|
descriptionList: [
|
||||||
|
'Display the local videos and images',
|
||||||
|
'Read the file content to upload to your Immich instance',
|
||||||
|
'Remove media from the device on your request',
|
||||||
|
],
|
||||||
|
onConfirm: onNextPage,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PermissionInfoTemplate extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String subtitle;
|
||||||
|
final List<String> descriptionList;
|
||||||
|
final VoidCallback onConfirm;
|
||||||
|
final IconData icon;
|
||||||
|
|
||||||
|
const PermissionInfoTemplate({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.subtitle,
|
||||||
|
required this.descriptionList,
|
||||||
|
required this.onConfirm,
|
||||||
|
required this.icon,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
size: 32,
|
||||||
|
color: context.primaryColor.withAlpha(250),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: context.textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
subtitle,
|
||||||
|
style: context.textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: context.colorScheme.onSurface.withAlpha(220),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
BulletList(descriptionList),
|
||||||
|
const Spacer(),
|
||||||
|
SizedBox(
|
||||||
|
height: 48,
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: onConfirm,
|
||||||
|
child: const Text(
|
||||||
|
'OK',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BulletList extends StatelessWidget {
|
||||||
|
final List<String> strings;
|
||||||
|
|
||||||
|
const BulletList(this.strings, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: strings.map((textString) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'\u2022',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
height: 1.25,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
textString,
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
softWrap: true,
|
||||||
|
style: context.textTheme.headlineSmall?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import 'package:immich_mobile/pages/library/favorite.page.dart';
|
|||||||
import 'package:immich_mobile/pages/library/trash.page.dart';
|
import 'package:immich_mobile/pages/library/trash.page.dart';
|
||||||
import 'package:immich_mobile/pages/login/change_password.page.dart';
|
import 'package:immich_mobile/pages/login/change_password.page.dart';
|
||||||
import 'package:immich_mobile/pages/login/login.page.dart';
|
import 'package:immich_mobile/pages/login/login.page.dart';
|
||||||
|
import 'package:immich_mobile/pages/onboarding/onboarding.page.dart';
|
||||||
import 'package:immich_mobile/pages/onboarding/permission_onboarding.page.dart';
|
import 'package:immich_mobile/pages/onboarding/permission_onboarding.page.dart';
|
||||||
import 'package:immich_mobile/pages/photos/memory.page.dart';
|
import 'package:immich_mobile/pages/photos/memory.page.dart';
|
||||||
import 'package:immich_mobile/pages/photos/photos.page.dart';
|
import 'package:immich_mobile/pages/photos/photos.page.dart';
|
||||||
@@ -90,7 +91,8 @@ class AppRouter extends RootStackRouter {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
late final List<AutoRoute> routes = [
|
late final List<AutoRoute> routes = [
|
||||||
AutoRoute(page: SplashScreenRoute.page, initial: true),
|
AutoRoute(page: OnboardingRoute.page, initial: true),
|
||||||
|
AutoRoute(page: SplashScreenRoute.page),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
page: PermissionOnboardingRoute.page,
|
page: PermissionOnboardingRoute.page,
|
||||||
guards: [_authGuard, _duplicateGuard],
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
|||||||
@@ -136,15 +136,10 @@ class AlbumAssetSelectionRouteArgs {
|
|||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [AlbumOptionsPage]
|
/// [AlbumOptionsPage]
|
||||||
class AlbumOptionsRoute extends PageRouteInfo<AlbumOptionsRouteArgs> {
|
class AlbumOptionsRoute extends PageRouteInfo<void> {
|
||||||
AlbumOptionsRoute({
|
const AlbumOptionsRoute({List<PageRouteInfo>? children})
|
||||||
Key? key,
|
: super(
|
||||||
List<PageRouteInfo>? children,
|
|
||||||
}) : super(
|
|
||||||
AlbumOptionsRoute.name,
|
AlbumOptionsRoute.name,
|
||||||
args: AlbumOptionsRouteArgs(
|
|
||||||
key: key,
|
|
||||||
),
|
|
||||||
initialChildren: children,
|
initialChildren: children,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -153,25 +148,11 @@ class AlbumOptionsRoute extends PageRouteInfo<AlbumOptionsRouteArgs> {
|
|||||||
static PageInfo page = PageInfo(
|
static PageInfo page = PageInfo(
|
||||||
name,
|
name,
|
||||||
builder: (data) {
|
builder: (data) {
|
||||||
final args = data.argsAs<AlbumOptionsRouteArgs>();
|
return const AlbumOptionsPage();
|
||||||
return AlbumOptionsPage(
|
|
||||||
key: args.key,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlbumOptionsRouteArgs {
|
|
||||||
const AlbumOptionsRouteArgs({this.key});
|
|
||||||
|
|
||||||
final Key? key;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'AlbumOptionsRouteArgs{key: $key}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [AlbumPreviewPage]
|
/// [AlbumPreviewPage]
|
||||||
class AlbumPreviewRoute extends PageRouteInfo<AlbumPreviewRouteArgs> {
|
class AlbumPreviewRoute extends PageRouteInfo<AlbumPreviewRouteArgs> {
|
||||||
@@ -1129,6 +1110,25 @@ class NativeVideoViewerRouteArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [OnboardingPage]
|
||||||
|
class OnboardingRoute extends PageRouteInfo<void> {
|
||||||
|
const OnboardingRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(
|
||||||
|
OnboardingRoute.name,
|
||||||
|
initialChildren: children,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const String name = 'OnboardingRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const OnboardingPage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [PartnerDetailPage]
|
/// [PartnerDetailPage]
|
||||||
class PartnerDetailRoute extends PageRouteInfo<PartnerDetailRouteArgs> {
|
class PartnerDetailRoute extends PageRouteInfo<PartnerDetailRouteArgs> {
|
||||||
|
|||||||
@@ -372,6 +372,7 @@ class BackgroundService {
|
|||||||
HttpOverrides.global = HttpSSLCertOverride();
|
HttpOverrides.global = HttpSSLCertOverride();
|
||||||
ApiService apiService = ApiService();
|
ApiService apiService = ApiService();
|
||||||
apiService.setAccessToken(Store.get(StoreKey.accessToken));
|
apiService.setAccessToken(Store.get(StoreKey.accessToken));
|
||||||
|
AppSettingsService settingService = AppSettingsService();
|
||||||
AppSettingsService settingsService = AppSettingsService();
|
AppSettingsService settingsService = AppSettingsService();
|
||||||
AlbumRepository albumRepository = AlbumRepository(db);
|
AlbumRepository albumRepository = AlbumRepository(db);
|
||||||
AssetRepository assetRepository = AssetRepository(db);
|
AssetRepository assetRepository = AssetRepository(db);
|
||||||
@@ -421,7 +422,7 @@ class BackgroundService {
|
|||||||
);
|
);
|
||||||
BackupService backupService = BackupService(
|
BackupService backupService = BackupService(
|
||||||
apiService,
|
apiService,
|
||||||
settingsService,
|
settingService,
|
||||||
albumService,
|
albumService,
|
||||||
albumMediaRepository,
|
albumMediaRepository,
|
||||||
fileMediaRepository,
|
fileMediaRepository,
|
||||||
|
|||||||
@@ -313,12 +313,15 @@ class BackupService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file =
|
if (asset.type == AssetType.video) {
|
||||||
await asset.local!.originFile.timeout(const Duration(seconds: 5));
|
file = await asset.local!.originFile;
|
||||||
|
} else {
|
||||||
if (asset.local!.isLivePhoto) {
|
file = await asset.local!.originFile
|
||||||
livePhotoFile = await asset.local!.originFileWithSubtype
|
|
||||||
.timeout(const Duration(seconds: 5));
|
.timeout(const Duration(seconds: 5));
|
||||||
|
if (asset.local!.isLivePhoto) {
|
||||||
|
livePhotoFile = await asset.local!.originFileWithSubtype
|
||||||
|
.timeout(const Duration(seconds: 5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,12 @@ import 'package:immich_mobile/entities/asset.entity.dart';
|
|||||||
|
|
||||||
class AdvancedBottomSheet extends HookConsumerWidget {
|
class AdvancedBottomSheet extends HookConsumerWidget {
|
||||||
final Asset assetDetail;
|
final Asset assetDetail;
|
||||||
final ScrollController? scrollController;
|
|
||||||
|
|
||||||
const AdvancedBottomSheet({
|
const AdvancedBottomSheet({super.key, required this.assetDetail});
|
||||||
super.key,
|
|
||||||
required this.assetDetail,
|
|
||||||
this.scrollController,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
controller: scrollController,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 8.0),
|
margin: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ import 'package:immich_mobile/entities/asset.entity.dart';
|
|||||||
|
|
||||||
class DetailPanel extends HookConsumerWidget {
|
class DetailPanel extends HookConsumerWidget {
|
||||||
final Asset asset;
|
final Asset asset;
|
||||||
final ScrollController? scrollController;
|
|
||||||
|
|
||||||
const DetailPanel({super.key, required this.asset, this.scrollController});
|
const DetailPanel({super.key, required this.asset});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return ListView(
|
return ListView(
|
||||||
controller: scrollController,
|
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class FileInfo extends StatelessWidget {
|
|||||||
final height = asset.orientatedHeight ?? asset.height;
|
final height = asset.orientatedHeight ?? asset.height;
|
||||||
final width = asset.orientatedWidth ?? asset.width;
|
final width = asset.orientatedWidth ?? asset.width;
|
||||||
String resolution =
|
String resolution =
|
||||||
height != null && width != null ? "$width x $height " : "";
|
height != null && width != null ? "$height x $width " : "";
|
||||||
String fileSize = asset.exifInfo?.fileSize != null
|
String fileSize = asset.exifInfo?.fileSize != null
|
||||||
? formatBytes(asset.exifInfo!.fileSize!)
|
? formatBytes(asset.exifInfo!.fileSize!)
|
||||||
: "";
|
: "";
|
||||||
|
|||||||
8
mobile/openapi/README.md
generated
8
mobile/openapi/README.md
generated
@@ -93,17 +93,17 @@ Class | Method | HTTP request | Description
|
|||||||
*AlbumsApi* | [**removeUserFromAlbum**](doc//AlbumsApi.md#removeuserfromalbum) | **DELETE** /albums/{id}/user/{userId} |
|
*AlbumsApi* | [**removeUserFromAlbum**](doc//AlbumsApi.md#removeuserfromalbum) | **DELETE** /albums/{id}/user/{userId} |
|
||||||
*AlbumsApi* | [**updateAlbumInfo**](doc//AlbumsApi.md#updatealbuminfo) | **PATCH** /albums/{id} |
|
*AlbumsApi* | [**updateAlbumInfo**](doc//AlbumsApi.md#updatealbuminfo) | **PATCH** /albums/{id} |
|
||||||
*AlbumsApi* | [**updateAlbumUser**](doc//AlbumsApi.md#updatealbumuser) | **PUT** /albums/{id}/user/{userId} |
|
*AlbumsApi* | [**updateAlbumUser**](doc//AlbumsApi.md#updatealbumuser) | **PUT** /albums/{id}/user/{userId} |
|
||||||
*AssetsApi* | [**checkBulkUpload**](doc//AssetsApi.md#checkbulkupload) | **POST** /assets/bulk-upload-check | Checks if assets exist by checksums
|
*AssetsApi* | [**checkBulkUpload**](doc//AssetsApi.md#checkbulkupload) | **POST** /assets/bulk-upload-check |
|
||||||
*AssetsApi* | [**checkExistingAssets**](doc//AssetsApi.md#checkexistingassets) | **POST** /assets/exist | Checks if multiple assets exist on the server and returns all existing - used by background backup
|
*AssetsApi* | [**checkExistingAssets**](doc//AssetsApi.md#checkexistingassets) | **POST** /assets/exist |
|
||||||
*AssetsApi* | [**deleteAssets**](doc//AssetsApi.md#deleteassets) | **DELETE** /assets |
|
*AssetsApi* | [**deleteAssets**](doc//AssetsApi.md#deleteassets) | **DELETE** /assets |
|
||||||
*AssetsApi* | [**downloadAsset**](doc//AssetsApi.md#downloadasset) | **GET** /assets/{id}/original |
|
*AssetsApi* | [**downloadAsset**](doc//AssetsApi.md#downloadasset) | **GET** /assets/{id}/original |
|
||||||
*AssetsApi* | [**getAllUserAssetsByDeviceId**](doc//AssetsApi.md#getalluserassetsbydeviceid) | **GET** /assets/device/{deviceId} | Get all asset of a device that are in the database, ID only.
|
*AssetsApi* | [**getAllUserAssetsByDeviceId**](doc//AssetsApi.md#getalluserassetsbydeviceid) | **GET** /assets/device/{deviceId} |
|
||||||
*AssetsApi* | [**getAssetInfo**](doc//AssetsApi.md#getassetinfo) | **GET** /assets/{id} |
|
*AssetsApi* | [**getAssetInfo**](doc//AssetsApi.md#getassetinfo) | **GET** /assets/{id} |
|
||||||
*AssetsApi* | [**getAssetStatistics**](doc//AssetsApi.md#getassetstatistics) | **GET** /assets/statistics |
|
*AssetsApi* | [**getAssetStatistics**](doc//AssetsApi.md#getassetstatistics) | **GET** /assets/statistics |
|
||||||
*AssetsApi* | [**getMemoryLane**](doc//AssetsApi.md#getmemorylane) | **GET** /assets/memory-lane |
|
*AssetsApi* | [**getMemoryLane**](doc//AssetsApi.md#getmemorylane) | **GET** /assets/memory-lane |
|
||||||
*AssetsApi* | [**getRandom**](doc//AssetsApi.md#getrandom) | **GET** /assets/random |
|
*AssetsApi* | [**getRandom**](doc//AssetsApi.md#getrandom) | **GET** /assets/random |
|
||||||
*AssetsApi* | [**playAssetVideo**](doc//AssetsApi.md#playassetvideo) | **GET** /assets/{id}/video/playback |
|
*AssetsApi* | [**playAssetVideo**](doc//AssetsApi.md#playassetvideo) | **GET** /assets/{id}/video/playback |
|
||||||
*AssetsApi* | [**replaceAsset**](doc//AssetsApi.md#replaceasset) | **PUT** /assets/{id}/original | Replace the asset with new file, without changing its id
|
*AssetsApi* | [**replaceAsset**](doc//AssetsApi.md#replaceasset) | **PUT** /assets/{id}/original |
|
||||||
*AssetsApi* | [**runAssetJobs**](doc//AssetsApi.md#runassetjobs) | **POST** /assets/jobs |
|
*AssetsApi* | [**runAssetJobs**](doc//AssetsApi.md#runassetjobs) | **POST** /assets/jobs |
|
||||||
*AssetsApi* | [**updateAsset**](doc//AssetsApi.md#updateasset) | **PUT** /assets/{id} |
|
*AssetsApi* | [**updateAsset**](doc//AssetsApi.md#updateasset) | **PUT** /assets/{id} |
|
||||||
*AssetsApi* | [**updateAssets**](doc//AssetsApi.md#updateassets) | **PUT** /assets |
|
*AssetsApi* | [**updateAssets**](doc//AssetsApi.md#updateassets) | **PUT** /assets |
|
||||||
|
|||||||
18
mobile/openapi/lib/model/album_user_add_dto.dart
generated
18
mobile/openapi/lib/model/album_user_add_dto.dart
generated
@@ -13,11 +13,17 @@ part of openapi.api;
|
|||||||
class AlbumUserAddDto {
|
class AlbumUserAddDto {
|
||||||
/// Returns a new [AlbumUserAddDto] instance.
|
/// Returns a new [AlbumUserAddDto] instance.
|
||||||
AlbumUserAddDto({
|
AlbumUserAddDto({
|
||||||
this.role = AlbumUserRole.editor,
|
this.role,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
});
|
});
|
||||||
|
|
||||||
AlbumUserRole role;
|
///
|
||||||
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
/// source code must fall back to having a nullable type.
|
||||||
|
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||||
|
///
|
||||||
|
AlbumUserRole? role;
|
||||||
|
|
||||||
String userId;
|
String userId;
|
||||||
|
|
||||||
@@ -29,7 +35,7 @@ class AlbumUserAddDto {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(role.hashCode) +
|
(role == null ? 0 : role!.hashCode) +
|
||||||
(userId.hashCode);
|
(userId.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -37,7 +43,11 @@ class AlbumUserAddDto {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
|
if (this.role != null) {
|
||||||
json[r'role'] = this.role;
|
json[r'role'] = this.role;
|
||||||
|
} else {
|
||||||
|
// json[r'role'] = null;
|
||||||
|
}
|
||||||
json[r'userId'] = this.userId;
|
json[r'userId'] = this.userId;
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@@ -51,7 +61,7 @@ class AlbumUserAddDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return AlbumUserAddDto(
|
return AlbumUserAddDto(
|
||||||
role: AlbumUserRole.fromJson(json[r'role']) ?? AlbumUserRole.editor,
|
role: AlbumUserRole.fromJson(json[r'role']),
|
||||||
userId: mapValueOfType<String>(json, r'userId')!,
|
userId: mapValueOfType<String>(json, r'userId')!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
20
mobile/openapi/lib/model/create_library_dto.dart
generated
20
mobile/openapi/lib/model/create_library_dto.dart
generated
@@ -13,15 +13,15 @@ part of openapi.api;
|
|||||||
class CreateLibraryDto {
|
class CreateLibraryDto {
|
||||||
/// Returns a new [CreateLibraryDto] instance.
|
/// Returns a new [CreateLibraryDto] instance.
|
||||||
CreateLibraryDto({
|
CreateLibraryDto({
|
||||||
this.exclusionPatterns = const {},
|
this.exclusionPatterns = const [],
|
||||||
this.importPaths = const {},
|
this.importPaths = const [],
|
||||||
this.name,
|
this.name,
|
||||||
required this.ownerId,
|
required this.ownerId,
|
||||||
});
|
});
|
||||||
|
|
||||||
Set<String> exclusionPatterns;
|
List<String> exclusionPatterns;
|
||||||
|
|
||||||
Set<String> importPaths;
|
List<String> importPaths;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
@@ -53,8 +53,8 @@ class CreateLibraryDto {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'exclusionPatterns'] = this.exclusionPatterns.toList(growable: false);
|
json[r'exclusionPatterns'] = this.exclusionPatterns;
|
||||||
json[r'importPaths'] = this.importPaths.toList(growable: false);
|
json[r'importPaths'] = this.importPaths;
|
||||||
if (this.name != null) {
|
if (this.name != null) {
|
||||||
json[r'name'] = this.name;
|
json[r'name'] = this.name;
|
||||||
} else {
|
} else {
|
||||||
@@ -74,11 +74,11 @@ class CreateLibraryDto {
|
|||||||
|
|
||||||
return CreateLibraryDto(
|
return CreateLibraryDto(
|
||||||
exclusionPatterns: json[r'exclusionPatterns'] is Iterable
|
exclusionPatterns: json[r'exclusionPatterns'] is Iterable
|
||||||
? (json[r'exclusionPatterns'] as Iterable).cast<String>().toSet()
|
? (json[r'exclusionPatterns'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const {},
|
: const [],
|
||||||
importPaths: json[r'importPaths'] is Iterable
|
importPaths: json[r'importPaths'] is Iterable
|
||||||
? (json[r'importPaths'] as Iterable).cast<String>().toSet()
|
? (json[r'importPaths'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const {},
|
: const [],
|
||||||
name: mapValueOfType<String>(json, r'name'),
|
name: mapValueOfType<String>(json, r'name'),
|
||||||
ownerId: mapValueOfType<String>(json, r'ownerId')!,
|
ownerId: mapValueOfType<String>(json, r'ownerId')!,
|
||||||
);
|
);
|
||||||
|
|||||||
20
mobile/openapi/lib/model/update_library_dto.dart
generated
20
mobile/openapi/lib/model/update_library_dto.dart
generated
@@ -13,14 +13,14 @@ part of openapi.api;
|
|||||||
class UpdateLibraryDto {
|
class UpdateLibraryDto {
|
||||||
/// Returns a new [UpdateLibraryDto] instance.
|
/// Returns a new [UpdateLibraryDto] instance.
|
||||||
UpdateLibraryDto({
|
UpdateLibraryDto({
|
||||||
this.exclusionPatterns = const {},
|
this.exclusionPatterns = const [],
|
||||||
this.importPaths = const {},
|
this.importPaths = const [],
|
||||||
this.name,
|
this.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
Set<String> exclusionPatterns;
|
List<String> exclusionPatterns;
|
||||||
|
|
||||||
Set<String> importPaths;
|
List<String> importPaths;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
@@ -48,8 +48,8 @@ class UpdateLibraryDto {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'exclusionPatterns'] = this.exclusionPatterns.toList(growable: false);
|
json[r'exclusionPatterns'] = this.exclusionPatterns;
|
||||||
json[r'importPaths'] = this.importPaths.toList(growable: false);
|
json[r'importPaths'] = this.importPaths;
|
||||||
if (this.name != null) {
|
if (this.name != null) {
|
||||||
json[r'name'] = this.name;
|
json[r'name'] = this.name;
|
||||||
} else {
|
} else {
|
||||||
@@ -68,11 +68,11 @@ class UpdateLibraryDto {
|
|||||||
|
|
||||||
return UpdateLibraryDto(
|
return UpdateLibraryDto(
|
||||||
exclusionPatterns: json[r'exclusionPatterns'] is Iterable
|
exclusionPatterns: json[r'exclusionPatterns'] is Iterable
|
||||||
? (json[r'exclusionPatterns'] as Iterable).cast<String>().toSet()
|
? (json[r'exclusionPatterns'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const {},
|
: const [],
|
||||||
importPaths: json[r'importPaths'] is Iterable
|
importPaths: json[r'importPaths'] is Iterable
|
||||||
? (json[r'importPaths'] as Iterable).cast<String>().toSet()
|
? (json[r'importPaths'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const {},
|
: const [],
|
||||||
name: mapValueOfType<String>(json, r'name'),
|
name: mapValueOfType<String>(json, r'name'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
20
mobile/openapi/lib/model/validate_library_dto.dart
generated
20
mobile/openapi/lib/model/validate_library_dto.dart
generated
@@ -13,13 +13,13 @@ part of openapi.api;
|
|||||||
class ValidateLibraryDto {
|
class ValidateLibraryDto {
|
||||||
/// Returns a new [ValidateLibraryDto] instance.
|
/// Returns a new [ValidateLibraryDto] instance.
|
||||||
ValidateLibraryDto({
|
ValidateLibraryDto({
|
||||||
this.exclusionPatterns = const {},
|
this.exclusionPatterns = const [],
|
||||||
this.importPaths = const {},
|
this.importPaths = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
Set<String> exclusionPatterns;
|
List<String> exclusionPatterns;
|
||||||
|
|
||||||
Set<String> importPaths;
|
List<String> importPaths;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is ValidateLibraryDto &&
|
bool operator ==(Object other) => identical(this, other) || other is ValidateLibraryDto &&
|
||||||
@@ -37,8 +37,8 @@ class ValidateLibraryDto {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'exclusionPatterns'] = this.exclusionPatterns.toList(growable: false);
|
json[r'exclusionPatterns'] = this.exclusionPatterns;
|
||||||
json[r'importPaths'] = this.importPaths.toList(growable: false);
|
json[r'importPaths'] = this.importPaths;
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +52,11 @@ class ValidateLibraryDto {
|
|||||||
|
|
||||||
return ValidateLibraryDto(
|
return ValidateLibraryDto(
|
||||||
exclusionPatterns: json[r'exclusionPatterns'] is Iterable
|
exclusionPatterns: json[r'exclusionPatterns'] is Iterable
|
||||||
? (json[r'exclusionPatterns'] as Iterable).cast<String>().toSet()
|
? (json[r'exclusionPatterns'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const {},
|
: const [],
|
||||||
importPaths: json[r'importPaths'] is Iterable
|
importPaths: json[r'importPaths'] is Iterable
|
||||||
? (json[r'importPaths'] as Iterable).cast<String>().toSet()
|
? (json[r'importPaths'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const {},
|
: const [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1424,6 +1424,7 @@
|
|||||||
},
|
},
|
||||||
"/assets/bulk-upload-check": {
|
"/assets/bulk-upload-check": {
|
||||||
"post": {
|
"post": {
|
||||||
|
"description": "Checks if assets exist by checksums",
|
||||||
"operationId": "checkBulkUpload",
|
"operationId": "checkBulkUpload",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
@@ -1459,7 +1460,6 @@
|
|||||||
"api_key": []
|
"api_key": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"summary": "Checks if assets exist by checksums",
|
|
||||||
"tags": [
|
"tags": [
|
||||||
"Assets"
|
"Assets"
|
||||||
]
|
]
|
||||||
@@ -1467,6 +1467,7 @@
|
|||||||
},
|
},
|
||||||
"/assets/device/{deviceId}": {
|
"/assets/device/{deviceId}": {
|
||||||
"get": {
|
"get": {
|
||||||
|
"description": "Get all asset of a device that are in the database, ID only.",
|
||||||
"operationId": "getAllUserAssetsByDeviceId",
|
"operationId": "getAllUserAssetsByDeviceId",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -1504,7 +1505,6 @@
|
|||||||
"api_key": []
|
"api_key": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"summary": "Get all asset of a device that are in the database, ID only.",
|
|
||||||
"tags": [
|
"tags": [
|
||||||
"Assets"
|
"Assets"
|
||||||
]
|
]
|
||||||
@@ -1512,6 +1512,7 @@
|
|||||||
},
|
},
|
||||||
"/assets/exist": {
|
"/assets/exist": {
|
||||||
"post": {
|
"post": {
|
||||||
|
"description": "Checks if multiple assets exist on the server and returns all existing - used by background backup",
|
||||||
"operationId": "checkExistingAssets",
|
"operationId": "checkExistingAssets",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
@@ -1547,7 +1548,6 @@
|
|||||||
"api_key": []
|
"api_key": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"summary": "Checks if multiple assets exist on the server and returns all existing - used by background backup",
|
|
||||||
"tags": [
|
"tags": [
|
||||||
"Assets"
|
"Assets"
|
||||||
]
|
]
|
||||||
@@ -1903,6 +1903,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
|
"description": "Replace the asset with new file, without changing its id",
|
||||||
"operationId": "replaceAsset",
|
"operationId": "replaceAsset",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -1956,7 +1957,6 @@
|
|||||||
"api_key": []
|
"api_key": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"summary": "Replace the asset with new file, without changing its id",
|
|
||||||
"tags": [
|
"tags": [
|
||||||
"Assets"
|
"Assets"
|
||||||
],
|
],
|
||||||
@@ -7492,7 +7492,6 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/Permission"
|
"$ref": "#/components/schemas/Permission"
|
||||||
},
|
},
|
||||||
"minItems": 1,
|
|
||||||
"type": "array"
|
"type": "array"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -7573,11 +7572,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/ReactionType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/ReactionType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -7604,11 +7599,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/ReactionType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/ReactionType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"$ref": "#/components/schemas/UserResponseDto"
|
"$ref": "#/components/schemas/UserResponseDto"
|
||||||
@@ -7640,7 +7631,6 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/AlbumUserAddDto"
|
"$ref": "#/components/schemas/AlbumUserAddDto"
|
||||||
},
|
},
|
||||||
"minItems": 1,
|
|
||||||
"type": "array"
|
"type": "array"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -7709,11 +7699,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetOrder"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetOrder"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"owner": {
|
"owner": {
|
||||||
"$ref": "#/components/schemas/UserResponseDto"
|
"$ref": "#/components/schemas/UserResponseDto"
|
||||||
@@ -7773,12 +7759,7 @@
|
|||||||
"AlbumUserAddDto": {
|
"AlbumUserAddDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"role": {
|
"role": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AlbumUserRole"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AlbumUserRole"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default": "editor"
|
|
||||||
},
|
},
|
||||||
"userId": {
|
"userId": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
@@ -7793,11 +7774,7 @@
|
|||||||
"AlbumUserCreateDto": {
|
"AlbumUserCreateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"role": {
|
"role": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AlbumUserRole"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AlbumUserRole"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"userId": {
|
"userId": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
@@ -7813,11 +7790,7 @@
|
|||||||
"AlbumUserResponseDto": {
|
"AlbumUserResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"role": {
|
"role": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AlbumUserRole"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AlbumUserRole"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"$ref": "#/components/schemas/UserResponseDto"
|
"$ref": "#/components/schemas/UserResponseDto"
|
||||||
@@ -8114,11 +8087,7 @@
|
|||||||
"nullable": true
|
"nullable": true
|
||||||
},
|
},
|
||||||
"sourceType": {
|
"sourceType": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/SourceType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/SourceType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -8189,11 +8158,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"sourceType": {
|
"sourceType": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/SourceType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/SourceType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -8289,11 +8254,7 @@
|
|||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetJobName"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetJobName"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -8391,11 +8352,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetMediaStatus"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetMediaStatus"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -8533,11 +8490,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetTypeEnum"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetTypeEnum"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"unassignedFaces": {
|
"unassignedFaces": {
|
||||||
"items": {
|
"items": {
|
||||||
@@ -8650,11 +8603,7 @@
|
|||||||
"AvatarResponse": {
|
"AvatarResponse": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"color": {
|
"color": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserAvatarColor"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -8665,11 +8614,7 @@
|
|||||||
"AvatarUpdate": {
|
"AvatarUpdate": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"color": {
|
"color": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserAvatarColor"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
@@ -8760,7 +8705,6 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"minItems": 1,
|
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"deviceId": {
|
"deviceId": {
|
||||||
@@ -8827,17 +8771,13 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"maxItems": 128,
|
"type": "array"
|
||||||
"type": "array",
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
},
|
||||||
"importPaths": {
|
"importPaths": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"maxItems": 128,
|
"type": "array"
|
||||||
"type": "array",
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -9306,18 +9246,10 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"entityType": {
|
"entityType": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/PathEntityType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/PathEntityType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"pathType": {
|
"pathType": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/PathType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/PathType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"pathValue": {
|
"pathValue": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -9379,11 +9311,7 @@
|
|||||||
"JobCommandDto": {
|
"JobCommandDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"command": {
|
"command": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/JobCommand"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/JobCommand"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"force": {
|
"force": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@@ -9428,11 +9356,7 @@
|
|||||||
"JobCreateDto": {
|
"JobCreateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/ManualJobName"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/ManualJobName"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -9620,7 +9544,6 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"example": "testuser@email.com",
|
"example": "testuser@email.com",
|
||||||
"format": "email",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
@@ -9794,11 +9717,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/MemoryType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/MemoryType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -9863,11 +9782,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/MemoryType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/MemoryType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"updatedAt": {
|
"updatedAt": {
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -9996,11 +9911,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetOrder"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetOrder"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"originalFileName": {
|
"originalFileName": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -10051,11 +9962,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetTypeEnum"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetTypeEnum"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"updatedAfter": {
|
"updatedAfter": {
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -10139,11 +10046,7 @@
|
|||||||
"PartnerResponseDto": {
|
"PartnerResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"avatarColor": {
|
"avatarColor": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserAvatarColor"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -10661,11 +10564,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetTypeEnum"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetTypeEnum"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"updatedAfter": {
|
"updatedAfter": {
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -11333,11 +11232,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/SharedLinkType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/SharedLinkType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -11422,11 +11317,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/SharedLinkType"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/SharedLinkType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"userId": {
|
"userId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -11459,7 +11350,6 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"example": "testuser@email.com",
|
"example": "testuser@email.com",
|
||||||
"format": "email",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
@@ -11576,11 +11466,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetTypeEnum"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetTypeEnum"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"updatedAfter": {
|
"updatedAfter": {
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -11621,7 +11507,6 @@
|
|||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"minItems": 2,
|
|
||||||
"type": "array"
|
"type": "array"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -11762,11 +11647,7 @@
|
|||||||
"SystemConfigFFmpegDto": {
|
"SystemConfigFFmpegDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"accel": {
|
"accel": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/TranscodeHWAccel"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/TranscodeHWAccel"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"accelDecode": {
|
"accelDecode": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@@ -11795,11 +11676,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"cqMode": {
|
"cqMode": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/CQMode"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/CQMode"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"crf": {
|
"crf": {
|
||||||
"maximum": 51,
|
"maximum": 51,
|
||||||
@@ -11825,21 +11702,13 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"targetAudioCodec": {
|
"targetAudioCodec": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AudioCodec"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AudioCodec"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"targetResolution": {
|
"targetResolution": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"targetVideoCodec": {
|
"targetVideoCodec": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/VideoCodec"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/VideoCodec"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"temporalAQ": {
|
"temporalAQ": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@@ -11849,18 +11718,10 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"tonemap": {
|
"tonemap": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/ToneMapping"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/ToneMapping"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"transcode": {
|
"transcode": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/TranscodePolicy"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/TranscodePolicy"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"twoPass": {
|
"twoPass": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@@ -11905,11 +11766,7 @@
|
|||||||
"SystemConfigGeneratedImageDto": {
|
"SystemConfigGeneratedImageDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"format": {
|
"format": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/ImageFormat"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/ImageFormat"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"quality": {
|
"quality": {
|
||||||
"maximum": 100,
|
"maximum": 100,
|
||||||
@@ -11931,11 +11788,7 @@
|
|||||||
"SystemConfigImageDto": {
|
"SystemConfigImageDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"colorspace": {
|
"colorspace": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/Colorspace"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/Colorspace"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"extractEmbedded": {
|
"extractEmbedded": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@@ -12053,11 +11906,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"level": {
|
"level": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/LogLevel"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/LogLevel"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -12086,7 +11935,6 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"urls": {
|
"urls": {
|
||||||
"format": "uri",
|
|
||||||
"items": {
|
"items": {
|
||||||
"format": "uri",
|
"format": "uri",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -12107,14 +11955,12 @@
|
|||||||
"SystemConfigMapDto": {
|
"SystemConfigMapDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"darkStyle": {
|
"darkStyle": {
|
||||||
"format": "uri",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"lightStyle": {
|
"lightStyle": {
|
||||||
"format": "uri",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -12189,7 +12035,6 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"mobileRedirectUri": {
|
"mobileRedirectUri": {
|
||||||
"format": "uri",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"profileSigningAlgorithm": {
|
"profileSigningAlgorithm": {
|
||||||
@@ -12252,7 +12097,6 @@
|
|||||||
"SystemConfigServerDto": {
|
"SystemConfigServerDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"externalDomain": {
|
"externalDomain": {
|
||||||
"format": "uri",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"loginPageMessage": {
|
"loginPageMessage": {
|
||||||
@@ -12509,7 +12353,6 @@
|
|||||||
"TagCreateDto": {
|
"TagCreateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"color": {
|
"color": {
|
||||||
"pattern": "^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
@@ -12565,7 +12408,6 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"color": {
|
"color": {
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"pattern": "^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -12728,11 +12570,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AssetOrder"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AssetOrder"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
@@ -12740,11 +12578,7 @@
|
|||||||
"UpdateAlbumUserDto": {
|
"UpdateAlbumUserDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"role": {
|
"role": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/AlbumUserRole"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/AlbumUserRole"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -12791,17 +12625,13 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"maxItems": 128,
|
"type": "array"
|
||||||
"type": "array",
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
},
|
||||||
"importPaths": {
|
"importPaths": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"maxItems": 128,
|
"type": "array"
|
||||||
"type": "array",
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -12867,7 +12697,6 @@
|
|||||||
"UserAdminCreateDto": {
|
"UserAdminCreateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"format": "email",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
@@ -12911,11 +12740,7 @@
|
|||||||
"UserAdminResponseDto": {
|
"UserAdminResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"avatarColor": {
|
"avatarColor": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserAvatarColor"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"createdAt": {
|
"createdAt": {
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -12970,11 +12795,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/UserStatus"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserStatus"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"storageLabel": {
|
"storageLabel": {
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
@@ -13009,7 +12830,6 @@
|
|||||||
"UserAdminUpdateDto": {
|
"UserAdminUpdateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"format": "email",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
@@ -13147,11 +12967,7 @@
|
|||||||
"UserResponseDto": {
|
"UserResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"avatarColor": {
|
"avatarColor": {
|
||||||
"allOf": [
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserAvatarColor"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -13191,7 +13007,6 @@
|
|||||||
"UserUpdateMeDto": {
|
"UserUpdateMeDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"format": "email",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
@@ -13220,17 +13035,13 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"maxItems": 128,
|
"type": "array"
|
||||||
"type": "array",
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
},
|
||||||
"importPaths": {
|
"importPaths": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"maxItems": 128,
|
"type": "array"
|
||||||
"type": "array",
|
|
||||||
"uniqueItems": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
<a href="README_pt_BR.md">Português Brasileiro</a>
|
<a href="README_pt_BR.md">Português Brasileiro</a>
|
||||||
<a href="README_sv_SE.md">Svenska</a>
|
<a href="README_sv_SE.md">Svenska</a>
|
||||||
<a href="README_ar_JO.md">العربية</a>
|
<a href="README_ar_JO.md">العربية</a>
|
||||||
<a href="README_vi_VN.md">Tiếng Việt</a>
|
|
||||||
<a href="README_th_TH.md">ภาษาไทย</a>
|
<a href="README_th_TH.md">ภาษาไทย</a>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@@ -106,8 +105,6 @@
|
|||||||
| 离线支持 | 是 | 否 |
|
| 离线支持 | 是 | 否 |
|
||||||
| 只读相册 | 是 | 是 |
|
| 只读相册 | 是 | 是 |
|
||||||
| 照片堆叠 | 是 | 是 |
|
| 照片堆叠 | 是 | 是 |
|
||||||
| 标签 | 否 | 是 |
|
|
||||||
| 文件夹浏览 | 否 | 是 |
|
|
||||||
|
|
||||||
## 多语言
|
## 多语言
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# dev build
|
# dev build
|
||||||
FROM ghcr.io/immich-app/base-server-dev:20241224@sha256:6832c632c2a8cba5e20053ab694c9a8080e621841c784ed5d4675ef9dd203588 AS dev
|
FROM ghcr.io/immich-app/base-server-dev:20241217@sha256:7e69fa317cf90a0345927bbea13438dc39efc584bac13ff77ea5735c57cd008a AS dev
|
||||||
|
|
||||||
RUN apt-get install --no-install-recommends -yqq tini
|
RUN apt-get install --no-install-recommends -yqq tini
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
@@ -42,7 +42,7 @@ RUN npm run build
|
|||||||
|
|
||||||
|
|
||||||
# prod build
|
# prod build
|
||||||
FROM ghcr.io/immich-app/base-server-prod:20241224@sha256:69da007c241a961d6927d3d03f1c83ef0ec5c70bf656bff3ced32546a777e6f6
|
FROM ghcr.io/immich-app/base-server-prod:20241217@sha256:040c83a6d3e45755419837747fa70fa68cf92433d483c116a971b3400bb8415d
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
ENV NODE_ENV=production \
|
ENV NODE_ENV=production \
|
||||||
|
|||||||
36
server/package-lock.json
generated
36
server/package-lock.json
generated
@@ -16,7 +16,7 @@
|
|||||||
"@nestjs/platform-express": "^10.2.2",
|
"@nestjs/platform-express": "^10.2.2",
|
||||||
"@nestjs/platform-socket.io": "^10.2.2",
|
"@nestjs/platform-socket.io": "^10.2.2",
|
||||||
"@nestjs/schedule": "^4.0.0",
|
"@nestjs/schedule": "^4.0.0",
|
||||||
"@nestjs/swagger": "^8.0.0",
|
"@nestjs/swagger": "^7.1.8",
|
||||||
"@nestjs/typeorm": "^10.0.0",
|
"@nestjs/typeorm": "^10.0.0",
|
||||||
"@nestjs/websockets": "^10.2.2",
|
"@nestjs/websockets": "^10.2.2",
|
||||||
"@opentelemetry/auto-instrumentations-node": "^0.54.0",
|
"@opentelemetry/auto-instrumentations-node": "^0.54.0",
|
||||||
@@ -2099,9 +2099,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nestjs/mapped-types": {
|
"node_modules/@nestjs/mapped-types": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz",
|
||||||
"integrity": "sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==",
|
"integrity": "sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
||||||
@@ -2197,17 +2197,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@nestjs/swagger": {
|
"node_modules/@nestjs/swagger": {
|
||||||
"version": "8.1.0",
|
"version": "7.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.4.2.tgz",
|
||||||
"integrity": "sha512-8hzH+r/31XshzXHC9vww4T0xjDAxMzvOaT1xAOvvY1LtXTWyNRCUP2iQsCYJOnnMrR+vydWjvRZiuB3hdvaHxA==",
|
"integrity": "sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@microsoft/tsdoc": "^0.15.0",
|
"@microsoft/tsdoc": "^0.15.0",
|
||||||
"@nestjs/mapped-types": "2.0.6",
|
"@nestjs/mapped-types": "2.0.5",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"path-to-regexp": "3.3.0",
|
"path-to-regexp": "3.3.0",
|
||||||
"swagger-ui-dist": "5.18.2"
|
"swagger-ui-dist": "5.17.14"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@fastify/static": "^6.0.0 || ^7.0.0",
|
"@fastify/static": "^6.0.0 || ^7.0.0",
|
||||||
@@ -4464,13 +4464,6 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@scarf/scarf": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
|
||||||
"node_modules/@selderee/plugin-htmlparser2": {
|
"node_modules/@selderee/plugin-htmlparser2": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||||
@@ -13771,13 +13764,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/swagger-ui-dist": {
|
"node_modules/swagger-ui-dist": {
|
||||||
"version": "5.18.2",
|
"version": "5.17.14",
|
||||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz",
|
||||||
"integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==",
|
"integrity": "sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0"
|
||||||
"dependencies": {
|
|
||||||
"@scarf/scarf": "=1.4.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/symbol-observable": {
|
"node_modules/symbol-observable": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"@nestjs/platform-express": "^10.2.2",
|
"@nestjs/platform-express": "^10.2.2",
|
||||||
"@nestjs/platform-socket.io": "^10.2.2",
|
"@nestjs/platform-socket.io": "^10.2.2",
|
||||||
"@nestjs/schedule": "^4.0.0",
|
"@nestjs/schedule": "^4.0.0",
|
||||||
"@nestjs/swagger": "^8.0.0",
|
"@nestjs/swagger": "^7.1.8",
|
||||||
"@nestjs/typeorm": "^10.0.0",
|
"@nestjs/typeorm": "^10.0.0",
|
||||||
"@nestjs/websockets": "^10.2.2",
|
"@nestjs/websockets": "^10.2.2",
|
||||||
"@opentelemetry/auto-instrumentations-node": "^0.54.0",
|
"@opentelemetry/auto-instrumentations-node": "^0.54.0",
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ describe('getEnv', () => {
|
|||||||
it('should return default network options', () => {
|
it('should return default network options', () => {
|
||||||
const { network } = getEnv();
|
const { network } = getEnv();
|
||||||
expect(network).toEqual({
|
expect(network).toEqual({
|
||||||
trustedProxies: ['linklocal', 'uniquelocal'],
|
trustedProxies: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ const getEnv = (): EnvData => {
|
|||||||
licensePublicKey: isProd ? productionKeys : stagingKeys,
|
licensePublicKey: isProd ? productionKeys : stagingKeys,
|
||||||
|
|
||||||
network: {
|
network: {
|
||||||
trustedProxies: dto.IMMICH_TRUSTED_PROXIES ?? ['linklocal', 'uniquelocal'],
|
trustedProxies: dto.IMMICH_TRUSTED_PROXIES ?? [],
|
||||||
},
|
},
|
||||||
|
|
||||||
otel: {
|
otel: {
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ export class StorageRepository implements IStorageRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private asGlob(pathToCrawl: string): string {
|
private asGlob(pathToCrawl: string): string {
|
||||||
const escapedPath = escapePath(pathToCrawl).replaceAll('"', '["]').replaceAll("'", "[']").replaceAll('`', '[`]');
|
const escapedPath = escapePath(pathToCrawl);
|
||||||
const extensions = `*{${mimeTypes.getSupportedFileExtensions().join(',')}}`;
|
const extensions = `*{${mimeTypes.getSupportedFileExtensions().join(',')}}`;
|
||||||
return `${escapedPath}/**/${extensions}`;
|
return `${escapedPath}/**/${extensions}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ describe(LibraryService.name, () => {
|
|||||||
localDateTime: expect.any(Date),
|
localDateTime: expect.any(Date),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
originalFileName: 'photo.jpg',
|
originalFileName: 'photo.jpg',
|
||||||
|
sidecarPath: null,
|
||||||
isExternal: true,
|
isExternal: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -422,9 +423,57 @@ describe(LibraryService.name, () => {
|
|||||||
expect(jobMock.queue.mock.calls).toEqual([
|
expect(jobMock.queue.mock.calls).toEqual([
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: JobName.SIDECAR_DISCOVERY,
|
name: JobName.METADATA_EXTRACTION,
|
||||||
data: {
|
data: {
|
||||||
id: assetStub.image.id,
|
id: assetStub.image.id,
|
||||||
|
source: 'upload',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import a new asset with sidecar', async () => {
|
||||||
|
const mockLibraryJob: ILibraryFileJob = {
|
||||||
|
id: libraryStub.externalLibrary1.id,
|
||||||
|
ownerId: mockUser.id,
|
||||||
|
assetPath: '/data/user1/photo.jpg',
|
||||||
|
};
|
||||||
|
|
||||||
|
assetMock.getByLibraryIdAndOriginalPath.mockResolvedValue(null);
|
||||||
|
assetMock.create.mockResolvedValue(assetStub.image);
|
||||||
|
storageMock.checkFileExists.mockResolvedValue(true);
|
||||||
|
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
|
||||||
|
|
||||||
|
await expect(sut.handleSyncFile(mockLibraryJob)).resolves.toBe(JobStatus.SUCCESS);
|
||||||
|
|
||||||
|
expect(assetMock.create.mock.calls).toEqual([
|
||||||
|
[
|
||||||
|
{
|
||||||
|
ownerId: mockUser.id,
|
||||||
|
libraryId: libraryStub.externalLibrary1.id,
|
||||||
|
checksum: expect.any(Buffer),
|
||||||
|
originalPath: '/data/user1/photo.jpg',
|
||||||
|
deviceAssetId: expect.any(String),
|
||||||
|
deviceId: 'Library Import',
|
||||||
|
fileCreatedAt: expect.any(Date),
|
||||||
|
fileModifiedAt: expect.any(Date),
|
||||||
|
localDateTime: expect.any(Date),
|
||||||
|
type: AssetType.IMAGE,
|
||||||
|
originalFileName: 'photo.jpg',
|
||||||
|
sidecarPath: '/data/user1/photo.jpg.xmp',
|
||||||
|
isExternal: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(jobMock.queue.mock.calls).toEqual([
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: JobName.METADATA_EXTRACTION,
|
||||||
|
data: {
|
||||||
|
id: assetStub.image.id,
|
||||||
|
source: 'upload',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -458,6 +507,7 @@ describe(LibraryService.name, () => {
|
|||||||
localDateTime: expect.any(Date),
|
localDateTime: expect.any(Date),
|
||||||
type: AssetType.VIDEO,
|
type: AssetType.VIDEO,
|
||||||
originalFileName: 'video.mp4',
|
originalFileName: 'video.mp4',
|
||||||
|
sidecarPath: null,
|
||||||
isExternal: true,
|
isExternal: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -466,9 +516,10 @@ describe(LibraryService.name, () => {
|
|||||||
expect(jobMock.queue.mock.calls).toEqual([
|
expect(jobMock.queue.mock.calls).toEqual([
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: JobName.SIDECAR_DISCOVERY,
|
name: JobName.METADATA_EXTRACTION,
|
||||||
data: {
|
data: {
|
||||||
id: assetStub.image.id,
|
id: assetStub.image.id,
|
||||||
|
source: 'upload',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -396,6 +396,12 @@ export class LibraryService extends BaseService {
|
|||||||
|
|
||||||
const pathHash = this.cryptoRepository.hashSha1(`path:${assetPath}`);
|
const pathHash = this.cryptoRepository.hashSha1(`path:${assetPath}`);
|
||||||
|
|
||||||
|
// TODO: doesn't xmp replace the file extension? Will need investigation
|
||||||
|
let sidecarPath: string | null = null;
|
||||||
|
if (await this.storageRepository.checkFileExists(`${assetPath}.xmp`, R_OK)) {
|
||||||
|
sidecarPath = `${assetPath}.xmp`;
|
||||||
|
}
|
||||||
|
|
||||||
const assetType = mimeTypes.isVideo(assetPath) ? AssetType.VIDEO : AssetType.IMAGE;
|
const assetType = mimeTypes.isVideo(assetPath) ? AssetType.VIDEO : AssetType.IMAGE;
|
||||||
|
|
||||||
const mtime = stat.mtime;
|
const mtime = stat.mtime;
|
||||||
@@ -412,6 +418,8 @@ export class LibraryService extends BaseService {
|
|||||||
localDateTime: mtime,
|
localDateTime: mtime,
|
||||||
type: assetType,
|
type: assetType,
|
||||||
originalFileName: parse(assetPath).base,
|
originalFileName: parse(assetPath).base,
|
||||||
|
|
||||||
|
sidecarPath,
|
||||||
isExternal: true,
|
isExternal: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -423,11 +431,7 @@ export class LibraryService extends BaseService {
|
|||||||
async queuePostSyncJobs(asset: AssetEntity) {
|
async queuePostSyncJobs(asset: AssetEntity) {
|
||||||
this.logger.debug(`Queueing metadata extraction for: ${asset.originalPath}`);
|
this.logger.debug(`Queueing metadata extraction for: ${asset.originalPath}`);
|
||||||
|
|
||||||
// We queue a sidecar discovery which, in turn, queues metadata extraction
|
await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: asset.id, source: 'upload' } });
|
||||||
await this.jobRepository.queue({
|
|
||||||
name: JobName.SIDECAR_DISCOVERY,
|
|
||||||
data: { id: asset.id },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async queueScan(id: string) {
|
async queueScan(id: string) {
|
||||||
|
|||||||
@@ -698,7 +698,7 @@ export class MetadataService extends BaseService {
|
|||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSync && (!asset.isVisible || asset.sidecarPath) && !asset.isExternal) {
|
if (!isSync && (!asset.isVisible || asset.sidecarPath)) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,13 +720,6 @@ export class MetadataService extends BaseService {
|
|||||||
sidecarPath = sidecarPathWithoutExt;
|
sidecarPath = sidecarPathWithoutExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset.isExternal) {
|
|
||||||
if (sidecarPath !== asset.sidecarPath) {
|
|
||||||
await this.assetRepository.update({ id: asset.id, sidecarPath });
|
|
||||||
}
|
|
||||||
return JobStatus.SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidecarPath) {
|
if (sidecarPath) {
|
||||||
await this.assetRepository.update({ id: asset.id, sidecarPath });
|
await this.assetRepository.update({ id: asset.id, sidecarPath });
|
||||||
return JobStatus.SUCCESS;
|
return JobStatus.SUCCESS;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async function bootstrap() {
|
|||||||
|
|
||||||
logger.setContext('Bootstrap');
|
logger.setContext('Bootstrap');
|
||||||
app.useLogger(logger);
|
app.useLogger(logger);
|
||||||
app.set('trust proxy', ['loopback', ...network.trustedProxies]);
|
app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal', ...network.trustedProxies]);
|
||||||
app.set('etag', 'strong');
|
app.set('etag', 'strong');
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(json({ limit: '10mb' }));
|
app.use(json({ limit: '10mb' }));
|
||||||
|
|||||||
231
web/package-lock.json
generated
231
web/package-lock.json
generated
@@ -37,7 +37,7 @@
|
|||||||
"@socket.io/component-emitter": "^3.1.0",
|
"@socket.io/component-emitter": "^3.1.0",
|
||||||
"@sveltejs/adapter-static": "^3.0.5",
|
"@sveltejs/adapter-static": "^3.0.5",
|
||||||
"@sveltejs/enhanced-img": "^0.4.0",
|
"@sveltejs/enhanced-img": "^0.4.0",
|
||||||
"@sveltejs/kit": "^2.12.0",
|
"@sveltejs/kit": "^2.7.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
"@testing-library/jest-dom": "^6.4.2",
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
"@testing-library/svelte": "^5.2.4",
|
"@testing-library/svelte": "^5.2.4",
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.9.0",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1709,9 +1709,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz",
|
||||||
"integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==",
|
"integrity": "sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -1723,9 +1723,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz",
|
||||||
"integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==",
|
"integrity": "sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1737,9 +1737,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz",
|
||||||
"integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==",
|
"integrity": "sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1751,9 +1751,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz",
|
||||||
"integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==",
|
"integrity": "sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1764,38 +1764,10 @@
|
|||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
|
||||||
"version": "4.28.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz",
|
|
||||||
"integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
|
||||||
"version": "4.28.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz",
|
|
||||||
"integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz",
|
||||||
"integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==",
|
"integrity": "sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -1807,9 +1779,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz",
|
||||||
"integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==",
|
"integrity": "sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -1821,9 +1793,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz",
|
||||||
"integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==",
|
"integrity": "sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1835,9 +1807,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz",
|
||||||
"integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==",
|
"integrity": "sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1848,24 +1820,10 @@
|
|||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
|
||||||
"version": "4.28.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz",
|
|
||||||
"integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==",
|
|
||||||
"cpu": [
|
|
||||||
"loong64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz",
|
||||||
"integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==",
|
"integrity": "sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -1877,9 +1835,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz",
|
||||||
"integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==",
|
"integrity": "sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@@ -1891,9 +1849,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz",
|
||||||
"integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==",
|
"integrity": "sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -1905,9 +1863,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz",
|
||||||
"integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==",
|
"integrity": "sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1919,9 +1877,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz",
|
||||||
"integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==",
|
"integrity": "sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1933,9 +1891,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz",
|
||||||
"integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==",
|
"integrity": "sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1947,9 +1905,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz",
|
||||||
"integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==",
|
"integrity": "sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -1961,9 +1919,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz",
|
||||||
"integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==",
|
"integrity": "sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -2007,9 +1965,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/kit": {
|
"node_modules/@sveltejs/kit": {
|
||||||
"version": "2.13.0",
|
"version": "2.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.3.tgz",
|
||||||
"integrity": "sha512-6t6ne00vZx/TjD6s0Jvwt8wRLKBwbSAN1nhlOzcLUSTYX1hTp4eCBaTPB5Yz/lu+tYcvz4YPEEuPv3yfsNp2gw==",
|
"integrity": "sha512-DVBVwugfzzn0SxKA+eAmKqcZ7aHZROCHxH7/pyrOi+HLtQ721eEsctGb9MkhEuqj6q/9S/OFYdn37vdxzFPdvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -2017,7 +1975,7 @@
|
|||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
"devalue": "^5.1.0",
|
"devalue": "^5.1.0",
|
||||||
"esm-env": "^1.2.1",
|
"esm-env": "^1.0.0",
|
||||||
"import-meta-resolve": "^4.1.0",
|
"import-meta-resolve": "^4.1.0",
|
||||||
"kleur": "^4.1.5",
|
"kleur": "^4.1.5",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
@@ -2034,9 +1992,9 @@
|
|||||||
"node": ">=18.13"
|
"node": ">=18.13"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1",
|
||||||
"svelte": "^4.0.0 || ^5.0.0-next.0",
|
"svelte": "^4.0.0 || ^5.0.0-next.0",
|
||||||
"vite": "^5.0.3 || ^6.0.0"
|
"vite": "^5.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||||
@@ -2327,10 +2285,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/geojson": {
|
"node_modules/@types/geojson": {
|
||||||
"version": "7946.0.14",
|
"version": "7946.0.14",
|
||||||
@@ -4090,6 +4047,13 @@
|
|||||||
"url": "https://github.com/sponsors/nzakas"
|
"url": "https://github.com/sponsors/nzakas"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint/node_modules/@types/estree": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/eslint/node_modules/ansi-styles": {
|
"node_modules/eslint/node_modules/ansi-styles": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
@@ -4228,10 +4192,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esm-env": {
|
"node_modules/esm-env": {
|
||||||
"version": "1.2.1",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
|
||||||
"integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==",
|
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/esniff": {
|
"node_modules/esniff": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
@@ -5095,6 +5058,12 @@
|
|||||||
"@types/estree": "^1.0.6"
|
"@types/estree": "^1.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-reference/node_modules/@types/estree": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/is-wsl": {
|
"node_modules/is-wsl": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||||
@@ -5750,9 +5719,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -5760,7 +5729,6 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"nanoid": "bin/nanoid.cjs"
|
"nanoid": "bin/nanoid.cjs"
|
||||||
},
|
},
|
||||||
@@ -6675,13 +6643,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.28.1",
|
"version": "4.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.1.tgz",
|
||||||
"integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==",
|
"integrity": "sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.6"
|
"@types/estree": "1.0.5"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@@ -6691,25 +6659,22 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.28.1",
|
"@rollup/rollup-android-arm-eabi": "4.21.1",
|
||||||
"@rollup/rollup-android-arm64": "4.28.1",
|
"@rollup/rollup-android-arm64": "4.21.1",
|
||||||
"@rollup/rollup-darwin-arm64": "4.28.1",
|
"@rollup/rollup-darwin-arm64": "4.21.1",
|
||||||
"@rollup/rollup-darwin-x64": "4.28.1",
|
"@rollup/rollup-darwin-x64": "4.21.1",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.28.1",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.21.1",
|
||||||
"@rollup/rollup-freebsd-x64": "4.28.1",
|
"@rollup/rollup-linux-arm-musleabihf": "4.21.1",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.28.1",
|
"@rollup/rollup-linux-arm64-gnu": "4.21.1",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.28.1",
|
"@rollup/rollup-linux-arm64-musl": "4.21.1",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.28.1",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.21.1",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.28.1",
|
"@rollup/rollup-linux-riscv64-gnu": "4.21.1",
|
||||||
"@rollup/rollup-linux-loongarch64-gnu": "4.28.1",
|
"@rollup/rollup-linux-s390x-gnu": "4.21.1",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.28.1",
|
"@rollup/rollup-linux-x64-gnu": "4.21.1",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.28.1",
|
"@rollup/rollup-linux-x64-musl": "4.21.1",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.28.1",
|
"@rollup/rollup-win32-arm64-msvc": "4.21.1",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.28.1",
|
"@rollup/rollup-win32-ia32-msvc": "4.21.1",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.28.1",
|
"@rollup/rollup-win32-x64-msvc": "4.21.1",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.28.1",
|
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.28.1",
|
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.28.1",
|
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"@socket.io/component-emitter": "^3.1.0",
|
"@socket.io/component-emitter": "^3.1.0",
|
||||||
"@sveltejs/adapter-static": "^3.0.5",
|
"@sveltejs/adapter-static": "^3.0.5",
|
||||||
"@sveltejs/enhanced-img": "^0.4.0",
|
"@sveltejs/enhanced-img": "^0.4.0",
|
||||||
"@sveltejs/kit": "^2.12.0",
|
"@sveltejs/kit": "^2.7.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
"@testing-library/jest-dom": "^6.4.2",
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
"@testing-library/svelte": "^5.2.4",
|
"@testing-library/svelte": "^5.2.4",
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
|
||||||
import {
|
|
||||||
notificationController,
|
|
||||||
NotificationType,
|
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
|
||||||
import { updatePerson, type AssetResponseDto, type PersonResponseDto } from '@immich/sdk';
|
|
||||||
import { mdiFaceManProfile } from '@mdi/js';
|
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
asset: AssetResponseDto;
|
|
||||||
person: PersonResponseDto;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { asset, person }: Props = $props();
|
|
||||||
|
|
||||||
const handleSelectFeaturePhoto = async () => {
|
|
||||||
try {
|
|
||||||
await updatePerson({ id: person.id, personUpdateDto: { featureFaceAssetId: asset.id } });
|
|
||||||
notificationController.show({ message: $t('feature_photo_updated'), type: NotificationType.Info });
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error, $t('errors.unable_to_set_feature_photo'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<MenuOption text={$t('set_as_featured_photo')} icon={mdiFaceManProfile} onClick={handleSelectFeaturePhoto} />
|
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
import FavoriteAction from '$lib/components/asset-viewer/actions/favorite-action.svelte';
|
import FavoriteAction from '$lib/components/asset-viewer/actions/favorite-action.svelte';
|
||||||
import RestoreAction from '$lib/components/asset-viewer/actions/restore-action.svelte';
|
import RestoreAction from '$lib/components/asset-viewer/actions/restore-action.svelte';
|
||||||
import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/set-album-cover-action.svelte';
|
import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/set-album-cover-action.svelte';
|
||||||
import SetFeaturedPhotoAction from '$lib/components/asset-viewer/actions/set-person-featured-action.svelte';
|
|
||||||
import SetProfilePictureAction from '$lib/components/asset-viewer/actions/set-profile-picture-action.svelte';
|
import SetProfilePictureAction from '$lib/components/asset-viewer/actions/set-profile-picture-action.svelte';
|
||||||
import ShareAction from '$lib/components/asset-viewer/actions/share-action.svelte';
|
import ShareAction from '$lib/components/asset-viewer/actions/share-action.svelte';
|
||||||
import ShowDetailAction from '$lib/components/asset-viewer/actions/show-detail-action.svelte';
|
import ShowDetailAction from '$lib/components/asset-viewer/actions/show-detail-action.svelte';
|
||||||
@@ -28,7 +27,6 @@
|
|||||||
AssetTypeEnum,
|
AssetTypeEnum,
|
||||||
type AlbumResponseDto,
|
type AlbumResponseDto,
|
||||||
type AssetResponseDto,
|
type AssetResponseDto,
|
||||||
type PersonResponseDto,
|
|
||||||
type StackResponseDto,
|
type StackResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import {
|
import {
|
||||||
@@ -52,7 +50,6 @@
|
|||||||
interface Props {
|
interface Props {
|
||||||
asset: AssetResponseDto;
|
asset: AssetResponseDto;
|
||||||
album?: AlbumResponseDto | null;
|
album?: AlbumResponseDto | null;
|
||||||
person?: PersonResponseDto | null;
|
|
||||||
stack?: StackResponseDto | null;
|
stack?: StackResponseDto | null;
|
||||||
showDetailButton: boolean;
|
showDetailButton: boolean;
|
||||||
showSlideshow?: boolean;
|
showSlideshow?: boolean;
|
||||||
@@ -70,7 +67,6 @@
|
|||||||
let {
|
let {
|
||||||
asset,
|
asset,
|
||||||
album = null,
|
album = null,
|
||||||
person = null,
|
|
||||||
stack = null,
|
stack = null,
|
||||||
showDetailButton,
|
showDetailButton,
|
||||||
showSlideshow = false,
|
showSlideshow = false,
|
||||||
@@ -173,9 +169,6 @@
|
|||||||
{#if album}
|
{#if album}
|
||||||
<SetAlbumCoverAction {asset} {album} />
|
<SetAlbumCoverAction {asset} {album} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if person}
|
|
||||||
<SetFeaturedPhotoAction {asset} {person} />
|
|
||||||
{/if}
|
|
||||||
{#if asset.type === AssetTypeEnum.Image}
|
{#if asset.type === AssetTypeEnum.Image}
|
||||||
<SetProfilePictureAction {asset} />
|
<SetProfilePictureAction {asset} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
type ActivityResponseDto,
|
type ActivityResponseDto,
|
||||||
type AlbumResponseDto,
|
type AlbumResponseDto,
|
||||||
type AssetResponseDto,
|
type AssetResponseDto,
|
||||||
type PersonResponseDto,
|
|
||||||
type StackResponseDto,
|
type StackResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { onDestroy, onMount, untrack } from 'svelte';
|
import { onDestroy, onMount, untrack } from 'svelte';
|
||||||
@@ -57,7 +56,6 @@
|
|||||||
withStacked?: boolean;
|
withStacked?: boolean;
|
||||||
isShared?: boolean;
|
isShared?: boolean;
|
||||||
album?: AlbumResponseDto | null;
|
album?: AlbumResponseDto | null;
|
||||||
person?: PersonResponseDto | null;
|
|
||||||
onAction?: OnAction | undefined;
|
onAction?: OnAction | undefined;
|
||||||
reactions?: ActivityResponseDto[];
|
reactions?: ActivityResponseDto[];
|
||||||
onClose: (dto: { asset: AssetResponseDto }) => void;
|
onClose: (dto: { asset: AssetResponseDto }) => void;
|
||||||
@@ -74,7 +72,6 @@
|
|||||||
withStacked = false,
|
withStacked = false,
|
||||||
isShared = false,
|
isShared = false,
|
||||||
album = null,
|
album = null,
|
||||||
person = null,
|
|
||||||
onAction = undefined,
|
onAction = undefined,
|
||||||
reactions = $bindable([]),
|
reactions = $bindable([]),
|
||||||
onClose,
|
onClose,
|
||||||
@@ -432,7 +429,6 @@
|
|||||||
<AssetViewerNavBar
|
<AssetViewerNavBar
|
||||||
{asset}
|
{asset}
|
||||||
{album}
|
{album}
|
||||||
{person}
|
|
||||||
{stack}
|
{stack}
|
||||||
showDetailButton={enableDetailPanel}
|
showDetailButton={enableDetailPanel}
|
||||||
showSlideshow={!!assetStore}
|
showSlideshow={!!assetStore}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" module>
|
<script lang="ts" module>
|
||||||
export type Color = 'transparent' | 'light' | 'dark' | 'red' | 'gray' | 'primary' | 'opaque' | 'alert' | 'neutral';
|
export type Color = 'transparent' | 'light' | 'dark' | 'red' | 'gray' | 'primary' | 'opaque' | 'alert';
|
||||||
export type Padding = '1' | '2' | '3';
|
export type Padding = '1' | '2' | '3';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -68,8 +68,6 @@
|
|||||||
dark: 'bg-[#202123] hover:bg-[#d3d3d3]',
|
dark: 'bg-[#202123] hover:bg-[#d3d3d3]',
|
||||||
alert: 'text-[#ff0000] hover:text-white',
|
alert: 'text-[#ff0000] hover:text-white',
|
||||||
gray: 'bg-[#d3d3d3] hover:bg-[#e2e7e9] text-immich-dark-gray hover:text-black',
|
gray: 'bg-[#d3d3d3] hover:bg-[#e2e7e9] text-immich-dark-gray hover:text-black',
|
||||||
neutral:
|
|
||||||
'dark:bg-immich-dark-gray dark:text-gray-300 hover:dark:bg-immich-dark-gray/50 hover:dark:text-gray-300 bg-gray-200 text-gray-700 hover:bg-gray-300',
|
|
||||||
primary:
|
primary:
|
||||||
'bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 hover:dark:bg-immich-dark-primary/80 text-white dark:text-immich-dark-gray',
|
'bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 hover:dark:bg-immich-dark-primary/80 text-white dark:text-immich-dark-gray',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { ActionQueryParameterValue, AppRoute, QueryParameter } from '$lib/constants';
|
import { ActionQueryParameterValue, AppRoute, QueryParameter } from '$lib/constants';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
@@ -34,17 +34,15 @@
|
|||||||
let hasSelection = $derived(selectedPeople.length > 0);
|
let hasSelection = $derived(selectedPeople.length > 0);
|
||||||
let peopleToNotShow = $derived([...selectedPeople, person]);
|
let peopleToNotShow = $derived([...selectedPeople, person]);
|
||||||
|
|
||||||
const handleSearch = async (sortFaces: boolean = false) => {
|
onMount(async () => {
|
||||||
const data = await getAllPeople({ withHidden: false, closestPersonId: sortFaces ? person.id : undefined });
|
const data = await getAllPeople({ withHidden: false, closestPersonId: person.id });
|
||||||
people = data.people;
|
people = data.people;
|
||||||
};
|
});
|
||||||
|
|
||||||
onMount(handleSearch);
|
|
||||||
|
|
||||||
const handleSwapPeople = async () => {
|
const handleSwapPeople = async () => {
|
||||||
[person, selectedPeople[0]] = [selectedPeople[0], person];
|
[person, selectedPeople[0]] = [selectedPeople[0], person];
|
||||||
page.url.searchParams.set(QueryParameter.ACTION, ActionQueryParameterValue.MERGE);
|
$page.url.searchParams.set(QueryParameter.ACTION, ActionQueryParameterValue.MERGE);
|
||||||
await goto(`${AppRoute.PEOPLE}/${person.id}?${page.url.searchParams.toString()}`);
|
await goto(`${AppRoute.PEOPLE}/${person.id}?${$page.url.searchParams.toString()}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelect = async (selected: PersonResponseDto) => {
|
const onSelect = async (selected: PersonResponseDto) => {
|
||||||
@@ -151,7 +149,8 @@
|
|||||||
<FaceThumbnail {person} border circle selectable={false} thumbnailSize={180} />
|
<FaceThumbnail {person} border circle selectable={false} thumbnailSize={180} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<PeopleList {people} {peopleToNotShow} {screenHeight} {onSelect} {handleSearch} />
|
|
||||||
|
<PeopleList {people} {peopleToNotShow} {screenHeight} {onSelect} />
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -3,20 +3,18 @@
|
|||||||
import FaceThumbnail from './face-thumbnail.svelte';
|
import FaceThumbnail from './face-thumbnail.svelte';
|
||||||
import SearchPeople from '$lib/components/faces-page/people-search.svelte';
|
import SearchPeople from '$lib/components/faces-page/people-search.svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { mdiSwapVertical } from '@mdi/js';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
screenHeight: number;
|
screenHeight: number;
|
||||||
people: PersonResponseDto[];
|
people: PersonResponseDto[];
|
||||||
peopleToNotShow: PersonResponseDto[];
|
peopleToNotShow: PersonResponseDto[];
|
||||||
onSelect: (person: PersonResponseDto) => void;
|
onSelect: (person: PersonResponseDto) => void;
|
||||||
handleSearch?: (sortFaces: boolean) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let { screenHeight, people, peopleToNotShow, onSelect, handleSearch }: Props = $props();
|
let { screenHeight, people, peopleToNotShow, onSelect }: Props = $props();
|
||||||
|
|
||||||
let searchedPeopleLocal: PersonResponseDto[] = $state([]);
|
let searchedPeopleLocal: PersonResponseDto[] = $state([]);
|
||||||
let sortBySimilarirty = $state(false);
|
|
||||||
let name = $state('');
|
let name = $state('');
|
||||||
|
|
||||||
const showPeople = $derived(
|
const showPeople = $derived(
|
||||||
@@ -26,26 +24,12 @@
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-40 sm:w-48 md:w-full h-14 flex gap-4 place-items-center">
|
<div class=" w-40 sm:w-48 md:w-96 h-14 mb-8">
|
||||||
<div class="md:w-96">
|
<SearchPeople type="searchBar" placeholder={$t('search_people')} bind:searchName={name} bind:searchedPeopleLocal />
|
||||||
<SearchPeople type="searchBar" placeholder={$t('search_people')} bind:searchName={name} bind:searchedPeopleLocal />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if handleSearch}
|
|
||||||
<CircleIconButton
|
|
||||||
icon={mdiSwapVertical}
|
|
||||||
onclick={() => {
|
|
||||||
sortBySimilarirty = !sortBySimilarirty;
|
|
||||||
handleSearch(sortBySimilarirty);
|
|
||||||
}}
|
|
||||||
color="neutral"
|
|
||||||
title={$t('sort_people_by_similarity')}
|
|
||||||
></CircleIconButton>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="immich-scrollbar overflow-y-auto rounded-3xl bg-gray-200 p-10 dark:bg-immich-dark-gray mt-6"
|
class="immich-scrollbar overflow-y-auto rounded-3xl bg-gray-200 p-10 dark:bg-immich-dark-gray"
|
||||||
style:max-height={screenHeight - 400 + 'px'}
|
style:max-height={screenHeight - 400 + 'px'}
|
||||||
>
|
>
|
||||||
<div class="grid-col-2 grid gap-8 md:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
|
<div class="grid-col-2 grid gap-8 md:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
import Combobox, { type ComboBoxOption } from '../shared-components/combobox.svelte';
|
import Combobox, { type ComboBoxOption } from '../shared-components/combobox.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { getAllTags, upsertTags, type TagResponseDto } from '@immich/sdk';
|
import { getAllTags, type TagResponseDto } from '@immich/sdk';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
import { AppRoute } from '$lib/constants';
|
||||||
|
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
||||||
import { SvelteSet } from 'svelte/reactivity';
|
import { SvelteSet } from 'svelte/reactivity';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -20,7 +22,6 @@
|
|||||||
let tagMap = $derived(Object.fromEntries(allTags.map((tag) => [tag.id, tag])));
|
let tagMap = $derived(Object.fromEntries(allTags.map((tag) => [tag.id, tag])));
|
||||||
let selectedIds = $state(new SvelteSet<string>());
|
let selectedIds = $state(new SvelteSet<string>());
|
||||||
let disabled = $derived(selectedIds.size === 0);
|
let disabled = $derived(selectedIds.size === 0);
|
||||||
let allowCreate: boolean = $state(true);
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
allTags = await getAllTags();
|
allTags = await getAllTags();
|
||||||
@@ -28,18 +29,12 @@
|
|||||||
|
|
||||||
const handleSubmit = () => onTag([...selectedIds]);
|
const handleSubmit = () => onTag([...selectedIds]);
|
||||||
|
|
||||||
const handleSelect = async (option?: ComboBoxOption) => {
|
const handleSelect = (option?: ComboBoxOption) => {
|
||||||
if (!option) {
|
if (!option) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option.id) {
|
selectedIds.add(option.value);
|
||||||
selectedIds.add(option.value);
|
|
||||||
} else {
|
|
||||||
const [newTag] = await upsertTags({ tagUpsertDto: { tags: [option.label] } });
|
|
||||||
allTags.push(newTag);
|
|
||||||
selectedIds.add(newTag.id);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemove = (tag: string) => {
|
const handleRemove = (tag: string) => {
|
||||||
@@ -53,13 +48,22 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal title={$t('tag_assets')} icon={mdiTag} onClose={onCancel}>
|
<FullScreenModal title={$t('tag_assets')} icon={mdiTag} onClose={onCancel}>
|
||||||
|
<div class="text-sm">
|
||||||
|
<p>
|
||||||
|
<FormatMessage key="tag_not_found_question">
|
||||||
|
{#snippet children({ message })}
|
||||||
|
<a href={AppRoute.TAGS} class="text-immich-primary dark:text-immich-dark-primary underline">
|
||||||
|
{message}
|
||||||
|
</a>
|
||||||
|
{/snippet}
|
||||||
|
</FormatMessage>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<form {onsubmit} autocomplete="off" id="create-tag-form">
|
<form {onsubmit} autocomplete="off" id="create-tag-form">
|
||||||
<div class="my-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<Combobox
|
<Combobox
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
label={$t('tag')}
|
label={$t('tag')}
|
||||||
{allowCreate}
|
|
||||||
defaultFirstOption
|
|
||||||
options={allTags.map((tag) => ({ id: tag.id, label: tag.value, value: tag.id }))}
|
options={allTags.map((tag) => ({ id: tag.id, label: tag.value, value: tag.id }))}
|
||||||
placeholder={$t('search_tags')}
|
placeholder={$t('search_tags')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
type ScrollTargetListener,
|
type ScrollTargetListener,
|
||||||
} from '$lib/utils/timeline-util';
|
} from '$lib/utils/timeline-util';
|
||||||
import { TUNABLES } from '$lib/utils/tunables';
|
import { TUNABLES } from '$lib/utils/tunables';
|
||||||
import type { AlbumResponseDto, AssetResponseDto, PersonResponseDto } from '@immich/sdk';
|
import type { AlbumResponseDto, AssetResponseDto } from '@immich/sdk';
|
||||||
import { throttle } from 'lodash-es';
|
import { throttle } from 'lodash-es';
|
||||||
import { onDestroy, onMount, type Snippet } from 'svelte';
|
import { onDestroy, onMount, type Snippet } from 'svelte';
|
||||||
import Portal from '../shared-components/portal/portal.svelte';
|
import Portal from '../shared-components/portal/portal.svelte';
|
||||||
@@ -52,7 +52,6 @@
|
|||||||
showArchiveIcon?: boolean;
|
showArchiveIcon?: boolean;
|
||||||
isShared?: boolean;
|
isShared?: boolean;
|
||||||
album?: AlbumResponseDto | null;
|
album?: AlbumResponseDto | null;
|
||||||
person?: PersonResponseDto | null;
|
|
||||||
isShowDeleteConfirmation?: boolean;
|
isShowDeleteConfirmation?: boolean;
|
||||||
onSelect?: (asset: AssetResponseDto) => void;
|
onSelect?: (asset: AssetResponseDto) => void;
|
||||||
onEscape?: () => void;
|
onEscape?: () => void;
|
||||||
@@ -71,7 +70,6 @@
|
|||||||
showArchiveIcon = false,
|
showArchiveIcon = false,
|
||||||
isShared = false,
|
isShared = false,
|
||||||
album = null,
|
album = null,
|
||||||
person = null,
|
|
||||||
isShowDeleteConfirmation = $bindable(false),
|
isShowDeleteConfirmation = $bindable(false),
|
||||||
onSelect = () => {},
|
onSelect = () => {},
|
||||||
onEscape = () => {},
|
onEscape = () => {},
|
||||||
@@ -916,7 +914,6 @@
|
|||||||
preloadAssets={$preloadAssets}
|
preloadAssets={$preloadAssets}
|
||||||
{isShared}
|
{isShared}
|
||||||
{album}
|
{album}
|
||||||
{person}
|
|
||||||
onAction={handleAction}
|
onAction={handleAction}
|
||||||
onPrevious={handlePrevious}
|
onPrevious={handlePrevious}
|
||||||
onNext={handleNext}
|
onNext={handleNext}
|
||||||
|
|||||||
@@ -36,14 +36,6 @@
|
|||||||
options?: ComboBoxOption[];
|
options?: ComboBoxOption[];
|
||||||
selectedOption?: ComboBoxOption | undefined;
|
selectedOption?: ComboBoxOption | undefined;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
/**
|
|
||||||
* whether creating new items is allowed.
|
|
||||||
*/
|
|
||||||
allowCreate?: boolean;
|
|
||||||
/**
|
|
||||||
* select first matching option on enter key.
|
|
||||||
*/
|
|
||||||
defaultFirstOption?: boolean;
|
|
||||||
onSelect?: (option: ComboBoxOption | undefined) => void;
|
onSelect?: (option: ComboBoxOption | undefined) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,8 +45,6 @@
|
|||||||
options = [],
|
options = [],
|
||||||
selectedOption = $bindable(),
|
selectedOption = $bindable(),
|
||||||
placeholder = '',
|
placeholder = '',
|
||||||
allowCreate = false,
|
|
||||||
defaultFirstOption = false,
|
|
||||||
onSelect = () => {},
|
onSelect = () => {},
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
@@ -151,7 +141,7 @@
|
|||||||
const onInput: FormEventHandler<HTMLInputElement> = (event) => {
|
const onInput: FormEventHandler<HTMLInputElement> = (event) => {
|
||||||
openDropdown();
|
openDropdown();
|
||||||
searchQuery = event.currentTarget.value;
|
searchQuery = event.currentTarget.value;
|
||||||
selectedIndex = defaultFirstOption ? 0 : undefined;
|
selectedIndex = undefined;
|
||||||
optionRefs[0]?.scrollIntoView({ block: 'nearest' });
|
optionRefs[0]?.scrollIntoView({ block: 'nearest' });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,15 +221,9 @@
|
|||||||
searchQuery = selectedOption ? selectedOption.label : '';
|
searchQuery = selectedOption ? selectedOption.label : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
let filteredOptions = $derived.by(() => {
|
let filteredOptions = $derived(
|
||||||
const _options = options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase()));
|
options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())),
|
||||||
|
);
|
||||||
if (allowCreate && searchQuery !== '' && _options.filter((option) => option.label === searchQuery).length === 0) {
|
|
||||||
_options.unshift({ label: searchQuery, value: searchQuery });
|
|
||||||
}
|
|
||||||
|
|
||||||
return _options;
|
|
||||||
});
|
|
||||||
let position = $derived(calculatePosition(bounds));
|
let position = $derived(calculatePosition(bounds));
|
||||||
let dropdownDirection: 'bottom' | 'top' = $derived(getComboboxDirection(bounds, visualViewport));
|
let dropdownDirection: 'bottom' | 'top' = $derived(getComboboxDirection(bounds, visualViewport));
|
||||||
</script>
|
</script>
|
||||||
@@ -368,7 +352,7 @@
|
|||||||
id={`${listboxId}-${0}`}
|
id={`${listboxId}-${0}`}
|
||||||
onclick={() => closeDropdown()}
|
onclick={() => closeDropdown()}
|
||||||
>
|
>
|
||||||
{allowCreate ? searchQuery : $t('no_results')}
|
{$t('no_results')}
|
||||||
</li>
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
{#each filteredOptions as option, index (option.id || option.label)}
|
{#each filteredOptions as option, index (option.id || option.label)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import { shouldIgnoreEvent } from '$lib/actions/shortcut';
|
import { shouldIgnoreEvent } from '$lib/actions/shortcut';
|
||||||
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
|
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
|
||||||
import { fileUploadHandler } from '$lib/utils/file-uploader';
|
import { fileUploadHandler } from '$lib/utils/file-uploader';
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import ImmichLogo from './immich-logo.svelte';
|
import ImmichLogo from './immich-logo.svelte';
|
||||||
|
|
||||||
let albumId = $derived(isAlbumsRoute(page.route?.id) ? page.params.albumId : undefined);
|
let albumId = $derived(isAlbumsRoute($page.route?.id) ? $page.params.albumId : undefined);
|
||||||
let isShare = $derived(isSharedLinkRoute(page.route?.id));
|
let isShare = $derived(isSharedLinkRoute($page.route?.id));
|
||||||
|
|
||||||
let dragStartTarget: EventTarget | null = $state(null);
|
let dragStartTarget: EventTarget | null = $state(null);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import { focusTrap } from '$lib/actions/focus-trap';
|
import { focusTrap } from '$lib/actions/focus-trap';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
size="sm"
|
size="sm"
|
||||||
shadow={false}
|
shadow={false}
|
||||||
border
|
border
|
||||||
aria-current={page.url.pathname.includes('/admin') ? 'page' : undefined}
|
aria-current={$page.url.pathname.includes('/admin') ? 'page' : undefined}
|
||||||
>
|
>
|
||||||
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
||||||
<Icon path={mdiWrench} size="18" ariaHidden />
|
<Icon path={mdiWrench} size="18" ariaHidden />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import { clickOutside } from '$lib/actions/click-outside';
|
import { clickOutside } from '$lib/actions/click-outside';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if !page.url.pathname.includes('/admin') && showUploadButton}
|
{#if !$page.url.pathname.includes('/admin') && showUploadButton}
|
||||||
<LinkButton onclick={onUploadClick} class="hidden lg:block">
|
<LinkButton onclick={onUploadClick} class="hidden lg:block">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Icon path={mdiTrayArrowUp} size="1.5em" />
|
<Icon path={mdiTrayArrowUp} size="1.5em" />
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { writable, type Writable } from 'svelte/store';
|
import { writable, type Writable } from 'svelte/store';
|
||||||
import { createContext } from '$lib/utils/context';
|
import { createContext } from '$lib/utils/context';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
|
import { handlePromiseError } from '$lib/utils';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import { handlePromiseError } from '$lib/utils';
|
|
||||||
|
|
||||||
const getParamValues = (param: string) => {
|
const getParamValues = (param: string) => {
|
||||||
return new Set((page.url.searchParams.get(param) || '').split(' ').filter((x) => x !== ''));
|
return new Set(($page.url.searchParams.get(param) || '').split(' ').filter((x) => x !== ''));
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -26,16 +26,17 @@
|
|||||||
let { queryParam, state = writable(getParamValues(queryParam)), children }: Props = $props();
|
let { queryParam, state = writable(getParamValues(queryParam)), children }: Props = $props();
|
||||||
setAccordionState(state);
|
setAccordionState(state);
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(page.url.searchParams);
|
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if ($state.size > 0) {
|
if (queryParam && $state) {
|
||||||
searchParams.set(queryParam, [...$state].join(' '));
|
const searchParams = new URLSearchParams($page.url.searchParams);
|
||||||
} else {
|
if ($state.size > 0) {
|
||||||
searchParams.delete(queryParam);
|
searchParams.set(queryParam, [...$state].join(' '));
|
||||||
}
|
} else {
|
||||||
|
searchParams.delete(queryParam);
|
||||||
|
}
|
||||||
|
|
||||||
handlePromiseError(goto(`?${searchParams.toString()}`, { replaceState: true, noScroll: true, keepFocus: true }));
|
handlePromiseError(goto(`?${searchParams.toString()}`, { replaceState: true, noScroll: true, keepFocus: true }));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { mdiChevronDown, mdiChevronLeft } from '@mdi/js';
|
import { mdiChevronDown, mdiChevronLeft } from '@mdi/js';
|
||||||
import { resolveRoute } from '$app/paths';
|
import { resolveRoute } from '$app/paths';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
let routePath = $derived(resolveRoute(routeId, {}));
|
let routePath = $derived(resolveRoute(routeId, {}));
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
isSelected = (page.route.id?.match(/^\/(admin|\(user\))\/[^/]*/) || [])[0] === routeId;
|
isSelected = ($page.route.id?.match(/^\/(admin|\(user\))\/[^/]*/) || [])[0] === routeId;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -17,14 +17,4 @@
|
|||||||
</span>
|
</span>
|
||||||
{$t('review_duplicates')}
|
{$t('review_duplicates')}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
|
||||||
href={AppRoute.WORKFLOWS}
|
|
||||||
class="w-full hover:bg-gray-100 dark:hover:bg-immich-dark-gray flex items-center gap-4 p-4"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
><Icon path={mdiContentDuplicate} class="text-immich-primary dark:text-immich-dark-primary" size="24" />
|
|
||||||
</span>
|
|
||||||
{$t('workflows')}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ export enum AppRoute {
|
|||||||
|
|
||||||
UTILITIES = '/utilities',
|
UTILITIES = '/utilities',
|
||||||
DUPLICATES = '/utilities/duplicates',
|
DUPLICATES = '/utilities/duplicates',
|
||||||
WORKFLOWS = '/utilities/workflows',
|
|
||||||
|
|
||||||
FOLDERS = '/folders',
|
FOLDERS = '/folders',
|
||||||
TAGS = '/tags',
|
TAGS = '/tags',
|
||||||
|
|||||||
@@ -398,9 +398,7 @@ export class AssetStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateOptions(options: AssetStoreOptions) {
|
async updateOptions(options: AssetStoreOptions) {
|
||||||
// Make sure to re-initialize if the personId changes
|
if (!this.initialized) {
|
||||||
const needsReinitializing = this.options.personId !== options.personId;
|
|
||||||
if (!this.initialized && !needsReinitializing) {
|
|
||||||
this.setOptions(options);
|
this.setOptions(options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,13 +74,8 @@
|
|||||||
const assetStore = new AssetStore(assetStoreOptions);
|
const assetStore = new AssetStore(assetStoreOptions);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
// Check to trigger rebuild the timeline when navigating between people from the info panel
|
|
||||||
const change = assetStoreOptions.personId !== data.person.id;
|
|
||||||
assetStoreOptions.personId = data.person.id;
|
assetStoreOptions.personId = data.person.id;
|
||||||
handlePromiseError(assetStore.updateOptions(assetStoreOptions));
|
handlePromiseError(assetStore.updateOptions(assetStoreOptions));
|
||||||
if (change) {
|
|
||||||
assetStore.triggerUpdate();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const assetInteraction = new AssetInteraction();
|
const assetInteraction = new AssetInteraction();
|
||||||
@@ -459,7 +454,6 @@
|
|||||||
{#key person.id}
|
{#key person.id}
|
||||||
<AssetGrid
|
<AssetGrid
|
||||||
enableRouting={true}
|
enableRouting={true}
|
||||||
{person}
|
|
||||||
{assetStore}
|
{assetStore}
|
||||||
{assetInteraction}
|
{assetInteraction}
|
||||||
isSelectionMode={viewMode === PersonPageViewMode.SELECT_PERSON}
|
isSelectionMode={viewMode === PersonPageViewMode.SELECT_PERSON}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<section class="flex flex-col px-4 h-screen w-screen place-content-center place-items-center">
|
<section class="flex flex-col px-4 h-screen w-screen place-content-center place-items-center">
|
||||||
<h1 class="py-10 text-4xl text-immich-primary dark:text-immich-dark-primary">Page not found :/</h1>
|
<h1 class="py-10 text-4xl text-immich-primary dark:text-immich-dark-primary">Page not found :/</h1>
|
||||||
{#if page.error?.message}
|
{#if $page.error?.message}
|
||||||
<h2 class="text-xl text-immich-fg dark:text-immich-dark-fg">{page.error.message}</h2>
|
<h2 class="text-xl text-immich-fg dark:text-immich-dark-fg">{$page.error.message}</h2>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
|
||||||
import type { PageData } from './$types';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
data: PageData;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<UserPageLayout title={data.meta.title}>
|
|
||||||
<div class="w-full h-full bg-gray-50 dark:bg-immich-dark-gray rounded-xl p-6">hello</div>
|
|
||||||
</UserPageLayout>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { authenticate } from '$lib/utils/auth';
|
|
||||||
import { getFormatter } from '$lib/utils/i18n';
|
|
||||||
import type { PageLoad } from './$types';
|
|
||||||
|
|
||||||
export const load = (async () => {
|
|
||||||
await authenticate();
|
|
||||||
const $t = await getFormatter();
|
|
||||||
|
|
||||||
return {
|
|
||||||
meta: {
|
|
||||||
title: $t('workflows'),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}) satisfies PageLoad;
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import Error from '$lib/components/error.svelte';
|
import Error from '$lib/components/error.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Error error={page.error}></Error>
|
<Error error={$page.error}></Error>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { run } from 'svelte/legacy';
|
import { run } from 'svelte/legacy';
|
||||||
|
|
||||||
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/stores';
|
||||||
import DownloadPanel from '$lib/components/asset-viewer/download-panel.svelte';
|
import DownloadPanel from '$lib/components/asset-viewer/download-panel.svelte';
|
||||||
import AppleHeader from '$lib/components/shared-components/apple-header.svelte';
|
import AppleHeader from '$lib/components/shared-components/apple-header.svelte';
|
||||||
import FullscreenContainer from '$lib/components/shared-components/fullscreen-container.svelte';
|
import FullscreenContainer from '$lib/components/shared-components/fullscreen-container.svelte';
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getMyImmichLink = () => {
|
const getMyImmichLink = () => {
|
||||||
return new URL(page.url.pathname + page.url.search, 'https://my.immich.app');
|
return new URL($page.url.pathname + $page.url.search, 'https://my.immich.app');
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -66,8 +66,8 @@
|
|||||||
document.removeEventListener('change', handleChangeTheme);
|
document.removeEventListener('change', handleChangeTheme);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isSharedLinkRoute(page.route?.id)) {
|
if (isSharedLinkRoute($page.route?.id)) {
|
||||||
setKey(page.params.key);
|
setKey($page.params.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeNavigate(({ from, to }) => {
|
beforeNavigate(({ from, to }) => {
|
||||||
@@ -95,33 +95,33 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{page.data.meta?.title || 'Web'} - Immich</title>
|
<title>{$page.data.meta?.title || 'Web'} - Immich</title>
|
||||||
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||||
<meta name="theme-color" content="currentColor" />
|
<meta name="theme-color" content="currentColor" />
|
||||||
<AppleHeader />
|
<AppleHeader />
|
||||||
|
|
||||||
{#if page.data.meta}
|
{#if $page.data.meta}
|
||||||
<meta name="description" content={page.data.meta.description} />
|
<meta name="description" content={$page.data.meta.description} />
|
||||||
|
|
||||||
<!-- Facebook Meta Tags -->
|
<!-- Facebook Meta Tags -->
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:title" content={page.data.meta.title} />
|
<meta property="og:title" content={$page.data.meta.title} />
|
||||||
<meta property="og:description" content={page.data.meta.description} />
|
<meta property="og:description" content={$page.data.meta.description} />
|
||||||
{#if page.data.meta.imageUrl}
|
{#if $page.data.meta.imageUrl}
|
||||||
<meta
|
<meta
|
||||||
property="og:image"
|
property="og:image"
|
||||||
content={new URL(page.data.meta.imageUrl, $serverConfig.externalDomain || globalThis.location.origin).href}
|
content={new URL($page.data.meta.imageUrl, $serverConfig.externalDomain || globalThis.location.origin).href}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Twitter Meta Tags -->
|
<!-- Twitter Meta Tags -->
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content={page.data.meta.title} />
|
<meta name="twitter:title" content={$page.data.meta.title} />
|
||||||
<meta name="twitter:description" content={page.data.meta.description} />
|
<meta name="twitter:description" content={$page.data.meta.description} />
|
||||||
{#if page.data.meta.imageUrl}
|
{#if $page.data.meta.imageUrl}
|
||||||
<meta
|
<meta
|
||||||
name="twitter:image"
|
name="twitter:image"
|
||||||
content={new URL(page.data.meta.imageUrl, $serverConfig.externalDomain || globalThis.location.origin).href}
|
content={new URL($page.data.meta.imageUrl, $serverConfig.externalDomain || globalThis.location.origin).href}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
@@ -142,8 +142,8 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if page.data.error}
|
{#if $page.data.error}
|
||||||
<Error error={page.data.error}></Error>
|
<Error error={$page.data.error}></Error>
|
||||||
{:else}
|
{:else}
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user