Compare commits

...

6 Commits

Author SHA1 Message Date
Alex
7fd0b41f30 fix(mobile): oauth login flow 2025-03-27 10:41:39 -05:00
Min Idzelis
c26b28f6a4 fix: bug with svelte gestures (#17154)
* fix: bug with svelte gestures

* lint
2025-03-27 08:51:52 -05:00
shenlong
c72c82c401 fix(mobile): faster device album refresh after initial sync (#17170)
fix(mobile): faster device album refresh after fresh sync

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-27 08:47:05 -05:00
Alex
fecf3809a6 fix(server): album count does not account for assets without exif (#17150)
* fix(server): album count doesn't accounted for assets without exif

* sql
2025-03-26 21:24:22 -05:00
Mert
619bd72de9 docs: mention rknn among image options (#17156)
mention rknn
2025-03-26 19:05:48 -04:00
Jason Rasmussen
fd4a5f71b5 fix: broken album page (#17149) 2025-03-26 18:59:23 -04:00
10 changed files with 41 additions and 23 deletions

View File

@@ -71,7 +71,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele
1. If you do not already have it, download the latest [`hwaccel.ml.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`. 1. If you do not already have it, download the latest [`hwaccel.ml.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
2. In the `docker-compose.yml` under `immich-machine-learning`, uncomment the `extends` section and change `cpu` to the appropriate backend. 2. In the `docker-compose.yml` under `immich-machine-learning`, uncomment the `extends` section and change `cpu` to the appropriate backend.
3. Still in `immich-machine-learning`, add one of -[armnn, cuda, rocm, openvino] to the `image` section's tag at the end of the line. 3. Still in `immich-machine-learning`, add one of -[armnn, cuda, rocm, openvino, rknn] to the `image` section's tag at the end of the line.
4. Redeploy the `immich-machine-learning` container with these updated settings. 4. Redeploy the `immich-machine-learning` container with these updated settings.
### Confirming Device Usage ### Confirming Device Usage

View File

@@ -23,12 +23,12 @@ name: immich_remote_ml
services: services:
immich-machine-learning: immich-machine-learning:
container_name: immich_machine_learning container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino] to the image tag. # For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda # Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # extends:
# file: hwaccel.ml.yml # file: hwaccel.ml.yml
# service: # set to one of [armnn, cuda, rocm, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable # service: # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes: volumes:
- model-cache:/cache - model-cache:/cache
restart: always restart: always

View File

@@ -737,6 +737,11 @@ class SyncService {
album.thumbnail.value = thumb; album.thumbnail.value = thumb;
try { try {
await _albumRepository.create(album); await _albumRepository.create(album);
final int assetCount =
await _albumMediaRepository.getAssetCount(album.localId!);
await _eTagRepository.upsertAll([
ETag(id: album.eTagKeyAssetCount, assetCount: assetCount),
]);
_log.info("Added a new local album to DB: ${album.name}"); _log.info("Added a new local album to DB: ${album.name}");
} catch (e) { } catch (e) {
_log.severe("Failed to add new local album ${album.name} to DB", e); _log.severe("Failed to add new local album ${album.name} to DB", e);

View File

@@ -210,6 +210,9 @@ class LoginForm extends HookConsumerWidget {
.getOAuthServerUrl(sanitizeUrl(serverEndpointController.text)); .getOAuthServerUrl(sanitizeUrl(serverEndpointController.text));
isLoading.value = true; isLoading.value = true;
// Invalidate all api repository provider instance to take into account new access token
invalidateAllApiRepositoryProviders(ref);
} catch (error, stack) { } catch (error, stack) {
log.severe('Error getting OAuth server Url: $error', stack); log.severe('Error getting OAuth server Url: $error', stack);

View File

@@ -93,7 +93,7 @@ select
"exif" as "exifInfo" "exif" as "exifInfo"
from from
"assets" "assets"
inner join "exif" on "assets"."id" = "exif"."assetId" left join "exif" on "assets"."id" = "exif"."assetId"
inner join "albums_assets_assets" on "albums_assets_assets"."assetsId" = "assets"."id" inner join "albums_assets_assets" on "albums_assets_assets"."assetsId" = "assets"."id"
where where
"albums_assets_assets"."albumsId" = "albums"."id" "albums_assets_assets"."albumsId" = "albums"."id"

View File

@@ -68,7 +68,7 @@ const withAssets = (eb: ExpressionBuilder<DB, 'albums'>) => {
eb eb
.selectFrom('assets') .selectFrom('assets')
.selectAll('assets') .selectAll('assets')
.innerJoin('exif', 'assets.id', 'exif.assetId') .leftJoin('exif', 'assets.id', 'exif.assetId')
.select((eb) => eb.table('exif').as('exifInfo')) .select((eb) => eb.table('exif').as('exifInfo'))
.innerJoin('albums_assets_assets', 'albums_assets_assets.assetsId', 'assets.id') .innerJoin('albums_assets_assets', 'albums_assets_assets.assetsId', 'assets.id')
.whereRef('albums_assets_assets.albumsId', '=', 'albums.id') .whereRef('albums_assets_assets.albumsId', '=', 'albums.id')

8
web/package-lock.json generated
View File

@@ -70,7 +70,7 @@
"prettier-plugin-sort-json": "^4.1.1", "prettier-plugin-sort-json": "^4.1.1",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"rollup-plugin-visualizer": "^5.14.0", "rollup-plugin-visualizer": "^5.14.0",
"svelte": "^5.22.6", "svelte": "^5.25.3",
"svelte-check": "^4.1.5", "svelte-check": "^4.1.5",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"tslib": "^2.6.2", "tslib": "^2.6.2",
@@ -8350,9 +8350,9 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "5.23.0", "version": "5.25.3",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.23.0.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.25.3.tgz",
"integrity": "sha512-v0lL3NuKontiCxholEiAXCB+BYbndlKbwlDMK0DS86WgGELMJSpyqCSbJeMEMBDwOglnS7Ar2Rq0wwa/z2L8Vg==", "integrity": "sha512-J9rcZ/xVJonAoESqVGHHZhrNdVbrCfkdB41BP6eiwHMoFShD9it3yZXApVYMHdGfCshBsZCKsajwJeBbS/M1zg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.3.0", "@ampproject/remapping": "^2.3.0",

View File

@@ -56,7 +56,7 @@
"prettier-plugin-sort-json": "^4.1.1", "prettier-plugin-sort-json": "^4.1.1",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"rollup-plugin-visualizer": "^5.14.0", "rollup-plugin-visualizer": "^5.14.0",
"svelte": "^5.22.6", "svelte": "^5.25.3",
"svelte-check": "^4.1.5", "svelte-check": "^4.1.5",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"tslib": "^2.6.2", "tslib": "^2.6.2",

View File

@@ -1,6 +1,4 @@
<script lang="ts"> <script lang="ts">
import { press, tap } from 'svelte-gestures';
import Icon from '$lib/components/elements/icon.svelte'; import Icon from '$lib/components/elements/icon.svelte';
import { ProjectionType } from '$lib/constants'; import { ProjectionType } from '$lib/constants';
import { getAssetThumbnailUrl, isSharedLink } from '$lib/utils'; import { getAssetThumbnailUrl, isSharedLink } from '$lib/utils';
@@ -103,10 +101,8 @@
} }
onClick?.($state.snapshot(asset)); onClick?.($state.snapshot(asset));
}; };
const handleClick = (e: MouseEvent) => { const handleClick = (e: MouseEvent) => {
if (isTouchDevice) {
return;
}
if (e.ctrlKey || e.metaKey) { if (e.ctrlKey || e.metaKey) {
return; return;
} }
@@ -126,6 +122,25 @@
const onMouseLeave = () => { const onMouseLeave = () => {
mouseOver = false; mouseOver = false;
}; };
function longPress(element: HTMLElement, { onLongPress }: { onLongPress: () => void }) {
let timer: ReturnType<typeof setTimeout>;
const start = (event: TouchEvent) => {
timer = setTimeout(() => {
onLongPress();
event.preventDefault();
}, 350);
};
const end = () => clearTimeout(timer);
element.addEventListener('touchstart', start);
element.addEventListener('touchend', end);
return {
destroy: () => {
element.removeEventListener('touchstart', start);
element.removeEventListener('touchend', end);
},
};
}
</script> </script>
<div <div
@@ -146,9 +161,6 @@
></canvas> ></canvas>
{/if} {/if}
<!-- svelte queries for all links on afterNavigate, leading to performance problems in asset-grid which updates
the navigation url on scroll. Replace this with button for now. -->
<!-- as of iOS17, there is a preference for long press speed, which is not available for mobile web. <!-- as of iOS17, there is a preference for long press speed, which is not available for mobile web.
The defaults are as follows: The defaults are as follows:
fast: 200ms fast: 200ms
@@ -163,10 +175,7 @@
class:cursor-pointer={!disabled} class:cursor-pointer={!disabled}
onmouseenter={onMouseEnter} onmouseenter={onMouseEnter}
onmouseleave={onMouseLeave} onmouseleave={onMouseLeave}
use:press={() => ({ timeframe: 350, triggerBeforeFinished: true })} use:longPress={{ onLongPress: () => onSelect?.($state.snapshot(asset)) }}
use:tap={() => ({ timeframe: 350 })}
onpress={(evt) => (evt.detail.pointerType === 'mouse' ? void 0 : onSelect?.($state.snapshot(asset)))}
ontap={(evt) => (evt.detail.pointerType === 'mouse' ? void 0 : callClickHandlers())}
onkeydown={(evt) => { onkeydown={(evt) => {
if (evt.key === 'Enter') { if (evt.key === 'Enter') {
callClickHandlers(); callClickHandlers();

View File

@@ -394,7 +394,7 @@
} }
}); });
let album = $state(data.album); let album = $derived(data.album);
let albumId = $derived(album.id); let albumId = $derived(album.id);
$effect(() => { $effect(() => {
@@ -404,6 +404,7 @@
}); });
let assetStore = new AssetStore(); let assetStore = new AssetStore();
$effect(() => { $effect(() => {
if (viewMode === AlbumPageViewMode.VIEW) { if (viewMode === AlbumPageViewMode.VIEW) {
void assetStore.updateOptions({ albumId, order: albumOrder }); void assetStore.updateOptions({ albumId, order: albumOrder });