class ENNoteObj: """ wrap NoteMetadata object (evernote.edam.notestore.ttypes.NoteMetadata) for mongo sync """ def __init__(self, note, sleep_on_ratelimit): self.sleep_on_ratelimit = sleep_on_ratelimit self._note = note self._note.content = None def load_tags(self): self.gn = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit) self.gn.loadNoteTags(self._note) def load_content(self): self.gn = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit) self.gn.loadNoteContent(self._note) def get_image_resource(self, imageInfo): guid = self._note.guid binary_hash = binascii.unhexlify(imageInfo['hash']) try: resource = self.gn.handleMedia(guid, binary_hash, lambda r: r) except Exception as err: # EDAMNotFoundException - what else? logger.error('failed to lookup image for %s - %s', imageInfo, err) return None return resource def __getattr__(self, name): notfound = object() value = getattr(self._note, name, notfound) if value is notfound: raise AttributeError(name) return value
def _get_notebook(self, notebook_name): """ Get notebook guid and name. Takes default notebook if notebook's name does not select. """ notebooks = GeekNote( sleepOnRateLimit=self.sleep_on_ratelimit).findNotebooks() assert notebook_name notebook_name = notebook_name.lower( ) # avoid troubles with case-sensitivity notebook = [ item for item in notebooks if item.name.lower() == notebook_name ] guid = None if notebook: guid = notebook[0].guid else: logger.warning("missing notebook %s", notebook_name) if not guid: notebook = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit ).createNotebook(notebook_name) if (notebook): logger.info('Notebook "{0}" was' ' created'.format(notebook_name)) else: raise Exception('Notebook "{0}" was' ' not created'.format(notebook_name)) guid = notebook.guid return (guid, notebook_name)
def _create_file(self, note): """ Creates file from note """ GeekNote().loadNoteContent(note) # Save images if 'saveImages' in self.imageOptions and self.imageOptions['saveImages']: imageList = Editor.getImages(note.content) if imageList: if 'imagesInSubdir' in self.imageOptions and self.imageOptions['imagesInSubdir']: os.mkdir(os.path.join(self.path, note.title + "_images")) imagePath = os.path.join(self.path, note.title + "_images", note.title) self.imageOptions['baseFilename'] = note.title + "_images/" + note.title else: imagePath = os.path.join(self.path, note.title) self.imageOptions['baseFilename'] = note.title for imageInfo in imageList: filename = "{}-{}.{}".format(imagePath, imageInfo['hash'], imageInfo['extension']) logger.info('Saving image to {}'.format(filename)) binaryHash = binascii.unhexlify(imageInfo['hash']) GeekNote().saveMedia(note.guid, binaryHash, filename) content = Editor.ENMLtoText(note.content, self.imageOptions) path = os.path.join(self.path, note.title + self.extension) open(path, "w").write(content) os.utime(path, (-1, note.updated / 1000)) return True
def _get_notebook(self, notebook_name, path): """ Get notebook guid and name. Takes default notebook if notebook's name does not select. """ notebooks = GeekNote().findNotebooks() if not notebook_name: notebook_name = os.path.basename(os.path.realpath(path)) notebook = [item for item in notebooks if item.name == notebook_name] guid = None if notebook: guid = notebook[0].guid if not guid: notebook = GeekNote().createNotebook(notebook_name) if(notebook): logger.info('Notebook "{0}" was' ' created'.format(notebook_name)) else: raise Exception('Notebook "{0}" was' ' not created'.format(notebook_name)) guid = notebook.guid return (guid, notebook_name)
def _create_file(self, note): """ Creates file from note """ GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit).loadNoteContent(note) escaped_title = re.sub(os.sep,'-', note.title) # Save images if 'saveImages' in self.imageOptions and self.imageOptions['saveImages']: imageList = Editor.getImages(note.content) if imageList: if 'imagesInSubdir' in self.imageOptions and self.imageOptions['imagesInSubdir']: os.mkdir(os.path.join(self.path, escaped_title + "_images")) imagePath = os.path.join(self.path, escaped_title + "_images", escaped_title) self.imageOptions['baseFilename'] = escaped_title + "_images/" + escaped_title else: imagePath = os.path.join(self.path, escaped_title) self.imageOptions['baseFilename'] = escaped_title for imageInfo in imageList: filename = "{}-{}.{}".format(imagePath, imageInfo['hash'], imageInfo['extension']) logger.info('Saving image to {}'.format(filename)) binaryHash = binascii.unhexlify(imageInfo['hash']) GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit).saveMedia(note.guid, binaryHash, filename) content = Editor.ENMLtoText(note.content.encode('utf-8'), self.imageOptions) path = os.path.join(self.path, escaped_title + self.extension) open(path, "w").write(content) updated_seconds = note.updated / 1000.0 os.utime(path, (updated_seconds, updated_seconds)) return True
def _get_notes(self): """ Get notes from evernote. """ # keywords = 'notebook:"{0}"'.format(tools.strip(self.notebook_name.encode('utf-8'))) # keywords = 'intitle:"" notebook:"{0}"'.format(tools.strip(self.notebook_name.encode('utf-8'))) # unfortunately above not working keywords = '' gn = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit) return gn.findNotes(keywords, EDAM_USER_NOTES_MAX, notebookGuid=self.notebook_guid).notes
def _create_file(self, note): """ Creates file from note """ GeekNote( sleepOnRateLimit=self.sleep_on_ratelimit).loadNoteContent(note) escaped_title = re.sub(os.sep, "-", note.title) # Save images if "saveImages" in self.imageOptions and self.imageOptions[ "saveImages"]: imageList = Editor.getImages(note.content) if imageList: if ("imagesInSubdir" in self.imageOptions and self.imageOptions["imagesInSubdir"]): try: os.mkdir( os.path.join(self.path, escaped_title + "_images")) except OSError: # Folder already exists pass imagePath = os.path.join(self.path, escaped_title + "_images", escaped_title) self.imageOptions["baseFilename"] = (escaped_title + "_images/" + escaped_title) else: imagePath = os.path.join(self.path, escaped_title) self.imageOptions["baseFilename"] = escaped_title for imageInfo in imageList: filename = "{}-{}.{}".format(imagePath, imageInfo["hash"], imageInfo["extension"]) logger.info("Saving image to {}".format(filename)) binaryHash = binascii.unhexlify(imageInfo["hash"]) if not GeekNote(sleepOnRateLimit=self. sleep_on_ratelimit).saveMedia( note.guid, binaryHash, filename): logger.warning( "Failed to save image {}".format(filename)) content = Editor.ENMLtoText(note.content, self.imageOptions) path = os.path.join(self.path, escaped_title + self.extension) open(path, "w").write(content) updated_seconds = note.updated / 1000.0 os.utime(path, (updated_seconds, updated_seconds)) return True
def _get_notes(self, changed_after=None): """ Get notes from evernote notebook. """ gn = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit) if changed_after is not None: # limit number of notes to check using constraint on date updated # e.g. 'updated:20070704T150000Z' # does not work as expected (in EN sandbox) # keywords = 'updated:' + changed_after.strftime("%Y%m%dT%H%M%S") # e.g. 'updated:20070704T20190801' # fails!! keywords = 'updated:' + changed_after.strftime( "%Y%m%d") # e.g. 'updated:20070704T20190801' # logger.debug("restrict notes using filter: %s", keywords) # log bloat else: keywords = '' return gn.findNotes(keywords, EDAM_USER_NOTES_MAX, notebookGuid=self.notebook_guid).notes
def _update_note(self, file_note, note, title=None, content=None, tags=None): """ Updates note from file """ if content is None: content = self._get_file_content(file_note['path'], file_note['format']) try: tags = tags or note.tagNames except AttributeError: tags = None result = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit).updateNote( guid=note.guid, title=title or note.title, content=content, tags=tags, notebook=self.notebook_guid) if result: logger.info('Note "{0}" was updated'.format(note.title)) else: raise Exception('Note "{0}" was not updated'.format(note.title)) return result
def _create_note(self, file_note, title=None, content=None, tags=None): """ Creates note from file """ content = content or self._get_file_content(file_note['path'], file_note['format']) if content is None: return result = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit).createNote( title=title or file_note['name'], content=content, notebook=self.notebook_guid, tags=tags or None, created=file_note['mtime']) if result: logger.info('Note "{0}" was created'.format(title or file_note['name'])) else: raise Exception('Note "{0}" was not' ' created'.format(title or file_note['name'])) return result
def _update_file(self, file_note, note): """ Updates file from note """ GeekNote().loadNoteContent(note) content = Editor.ENMLtoText(note.content) open(file_note['path'], "w").write(content)
def _get_notes(self): """ Get notes from evernote. """ keywords = 'notebook:"{0}"'.format( tools.strip(self.notebook_name.encode("utf-8"))) return (GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit).findNotes( keywords, EDAM_USER_NOTES_MAX).notes)
def _create_file(self, note): """ Creates file from note """ GeekNote().loadNoteContent(note) escaped_title = note.title.replace(os.sep, '-') path = os.path.join( self.path, escaped_title.decode('utf8').encode(os_encoding) + self.extension) if self.format != "enex": # Save images if 'saveImages' in self.imageOptions and self.imageOptions[ 'saveImages'] and self.format != "enex": imageList = Editor.getImages(note.content) if imageList: if 'imagesInSubdir' in self.imageOptions and self.imageOptions[ 'imagesInSubdir']: os.mkdir( os.path.join(self.path, escaped_title + "_images")) imagePath = os.path.join(self.path, escaped_title + "_images", escaped_title) self.imageOptions[ 'baseFilename'] = escaped_title + "_images/" + escaped_title else: imagePath = os.path.join(self.path, escaped_title) self.imageOptions['baseFilename'] = escaped_title for imageInfo in imageList: filename = "{}-{}.{}".format(imagePath, imageInfo['hash'], imageInfo['extension']) logger.info('Saving image to {}'.format(filename)) binaryHash = binascii.unhexlify(imageInfo['hash']) GeekNote().saveMedia(note.guid, binaryHash, filename) content = Editor.ENMLtoText(note.content, self.imageOptions) open(path, "w").write(content) else: enex.note_to_file(note, path) logger.info("create file {}".format(path)) updated_seconds = note.updated / 1000.0 os.utime(path, (updated_seconds, updated_seconds)) return True
def _create_file(self, note): """ Creates file from note """ GeekNote().loadNoteContent(note) content = Editor.ENMLtoText(note.content) path = os.path.join(self.path, note.title + self.extension) open(path, "w").write(content) return True
def _update_file(self, file_note, note): """ Updates file from note """ GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit).loadNoteContent(note) content = Editor.ENMLtoText(note.content) open(file_note['path'], "w").write(content) updated_seconds = note.updated / 1000.0 os.utime(file_note['path'], (updated_seconds, updated_seconds))
def _get_notes(self): """ Get notes from evernote. """ keywords = 'notebook:"{0}"'.format(tools.strip(self.notebook_name)) #print GeekNote().findNotes(keywords, 10000) #try to get all notes in a notebook #assum that the notebook has less than 10000 notes noteMetadataResultSpec = NoteStore.NotesMetadataResultSpec(includeTitle=True,\ includeUpdated=True) noteList = GeekNote().findNotesMetadata(keywords, 10000, noteMetadataResultSpec) notes = noteList.notes notesSize = len(notes) while (notesSize < noteList.totalNotes): noteList = GeekNote().findNotesMetadata(keywords, 10000, offset=notesSize) notes += noteList.notes notesSize = len(notes) print notesSize return notes
def _update_file(self, file_note, note): """ Updates file from note """ GeekNote().loadNoteContent(note) print("update {}".format(file_note['path'])) if self.format != "enex": open(file_note['path'], "w").write(content) content = Editor.ENMLtoText(note.content) else: enex.note_to_file(note, file_note['path']) updated_seconds = note.updated / 1000.0 os.utime(file_note['path'], (updated_seconds, updated_seconds))
def sync(self): """ Synchronize files to notes TODO: add two way sync with meta support TODO: add specific notebook support """ if not self.all_set: return files = self._get_files() notes = self._get_notes() for f in files: has_note = False meta = self._parse_meta(self._get_file_content(f['path'])) title = f['name'] if 'title' not in meta else meta['title'].strip() tags = None if 'tags' not in meta else meta['tags'] \ .replace('[', '').replace(']','').split(',') tags = None if tags == '' else map(lambda x:x.strip(), tags) note = None if self.format == 'html': meta['mtime'] = f['mtime'] note = self._html2note(meta) for n in notes: if title == n.title: has_note = True if f['mtime'] > n.updated: if self.format == 'html': gn = GeekNote() note.guid = n.guid gn.getNoteStore().updateNote(gn.authToken, note) logger.info('Note "{0}" was updated'.format(note.title)) else: self._update_note(f, n, title, meta['content'], tags) break if not has_note: if self.format == 'html': gn = GeekNote() gn.getNoteStore().createNote(gn.authToken, note) logger.info('Note "{0}" was created'.format(note.title)) else: self._create_note(f, title, meta['content'], tags) if self.twoway: for n in notes: has_file = False for f in files: if f['name'] == n.title: has_file = True if f['mtime'] < n.updated: self._update_file(f, n) break if not has_file: self._create_file(n) logger.info('Sync Complete')
def _update_note(self, file_note, note): """ Updates note from file """ content = self._get_file_content(file_note['path']) result = GeekNote().updateNote(guid=note.guid, title=note.title, content=content, notebook=self.notebook_guid) if result: logger.info('Note "{0}" was updated'.format(note.title)) else: raise Exception('Note "{0}" was not updated'.format(note.title)) return result
def _update_note(self, file_note, note, title=None, content=None, tags=None): """ Updates note from file """ # content = self._get_file_content(file_note['path']) if content is None else content result = GeekNote().updateNote( guid=note.guid, title=title or note.title, content=content or self._get_file_content(file_note['path']), tags=tags or note.tagNames, notebook=self.notebook_guid) if result: logger.info('Note "{0}" was updated'.format(note.title)) else: raise Exception('Note "{0}" was not updated'.format(note.title)) return result
def _create_note(self, file_note): """ Creates note from file """ content = self._get_file_content(file_note['path']) if content is None: return result = GeekNote().createNote(title=file_note['name'], content=content, notebook=self.notebook_guid) if result: logger.info('Note "{0}" was created'.format(file_note['name'])) else: raise Exception('Note "{0}" was not created'.format( file_note['name'])) return result
def _get_notes(self): """ Get notes from evernote. """ keywords = 'notebook:"{0}"'.format(tools.strip(self.notebook_name)) return GeekNote().findNotes(keywords, EDAM_USER_NOTES_MAX).notes
def all_notebooks(): geeknote = GeekNote() return [notebook.name for notebook in geeknote.findNotebooks()]
def __init__(self, notebook_name, path, mask, format, twoway=False, download_only=False, nodownsync=False, imageOptions={ 'saveImages': False, 'imagesInSubdir': False }): # check auth if not Storage().getUserToken(): raise Exception("Auth error. There is not any oAuthToken.") # set path if not path: raise Exception("Path to sync directories does not select.") if not os.path.exists(path): raise Exception("Path to sync directories does not exist.") self.path = path # set mask if not mask: mask = "*.*" self.mask = mask # set format if not format: format = "plain" self.format = format if format == "markdown": self.extension = ".md" elif format == "html": self.extension = ".html" elif format == "enex": self.extension = ".enex" else: self.extension = ".txt" print("Download notebook {} in {} file".format(notebook_name, self.format)) self.twoway = twoway self.download_only = download_only self.nodownsync = nodownsync logger.info('Sync Start') # set notebook self.notebook_guid,\ self.notebook_name = self._get_notebook(notebook_name, path) # set image options self.imageOptions = imageOptions self.user_info = GeekNote().getUserInfo() # all is Ok self.all_set = True
def sync(self): """ Synchronize files to notes TODO: add two way sync with meta support TODO: add specific notebook support """ if not self.all_set: return files = self._get_files() notes = self._get_notes() if not self.download_only: for f in files: has_note = False content = self._get_file_content(f['path'], f['format']) meta = self._parse_meta(content, f['format']) title = f['name'] if 'title' not in meta else meta[ 'title'].strip() tags = None if 'tags' not in meta else meta['tags'] \ .replace('[', '').replace(']', '').split(',') tags = None if not tags else map(lambda x: x.strip(), tags) meta['tags'] = tags meta['title'] = title note = None meta['mtime'] = f['mtime'] if f['format'] == 'html': note = self._html2note(meta) elif f['format'] == 'markdown': # note = self._md2note(meta) # as Editor.textToENML converts markdown to HTML, reuse note = self._html2note(meta) else: assert False, "unsupported format for upload: %s" % f[ 'format'] for n in notes: if title == n.title: has_note = True if f['mtime'] > n.updated: if self.format == 'html': gn = GeekNote( sleepOnRateLimit=self.sleep_on_ratelimit) note.guid = n.guid gn.getNoteStore().updateNote( gn.authToken, note) logger.info('Note "{0}" was updated'.format( note.title)) else: self._update_note(f, n, title, meta['content'], tags) break if not has_note: if self.format == 'html': gn = GeekNote(sleepOnRateLimit=self.sleep_on_ratelimit) gn.getNoteStore().createNote(gn.authToken, note) logger.info('Note "{0}" was created'.format( note.title)) else: self._create_note(f, title, meta['content'], tags) if self.twoway or self.download_only: for n in notes: has_file = False for f in files: if f['name'] == n.title: has_file = True if f['mtime'] < n.updated: self._update_file(f, n) break if not self.nodownsync: if not has_file: self._create_file(n) logger.info('Sync Complete')
def sync(self): """ Synchronize files to notes TODO: add two way sync with meta support TODO: add specific notebook support """ if not self.all_set: return files = self._get_files() notes = self._get_notes() if not self.download_only: for f in files: has_note = False meta = self._parse_meta(self._get_file_content(f['path'])) title = f['name'] if 'title' not in meta else meta['title'].strip() tags = None if 'tags' not in meta else meta['tags'] \ .replace('[', '').replace(']', '').split(',') tags = None if not tags else map(lambda x: x.strip(), tags) meta['tags'] = tags meta['title'] = title note = None if self.format == 'html': meta['mtime'] = f['mtime'] note = self._html2note(meta) for n in notes: if title == n.title: has_note = True if f['mtime'] > n.updated: if self.format == 'html': gn = GeekNote() note.guid = n.guid gn.getNoteStore().updateNote(gn.authToken, note) logger.info('Note "{0}" was updated'.format(note.title)) else: self._update_note(f, n, title, meta['content'], tags) break if not has_note: if self.format == 'html': gn = GeekNote() gn.getNoteStore().createNote(gn.authToken, note) logger.info('Note "{0}" was created'.format(note.title)) else: self._create_note(f, title, meta['content'], tags) if self.twoway or self.download_only: for n in notes: has_file = False for f in files: if f['name'] == n.title: has_file = True if f['mtime'] < n.updated: self._update_file(f, n) break if not self.nodownsync: if not has_file: self._create_file(n) logger.info('Sync Complete')
from time import gmtime, strftime import base64 import lxml.etree as ET from lxml.etree import SubElement # import xml.etree.ElementTree as ET # from xml.etree.ElementTree import SubElement from xml.sax.saxutils import escape, unescape import config from geeknote import GeekNote from gnsync import GNSync os_encoding = locale.getpreferredencoding() user_info = GeekNote().getUserInfo() def log(func): def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception, e: print e traceback.print_exc() logger.error("%s", str(e)) return wrapper def _list_member(obj):
def all_linked_notebooks(): geeknote = GeekNote() return geeknote.findLinkedNotebooks()
def all_notebooks(sleep_on_ratelimit=False): geeknote = GeekNote(sleepOnRateLimit=sleep_on_ratelimit) return [notebook.name for notebook in geeknote.findNotebooks()]
def main(): try: parser = argparse.ArgumentParser() parser.add_argument('--path', '-p', action='store', help='Path to synchronize directory') parser.add_argument('--mask', '-m', action='store', help='Mask of files to synchronize. Default is "*.*"') parser.add_argument('--format', '-f', action='store', default='plain', choices=['plain', 'markdown', 'html'], help='The format of the file contents. Default is "plain". Valid values are "plain" "html" and "markdown"') parser.add_argument('--notebook', '-n', action='store', help='Notebook name for synchronize. Default is default notebook unless all is selected') parser.add_argument('--all', '-a', action='store_true', help='Synchronize all notebooks', default=False) parser.add_argument('--all-linked', action='store_true', help='Get all linked notebooks') parser.add_argument('--logpath', '-l', action='store', help='Path to log file. Default is GeekNoteSync in home dir') parser.add_argument('--two-way', '-t', action='store_true', help='Two-way sync (also download from evernote)', default=False) parser.add_argument('--download-only', action='store_true', help='Only download from evernote; no upload', default=False) parser.add_argument('--nodownsync', '-d', action='store', help='Sync from Evernote only if the file is already local.') parser.add_argument('--save-images', action='store_true', help='save images along with text') parser.add_argument('--sleep-on-ratelimit', action='store_true', help='sleep on being ratelimited') parser.add_argument('--images-in-subdir', action='store_true', help='save images in a subdirectory (instead of same directory as file)') args = parser.parse_args() path = args.path if args.path else "." mask = args.mask if args.mask else None format = args.format if args.format else None notebook = args.notebook if args.notebook else None logpath = args.logpath if args.logpath else None twoway = args.two_way download_only = args.download_only nodownsync = True if args.nodownsync else False # image options imageOptions = {} imageOptions['saveImages'] = args.save_images imageOptions['imagesInSubdir'] = args.images_in_subdir reset_logpath(logpath) geeknote = GeekNote() if args.all_linked: my_map = {} for notebook in all_linked_notebooks(): print "Syncing notebook: " + notebook.shareName notebook_url = urlparse.urlparse(notebook.noteStoreUrl) sharedNoteStoreClient = THttpClient.THttpClient(notebook.noteStoreUrl) sharedNoteStoreProtocol = TBinaryProtocol.TBinaryProtocol(sharedNoteStoreClient) sharedNoteStore = NoteStore.Client(sharedNoteStoreProtocol) sharedAuthResult = sharedNoteStore.authenticateToSharedNotebook(notebook.shareKey, geeknote.authToken) sharedAuthToken = sharedAuthResult.authenticationToken sharedNotebook = sharedNoteStore.getSharedNotebookByAuth(sharedAuthToken) my_filter = NoteStore.NoteFilter(notebookGuid = sharedNotebook.notebookGuid) noteList = sharedNoteStore.findNotes(sharedAuthToken, my_filter, 0, 10) print "Found " + str(noteList.totalNotes) + " shared notes." print noteList.notes filename = notebook.shareName + '-' + noteList.notes[0].title + '.html' filename = filename.replace(' ','-').replace('/', '-') content = sharedNoteStore.getNoteContent(sharedAuthToken, noteList.notes[0].guid) with open(filename, 'w') as f: f.write(content) return if args.all: for notebook in all_notebooks(sleep_on_ratelimit=args.sleep_on_ratelimit): logger.info("Syncing notebook %s", notebook) escaped_notebook_path = re.sub(os.sep, '-', notebook) notebook_path = os.path.join(path, escaped_notebook_path) if not os.path.exists(notebook_path): os.mkdir(notebook_path) GNS = GNSync(notebook, notebook_path, mask, format, twoway, download_only, nodownsync, sleep_on_ratelimit=args.sleep_on_ratelimit, imageOptions=imageOptions) GNS.sync() else: GNS = GNSync(notebook, path, mask, format, twoway, download_only, nodownsync, sleep_on_ratelimit=args.sleep_on_ratelimit, imageOptions=imageOptions) GNS.sync() except (KeyboardInterrupt, SystemExit, tools.ExitException): pass except Exception, e: logger.error(str(e))
def note_to_file(note, path): old_tree = None if os.path.isfile(path): print("parse file {}".format(path)) try: old_tree = ET.parse(path) except: print("fail") enex_file = open(path, "wb+") enex_file.write( '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE en-export PUBLIC "SYSTEM" "http://xml.evernote.com/pub/evernote-export3.dtd">\n' ) export_elm = ET.Element('en-export') tree = ET.ElementTree(export_elm) note_elm = SubElement(export_elm, 'note') title_elm = SubElement(note_elm, 'title') title_elm.text = note.title.decode('utf-8') content_elm = SubElement(note_elm, "content") print_title = title_elm.text.encode(os_encoding) content_elm.text = ET.CDATA(note.content.decode('utf-8')) SubElement(note_elm, 'created').text = strftime("%Y%m%dT%H%M%SZ", gmtime(note.created / 1000)) SubElement(note_elm, 'updated').text = strftime("%Y%m%dT%H%M%SZ", gmtime(note.updated / 1000)) if (note.tagGuids): for tag in note.tagNames: SubElement(note_elm, 'tag').text = tag note_attr_elm = SubElement(note_elm, 'note-attributes') upper_regex = re.compile("[A-Z]") first_cap_re = re.compile('(.)([A-Z][a-z]+)') all_cap_re = re.compile('([a-z0-9])([A-Z])') def _conv_export_name(name): s1 = first_cap_re.sub(r'\1_\2', name) return all_cap_re.sub(r'\1_\2', s1).lower() for attr_name, attr in note.attributes.__dict__.items(): # print (attr_name, type(attr), attr) if attr != None: attr_name = _conv_export_name(attr_name) if isinstance(attr, basestring): SubElement(note_attr_elm, attr_name).text = attr.decode("utf-8") if isinstance(attr, long): if ('time' in attr_name or 'date' in attr_name): SubElement(note_attr_elm, attr_name).text = strftime( "%Y%m%dT%H%M%SZ", gmtime(attr / 1000)) else: SubElement(note_attr_elm, attr_name).text = str(attr) if isinstance(attr, (float, bool)): SubElement(note_attr_elm, attr_name).text = str(attr) if (note.largestResourceSize) is not None: print("largest resource size of {} = {} ".format( print_title, note.largestResourceSize)) note_obj = GeekNote().getNote(note.guid, withResourcesData=True, withResourcesRecognition=True) for res in note_obj.resources: res_elm = SubElement(note_elm, 'resource') print("found resource with size {} in {} ".format( res.data.size, print_title)) SubElement(res_elm, 'data', encoding="base64").text = str( base64.b64encode(res.data.body)) SubElement(res_elm, 'mime').text = res.mime if res.width != None: SubElement(res_elm, 'width').text = str(res.width) if res.height != None: SubElement(res_elm, 'height').text = str(res.height) if res.recognition != None: SubElement(res_elm, 'recognition').text = ET.CDATA( res.recognition.body.decode("utf-8")) res_attr_elm = SubElement(res_elm, 'resource-attributes') for attr_name, attr in res.attributes.__dict__.items(): if attr == None: continue attr_name = _conv_export_name(attr_name) if isinstance(attr, basestring): attr = attr.decode("utf-8") SubElement(res_attr_elm, attr_name).text = attr if ('time' in attr_name or 'date' in attr_name): SubElement(res_attr_elm, attr_name).text = strftime( "%Y%m%dT%H%M%SZ", gmtime(attr / 1000)) if isinstance(attr, (float, bool)): SubElement(res_attr_elm, attr_name).text = str(attr) if (old_tree != None): prst_servers_info = old_tree.find("server_info") if prst_servers_info is not None: for account in prst_servers_info: if account.find("note_id").text == note.guid: print("Remove old server info") # prst_servers_info.remove(account) # print (server.find("base_site")) # print ("note stored in {} with account {}".format(server.find("base_site").text,(server.find("account").text))) # _list_member(user_info) server_elm = SubElement(export_elm, 'server_info') account_elm = SubElement(server_elm, 'account') SubElement(account_elm, "note_id").text = note.guid SubElement(account_elm, "notebook_name").text = note.notebookName SubElement(account_elm, "user_id").text = str(user_info.id) SubElement(account_elm, "user_full_name").text = user_info.name.decode("utf-8") SubElement(account_elm, "base_site").text = config.USER_BASE_URL SubElement(account_elm, "last_update").text = str(note.updated) enex_file.write( unescape(ET.tostring(export_elm, encoding='utf-8', pretty_print=True))) enex_file.truncate() return True