mirror of
https://github.com/zadam/trilium.git
synced 2026-05-06 19:06:35 +02:00
feat(standalone): get enex import to work
This commit is contained in:
@@ -5,7 +5,7 @@ type ImportRequest<P> = Omit<Request<P>, "file"> & { file?: File };
|
||||
|
||||
import becca from "../../becca/becca.js";
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
// import enexImportService from "../../services/import/enex.js";
|
||||
import enexImportService from "../../services/import/enex.js";
|
||||
import opmlImportService from "../../services/import/opml.js";
|
||||
import singleImportService from "../../services/import/single.js";
|
||||
import zipImportService from "../../services/import/zip.js";
|
||||
@@ -62,18 +62,18 @@ async function importNotesToBranch(req: ImportRequest<{ parentNoteId: string }>)
|
||||
return importResult;
|
||||
}
|
||||
} else if (extension === ".enex" && options.explodeArchives) {
|
||||
throw "ENEX import is currently not supported. Please use the desktop app to import ENEX files and then sync with the server.";
|
||||
// const importResult = await enexImportService.importEnex(taskContext, file, parentNote);
|
||||
// if (!Array.isArray(importResult)) {
|
||||
// note = importResult;
|
||||
// } else {
|
||||
// return importResult;
|
||||
// }
|
||||
const importResult = await enexImportService.importEnex(taskContext, file, parentNote);
|
||||
if (!Array.isArray(importResult)) {
|
||||
note = importResult;
|
||||
} else {
|
||||
return importResult;
|
||||
}
|
||||
} else {
|
||||
note = singleImportService.importSingleFile(taskContext, file, parentNote);
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||
console.warn(e);
|
||||
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
||||
taskContext.reportError(message);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { AttributeType } from "@triliumnext/commons";
|
||||
import { dayjs } from "@triliumnext/commons";
|
||||
import sax from "sax";
|
||||
import stream from "stream";
|
||||
import { Throttle } from "stream-throttle";
|
||||
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
import date_utils from "../utils/date.js";
|
||||
@@ -59,8 +57,8 @@ interface Note {
|
||||
let note: Partial<Note> = {};
|
||||
let resource: Resource;
|
||||
|
||||
function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote): Promise<BNote> {
|
||||
const saxStream = sax.createStream(true);
|
||||
function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote): BNote {
|
||||
const parser = sax.parser(true);
|
||||
|
||||
const rootNoteTitle = file.originalname.toLowerCase().endsWith(".enex") ? file.originalname.substr(0, file.originalname.length - 5) : file.originalname;
|
||||
|
||||
@@ -138,15 +136,14 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
}
|
||||
}
|
||||
|
||||
saxStream.on("error", (e) => {
|
||||
// unhandled errors will throw, since this is a proper node event emitter.
|
||||
parser.onerror = (e) => {
|
||||
getLog().error(`error when parsing ENEX file: ${e}`);
|
||||
// clear the error
|
||||
(saxStream._parser as any).error = null;
|
||||
saxStream._parser.resume();
|
||||
});
|
||||
// clear the error and resume
|
||||
parser.error = null;
|
||||
parser.resume();
|
||||
};
|
||||
|
||||
saxStream.on("text", (text) => {
|
||||
parser.ontext = (text) => {
|
||||
const currentTag = getCurrentTag();
|
||||
const previousTag = getPreviousTag();
|
||||
|
||||
@@ -209,13 +206,9 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
}
|
||||
// unknown tags are just ignored
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
saxStream.on("attribute", (attr) => {
|
||||
// an attribute. attr has "name" and "value"
|
||||
});
|
||||
|
||||
saxStream.on("opentag", (tag) => {
|
||||
parser.onopentag = (tag) => {
|
||||
path.push(tag.name);
|
||||
|
||||
if (tag.name === "note") {
|
||||
@@ -235,7 +228,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
note.resources.push(resource);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const sql = getSql();
|
||||
|
||||
@@ -381,38 +374,22 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
updateDates(noteEntity, utcDateCreated, utcDateModified);
|
||||
}
|
||||
|
||||
saxStream.on("closetag", (tag) => {
|
||||
parser.onclosetag = (tag) => {
|
||||
path.pop();
|
||||
|
||||
if (tag === "note") {
|
||||
saveNote();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
saxStream.on("opencdata", () => {
|
||||
//console.log("opencdata");
|
||||
});
|
||||
|
||||
saxStream.on("cdata", (text) => {
|
||||
parser.oncdata = (text) => {
|
||||
note.content += text;
|
||||
});
|
||||
};
|
||||
|
||||
saxStream.on("closecdata", () => {
|
||||
//console.log("closecdata");
|
||||
});
|
||||
const content = typeof file.buffer === "string" ? file.buffer : new TextDecoder().decode(file.buffer);
|
||||
parser.write(content).close();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// resolve only when we parse the whole document AND saving of all notes have been finished
|
||||
saxStream.on("end", () => resolve(rootNote));
|
||||
|
||||
const bufferStream = new stream.PassThrough();
|
||||
bufferStream.end(file.buffer);
|
||||
|
||||
bufferStream
|
||||
// rate limiting to improve responsiveness during / after import
|
||||
.pipe(new Throttle({ rate: 500000 }))
|
||||
.pipe(saxStream);
|
||||
});
|
||||
return rootNote;
|
||||
}
|
||||
|
||||
function formatDateTimeToLocalDbFormat(
|
||||
|
||||
@@ -199,7 +199,15 @@ export function randomSecureToken(bytes = 32) {
|
||||
}
|
||||
|
||||
export function safeExtractMessageAndStackFromError(err: unknown): [errMessage: string, errStack: string | undefined] {
|
||||
return (err instanceof Error) ? [err.message, err.stack] as const : ["Unknown Error", undefined] as const;
|
||||
if (err instanceof Error) {
|
||||
return [err.message, err.stack] as const;
|
||||
}
|
||||
|
||||
if (typeof err === "string") {
|
||||
return [err, undefined] as const;
|
||||
}
|
||||
|
||||
return ["Unknown Error", undefined] as const;
|
||||
}
|
||||
|
||||
export function isEmptyOrWhitespace(str: string | null | undefined) {
|
||||
|
||||
Reference in New Issue
Block a user