mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-02 19:55:18 +02:00
feat: enhance Immich integration with local copy option and validation for image handling
This commit is contained in:
parent
f95afdc35c
commit
06787bccf6
12 changed files with 214 additions and 37 deletions
|
@ -22,7 +22,7 @@
|
|||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let images: { id: string; image: string; is_primary: boolean }[] = [];
|
||||
let images: { id: string; image: string; is_primary: boolean; immich_id: string | null }[] = [];
|
||||
let warningMessage: string = '';
|
||||
let constrainDates: boolean = false;
|
||||
|
||||
|
@ -82,6 +82,7 @@
|
|||
|
||||
let fileInput: HTMLInputElement;
|
||||
let immichIntegration: boolean = false;
|
||||
let copyImmichLocally: boolean = false;
|
||||
|
||||
import ActivityComplete from './ActivityComplete.svelte';
|
||||
import CategoryDropdown from './CategoryDropdown.svelte';
|
||||
|
@ -161,13 +162,19 @@
|
|||
addToast('error', $t('adventures.category_fetch_error'));
|
||||
}
|
||||
// Check for Immich Integration
|
||||
let res = await fetch('/api/integrations');
|
||||
if (!res.ok) {
|
||||
let res = await fetch('/api/integrations/immich/');
|
||||
// If the response is not ok, we assume Immich integration is not available
|
||||
if (!res.ok && res.status !== 404) {
|
||||
addToast('error', $t('immich.integration_fetch_error'));
|
||||
} else {
|
||||
let data = await res.json();
|
||||
if (data.immich) {
|
||||
if (data.error) {
|
||||
immichIntegration = false;
|
||||
} else if (data.id) {
|
||||
immichIntegration = true;
|
||||
copyImmichLocally = data.copy_locally || false;
|
||||
} else {
|
||||
immichIntegration = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -330,7 +337,12 @@
|
|||
});
|
||||
if (res.ok) {
|
||||
let newData = deserialize(await res.text()) as { data: { id: string; image: string } };
|
||||
let newImage = { id: newData.data.id, image: newData.data.image, is_primary: false };
|
||||
let newImage = {
|
||||
id: newData.data.id,
|
||||
image: newData.data.image,
|
||||
is_primary: false,
|
||||
immich_id: null
|
||||
};
|
||||
images = [...images, newImage];
|
||||
adventure.images = images;
|
||||
addToast('success', $t('adventures.image_upload_success'));
|
||||
|
@ -381,7 +393,12 @@
|
|||
});
|
||||
if (res2.ok) {
|
||||
let newData = deserialize(await res2.text()) as { data: { id: string; image: string } };
|
||||
let newImage = { id: newData.data.id, image: newData.data.image, is_primary: false };
|
||||
let newImage = {
|
||||
id: newData.data.id,
|
||||
image: newData.data.image,
|
||||
is_primary: false,
|
||||
immich_id: null
|
||||
};
|
||||
images = [...images, newImage];
|
||||
adventure.images = images;
|
||||
addToast('success', $t('adventures.image_upload_success'));
|
||||
|
@ -817,6 +834,18 @@
|
|||
url = e.detail;
|
||||
fetchImage();
|
||||
}}
|
||||
{copyImmichLocally}
|
||||
on:remoteImmichSaved={(e) => {
|
||||
const newImage = {
|
||||
id: e.detail.id,
|
||||
image: e.detail.image,
|
||||
is_primary: e.detail.is_primary,
|
||||
immich_id: e.detail.immich_id
|
||||
};
|
||||
images = [...images, newImage];
|
||||
adventure.images = images;
|
||||
addToast('success', $t('adventures.image_upload_success'));
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
let loading = false;
|
||||
|
||||
export let adventure: Adventure | null = null;
|
||||
export let copyImmichLocally: boolean = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
|
@ -45,6 +46,36 @@
|
|||
return fetchAssets(immichNextURL, true);
|
||||
}
|
||||
|
||||
async function saveImmichRemoteUrl(imageId: string) {
|
||||
if (!adventure) {
|
||||
console.error('No adventure provided to save the image URL');
|
||||
return;
|
||||
}
|
||||
let res = await fetch('/api/images', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
immich_id: imageId,
|
||||
adventure: adventure.id
|
||||
})
|
||||
});
|
||||
if (res.ok) {
|
||||
let data = await res.json();
|
||||
if (!data.image) {
|
||||
console.error('No image data returned from the server');
|
||||
immichError = $t('immich.error_saving_image');
|
||||
return;
|
||||
}
|
||||
dispatch('remoteImmichSaved', data);
|
||||
} else {
|
||||
let errorData = await res.json();
|
||||
console.error('Error saving image URL:', errorData);
|
||||
immichError = $t(errorData.message || 'immich.error_saving_image');
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAssets(url: string, usingNext = false) {
|
||||
loading = true;
|
||||
try {
|
||||
|
@ -191,7 +222,11 @@
|
|||
on:click={() => {
|
||||
let currentDomain = window.location.origin;
|
||||
let fullUrl = `${currentDomain}/immich/${image.id}`;
|
||||
dispatch('fetchImage', fullUrl);
|
||||
if (copyImmichLocally) {
|
||||
dispatch('fetchImage', fullUrl);
|
||||
} else {
|
||||
saveImmichRemoteUrl(image.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{$t('adventures.upload_image')}
|
||||
|
|
|
@ -27,6 +27,7 @@ export type Adventure = {
|
|||
id: string;
|
||||
image: string;
|
||||
is_primary: boolean;
|
||||
immich_id: string | null;
|
||||
}[];
|
||||
visits: {
|
||||
id: string;
|
||||
|
@ -242,6 +243,7 @@ export type ImmichIntegration = {
|
|||
id: string;
|
||||
server_url: string;
|
||||
api_key: string;
|
||||
copy_locally: boolean;
|
||||
};
|
||||
|
||||
export type ImmichAlbum = {
|
||||
|
|
|
@ -699,7 +699,10 @@
|
|||
"localhost_note": "Note: localhost will most likely not work unless you have setup docker networks accordingly. It is recommended to use the IP address of the server or the domain name.",
|
||||
"documentation": "Immich Integration Documentation",
|
||||
"api_key_placeholder": "Enter your Immich API key",
|
||||
"need_help": "Need help setting this up? Check out the"
|
||||
"need_help": "Need help setting this up? Check out the",
|
||||
"copy_locally": "Copy Images Locally",
|
||||
"copy_locally_desc": "Copy images to the server for offline access. Uses more disk space.",
|
||||
"error_saving_image": "Error saving image"
|
||||
},
|
||||
"recomendations": {
|
||||
"address": "Address",
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
let newImmichIntegration: ImmichIntegration = {
|
||||
server_url: '',
|
||||
api_key: '',
|
||||
id: ''
|
||||
id: '',
|
||||
copy_locally: true
|
||||
};
|
||||
|
||||
let isMFAModalOpen: boolean = false;
|
||||
|
@ -833,6 +834,26 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<!-- Toggle for copy_locally -->
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer justify-start gap-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={newImmichIntegration.copy_locally}
|
||||
class="toggle toggle-primary"
|
||||
/>
|
||||
<div>
|
||||
<span class="label-text font-medium">
|
||||
{$t('immich.copy_locally') || 'Copy Locally'}
|
||||
</span>
|
||||
<p class="text-sm text-base-content/70">
|
||||
{$t('immich.copy_locally_desc') ||
|
||||
'If enabled, files will be copied locally.'}
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button on:click={enableImmichIntegration} class="btn btn-primary w-full">
|
||||
{!immichIntegration?.id
|
||||
? `🔗 ${$t('immich.enable_integration')}`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue