mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
OPML import support (issue #78)
This commit is contained in:
parent
f47ae12019
commit
be51e533fc
8
package-lock.json
generated
8
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.12.0",
|
||||
"version": "0.13.0-beta",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -13618,9 +13618,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz",
|
||||
"integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8="
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -59,7 +59,8 @@
|
||||
"sqlite": "^2.9.2",
|
||||
"tar-stream": "^1.6.1",
|
||||
"unescape": "^1.0.1",
|
||||
"ws": "^5.2.0"
|
||||
"ws": "^5.2.0",
|
||||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^2.0.1",
|
||||
|
@ -98,7 +98,7 @@ const contextMenuOptions = {
|
||||
{title: "Native Tar", cmd: "exportBranchToTar"},
|
||||
{title: "OPML", cmd: "exportBranchToOpml"}
|
||||
]},
|
||||
{title: "Import into branch", cmd: "importBranch", uiIcon: "ui-icon-arrowthick-1-sw"},
|
||||
{title: "Import into branch (tar, opml)", cmd: "importBranch", uiIcon: "ui-icon-arrowthick-1-sw"},
|
||||
{title: "----"},
|
||||
{title: "Collapse branch <kbd>Alt+-</kbd>", cmd: "collapseBranch", uiIcon: "ui-icon-minus"},
|
||||
{title: "Force note sync", cmd: "forceNoteSync", uiIcon: "ui-icon-refresh"},
|
||||
|
@ -29,7 +29,7 @@ $("#import-upload").change(async function() {
|
||||
type: 'POST',
|
||||
contentType: false, // NEEDED, DON'T OMIT THIS
|
||||
processData: false, // NEEDED, DON'T OMIT THIS
|
||||
});
|
||||
}).fail((xhr, status, error) => alert('Import error: ' + xhr.responseText));
|
||||
|
||||
await treeService.reload();
|
||||
});
|
||||
|
@ -7,6 +7,75 @@ const Branch = require('../../entities/branch');
|
||||
const tar = require('tar-stream');
|
||||
const stream = require('stream');
|
||||
const path = require('path');
|
||||
const parseString = require('xml2js').parseString;
|
||||
|
||||
async function importToBranch(req) {
|
||||
const parentNoteId = req.params.parentNoteId;
|
||||
const file = req.file;
|
||||
|
||||
const parentNote = await repository.getNote(parentNoteId);
|
||||
|
||||
if (!parentNote) {
|
||||
return [404, `Note ${parentNoteId} doesn't exist.`];
|
||||
}
|
||||
|
||||
const extension = path.extname(file.originalname).toLowerCase();
|
||||
|
||||
if (extension === '.tar') {
|
||||
await importTar(file, parentNoteId);
|
||||
}
|
||||
else if (extension === '.opml') {
|
||||
return await importOpml(file, parentNoteId);
|
||||
}
|
||||
else {
|
||||
return [400, `Unrecognized extension ${extension}, must be .tar or .opml`];
|
||||
}
|
||||
}
|
||||
|
||||
function toHtml(text) {
|
||||
return '<p>' + text.replace(/(?:\r\n|\r|\n)/g, '</p><p>') + '</p>';
|
||||
}
|
||||
|
||||
async function importOutline(outline, parentNoteId) {
|
||||
const {note} = await noteService.createNote(parentNoteId, outline.$.title, toHtml(outline.$.text));
|
||||
|
||||
for (const childOutline of (outline.outline || [])) {
|
||||
await importOutline(childOutline, note.noteId);
|
||||
}
|
||||
}
|
||||
|
||||
async function importOpml(file, parentNoteId) {
|
||||
const xml = await new Promise(function(resolve, reject)
|
||||
{
|
||||
parseString(file.buffer, function (err, result) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (xml.opml.$.version !== '1.0' && xml.opml.$.version !== '1.1') {
|
||||
return [400, 'Unsupported OPML version ' + xml.opml.$.version + ', 1.0 or 1.1 expected instead.'];
|
||||
}
|
||||
|
||||
const outlines = xml.opml.body[0].outline || [];
|
||||
|
||||
for (const outline of outlines) {
|
||||
await importOutline(outline, parentNoteId);
|
||||
}
|
||||
}
|
||||
|
||||
async function importTar(file, parentNoteId) {
|
||||
const files = await parseImportFile(file);
|
||||
|
||||
// maps from original noteId (in tar file) to newly generated noteId
|
||||
const noteIdMap = {};
|
||||
|
||||
await importNotes(files, parentNoteId, noteIdMap);
|
||||
}
|
||||
|
||||
function getFileName(name) {
|
||||
let key;
|
||||
@ -86,24 +155,6 @@ async function parseImportFile(file) {
|
||||
});
|
||||
}
|
||||
|
||||
async function importTar(req) {
|
||||
const parentNoteId = req.params.parentNoteId;
|
||||
const file = req.file;
|
||||
|
||||
const parentNote = await repository.getNote(parentNoteId);
|
||||
|
||||
if (!parentNote) {
|
||||
return [404, `Note ${parentNoteId} doesn't exist.`];
|
||||
}
|
||||
|
||||
const files = await parseImportFile(file);
|
||||
|
||||
// maps from original noteId (in tar file) to newly generated noteId
|
||||
const noteIdMap = {};
|
||||
|
||||
await importNotes(files, parentNoteId, noteIdMap);
|
||||
}
|
||||
|
||||
async function importNotes(files, parentNoteId, noteIdMap) {
|
||||
for (const file of files) {
|
||||
if (file.meta.version !== 1) {
|
||||
@ -143,5 +194,5 @@ async function importNotes(files, parentNoteId, noteIdMap) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
importTar
|
||||
importToBranch
|
||||
};
|
@ -123,7 +123,7 @@ function register(app) {
|
||||
apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter);
|
||||
|
||||
route(GET, '/api/notes/:noteId/export/:format', [auth.checkApiAuthOrElectron], exportRoute.exportNote);
|
||||
route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware], importRoute.importTar, apiResultHandler);
|
||||
route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware], importRoute.importToBranch, apiResultHandler);
|
||||
|
||||
route(POST, '/api/notes/:parentNoteId/upload', [auth.checkApiAuthOrElectron, uploadMiddleware],
|
||||
filesRoute.uploadFile, apiResultHandler);
|
||||
|
Loading…
x
Reference in New Issue
Block a user