Skip to content

Commit

Permalink
Merge branch 'release/0.5.1' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
djsudduth committed Jun 29, 2023
2 parents 6ab62e2 + 3fc4667 commit 6a6f9e8
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 37 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Exported note titles use Keep titles in conversion as best it can. In many cases
```bash
> python kim.py -c
```
if the note has no title or text in the body then the date will be used as default.

#### Overwriting or Skipping
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
Expand Down Expand Up @@ -138,13 +139,13 @@ KIM now supports importing markdown note files back into Keep using
```bash
> python kim.py -i
```
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.
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.

To add the path and desired labels for import in **settings.cfg**, add or update these two additional settings:
**input_path** = path to where the input md files are located. Windows users use forward slashes, e.g. -> c:/md-files/import
**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)

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

#### Combinations
Example: to export all achived notes, using content for blank note titles, with overwriting, preserving Keep label format and logseq style paragraphs in batch:
Expand Down Expand Up @@ -203,4 +204,10 @@ Refactored code to be more extensible for different import and export options
Added LogSeq switch to add bullets in exports to be more compatible
Added simple note import to Keep option
Removed microseconds from note create and update dates
Fixed null image crashing
Fixed null image crashing

## 0.5.1 Recent Changes
Fixed image overwrite if note has no title or text and using -c switch
Fixed error of markdown note imports if there are special characters within
Added create and update dates of markdown files to imported notes
Added option to update Keep notes to archive after conversion
2 changes: 1 addition & 1 deletion keep-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def main(argv):

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



Expand Down
58 changes: 25 additions & 33 deletions kim.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
import configparser
import click
import datetime
from os.path import join
from pathlib import Path
from dataclasses import dataclass
Expand Down Expand Up @@ -93,18 +94,15 @@ def __str__(self):
return self.msg


# This is a static class instance - not really necessary but saves a tiny bit of memory
# This is a singleton class instance - not really necessary but saves a tiny bit of memory
# Very useful for single connections and loading config files once
class Config:

_config = configparser.ConfigParser()
_configdict = {}

def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Config, cls).__new__(cls)
#cls.instance._config = configparser.ConfigParser()
#cls.instance._configdict = {}
cls.instance.__read()
cls.instance.__load()
return cls.instance
Expand Down Expand Up @@ -142,8 +140,6 @@ def get(self, key):

#All conversions to markdown are static methods
class Markdown:
#Note that the use of temporary %%% is because notes
# can have the same URL repeated and replace would fail
@staticmethod
def convert_urls(text):
# pylint: disable=anomalous-backslash-in-string
Expand All @@ -152,7 +148,8 @@ def convert_urls(text):
"|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",
text
)

