mirror of
https://github.com/laurent22/joplin.git
synced 2026-06-18 20:16:34 +02:00
Import enex integration
This commit is contained in:
1 parent
96e77cbb56
commit
62cdc30fc2
5 files changed
+82
-26
No files matched your search
@@ -86,9 +86,10 @@ async function fuzzyMatch(note) {
|
||||
return null;
|
||||
}
|
||||
|
||||
async function saveNoteToStorage(note) {
|
||||
async function saveNoteToStorage(note, fuzzyMatching = false) {
|
||||
note = Note.filter(note);
|
||||
let existingNote = await fuzzyMatch(note);
|
||||
|
||||
let existingNote = fuzzyMatching ? await fuzzyMatch(note) : null;
|
||||
|
||||
if (existingNote) {
|
||||
let diff = BaseModel.diffObjects(existingNote, note);
|
||||
@@ -117,11 +118,7 @@ async function saveNoteToStorage(note) {
|
||||
// In that case, just skip it - it means two different notes might be linked to the
|
||||
// same resource.
|
||||
let existingResource = await Resource.load(toSave.id);
|
||||
if (existingResource) {
|
||||
// console.warn('Trying to save: ' + JSON.stringify(toSave));
|
||||
// console.warn('But duplicate: ' + JSON.stringify(existingResource));
|
||||
continue;
|
||||
}
|
||||
if (existingResource) continue;
|
||||
|
||||
await Resource.save(toSave, { isNew: true });
|
||||
await filePutContents(Resource.fullPath(toSave), resource.data);
|
||||
@@ -134,7 +131,10 @@ async function saveNoteToStorage(note) {
|
||||
}
|
||||
}
|
||||
|
||||
function importEnex(parentFolderId, filePath) {
|
||||
function importEnex(parentFolderId, filePath, importOptions = null) {
|
||||
if (!importOptions) importOptions = {};
|
||||
if (!('fuzzyMatching' in importOptions)) importOptions.fuzzyMatching = false;
|
||||
|
||||
let stream = fs.createReadStream(filePath);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -177,7 +177,7 @@ function importEnex(parentFolderId, filePath) {
|
||||
note.parent_id = parentFolderId;
|
||||
note.body = body;
|
||||
|
||||
return saveNoteToStorage(note);
|
||||
return saveNoteToStorage(note, importOptions.fuzzyMatching);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+68
-9
@@ -15,6 +15,7 @@ import { Logger } from 'lib/logger.js';
|
||||
import { uuid } from 'lib/uuid.js';
|
||||
import { sprintf } from 'sprintf-js';
|
||||
import { importEnex } from 'import-enex';
|
||||
import { filename, basename } from 'lib/path-utils.js';
|
||||
import { _ } from 'lib/locale.js';
|
||||
import os from 'os';
|
||||
import fs from 'fs-extra';
|
||||
@@ -179,11 +180,29 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
function commandError(commandInstance, msg, end) {
|
||||
function cmdError(commandInstance, msg, end) {
|
||||
commandInstance.log(msg);
|
||||
end();
|
||||
}
|
||||
|
||||
function cmdPromptConfirm(commandInstance, message) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let options = {
|
||||
type: 'confirm',
|
||||
name: 'ok',
|
||||
default: false, // This needs to be false so that, when pressing Ctrl+C, the prompt returns false
|
||||
message: message,
|
||||
};
|
||||
commandInstance.prompt(options, (result) => {
|
||||
if (result.ok) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
process.stdin.on('keypress', (_, key) => {
|
||||
if (key && key.name === 'return') {
|
||||
updatePrompt();
|
||||
@@ -240,7 +259,7 @@ async function main() {
|
||||
let folderTitle = args['notebook-title'];
|
||||
|
||||
let folder = await Folder.loadByField('title', folderTitle);
|
||||
if (!folder) return commandError(this, _('Invalid folder title: %s', folderTitle), end);
|
||||
if (!folder) return cmdError(this, _('Invalid folder title: %s', folderTitle), end);
|
||||
switchCurrentFolder(folder);
|
||||
end();
|
||||
},
|
||||
@@ -335,7 +354,7 @@ async function main() {
|
||||
}
|
||||
|
||||
let item = await BaseItem.loadItemByField(itemType, 'title', title);
|
||||
if (!item) return commandError(this, _('No item with title "%s" found.', title), end);
|
||||
if (!item) return cmdError(this, _('No item with title "%s" found.', title), end);
|
||||
await BaseItem.deleteItem(itemType, item.id);
|
||||
|
||||
if (currentFolder && currentFolder.id == item.id) {
|
||||
@@ -389,7 +408,7 @@ async function main() {
|
||||
folder = currentFolder;
|
||||
}
|
||||
|
||||
if (!folder) return commandError(this, _('Unknown notebook: "%s"', folderTitle), end);
|
||||
if (!folder) return cmdError(this, _('Unknown notebook: "%s"', folderTitle), end);
|
||||
|
||||
items = await Note.previews(folder.id, queryOptions);
|
||||
}
|
||||
@@ -424,11 +443,51 @@ async function main() {
|
||||
});
|
||||
|
||||
commands.push({
|
||||
usage: 'import-enex',
|
||||
description: _('Imports a .enex file (Evernote notebook file).'),
|
||||
action: function(args, end) {
|
||||
|
||||
end();
|
||||
usage: 'import-enex <file> [notebook-title]',
|
||||
description: _('Imports en Evernote notebook file (.enex file).'),
|
||||
options: [
|
||||
['--fuzzy-matching', 'For debugging purposes. Do not use.'],
|
||||
],
|
||||
action: async function(args, end) {
|
||||
let filePath = args.file;
|
||||
let folder = null;
|
||||
let folderTitle = args['notebook-title'];
|
||||
|
||||
if (folderTitle) {
|
||||
folder = await Folder.loadByField('title', folderTitle);
|
||||
if (!folder) return cmdError(this, _('Folder does not exists: "%s"', folderTitle), end);
|
||||
} else {
|
||||
folderTitle = filename(filePath);
|
||||
folderTitle = _('Imported - %s', folderTitle);
|
||||
let inc = 0;
|
||||
while (true) {
|
||||
let t = folderTitle + (inc ? ' (' + inc + ')' : '');
|
||||
let f = await Folder.loadByField('title', t);
|
||||
if (!f) {
|
||||
folderTitle = t;
|
||||
break;
|
||||
}
|
||||
inc++;
|
||||
}
|
||||
}
|
||||
|
||||
let ok = await cmdPromptConfirm(this, _('File "%s" will be imported into notebook "%s". Continue?', basename(filePath), folderTitle))
|
||||
|
||||
if (!ok) {
|
||||
end();
|
||||
return;
|
||||
}
|
||||
|
||||
let options = {
|
||||
fuzzyMatching: args.options['fuzzy-matching'] === true,
|
||||
}
|
||||
|
||||
folder = !folder ? await Folder.save({ title: folderTitle }) : folder;
|
||||
this.log(_('Importing notes...'));
|
||||
await importEnex(folder.id, filePath, options);
|
||||
this.log(_('The notes have been imported into "%s"', folderTitle));
|
||||
|
||||
end();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ class BaseModel {
|
||||
});
|
||||
}
|
||||
|
||||
static loadByField(fieldName, fieldValue) {
|
||||
static loadByField(fieldName, fieldValue) {
|
||||
return this.modelSelectOne('SELECT * FROM `' + this.tableName() + '` WHERE `' + fieldName + '` = ?', [fieldValue]);
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -285,11 +285,8 @@ class Database {
|
||||
logQuery(sql, params = null) {
|
||||
if (!this.debugMode()) return;
|
||||
|
||||
if (params !== null) {
|
||||
this.logger().debug('DB: ' + sql, JSON.stringify(params));
|
||||
} else {
|
||||
this.logger().debug('DB: ' + sql);
|
||||
}
|
||||
this.logger().debug(sql);
|
||||
if (params !== null) this.logger().debug(JSON.stringify(params));
|
||||
}
|
||||
|
||||
static insertQuery(tableName, data) {
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ function basename(path) {
|
||||
|
||||
function filename(path) {
|
||||
if (!path) throw new Error('Path is empty');
|
||||
let output = dirname(path);
|
||||
let output = basename(path);
|
||||
if (output.indexOf('.') < 0) return output;
|
||||
|
||||
output = output.split('.');
|
||||
@@ -27,4 +27,4 @@ function isHidden(path) {
|
||||
return b[0] === '.';
|
||||
}
|
||||
|
||||
export { basename, dirname, isHidden };
|
||||
export { basename, dirname, filename, isHidden };
|
||||
Reference in new issue
Block a user