Feature - Add upload functionality on Web (#231)

* Added file selector

* Extract metadata to upload files to the web

* Added request for uploading

* Generate jpeg/Webp thumbnail for asset uploaded without thumbnail data

* Added generating thumbnail for video and WebSocket broadcast after thumbnail is generated

* Added video length extraction

* Added Uploading Panel

* Added upload progress store and styling the uploaded asset

* Added condition to only show upload panel when there is upload in progress

* Remove asset from the upload list after successfully uploading

* Added WebSocket to listen to upload event on the web

* Added mechanism to check for existing assets before uploading on the web

* Added test workflow

* Update readme
This commit is contained in:
Alex
2022-06-19 08:16:35 -05:00
committed by GitHub
parent b7603fd150
commit 1e3464fe47
33 changed files with 859 additions and 220 deletions

View File

@@ -1,33 +1,29 @@
import { writable, derived } from 'svelte/store';
import { getRequest } from '$lib/api';
import type { ImmichAsset } from '$lib/models/immich-asset'
import type { ImmichAsset } from '$lib/models/immich-asset';
import lodash from 'lodash-es';
import moment from 'moment';
export const assets = writable<ImmichAsset[]>([]);
export const assetsGroupByDate = derived(assets, ($assets) => {
try {
return lodash.chain($assets)
.groupBy((a) => moment(a.createdAt).format('ddd, MMM DD'))
.sortBy((group) => $assets.indexOf(group[0]))
.value();
} catch (e) {
console.log("error deriving state assets", e)
return []
}
})
try {
return lodash
.chain($assets)
.groupBy((a) => moment(a.createdAt).format('ddd, MMM DD'))
.sortBy((group) => $assets.indexOf(group[0]))
.value();
} catch (e) {
console.log('error deriving state assets', e);
return [];
}
});
export const flattenAssetGroupByDate = derived(assetsGroupByDate, ($assetsGroupByDate) => {
return $assetsGroupByDate.flat();
})
return $assetsGroupByDate.flat();
});
export const getAssetsInfo = async (accessToken: string) => {
const res = await getRequest('asset', accessToken);
assets.set(res);
}
const res = await getRequest('asset', accessToken);
assets.set(res);
};

View File

@@ -0,0 +1,45 @@
import { writable, derived } from 'svelte/store';
import type { UploadAsset } from '../models/upload-asset';
function createUploadStore() {
const uploadAssets = writable<Array<UploadAsset>>([]);
const { subscribe } = uploadAssets;
const isUploading = derived(uploadAssets, ($uploadAssets) => {
return $uploadAssets.length > 0 ? true : false;
});
const addNewUploadAsset = (newAsset: UploadAsset) => {
uploadAssets.update((currentSet) => [...currentSet, newAsset]);
};
const updateProgress = (id: string, progress: number) => {
uploadAssets.update((uploadingAssets) => {
return uploadingAssets.map((asset) => {
if (asset.id == id) {
return {
...asset,
progress: progress,
};
}
return asset;
});
});
};
const removeUploadAsset = (id: string) => {
uploadAssets.update((uploadingAsset) => uploadingAsset.filter((a) => a.id != id));
};
return {
subscribe,
isUploading,
addNewUploadAsset,
updateProgress,
removeUploadAsset,
};
}
export const uploadAssetsStore = createUploadStore();

View File

@@ -0,0 +1,30 @@
import { Socket, io } from 'socket.io-client';
import { serverEndpoint } from '../constants';
import type { ImmichAsset } from '../models/immich-asset';
import { assets } from './assets';
export const openWebsocketConnection = (accessToken: string) => {
const websocket = io(serverEndpoint, {
transports: ['polling'],
reconnection: true,
forceNew: true,
autoConnect: true,
extraHeaders: {
Authorization: 'Bearer ' + accessToken,
},
});
listenToEvent(websocket);
};
const listenToEvent = (socket: Socket) => {
socket.on('on_upload_success', (data) => {
const newUploadedAsset: ImmichAsset = JSON.parse(data);
assets.update((assets) => [...assets, newUploadedAsset]);
});
socket.on('error', (e) => {
console.log('Websocket Error', e);
});
};