You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-06-16 03:40:33 +02:00
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:
113
web/src/lib/utils/file-uploader.ts
Normal file
113
web/src/lib/utils/file-uploader.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import * as exifr from 'exifr';
|
||||
import { serverEndpoint } from '../constants';
|
||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||
import type { UploadAsset } from '../models/upload-asset';
|
||||
|
||||
export async function fileUploader(asset: File, accessToken: string) {
|
||||
const assetType = asset.type.split('/')[0].toUpperCase();
|
||||
const temp = asset.name.split('.');
|
||||
const fileExtension = temp[temp.length - 1];
|
||||
const formData = new FormData();
|
||||
|
||||
try {
|
||||
let exifData = null;
|
||||
|
||||
if (assetType !== 'VIDEO') {
|
||||
exifData = await exifr.parse(asset);
|
||||
}
|
||||
|
||||
const createdAt =
|
||||
exifData && exifData.DateTimeOriginal != null
|
||||
? new Date(exifData.DateTimeOriginal).toISOString()
|
||||
: new Date(asset.lastModified).toISOString();
|
||||
|
||||
const deviceAssetId = 'web' + '-' + asset.name + '-' + asset.lastModified;
|
||||
|
||||
// Create and add Unique ID of asset on the device
|
||||
formData.append('deviceAssetId', deviceAssetId);
|
||||
|
||||
// Get device id - for web -> use WEB
|
||||
formData.append('deviceId', 'WEB');
|
||||
|
||||
// Get asset type
|
||||
formData.append('assetType', assetType);
|
||||
|
||||
// Get Asset Created Date
|
||||
formData.append('createdAt', createdAt);
|
||||
|
||||
// Get Asset Modified At
|
||||
formData.append('modifiedAt', new Date(asset.lastModified).toISOString());
|
||||
|
||||
// Set Asset is Favorite to false
|
||||
formData.append('isFavorite', 'false');
|
||||
|
||||
// Get asset duration
|
||||
formData.append('duration', '0:00:00.000000');
|
||||
|
||||
// Get asset file extension
|
||||
formData.append('fileExtension', '.' + fileExtension);
|
||||
|
||||
// Get asset binary data.
|
||||
formData.append('assetData', asset);
|
||||
|
||||
// Check if asset upload on server before performing upload
|
||||
const res = await fetch(serverEndpoint + '/asset/check', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ deviceAssetId }),
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + accessToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
const { isExist } = await res.json();
|
||||
|
||||
if (isExist) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const request = new XMLHttpRequest();
|
||||
|
||||
request.upload.onloadstart = () => {
|
||||
const newUploadAsset: UploadAsset = {
|
||||
id: deviceAssetId,
|
||||
file: asset,
|
||||
progress: 0,
|
||||
fileExtension: fileExtension,
|
||||
};
|
||||
|
||||
uploadAssetsStore.addNewUploadAsset(newUploadAsset);
|
||||
};
|
||||
|
||||
request.upload.onload = () => {
|
||||
setTimeout(() => {
|
||||
uploadAssetsStore.removeUploadAsset(deviceAssetId);
|
||||
}, 2500);
|
||||
};
|
||||
|
||||
// listen for `error` event
|
||||
request.upload.onerror = () => {
|
||||
uploadAssetsStore.removeUploadAsset(deviceAssetId);
|
||||
};
|
||||
|
||||
// listen for `abort` event
|
||||
request.upload.onabort = () => {
|
||||
uploadAssetsStore.removeUploadAsset(deviceAssetId);
|
||||
};
|
||||
|
||||
// listen for `progress` event
|
||||
request.upload.onprogress = (event) => {
|
||||
const percentComplete = Math.floor((event.loaded / event.total) * 100);
|
||||
uploadAssetsStore.updateProgress(deviceAssetId, percentComplete);
|
||||
};
|
||||
|
||||
request.open('POST', `${serverEndpoint}/asset/upload`);
|
||||
request.setRequestHeader('Authorization', `Bearer ${accessToken}`);
|
||||
|
||||
request.send(formData);
|
||||
} catch (e) {
|
||||
console.log('error uploading file ', e);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user