2021-07-05 10:25:42 +00:00
|
|
|
import { retryPromise, runningInBrowser } from 'utils/common';
|
2021-06-12 17:14:21 +00:00
|
|
|
import { logError } from 'utils/sentry';
|
2021-05-30 16:56:48 +00:00
|
|
|
import { Collection } from './collectionService';
|
2021-03-29 05:15:08 +00:00
|
|
|
import downloadManager from './downloadManager';
|
2021-05-30 16:56:48 +00:00
|
|
|
import { File } from './fileService';
|
2021-03-29 05:15:08 +00:00
|
|
|
|
2021-03-30 11:37:32 +00:00
|
|
|
enum ExportNotification {
|
|
|
|
START = 'export started',
|
2021-03-31 07:13:01 +00:00
|
|
|
IN_PROGRESS = 'export already in progress',
|
2021-03-30 11:37:32 +00:00
|
|
|
FINISH = 'export finished',
|
2021-03-31 08:34:00 +00:00
|
|
|
ABORT = 'export aborted',
|
2021-03-30 11:37:32 +00:00
|
|
|
}
|
2021-03-29 05:15:08 +00:00
|
|
|
class ExportService {
|
2021-05-29 06:31:00 +00:00
|
|
|
ElectronAPIs: any = runningInBrowser() && window['ElectronAPIs'];
|
2021-05-29 06:27:52 +00:00
|
|
|
|
2021-03-31 07:13:01 +00:00
|
|
|
exportInProgress: Promise<void> = null;
|
2021-05-29 06:27:52 +00:00
|
|
|
|
2021-03-31 08:34:00 +00:00
|
|
|
abortExport: boolean = false;
|
2021-03-31 07:13:01 +00:00
|
|
|
|
2021-04-27 09:17:38 +00:00
|
|
|
async exportFiles(files: File[], collections: Collection[]) {
|
2021-03-31 07:13:01 +00:00
|
|
|
if (this.exportInProgress) {
|
|
|
|
this.ElectronAPIs.sendNotification(ExportNotification.IN_PROGRESS);
|
|
|
|
return this.exportInProgress;
|
|
|
|
}
|
|
|
|
this.exportInProgress = this.fileExporter(files, collections);
|
|
|
|
return this.exportInProgress;
|
|
|
|
}
|
2021-05-29 06:27:52 +00:00
|
|
|
|
2021-04-27 09:17:38 +00:00
|
|
|
async fileExporter(files: File[], collections: Collection[]) {
|
2021-03-30 13:00:09 +00:00
|
|
|
try {
|
2021-03-31 05:53:21 +00:00
|
|
|
const dir = await this.ElectronAPIs.selectRootDirectory();
|
2021-03-30 13:00:09 +00:00
|
|
|
if (!dir) {
|
|
|
|
// directory selector closed
|
|
|
|
return;
|
2021-03-29 12:45:54 +00:00
|
|
|
}
|
2021-03-30 13:00:09 +00:00
|
|
|
const exportedFiles: Set<string> = await this.ElectronAPIs.getExportedFiles(
|
2021-05-29 06:27:52 +00:00
|
|
|
dir,
|
2021-03-30 13:00:09 +00:00
|
|
|
);
|
2021-05-29 06:27:52 +00:00
|
|
|
this.ElectronAPIs.showOnTray('starting export');
|
2021-03-31 08:34:00 +00:00
|
|
|
this.ElectronAPIs.registerStopExportListener(
|
2021-05-29 06:27:52 +00:00
|
|
|
() => (this.abortExport = true),
|
2021-03-31 08:34:00 +00:00
|
|
|
);
|
2021-03-31 05:53:21 +00:00
|
|
|
const collectionIDMap = new Map<number, string>();
|
2021-05-29 06:27:52 +00:00
|
|
|
for (const collection of collections) {
|
2021-06-07 05:04:50 +00:00
|
|
|
const collectionFolderPath = `${dir}/${collection.id}_${this.sanitizeName(collection.name)}`;
|
2021-03-31 05:53:21 +00:00
|
|
|
await this.ElectronAPIs.checkExistsAndCreateCollectionDir(
|
2021-05-29 06:27:52 +00:00
|
|
|
collectionFolderPath,
|
2021-03-31 05:53:21 +00:00
|
|
|
);
|
|
|
|
collectionIDMap.set(collection.id, collectionFolderPath);
|
|
|
|
}
|
2021-03-30 13:00:09 +00:00
|
|
|
this.ElectronAPIs.sendNotification(ExportNotification.START);
|
2021-05-29 06:27:52 +00:00
|
|
|
for (const [index, file] of files.entries()) {
|
2021-03-31 08:34:00 +00:00
|
|
|
if (this.abortExport) {
|
|
|
|
break;
|
|
|
|
}
|
2021-04-04 08:34:42 +00:00
|
|
|
const uid = `${file.id}_${this.sanitizeName(
|
2021-05-29 06:27:52 +00:00
|
|
|
file.metadata.title,
|
2021-03-31 05:53:21 +00:00
|
|
|
)}`;
|
2021-05-29 06:27:52 +00:00
|
|
|
const filePath = `${collectionIDMap.get(file.collectionID)}/${uid}`;
|
2021-03-31 05:53:21 +00:00
|
|
|
if (!exportedFiles.has(filePath)) {
|
|
|
|
await this.downloadAndSave(file, filePath);
|
|
|
|
this.ElectronAPIs.updateExportRecord(dir, filePath);
|
2021-03-30 13:00:09 +00:00
|
|
|
}
|
2021-03-31 08:34:00 +00:00
|
|
|
this.ElectronAPIs.showOnTray(
|
2021-05-29 06:27:52 +00:00
|
|
|
`exporting file ${index + 1} / ${files.length}`,
|
2021-03-31 08:34:00 +00:00
|
|
|
);
|
2021-03-30 13:00:09 +00:00
|
|
|
}
|
2021-03-31 08:34:00 +00:00
|
|
|
this.ElectronAPIs.sendNotification(
|
2021-05-29 06:27:52 +00:00
|
|
|
this.abortExport ?
|
|
|
|
ExportNotification.ABORT :
|
|
|
|
ExportNotification.FINISH,
|
2021-03-31 08:34:00 +00:00
|
|
|
);
|
2021-03-30 13:00:09 +00:00
|
|
|
} catch (e) {
|
2021-06-12 17:14:21 +00:00
|
|
|
logError(e);
|
2021-03-31 08:34:00 +00:00
|
|
|
} finally {
|
|
|
|
this.exportInProgress = null;
|
|
|
|
this.ElectronAPIs.showOnTray();
|
|
|
|
this.abortExport = false;
|
2021-03-29 05:15:08 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 11:29:19 +00:00
|
|
|
|
2021-04-27 09:17:38 +00:00
|
|
|
async downloadAndSave(file: File, path) {
|
2021-07-05 10:25:42 +00:00
|
|
|
const fileStream = await retryPromise(downloadManager.downloadFile(file));
|
2021-03-31 06:45:41 +00:00
|
|
|
this.ElectronAPIs.saveStreamToDisk(path, fileStream);
|
|
|
|
this.ElectronAPIs.saveFileToDisk(
|
|
|
|
`${path}.json`,
|
2021-05-29 06:27:52 +00:00
|
|
|
JSON.stringify(file.metadata, null, 2),
|
2021-03-31 06:45:41 +00:00
|
|
|
);
|
2021-03-29 11:29:19 +00:00
|
|
|
}
|
2021-05-29 06:27:52 +00:00
|
|
|
|
2021-04-04 08:23:00 +00:00
|
|
|
private sanitizeName(name) {
|
2021-03-31 05:53:21 +00:00
|
|
|
return name.replaceAll('/', '_').replaceAll(' ', '_');
|
|
|
|
}
|
2021-03-29 05:15:08 +00:00
|
|
|
}
|
|
|
|
export default new ExportService();
|