mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 21:11:30 +08:00 
			
		
		
		
	enex import recognizes images, media references are converted to links
This commit is contained in:
		
							parent
							
								
									b8eaff055a
								
							
						
					
					
						commit
						7bdbea81f1
					
				| @ -1,6 +1,6 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const image = require('../../services/image'); | const imageService = require('../../services/image'); | ||||||
| const repository = require('../../services/repository'); | const repository = require('../../services/repository'); | ||||||
| const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR; | const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR; | ||||||
| const fs = require('fs'); | const fs = require('fs'); | ||||||
| @ -35,11 +35,11 @@ async function uploadImage(req) { | |||||||
|         return [400, "Unknown image type: " + file.mimetype]; |         return [400, "Unknown image type: " + file.mimetype]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const {fileName, imageId} = await image.saveImage(file, noteId); |     const {url} = await imageService.saveImage(file.buffer, file.originalname, noteId); | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|         uploaded: true, |         uploaded: true, | ||||||
|         url: `/api/images/${imageId}/${fileName}` |         url | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ const xml2js = require('xml2js'); | |||||||
| const log = require("./log"); | const log = require("./log"); | ||||||
| const utils = require("./utils"); | const utils = require("./utils"); | ||||||
| const noteService = require("./notes"); | const noteService = require("./notes"); | ||||||
|  | const imageService = require("./image"); | ||||||
| 
 | 
 | ||||||
| // date format is e.g. 20181121T193703Z
 | // date format is e.g. 20181121T193703Z
 | ||||||
| function parseDate(text) { | function parseDate(text) { | ||||||
| @ -205,22 +206,52 @@ async function importEnex(file, parentNote) { | |||||||
|         // following is workaround for this issue: https://github.com/Leonidas-from-XIV/node-xml2js/issues/484
 |         // following is workaround for this issue: https://github.com/Leonidas-from-XIV/node-xml2js/issues/484
 | ||||||
|         content = extractContent(xmlObject['en-note']); |         content = extractContent(xmlObject['en-note']); | ||||||
| 
 | 
 | ||||||
|         const resp = await noteService.createNote(rootNote.noteId, title, content, { |         const noteEntity = (await noteService.createNote(rootNote.noteId, title, content, { | ||||||
|             attributes, |             attributes, | ||||||
|             dateCreated, |             dateCreated, | ||||||
|             type: 'text', |             type: 'text', | ||||||
|             mime: 'text/html' |             mime: 'text/html' | ||||||
|         }); |         })).note; | ||||||
| 
 | 
 | ||||||
|         for (const resource of resources) { |         for (const resource of resources) { | ||||||
|             await noteService.createNote(resp.note.noteId, resource.title, resource.content, { |             const hash = utils.md5(resource.content); | ||||||
|  | 
 | ||||||
|  |             const mediaRegex = new RegExp(`<en-media hash="${hash}"[^>]*>`, 'g'); | ||||||
|  | 
 | ||||||
|  |             if (resource.mime.startsWith("image/")) { | ||||||
|  |                 const originalName = "image." + resource.mime.substr(6); | ||||||
|  | 
 | ||||||
|  |                 const { url } = await imageService.saveImage(resource.content, originalName, noteEntity.noteId); | ||||||
|  | 
 | ||||||
|  |                 const imageLink = `<img src="${url}">`; | ||||||
|  | 
 | ||||||
|  |                 noteEntity.content = noteEntity.content.replace(mediaRegex, imageLink); | ||||||
|  | 
 | ||||||
|  |                 if (!note.content.includes(imageLink)) { | ||||||
|  |                     // if there wasn't any match for the reference, we'll add the image anyway
 | ||||||
|  |                     // otherwise image would be removed since no note would include it
 | ||||||
|  |                     note.content += imageLink; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 const resourceNote = (await noteService.createNote(noteEntity.noteId, resource.title, resource.content, { | ||||||
|                     attributes: resource.attributes, |                     attributes: resource.attributes, | ||||||
|                     type: 'file', |                     type: 'file', | ||||||
|                     mime: resource.mime |                     mime: resource.mime | ||||||
|             }); |                 })).note; | ||||||
|  | 
 | ||||||
|  |                 const resourceLink = `<a href="#root/${resourceNote.noteId}">${utils.escapeHtml(resource.title)}</a>`; | ||||||
|  | 
 | ||||||
|  |                 noteEntity.content = noteEntity.content.replace(mediaRegex, resourceLink); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // save updated content with links to files/images
 | ||||||
|  |         await noteEntity.save(); | ||||||
|  | 
 | ||||||
|  |         console.log(noteEntity.content); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     saxStream.on("closetag", async tag => { |     saxStream.on("closetag", async tag => { | ||||||
|         path.pop(); |         path.pop(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,14 +11,14 @@ const jimp = require('jimp'); | |||||||
| const imageType = require('image-type'); | const imageType = require('image-type'); | ||||||
| const sanitizeFilename = require('sanitize-filename'); | const sanitizeFilename = require('sanitize-filename'); | ||||||
| 
 | 
 | ||||||
| async function saveImage(file, noteId) { | async function saveImage(buffer, originalName, noteId) { | ||||||
|     const resizedImage = await resize(file.buffer); |     const resizedImage = await resize(buffer); | ||||||
|     const optimizedImage = await optimize(resizedImage); |     const optimizedImage = await optimize(resizedImage); | ||||||
| 
 | 
 | ||||||
|     const imageFormat = imageType(optimizedImage); |     const imageFormat = imageType(optimizedImage); | ||||||
| 
 | 
 | ||||||
|     const fileNameWithouExtension = file.originalname.replace(/\.[^/.]+$/, ""); |     const fileNameWithoutExtension = originalName.replace(/\.[^/.]+$/, ""); | ||||||
|     const fileName = sanitizeFilename(fileNameWithouExtension + "." + imageFormat.ext); |     const fileName = sanitizeFilename(fileNameWithoutExtension + "." + imageFormat.ext); | ||||||
| 
 | 
 | ||||||
|     const image = await new Image({ |     const image = await new Image({ | ||||||
|         format: imageFormat.ext, |         format: imageFormat.ext, | ||||||
| @ -32,7 +32,11 @@ async function saveImage(file, noteId) { | |||||||
|         imageId: image.imageId |         imageId: image.imageId | ||||||
|     }).save(); |     }).save(); | ||||||
| 
 | 
 | ||||||
|     return {fileName, imageId: image.imageId}; |     return { | ||||||
|  |         fileName, | ||||||
|  |         imageId: image.imageId, | ||||||
|  |         url: `/api/images/${image.imageId}/${fileName}` | ||||||
|  |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const MAX_SIZE = 1000; | const MAX_SIZE = 1000; | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| const crypto = require('crypto'); | const crypto = require('crypto'); | ||||||
| const randtoken = require('rand-token').generator({source: 'crypto'}); | const randtoken = require('rand-token').generator({source: 'crypto'}); | ||||||
| const unescape = require('unescape'); | const unescape = require('unescape'); | ||||||
|  | const escape = require('escape-html'); | ||||||
| 
 | 
 | ||||||
| function newEntityId() { | function newEntityId() { | ||||||
|     return randomString(12); |     return randomString(12); | ||||||
| @ -16,6 +17,10 @@ function randomSecureToken(bytes = 32) { | |||||||
|     return crypto.randomBytes(bytes).toString('base64'); |     return crypto.randomBytes(bytes).toString('base64'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function md5(content) { | ||||||
|  |     return crypto.createHash('md5').update(content).digest('hex'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function toBase64(plainText) { | function toBase64(plainText) { | ||||||
|     return Buffer.from(plainText).toString('base64'); |     return Buffer.from(plainText).toString('base64'); | ||||||
| } | } | ||||||
| @ -59,6 +64,10 @@ async function stopWatch(what, func) { | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function escapeHtml(str) { | ||||||
|  |     return escape(str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function unescapeHtml(str) { | function unescapeHtml(str) { | ||||||
|     return unescape(str); |     return unescape(str); | ||||||
| } | } | ||||||
| @ -108,6 +117,7 @@ function union(a, b) { | |||||||
| module.exports = { | module.exports = { | ||||||
|     randomSecureToken, |     randomSecureToken, | ||||||
|     randomString, |     randomString, | ||||||
|  |     md5, | ||||||
|     newEntityId, |     newEntityId, | ||||||
|     toBase64, |     toBase64, | ||||||
|     fromBase64, |     fromBase64, | ||||||
| @ -117,6 +127,7 @@ module.exports = { | |||||||
|     isEmptyOrWhitespace, |     isEmptyOrWhitespace, | ||||||
|     sanitizeSql, |     sanitizeSql, | ||||||
|     stopWatch, |     stopWatch, | ||||||
|  |     escapeHtml, | ||||||
|     unescapeHtml, |     unescapeHtml, | ||||||
|     toObject, |     toObject, | ||||||
|     stripTags, |     stripTags, | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd"> | <!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd"> | ||||||
| <en-export export-date="20181101T194259Z" application="Evernote/Windows" version="6.x"> | <en-export export-date="20181105T095144Z" application="Evernote/Windows" version="6.x"> | ||||||
| <note><title>Formatted text</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?> | <note><title>Formatted text</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?> | ||||||
| <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"> | <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"> | ||||||
| 
 | 
 | ||||||
| @ -5485,4 +5485,10 @@ OTg3NjMyOSwyNzkxMTA0MTYwLDEwNTc1NjM5NDksMzI1NTM2MzIzMSwzMDc1MzY3MjE4LDM0NjM5 | |||||||
| NjMyMjcsMTQ2OTA0Njc1NSw5ODU4ODc0NjJdLEU9WzEzMzI4OTk5NDQsMTcwMDg4NDAzNCwxNzAx | NjMyMjcsMTQ2OTA0Njc1NSw5ODU4ODc0NjJdLEU9WzEzMzI4OTk5NDQsMTcwMDg4NDAzNCwxNzAx | ||||||
| MzQzMDg0LDE2ODQzNzAwMDMsMTY2ODQ0NjUzMiwKMTg2OTk2Mzg5Ml07ay5lbmNvZGVCYXNlNjQ9 | MzQzMDg0LDE2ODQzNzAwMDMsMTY2ODQ0NjUzMiwKMTg2OTk2Mzg5Ml07ay5lbmNvZGVCYXNlNjQ9 | ||||||
| eDtrLmRlY29kZUJhc2U2ND1CO3JldHVybiBrfSk7Cg== | eDtrLmRlY29kZUJhc2U2ND1CO3JldHVybiBrfSk7Cg== | ||||||
| </data><mime>application/octet-stream</mime><resource-attributes><source-url>file://Z:\home\adam\Downloads\bcrypt.min.js</source-url><file-name>bcrypt.min.js</file-name><attachment>true</attachment></resource-attributes></resource></note></en-export> | </data><mime>application/octet-stream</mime><resource-attributes><source-url>file://Z:\home\adam\Downloads\bcrypt.min.js</source-url><file-name>bcrypt.min.js</file-name><attachment>true</attachment></resource-attributes></resource></note><note><title>Internal link to another note</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"> | ||||||
|  | 
 | ||||||
|  | <en-note><div>Link to another note: <a href="evernote:///view/2223880/s20/76fc5a06-19de-4f03-ad53-1816f307eb5c/76fc5a06-19de-4f03-ad53-1816f307eb5c/" style="color: #69aa35;">Formatted text</a></div></en-note>]]></content><created>20181105T094707Z</created><updated>20181105T095117Z</updated><note-attributes><author>Adam Zivner</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>Table</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"> | ||||||
|  | 
 | ||||||
|  | <en-note><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div><b>header1</b></div></td><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div><b>header2</b></div></td><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div><b>header3</b></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div>abc</div></td><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div>def</div></td><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div>ghi</div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div>123</div></td><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div>456</div></td><td style="width: 130px; padding: 8px; border: 1px solid rgb(204, 204, 204);"><div>789</div></td></tr></tbody></table><div><br/></div></div><div><br/></div></en-note>]]></content><created>20181105T094826Z</created><updated>20181105T094949Z</updated><note-attributes><author>Adam Zivner</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note></en-export> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 azivner
						azivner