#Note that the use of temporary %%% is because notes
# can have the same URL repeated and replace would fail
for url in urls:
text = text.replace(url,
"[" + url[:1] + "%%%" + url[2:] +
Expand Down Expand Up @@ -247,10 +244,7 @@ def set_token(self, keyring_reset, master_token):
def set_user(self, userid):
self._userid = userid


def login(self, pw, keyring_reset):

#self._userid = userid
try:
self._keepapi.login(self._userid, pw)
except:
Expand All @@ -261,7 +255,6 @@ def login(self, pw, keyring_reset):
self._securestorage.set_keyring(self._keep_token)
return self._keep_token


def resume(self):
self._keepapi.resume(self._userid, self._keep_token)

Expand All @@ -279,7 +272,13 @@ def findnotes(self, kquery, labels, archive_only):
def createnote(self, title, notetext):
self._note = self._keepapi.createNote(title, notetext)
return(None)


def appendnotes(self, kquery, append_text):
gnotes = self.findnotes(kquery, False, False)
for gnote in gnotes:
gnote.text += "\n\n" + append_text
self.keep_sync()
return(None)

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


def getmedia(self, blob):
try:
link = self._keepapi.getMediaLink(blob)
Expand Down Expand Up @@ -330,7 +328,6 @@ def check_file_exists(self, md_file, outpath, note_title, note_date):


class FileService:

def media_path (self):
outpath = Config().get("output_path").rstrip("/")
mediapath = outpath + "/" + Config().get("media_path").rstrip("/") + "/"
Expand All @@ -344,12 +341,10 @@ def inpath (self):
inpath = Config().get("input_path").rstrip("/") + "/"
return(inpath)


def create_path(self, path):
if not os.path.exists(path):
os.mkdir(path)


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


def download_file(self, file_url, file_name, file_path):
try:
data_file = file_path + file_name
Expand All @@ -378,7 +372,6 @@ def download_file(self, file_url, file_name, file_path):
raise

def set_file_extensions(self, data_file, file_name, file_path):

dest_path = file_path + file_name

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


def save_md_file(note, note_tags, note_date, overwrite, skip_existing):

try:

fs = FileService()

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


def keep_import_notes(keep):

def keep_import_notes(keep):
try:
dir_path = FileService().inpath()
in_labels = Config().get("input_labels").split(",")
for file in os.listdir(dir_path):
if os.path.isfile(dir_path + file) and file.endswith('.md'):
with open(dir_path + file, 'r') as md_file:
with open(dir_path + file, 'r', encoding="utf8") as md_file:
mod_time = datetime.datetime.fromtimestamp(
os.path.getmtime(dir_path + file)).strftime('%Y-%m-%d %H:%M:%S')
crt_time = datetime.datetime.fromtimestamp(
os.path.getctime(dir_path + file)).strftime('%Y-%m-%d %H:%M:%S')
data=md_file.read()
data += "\n\nCreated: " + crt_time + " - Updated: " + mod_time
print('Importing note:', file.replace('.md', '') + " from " + file)
keep.createnote(file.replace('.md', ''), data)
for in_label in in_labels:
Expand All @@ -469,7 +465,6 @@ def keep_import_notes(keep):


def keep_get_blobs(keep, note):

fs = FileService()
for idx, blob in enumerate(note.blobs):
note.blob_names[idx] = note.title + str(idx)
Expand All @@ -487,8 +482,6 @@ def keep_get_blobs(keep, note):


def keep_query_convert(keep, keepquery, opts):


try:
count = 0
ccnt = 0
Expand Down Expand Up @@ -526,7 +519,10 @@ def keep_query_convert(keep, keepquery, opts):

if note.title == '':
if opts.text_for_title:
note.title = re.sub('[' + re.escape(''.join(ILLEGAL_FILE_CHARS)) + ']', '', note.text[0:50]) #.replace(' ',''))
if note.text == '':
note.title = note_date
else:
note.title = re.sub('[' + re.escape(''.join(ILLEGAL_FILE_CHARS)) + ']', '', note.text[0:50]) #.replace(' ',''))
else:
note.title = note_date

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


if opts.logseq_style:
#Logseq test
note.text = "- " + note.text.replace("\n\n", "\n- ")
Expand Down Expand Up @@ -577,7 +572,6 @@ def keep_query_convert(keep, keepquery, opts):


def ui_login(keyring_reset, master_token):

try:
userid = Config().get("google_userid").strip().lower()

Expand Down Expand Up @@ -616,7 +610,6 @@ def ui_login(keyring_reset, master_token):


def ui_query(keep, search_term, opts):

try:
if search_term != None:
count = keep_query_convert(keep, search_term, opts)
Expand All @@ -642,7 +635,6 @@ def ui_query(keep, search_term, opts):

def ui_welcome_config():
try:

mp = Config().get("media_path")

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

try:

#i = True
opts = Options(o, a, p, s, c, l, i)

click.echo("\r\nWelcome to Keep it Markdown or KIM!\r\n")

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

keep = ui_login(r, master_token)

#i = True

if i:
keep_import_notes(keep)
else:
Expand All @@ -704,7 +696,7 @@ def main(r, o, a, p, s, c, l, i, search_term, master_token):
# raise Exception("Problem with markdown file creation: " + repr(e))


#Version 0.5.0
#Version 0.5.1

if __name__ == '__main__':

Expand Down

0 comments on commit 6a6f9e8

Please sign in to comment.