2023-06-02 15:55:08 +02:00
|
|
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
2023-07-17 18:22:29 +02:00
|
|
|
import { addAssetsToAlbum } from '$lib/utils/asset-utils';
|
2023-08-15 03:22:33 +02:00
|
|
|
import { api, AssetFileUploadResponseDto } from '@api';
|
2023-06-02 15:55:08 +02:00
|
|
|
import axios from 'axios';
|
2023-07-01 06:50:47 +02:00
|
|
|
import { notificationController, NotificationType } from './../components/shared-components/notification/notification';
|
2022-07-27 03:53:25 +02:00
|
|
|
|
2023-08-15 03:22:33 +02:00
|
|
|
let _extensions: string[];
|
|
|
|
|
|
|
|
const getExtensions = async () => {
|
|
|
|
if (!_extensions) {
|
|
|
|
const { data } = await api.serverInfoApi.getSupportedMediaTypes();
|
|
|
|
_extensions = [...data.image, ...data.video];
|
|
|
|
}
|
|
|
|
return _extensions;
|
|
|
|
};
|
2023-07-12 05:56:30 +02:00
|
|
|
|
2023-08-25 06:03:28 +02:00
|
|
|
export const openFileUploadDialog = async (albumId: string | undefined = undefined) => {
|
2023-08-15 03:22:33 +02:00
|
|
|
const extensions = await getExtensions();
|
|
|
|
|
2023-07-01 06:50:47 +02:00
|
|
|
return new Promise<(string | undefined)[]>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
const fileSelector = document.createElement('input');
|
|
|
|
|
|
|
|
fileSelector.type = 'file';
|
|
|
|
fileSelector.multiple = true;
|
2023-07-12 05:56:30 +02:00
|
|
|
fileSelector.accept = extensions.join(',');
|
2023-07-01 06:50:47 +02:00
|
|
|
fileSelector.onchange = async (e: Event) => {
|
|
|
|
const target = e.target as HTMLInputElement;
|
|
|
|
if (!target.files) {
|
|
|
|
return;
|
|
|
|
}
|
2023-07-17 18:22:29 +02:00
|
|
|
const files = Array.from(target.files);
|
2023-07-01 06:50:47 +02:00
|
|
|
|
2023-08-25 06:03:28 +02:00
|
|
|
resolve(fileUploadHandler(files, albumId));
|
2023-07-01 06:50:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fileSelector.click();
|
|
|
|
} catch (e) {
|
|
|
|
console.log('Error selecting file', e);
|
|
|
|
reject(e);
|
|
|
|
}
|
|
|
|
});
|
2022-07-27 03:53:25 +02:00
|
|
|
};
|
|
|
|
|
2023-08-25 06:03:28 +02:00
|
|
|
export const fileUploadHandler = async (files: File[], albumId: string | undefined = undefined) => {
|
2023-08-15 03:22:33 +02:00
|
|
|
const extensions = await getExtensions();
|
2023-07-17 18:22:29 +02:00
|
|
|
const iterable = {
|
2023-07-22 05:52:28 +02:00
|
|
|
files: files.filter((file) => extensions.some((ext) => file.name.toLowerCase().endsWith(ext)))[Symbol.iterator](),
|
2023-07-17 18:22:29 +02:00
|
|
|
|
|
|
|
async *[Symbol.asyncIterator]() {
|
|
|
|
for (const file of this.files) {
|
2023-08-25 06:03:28 +02:00
|
|
|
yield fileUploader(file, albumId);
|
2023-07-17 18:22:29 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const concurrency = 2;
|
|
|
|
// TODO: use Array.fromAsync instead when it's available universally.
|
|
|
|
return Promise.all([...Array(concurrency)].map(() => fromAsync(iterable))).then((res) => res.flat());
|
|
|
|
};
|
|
|
|
|
|
|
|
// polyfill for Array.fromAsync.
|
|
|
|
//
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync
|
|
|
|
const fromAsync = async function <T>(iterable: AsyncIterable<T>) {
|
|
|
|
const result = [];
|
|
|
|
for await (const value of iterable) {
|
|
|
|
result.push(value);
|
|
|
|
}
|
|
|
|
return result;
|
2022-12-30 03:07:18 +01:00
|
|
|
};
|
|
|
|
|
2023-07-17 18:22:29 +02:00
|
|
|
// TODO: should probably use the @api SDK
|
2023-08-25 06:03:28 +02:00
|
|
|
async function fileUploader(asset: File, albumId: string | undefined = undefined): Promise<string | undefined> {
|
2023-07-01 06:50:47 +02:00
|
|
|
const formData = new FormData();
|
|
|
|
const fileCreatedAt = new Date(asset.lastModified).toISOString();
|
|
|
|
const deviceAssetId = 'web' + '-' + asset.name + '-' + asset.lastModified;
|
|
|
|
|
|
|
|
try {
|
|
|
|
formData.append('deviceAssetId', deviceAssetId);
|
|
|
|
formData.append('deviceId', 'WEB');
|
|
|
|
formData.append('fileCreatedAt', fileCreatedAt);
|
|
|
|
formData.append('fileModifiedAt', new Date(asset.lastModified).toISOString());
|
|
|
|
formData.append('isFavorite', 'false');
|
|
|
|
formData.append('duration', '0:00:00.000000');
|
2023-07-12 05:56:30 +02:00
|
|
|
formData.append('assetData', new File([asset], asset.name));
|
2023-07-01 06:50:47 +02:00
|
|
|
|
2023-07-12 05:56:30 +02:00
|
|
|
uploadAssetsStore.addNewUploadAsset({
|
2023-07-01 06:50:47 +02:00
|
|
|
id: deviceAssetId,
|
|
|
|
file: asset,
|
|
|
|
progress: 0,
|
2023-07-12 05:56:30 +02:00
|
|
|
});
|
2023-07-01 06:50:47 +02:00
|
|
|
|
2023-07-17 18:22:29 +02:00
|
|
|
const response = await axios.post('/api/asset/upload', formData, {
|
2023-08-25 06:03:28 +02:00
|
|
|
params: { key: api.getKey() },
|
2023-07-01 06:50:47 +02:00
|
|
|
onUploadProgress: (event) => {
|
|
|
|
const percentComplete = Math.floor((event.loaded / event.total) * 100);
|
|
|
|
uploadAssetsStore.updateProgress(deviceAssetId, percentComplete);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
if (response.status == 200 || response.status == 201) {
|
|
|
|
const res: AssetFileUploadResponseDto = response.data;
|
|
|
|
|
2023-08-10 03:11:26 +02:00
|
|
|
if (res.duplicate) {
|
|
|
|
uploadAssetsStore.duplicateCounter.update((count) => count + 1);
|
|
|
|
}
|
|
|
|
|
2023-07-01 06:50:47 +02:00
|
|
|
if (albumId && res.id) {
|
2023-08-25 06:03:28 +02:00
|
|
|
await addAssetsToAlbum(albumId, [res.id]);
|
2023-07-01 06:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
uploadAssetsStore.removeUploadAsset(deviceAssetId);
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.log('error uploading file ', e);
|
|
|
|
handleUploadError(asset, JSON.stringify(e));
|
|
|
|
uploadAssetsStore.removeUploadAsset(deviceAssetId);
|
|
|
|
}
|
2022-06-19 15:16:35 +02:00
|
|
|
}
|
2022-12-30 03:07:18 +01:00
|
|
|
|
|
|
|
function handleUploadError(asset: File, respBody = '{}', extraMessage?: string) {
|
2023-08-10 15:38:29 +02:00
|
|
|
uploadAssetsStore.errorCounter.update((count) => count + 1);
|
|
|
|
|
2023-07-01 06:50:47 +02:00
|
|
|
try {
|
|
|
|
const res = JSON.parse(respBody);
|
|
|
|
|
|
|
|
const extraMsg = res ? ' ' + res?.message : '';
|
|
|
|
|
|
|
|
notificationController.show({
|
|
|
|
type: NotificationType.Error,
|
|
|
|
message: `Cannot upload file ${asset.name} ${extraMsg}${extraMessage}`,
|
|
|
|
timeout: 5000,
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
console.error('ERROR parsing data JSON in handleUploadError');
|
|
|
|
}
|
2022-08-31 15:12:31 +02:00
|
|
|
}
|