From 8a94020c62d0e63112b5b56c98faab97e173c102 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Thu, 5 Oct 2023 19:44:11 -0500 Subject: Initial commit --- keep-to-markdown.py | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100755 keep-to-markdown.py (limited to 'keep-to-markdown.py') 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!') -- cgit v1.2.3-70-g09d2