summaryrefslogtreecommitdiffstats
path: root/keep-to-markdown.py
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2023-10-05 19:44:11 -0500
committerToby Vincent <tobyv@tobyvin.dev>2023-10-06 13:44:49 -0500
commit8a94020c62d0e63112b5b56c98faab97e173c102 (patch)
treef65d73c2c6ca8d86ca4ae5795ac3958d2aefaebc /keep-to-markdown.py
Initial commit
Diffstat (limited to 'keep-to-markdown.py')
-rwxr-xr-xkeep-to-markdown.py198
1 files changed, 198 insertions, 0 deletions
diff --git a/keep-to-markdown.py b/keep-to-markdown.py
new file mode 100755
index 0000000..1ebe58e
--- /dev/null
+++ b/keep-to-markdown.py
@@ -0,0 +1,198 @@
+#!/bin/python
+
+import os
+import sys
+import platform
+import glob
+import json
+from datetime import datetime as dt
+from shutil import copy2 as cp
+import mimetypes
+import argparse
+
+
+def copy_file(file, path, notespath):
+ try:
+ cp(f'{path}{file}', os.path.join(notespath, 'resources'))
+ except FileNotFoundError:
+ print(f'File "{file}" not found in {path}')
+ return False
+ else:
+ return True
+
+# remove illegal chars for current OS
+def clean_title(title) -> str:
+ ostype = platform.system()
+ if ostype == 'Linux':
+ title = title.replace('/', '_')
+ elif ostype == 'Darwin':
+ title = title.replace(':', ' ')
+ title = title.replace('\\', '_').replace('/', '_').replace('|', '_')
+ elif ostype == 'Windows':
+ title = title.replace('\\', '_').replace('/', '_').replace('|', '_')
+ title = title.replace('<', '-').replace('>', '-').replace(':', ' ')
+ title = title.replace('?', '').replace('"', '').replace('*', '')
+ title = title.replace('\n', '')
+ return title
+
+def read_annotations(list) -> str:
+ annotations_list = '*Weblinks:*'
+ for entry in list:
+ if entry['source'] == 'WEBLINK':
+ title = entry['title']
+ url = entry['url']
+ annotations_list += f' [{title}]({url});'
+ return annotations_list
+
+def read_attachments(list, path, notespath) -> str:
+ attachments_list = '*Attachments:*\n'
+ for entry in list:
+ if 'image' in entry['mimetype']:
+ image = entry['filePath']
+ if copy_file(image, path, notespath) is False:
+ # If the file could not be found,
+ # it will be checked if the file can be found
+ # another file format.
+ # Google used '.jpeg' instead of '.jpg'
+ image_type = mimetypes.guess_type(f'{path}{image}')
+ types = mimetypes.guess_all_extensions(image_type[0])
+ for type in types:
+ if type in image:
+ image_name = image.replace(type, '')
+ for t in types:
+ if len(glob.glob(f'{path}{image_name}{t}')) > 0:
+ image = f'{image_name}{t}'
+ print(f'Found "{image}"')
+ copy_file(image, path, notespath)
+ respath = os.path.join('resources','')
+ attachments_list += f'![{image}]({respath}{image})\n'
+ return attachments_list
+
+def read_tasklist(list) -> str:
+ content_list = '*Tasklist:*\n'
+ for entry in list:
+ text = entry['text']
+ if entry['isChecked'] is True:
+ content_list += f'- [x] {text}\n'
+ else:
+ content_list += f'- [ ] {text}\n'
+ return content_list
+
+def format_tags(tags) -> str:
+ tag_list = 'tags:'
+ for tag in tags:
+ tag_list += f' {tag};'
+ return tag_list
+
+def read_write_notes(args):
+ path = args.i
+ conv_folders = args.t
+ jsonpath = os.path.join(path, '')
+ notes = glob.glob(f'{jsonpath}*.json')
+
+ for note in notes:
+ with open(note, 'r', encoding='utf-8') as jsonfile:
+ data = json.load(jsonfile)
+ timestamp = data['userEditedTimestampUsec']
+ tags = []
+ try:
+ tags = [label['name'] for label in data['labels']]
+ except KeyError:
+ print('No tags available.')
+
+ if timestamp == 0:
+ iso_datetime = dt.now().strftime('%Y%m%dT%H%M%S_edited')
+ else:
+ iso_datetime = dt.fromtimestamp(timestamp/1000000).strftime('%Y%m%dT%H%M%S')
+
+ # get filename by title
+ if data['title'] != '':
+ title = str(data['title'])
+ filename = clean_title(title)
+ if len(filename) > 100:
+ filename = filename[0:99]
+ else:
+ title = iso_datetime
+ filename = title
+
+ # create folders by tags
+ if conv_folders and len(tags):
+ subfolder = tags[0]
+ else:
+ subfolder = ''
+ notespath = os.path.join('notes', subfolder, '')
+
+ # check if filename exists
+ if os.path.exists(f'{notespath}{filename}.md'):
+ print(f'Existing file found: {notespath}{filename}.md')
+ # increment duplicate number, if already exists
+ dup_num = 1
+ while(os.path.exists(f'{notespath}{filename}({dup_num}).md')):
+ print(f'File "{notespath}{filename}({dup_num}).md" exists, increment number...')
+ dup_num = dup_num+1
+
+ filename = f'{filename}({dup_num})'
+ print(f'New filename: {filename}.md')
+
+ # create path to notes
+ if not os.path.exists(notespath):
+ os.makedirs(notespath)
+ os.makedirs(os.path.join(notespath, 'resources'))
+ print(f'Create tag and resources subfolder: {subfolder}')
+
+ # create Markdown file
+ print(f'Convert "{title}" to markdown file.')
+ with open(f'{notespath}{filename}.md', 'w', encoding='utf-8') as mdfile:
+ mdfile.write(f'---\n')
+ mdfile.write(f'title: {title}\n')
+ if (title != iso_datetime):
+ mdfile.write(f'date: {iso_datetime}\n')
+ # add tags
+ if(tags and not conv_folders):
+ mdfile.write(f'{format_tags(tags)}\n')
+ mdfile.write(f'---\n\n')
+ # add text content
+ try:
+ textContent = data['textContent']
+ mdfile.write(f'{textContent}\n\n')
+ except KeyError:
+ print('No text content available.')
+ # add tasklist
+ try:
+ tasklist = read_tasklist(data['listContent'])
+ mdfile.write(f'{tasklist}\n\n')
+ except KeyError:
+ print('No tasklist available.')
+ # add annotations
+ try:
+ annotations = read_annotations(data['annotations'])
+ mdfile.write(f'{annotations}')
+ except KeyError:
+ print('No annotations available.')
+ # add attachments
+ try:
+ attachments = read_attachments(data['attachments'], path, notespath)
+ mdfile.write(f'{attachments}')
+ except KeyError:
+ print('No attachments available.')
+
+def create_folder():
+ try:
+ workpath = os.path.join('notes', 'resources')
+ if not os.path.exists(workpath):
+ os.makedirs(workpath)
+ print('Create folder "notes" - home of markdown files.')
+ except OSError:
+ print('Creation of folders failed.')
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Converting Google Keep notes to markdown files.')
+ parser.add_argument('-i', metavar='PATH', required=True, help='The path to the Takeout folder.')
+ parser.add_argument('-t', action='store_true', help='Use folders instead of front-matter for tags.')
+ args = parser.parse_args()
+
+ create_folder()
+ try:
+ read_write_notes(args)
+ except IndexError:
+ print('Please enter a correct path!')