· 6 years ago · Nov 19, 2018, 08:54 AM
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import os, sys
5import argparse
6import glob
7import logging
8
9import markdown
10
11from geeknote import GeekNote
12from storage import Storage
13import editor
14import tools
15
16# set default logger (write log to file)
17def_logpath = os.path.join(os.getenv('USERPROFILE') or os.getenv('HOME'), 'GeekNoteSync.log')
18formatter = logging.Formatter('%(asctime)-15s : %(message)s')
19handler = logging.FileHandler(def_logpath)
20handler.setFormatter(formatter)
21
22logger = logging.getLogger(__name__)
23logger.setLevel(logging.DEBUG)
24logger.addHandler(handler)
25
26def log(func):
27 def wrapper(*args, **kwargs):
28 try:
29 return func(*args, **kwargs)
30 except Exception, e:
31 logger.error("%s", str(e))
32 return wrapper
33
34@log
35def reset_logpath(logpath):
36 """
37 Reset logpath to path from command line
38 """
39 global logger
40
41 if not logpath:
42 return
43
44 # remove temporary log file if it's empty
45 if os.path.isfile(def_logpath):
46 if os.path.getsize(def_logpath) == 0:
47 os.remove(def_logpath)
48
49 # save previous handlers
50 handlers = logger.handlers
51
52 # remove old handlers
53 for handler in handlers:
54 logger.removeHandler(handler)
55
56 # try to set new file handler
57 handler = logging.FileHandler(logpath)
58 handler.setFormatter(formatter)
59 logger.addHandler(handler)
60
61class GNSync:
62
63 notebook_name = None
64 path = None
65 mask = None
66
67 notebook_guid = None
68 all_set = False
69
70 @log
71 def __init__(self, notebook_name, path, mask, format):
72 # check auth
73 if not Storage().getUserToken():
74 raise Exception("Auth error. There is not any oAuthToken.")
75
76 #set path
77 if not path:
78 raise Exception("Path to sync directories does not select.")
79
80 if not os.path.exists(path):
81 raise Exception("Path to sync directories does not exist.")
82
83 self.path = path
84
85 #set mask
86 if not mask:
87 mask = "*.*"
88
89 self.mask = mask
90
91 #set format
92 if not format:
93 format = "plain"
94
95 self.format = format
96
97 logger.info('Sync Start')
98
99 #set notebook
100 self.notebook_guid, self.notebook_name = self._get_notebook(notebook_name, path)
101
102 # all is Ok
103 self.all_set = True
104
105 @log
106 def sync(self):
107 """
108 Synchronize files to notes
109 """
110 if not self.all_set:
111 return
112
113 files = self._get_files()
114 notes = self._get_notes()
115
116 for f in files:
117 has_note = False
118 for n in notes:
119 if f['name'] == n.title:
120 has_note = True
121 if f['mtime'] > n.updated:
122 self._update_note(f, n)
123 break
124
125 if not has_note :
126 self._create_note(f)
127
128 logger.info('Sync Complite')
129
130 @log
131 def _update_note(self, file_note, note):
132 """
133 Updates note from file
134 """
135 content = self._get_file_content(file_note['path'])
136
137 result = GeekNote().updateNote(
138 guid=note.guid,
139 title=note.title,
140 content=content,
141 notebook=self.notebook_guid)
142
143 if result:
144 logger.info('Note "{0}" was updated'.format(note.title))
145 else:
146 raise Exception('Note "{0}" was not updated'.format(note.title))
147
148 return result
149
150
151 @log
152 def _create_note(self, file_note):
153 """
154 Creates note from file
155 """
156
157 content = self._get_file_content(file_note['path'])
158
159 if content is None:
160 return
161
162 result = GeekNote().createNote(
163 title=file_note['name'],
164 content=content,
165 notebook=self.notebook_guid)
166
167 if result:
168 logger.info('Note "{0}" was created'.format(file_note['name']))
169 else:
170 raise Exception('Note "{0}" was not created'.format(file_note['name']))
171
172 return result
173
174 @log
175 def _get_file_content(self, path):
176 """
177 Get file content.
178 """
179 content = open(path, "r").read()
180 content = editor.textToENML(content)
181
182 if content is None:
183 logger.warning("File {0}. Content must be an UTF-8 encode.".format(path))
184 return None
185
186 return content
187
188 @log
189 def _get_notebook(self, notebook_name, path):
190 """
191 Get notebook guid and name. Takes default notebook if notebook's name does not
192 select.
193 """
194 notebooks = GeekNote().findNotebooks()
195
196 if not notebook_name:
197 notebook_name = os.path.basename(os.path.realpath(path))
198
199 notebook = [item for item in notebooks if item.name == notebook_name]
200 guid = None
201 if notebook:
202 guid = notebook[0].guid
203
204 if not guid:
205 notebook = GeekNote().createNotebook(notebook_name)
206
207 if(notebook):
208 logger.info('Notebook "{0}" was created'.format(notebook_name))
209 else:
210 raise Exception('Notebook "{0}" was not created'.format(notebook_name))
211
212 guid = notebook.guid
213
214 return (guid, notebook_name)
215
216 @log
217 def _get_files(self):
218 """
219 Get files by self.mask from self.path dir.
220 """
221
222 file_paths = glob.glob(os.path.join(self.path, self.mask))
223
224 files = []
225 for f in file_paths:
226 if os.path.isfile(f):
227 file_name = os.path.basename(f)
228 file_name = os.path.splitext(file_name)[0]
229
230 mtime = int(os.path.getmtime(f) * 1000)
231
232 files.append({'path': f,'name': file_name, 'mtime': mtime})
233
234 return files
235
236 @log
237 def _get_notes(self):
238 """
239 Get notes from evernote.
240 """
241 keywords = 'notebook:"{0}"'.format(tools.strip(self.notebook_name))
242 return GeekNote().findNotes(keywords, 10000).notes
243
244
245def main():
246 try:
247 parser = argparse.ArgumentParser()
248 parser.add_argument('--path', '-p', action='store', help='Path to synchronize directory')
249 parser.add_argument('--mask', '-m', action='store', help='Mask of files to synchronize. Default is "*.*"')
250 parser.add_argument('--format', '-f', action='store', default='plain', choices=['plain', 'markdown'], help='The format of the file contents. Default is "plain". Valid values ​​are "plain" and "markdown"')
251 parser.add_argument('--notebook', '-n', action='store', help='Notebook name for synchronize. Default is default notebook')
252 parser.add_argument('--logpath', '-l', action='store', help='Path to log file. Default is GeekNoteSync in home dir')
253
254 args = parser.parse_args()
255
256 path = args.path if args.path else None
257 mask = args.mask if args.mask else None
258 format = args.format if args.format else None
259 notebook = args.notebook if args.notebook else None
260 logpath = args.logpath if args.logpath else None
261
262 reset_logpath(logpath)
263
264 GNS = GNSync(notebook, path, mask, format)
265 GNS.sync()
266
267 except Exception, e:
268 logger.error(str(e));
269
270if __name__ == "__main__":
271 main()