-
-
Save jhonasn/479f28360041834a064163352d06e9fc to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3 | |
# from pdb import set_trace as bkp | |
from sys import argv, exit | |
from os import listdir, path, mkdir, utime | |
from json import loads as to_dict | |
from datetime import datetime as date | |
if '-h' in argv or '--help' in argv: | |
print(''' | |
The commands will print those informations on notes: | |
-a all | |
-p pinned | |
-c note color | |
-l labels (it will print only when there's more than one) | |
-le last edit date | |
-s people who the note is shared with | |
None will be printed by default | |
''') | |
exit() | |
is_printing = { | |
'pinned': '-a' in argv or '-p' in argv, | |
'color': '-a' in argv or '-c' in argv, | |
'labels': '-a' in argv or '-l' in argv, | |
'last-edit': '-a' in argv or '-c' in argv, | |
'shared': '-a' in argv or '-c' in argv, | |
'none': len(argv) == 1 | |
} | |
keep_dir = './Keep' | |
labels_file = 'Labels.txt' | |
nextcloud_dir = './nextcloud-notes' | |
if not path.exists(keep_dir): | |
print('"Keep" folder not found. Place this file on the same folder as "Keep" backup folder') | |
exit() | |
# get labels to create folders with the labels names | |
with open(path.join(keep_dir, labels_file), 'a+') as f: | |
f.seek(0) | |
labels = f.read().split('\n') | |
if len(labels): labels.pop() | |
labels.append('trash') | |
labels.append('archived') | |
# read files and separate the note jsons from attachments | |
files = listdir(keep_dir) | |
notes = list(filter(lambda f: '.json' in f, files)) | |
attachments = list(filter(lambda f: '.json' not in f and '.html' not in f and f != labels_file, files)) | |
print('{} notes found\n\n'.format(len(notes))) | |
def fix_filename(filename): | |
new_name = filename | |
for char in ['<', '>', ':', '"', '/', '\\', '|', '?', '*']: | |
new_name = new_name.replace(char, '-') | |
return new_name | |
# create nextcloud and label folders | |
if not path.exists(nextcloud_dir): | |
mkdir(nextcloud_dir) | |
print('created nextcloud folder') | |
for label in labels: | |
label_dir = path.join(nextcloud_dir, fix_filename(label)) | |
if not path.exists(label_dir): | |
mkdir(label_dir) | |
print('created "{}" folder inside nextcloud folder'.format(label_dir)) | |
# create notes | |
for note_file in notes: | |
# if note_file == 'file-to-debug.json': bkp() | |
print('processing note "{}"'.format(note_file)) | |
note = to_dict(open(path.join(keep_dir, note_file), encoding='utf-8').read()) | |
text = '' | |
note_labels = [] | |
# simplify labels array | |
if 'labels' in note: | |
for l in note['labels']: | |
note_labels.append(l['name']) | |
# create note body | |
if note['title']: text += '# ' + note['title'] + '\n' | |
if is_printing['pinned'] and note['isPinned']: text += '**PINNED**\n\n' | |
elif note['title']: text += '\n' | |
# | |
# create note content | |
# | |
if 'textContent' in note: text += note['textContent'] | |
elif 'listContent' in note: | |
# print MD list | |
for item in note['listContent']: | |
text += '- [{}] {}\n'.format('x' if item['isChecked'] else ' ', item['text']) | |
# attachments | |
if 'attachments' in note: | |
for a in note['attachments']: | |
text += '\n'.format(a['filePath']) | |
is_space_added = False | |
# add space before last information if it isn't added yet | |
def add_space(): | |
global is_space_added | |
global text | |
if not is_space_added: | |
text += '\n' | |
is_space_added = True | |
# print color | |
if is_printing['color'] and ('color' in note and note['color'] != 'DEFAULT'): | |
add_space() | |
text += '\ncolor: ' + note['color'] | |
# print label when it has more than one | |
if is_printing['labels'] and len(note_labels) > 1: | |
add_space() | |
text += '\nlabels: ' + str(note_labels)[1:len(str(note_labels))-1].replace('\'', '') | |
# print last edit time | |
if is_printing['last-edit']: | |
add_space() | |
timestamp = int(int(note['userEditedTimestampUsec']) / 1000 / 1000) | |
date_str = date.utcfromtimestamp(timestamp).strftime('%d %B %Y %H:%M:%S') | |
text += '\nlast edit: {}'.format(date_str) | |
# print if is shared | |
if is_printing['shared'] and 'sharees' in note: | |
add_space() | |
text += 'shared with: ' | |
for u in note['sharees']: | |
text += '{} {}'.format(u['email'], 'is the owner\n' if u['isOwner'] else '') | |
# | |
# end note content creation | |
# | |
# decide path | |
path_name = '' | |
if len(note_labels): path_name = fix_filename(note_labels[0]) | |
if note['isArchived']: path_name = 'archived' | |
elif note['isTrashed']: path_name = 'trash' | |
# create note | |
fname = '{}.{}'.format(note_file[0:len(note_file)-5], 'md') | |
with open(path.join(nextcloud_dir, path_name, fname), 'w', encoding='utf-8') as f: | |
# use the original modification time for the new file | |
original_mod_time = path.getmtime(path.join(keep_dir, note_file)) | |
utime(path.join(nextcloud_dir, path_name, fname), (original_mod_time, original_mod_time)) | |
f.write(text) | |
print('note created inside "{}" folder\n'.format(path_name or 'nextcloud')) | |
print('\nAll notes converted and placed into {} folder'.format(nextcloud_dir)) |
Hello Mageek627 thanks for the suggestions, I'm very happy that this was useful for someone!
I will pick your first suggestion, I'm not using the script in the moment too so i will change it and commit for the next one who will use it, if there's a problem i hope the people notify me.
Thanks man!
Just wanted to say thanks for providing this. Seems to have worked perfectly to convert, now I just need to import the resulting files into nextcloud.
Many thanks for this, very useful. I hit errors to do with Unicode character mapping e.g.:
UnicodeEncodeError: 'charmap' codec can't encode character '\u200b' in position 1: character maps to <undefined>
So I changed line 149 from:
f = open(path.join(nextcloud_dir, path_name, fname), 'w')
to:
f = open(path.join(nextcloud_dir, path_name, fname), 'w', encoding="utf-8")
I know, hardcoding character for an environment is wrong but I figured this would be okay for a one-off conversion.
Just wanted to say thanks for providing this. Seems to have worked perfectly to convert, now I just need to import the resulting files into nextcloud.
I'm very glad that this had helped you! :)
Many thanks for this, very useful. I hit errors to do with Unicode character mapping e.g.:
UnicodeEncodeError: 'charmap' codec can't encode character '\u200b' in position 1: character maps to <undefined>
So I changed line 149 from:
f = open(path.join(nextcloud_dir, path_name, fname), 'w')
to:
f = open(path.join(nextcloud_dir, path_name, fname), 'w', encoding="utf-8")
I know, hardcoding character for an environment is wrong but I figured this would be okay for a one-off conversion.
thanks for the suggestion, i'll implement here, i'm very glad that this helped you!
Thanks for this useful script.
This small change sets the file modification time so it matches the original Google file. I find this helpful as then the Notes app can sort by date.
Line 5:
from os import listdir, path, mkdir, utime
Insert at line 153:
# use the original modification time for the new file
original_mod_time = path.getmtime(path.join(keep_dir, note_file))
utime(path.join(nextcloud_dir, path_name, fname), (original_mod_time, original_mod_time))
Thanks for this useful script.
This small change sets the file modification time so it matches the original Google file. I find this helpful as then the Notes app can sort by date.
Line 5:
from os import listdir, path, mkdir, utime
Insert at line 153:
# use the original modification time for the new file
original_mod_time = path.getmtime(path.join(keep_dir, note_file))
utime(path.join(nextcloud_dir, path_name, fname), (original_mod_time, original_mod_time))
You're welcome, thanks for the suggestion i'll make it right now
The utime
call needs to follow the f.close()
statement. Otherwise, the close call will update the modification time to the current time. :)
The
utime
call needs to follow thef.close()
statement. Otherwise, the close call will update the modification time to the current time. :)
man, there's a lot of time that I don't put my hands on this, can you send me an example for me to update the script?
does anyone have an idea how to extend this ingenious script so that the german umlauts (ä, ö, ü, ß) are converted correctly?
EDIT: ok it was easier than I thought
Line 77:
From: note = to_dict(open(path.join(keep_dir, note_file)).read())
to this: note = to_dict(open(path.join(keep_dir, note_file), encoding='utf-8').read())
updated line 77 as @Expello mentioned
This is very useful! Thanks a lot.
I would suggest a small improvement, in my case I didn't have any label, and so the file "Labels.txt" didn't exist, which resulted in "FileNotFoundError". I think line 41 should be replaced by:
Or alternatively, replace line 41 and 42 with:
I didn't thoroughly test it, but it seems to work fine like that.