Skip to content

Commit 6a6f9e8

Browse files
committed
Merge branch 'release/0.5.1' into main
2 parents 6ab62e2 + 3fc4667 commit 6a6f9e8

File tree

3 files changed

+36
-37
lines changed

3 files changed

+36
-37
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Exported note titles use Keep titles in conversion as best it can. In many cases
8989
```bash
9090
> python kim.py -c
9191
```
92+
if the note has no title or text in the body then the date will be used as default.
9293

9394
#### Overwriting or Skipping
9495
KIM by default does not overwrite markdown files when exporting, principally because Keep notes can have the same titles. KIM will try to rename duplicate notes. However, notes can be overwritten with
@@ -138,13 +139,13 @@ KIM now supports importing markdown note files back into Keep using
138139
```bash
139140
> python kim.py -i
140141
```
141-
There are a number of restrictions for importing. First, KIM will only import files within a single directory (no subdirectories) and they must have an .md extension. KIM does not support importing any media (images/audio) at this point. Additionally, KIM will not scan files for tags/labels or create new ones. Only existing labels can be used and those must be setup in the **settings.cfg** file.
142+
There are a number of restrictions for importing. First, KIM will only import files within a single directory (no subdirectories) and they must have an .md extension. KIM does not support importing any media (images/audio) at this point. Additionally, KIM will not scan files for tags/labels or create new ones. The file create date and update date will be appended to the note (**Windows users note** - if you copy markdown files to a new directory, the create date will reflect the current date rather than the file's original create date - unless you use Robocopy). Only existing labels can be used and those must be setup in the **settings.cfg** file.
142143

143144
To add the path and desired labels for import in **settings.cfg**, add or update these two additional settings:
144145
**input_path** = path to where the input md files are located. Windows users use forward slashes, e.g. -> c:/md-files/import
145146
**input_labels** = a list of one or more comma delimited labels without the # leading character - e.g. -> computers, programming (this will tag all of the imported notes with both labels 'computers' and 'programming' within that import directory as long as you have those labels predefined within Keep already)
146147

147-
NOTE: the import switch -i is incompatible with all other switches for export. Be sure to test simple import examples before using this feature!!!
148+
NOTE: the import switch -i is incompatible with all other switches for export. Be sure to test simple import examples before using this feature!!!
148149

149150
#### Combinations
150151
Example: to export all achived notes, using content for blank note titles, with overwriting, preserving Keep label format and logseq style paragraphs in batch:
@@ -203,4 +204,10 @@ Refactored code to be more extensible for different import and export options
203204
Added LogSeq switch to add bullets in exports to be more compatible
204205
Added simple note import to Keep option
205206
Removed microseconds from note create and update dates
206-
Fixed null image crashing
207+
Fixed null image crashing
208+
209+
## 0.5.1 Recent Changes
210+
Fixed image overwrite if note has no title or text and using -c switch
211+
Fixed error of markdown note imports if there are special characters within
212+
Added create and update dates of markdown files to imported notes
213+
Added option to update Keep notes to archive after conversion

keep-test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def main(argv):
6363

6464
except Exception as e:
6565
print (e)
66-
print ("Please start your browswer and copy-paste this URL in the address bar: https://accounts.google.com/DisplayUnlockCaptcha - then, try logging in again.")
66+
print ("Please start your browser and copy-paste this URL in the address bar: https://accounts.google.com/DisplayUnlockCaptcha - then, try logging in again.")
6767

6868

6969

kim.py

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import re
99
import configparser
1010
import click
11+
import datetime
1112
from os.path import join
1213
from pathlib import Path
1314
from dataclasses import dataclass
@@ -93,18 +94,15 @@ def __str__(self):
9394
return self.msg
9495

9596

96-
# This is a static class instance - not really necessary but saves a tiny bit of memory
97+
# This is a singleton class instance - not really necessary but saves a tiny bit of memory
9798
# Very useful for single connections and loading config files once
9899
class Config:
99-
100100
_config = configparser.ConfigParser()
101101
_configdict = {}
102102

103103
def __new__(cls):
104104
if not hasattr(cls, 'instance'):
105105
cls.instance = super(Config, cls).__new__(cls)
106-
#cls.instance._config = configparser.ConfigParser()
107-
#cls.instance._configdict = {}
108106
cls.instance.__read()
109107
cls.instance.__load()
110108
return cls.instance
@@ -142,8 +140,6 @@ def get(self, key):
142140

143141
#All conversions to markdown are static methods
144142
class Markdown:
145-
#Note that the use of temporary %%% is because notes
146-
# can have the same URL repeated and replace would fail
147143
@staticmethod
148144
def convert_urls(text):
149145
# pylint: disable=anomalous-backslash-in-string
@@ -152,7 +148,8 @@ def convert_urls(text):
152148
"|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",
153149
text
154150
)
155-
151+
#Note that the use of temporary %%% is because notes
152+
# can have the same URL repeated and replace would fail
156153
for url in urls:
157154
text = text.replace(url,
158155
"[" + url[:1] + "%%%" + url[2:] +
@@ -247,10 +244,7 @@ def set_token(self, keyring_reset, master_token):
247244
def set_user(self, userid):
248245
self._userid = userid
249246

250-
251247
def login(self, pw, keyring_reset):
252-
253-
#self._userid = userid
254248
try:
255249
self._keepapi.login(self._userid, pw)
256250
except:
@@ -261,7 +255,6 @@ def login(self, pw, keyring_reset):
261255
self._securestorage.set_keyring(self._keep_token)
262256
return self._keep_token
263257

264-
265258
def resume(self):
266259
self._keepapi.resume(self._userid, self._keep_token)
267260

@@ -279,7 +272,13 @@ def findnotes(self, kquery, labels, archive_only):
279272
def createnote(self, title, notetext):
280273
self._note = self._keepapi.createNote(title, notetext)
281274
return(None)
282-
275+
276+
def appendnotes(self, kquery, append_text):
277+
gnotes = self.findnotes(kquery, False, False)
278+
for gnote in gnotes:
279+
gnote.text += "\n\n" + append_text
280+
self.keep_sync()
281+
return(None)
283282

284283
def setnotelabel(self, label):
285284
try:
@@ -289,7 +288,6 @@ def setnotelabel(self, label):
289288
print('Label doesn\'t exist! - label: ' + label + " Use pre-defined labels when importing")
290289
raise
291290

292-
293291
def getmedia(self, blob):
294292
try:
295293
link = self._keepapi.getMediaLink(blob)
@@ -330,7 +328,6 @@ def check_file_exists(self, md_file, outpath, note_title, note_date):
330328

331329

332330
class FileService:
333-
334331
def media_path (self):
335332
outpath = Config().get("output_path").rstrip("/")
336333
mediapath = outpath + "/" + Config().get("media_path").rstrip("/") + "/"
@@ -344,12 +341,10 @@ def inpath (self):
344341
inpath = Config().get("input_path").rstrip("/") + "/"
345342
return(inpath)
346343

347-
348344
def create_path(self, path):
349345
if not os.path.exists(path):
350346
os.mkdir(path)
351347

352-
353348
def write_file(self, file_name, data):
354349
try:
355350
f = open(file_name, "w+", encoding='utf-8', errors="ignore")
@@ -358,7 +353,6 @@ def write_file(self, file_name, data):
358353
except Exception as e:
359354
raise Exception("Error in write_file: " + " -- " + TECH_ERR + repr(e))
360355

361-
362356
def download_file(self, file_url, file_name, file_path):
363357
try:
364358
data_file = file_path + file_name
@@ -378,7 +372,6 @@ def download_file(self, file_url, file_name, file_path):
378372
raise
379373

380374
def set_file_extensions(self, data_file, file_name, file_path):
381-
382375
dest_path = file_path + file_name
383376

384377
if imghdr.what(data_file) == 'png':
@@ -408,9 +401,7 @@ def set_file_extensions(self, data_file, file_name, file_path):
408401

409402

410403
def save_md_file(note, note_tags, note_date, overwrite, skip_existing):
411-
412404
try:
413-
414405
fs = FileService()
415406

416407
md_text = Markdown().format_check_boxes(note.text)
@@ -449,15 +440,20 @@ def save_md_file(note, note_tags, note_date, overwrite, skip_existing):
449440
raise Exception("Problem with markdown file creation: " + str(md_file) + " -- " + TECH_ERR + repr(e))
450441

451442

452-
def keep_import_notes(keep):
453443

444+
def keep_import_notes(keep):
454445
try:
455446
dir_path = FileService().inpath()
456447
in_labels = Config().get("input_labels").split(",")
457448
for file in os.listdir(dir_path):
458449
if os.path.isfile(dir_path + file) and file.endswith('.md'):
459-
with open(dir_path + file, 'r') as md_file:
450+
with open(dir_path + file, 'r', encoding="utf8") as md_file:
451+
mod_time = datetime.datetime.fromtimestamp(
452+
os.path.getmtime(dir_path + file)).strftime('%Y-%m-%d %H:%M:%S')
453+
crt_time = datetime.datetime.fromtimestamp(
454+
os.path.getctime(dir_path + file)).strftime('%Y-%m-%d %H:%M:%S')
460455
data=md_file.read()
456+
data += "\n\nCreated: " + crt_time + " - Updated: " + mod_time
461457
print('Importing note:', file.replace('.md', '') + " from " + file)
462458
keep.createnote(file.replace('.md', ''), data)
463459
for in_label in in_labels:
@@ -469,7 +465,6 @@ def keep_import_notes(keep):
469465

470466

471467
def keep_get_blobs(keep, note):
472-
473468
fs = FileService()
474469
for idx, blob in enumerate(note.blobs):
475470
note.blob_names[idx] = note.title + str(idx)
@@ -487,8 +482,6 @@ def keep_get_blobs(keep, note):
487482

488483

489484
def keep_query_convert(keep, keepquery, opts):
490-
491-
492485
try:
493486
count = 0
494487
ccnt = 0
@@ -526,7 +519,10 @@ def keep_query_convert(keep, keepquery, opts):
526519

527520
if note.title == '':
528521
if opts.text_for_title:
529-
note.title = re.sub('[' + re.escape(''.join(ILLEGAL_FILE_CHARS)) + ']', '', note.text[0:50]) #.replace(' ',''))
522+
if note.text == '':
523+
note.title = note_date
524+
else:
525+
note.title = re.sub('[' + re.escape(''.join(ILLEGAL_FILE_CHARS)) + ']', '', note.text[0:50]) #.replace(' ',''))
530526
else:
531527
note.title = note_date
532528

@@ -543,7 +539,6 @@ def keep_query_convert(keep, keepquery, opts):
543539
note_labels = note_labels + " #" + str(label).replace(' ', '-').replace('&', 'and')
544540
note_labels = re.sub('[' + re.escape(''.join(ILLEGAL_TAG_CHARS)) + ']', '-', note_labels) #re.sub('[^A-z0-9-_# ]', '-', note_labels)
545541

546-
547542
if opts.logseq_style:
548543
#Logseq test
549544
note.text = "- " + note.text.replace("\n\n", "\n- ")
@@ -577,7 +572,6 @@ def keep_query_convert(keep, keepquery, opts):
577572

578573

579574
def ui_login(keyring_reset, master_token):
580-
581575
try:
582576
userid = Config().get("google_userid").strip().lower()
583577

@@ -616,7 +610,6 @@ def ui_login(keyring_reset, master_token):
616610

617611

618612
def ui_query(keep, search_term, opts):
619-
620613
try:
621614
if search_term != None:
622615
count = keep_query_convert(keep, search_term, opts)
@@ -642,7 +635,6 @@ def ui_query(keep, search_term, opts):
642635

643636
def ui_welcome_config():
644637
try:
645-
646638
mp = Config().get("media_path")
647639

648640
if ((":" in mp) or (mp[0] == '/')):
@@ -676,8 +668,8 @@ def main(r, o, a, p, s, c, l, i, search_term, master_token):
676668

677669
try:
678670

671+
#i = True
679672
opts = Options(o, a, p, s, c, l, i)
680-
681673
click.echo("\r\nWelcome to Keep it Markdown or KIM!\r\n")
682674

683675
if i and (r or o or a or s or p or c):
@@ -692,7 +684,7 @@ def main(r, o, a, p, s, c, l, i, search_term, master_token):
692684

693685
keep = ui_login(r, master_token)
694686

695-
#i = True
687+
696688
if i:
697689
keep_import_notes(keep)
698690
else:
@@ -704,7 +696,7 @@ def main(r, o, a, p, s, c, l, i, search_term, master_token):
704696
# raise Exception("Problem with markdown file creation: " + repr(e))
705697

706698

707-
#Version 0.5.0
699+
#Version 0.5.1
708700

709701
if __name__ == '__main__':
710702

0 commit comments

Comments
 (0)