1
1
#!/usr/local/bin/python3
2
+ from typing import List , Dict
2
3
from argparse import ArgumentParser
3
4
from configparser import ConfigParser
4
5
from enum import Enum
9
10
import urllib .request
10
11
11
12
from gkeepapi import Keep , node
12
- from notion_client import Client
13
+ from notion_client import Client , errors
13
14
import time
14
15
15
16
@@ -67,7 +68,7 @@ def _parse(self, text: str):
67
68
self .add_chunk (c )
68
69
69
70
@property
70
- def chunks (self ) -> list [ dict ]:
71
+ def chunks (self ) -> List [ Dict ]:
71
72
return self ._chunks
72
73
73
74
def add_chunk (self , text : str , url : str = '' ):
@@ -101,7 +102,7 @@ def __init__(self, title: str, parent_id: str):
101
102
self ._parent_id = parent_id
102
103
self ._children = []
103
104
104
- def render (self ) -> dict :
105
+ def render (self ) -> Dict :
105
106
return {
106
107
"properties" : {
107
108
"title" : [{"text" : {"content" : self ._title }}]
@@ -114,20 +115,20 @@ def render(self) -> dict:
114
115
}
115
116
116
117
@property
117
- def parent (self ) -> dict :
118
+ def parent (self ) -> Dict :
118
119
return {
119
120
"type" : "page_id" ,
120
121
"page_id" : self ._parent_id
121
122
}
122
123
123
124
@property
124
- def properties (self ) -> dict :
125
+ def properties (self ) -> Dict :
125
126
return {
126
127
"title" : [{"text" : {"content" : self ._title }}]
127
128
}
128
129
129
130
@property
130
- def children (self ) -> dict :
131
+ def children (self ) -> Dict :
131
132
return self ._children
132
133
133
134
@property
@@ -254,7 +255,7 @@ def downloadFile(url, path):
254
255
urllib .request .urlretrieve (url , path )
255
256
256
257
257
- def parseBlock (p : str ) -> dict :
258
+ def parseBlock (p : str ) -> Dict :
258
259
"""Parses a line from a Keep Note into a Notion block type and text
259
260
260
261
Supported block types:
@@ -296,14 +297,14 @@ def parseTextToPage(text: str, page: Page):
296
297
page .add_text (block ['text' ], block ['type' ])
297
298
298
299
299
- def getNoteCategories (note : node .TopLevelNode ) -> list [str ]:
300
+ def getNoteCategories (note : node .TopLevelNode ) -> List [str ]:
300
301
categories = []
301
302
for label in note .labels .all ():
302
303
categories .append (label .name )
303
304
return categories
304
305
305
306
306
- def importPageWithCategories (notion : Client , note : node .TopLevelNode , root : Page , categories : dict [str , Page ]) -> Page :
307
+ def importPageWithCategories (notion : Client , note : node .TopLevelNode , root : Page , categories : Dict [str , Page ]) -> Page :
307
308
# Extract categories
308
309
rootName = root .title
309
310
cats = getNoteCategories (note )
@@ -362,8 +363,14 @@ def parseNote(note: node.TopLevelNode, page: Page, keep: Keep, config: Config):
362
363
363
364
def parseList (list : node .List , page : Page ):
364
365
item : node .ListItem
365
- for item in list .items : # type: node.ListItem
366
- page .add_todo (item .text , item .checked )
366
+ for item in list .items :
367
+ while item .text :
368
+ # Take the first 1500 characters or less, notion sets max todo length to 2000
369
+ # so we take 1500 to be safe in case of emojis which take more
370
+ chunk = item .text [:1500 ]
371
+ item .text = item .text [1500 :] if len (item .text ) > 1500 else ""
372
+ # Add a new to-do item with the chunk of text
373
+ page .add_todo (chunk , item .checked )
367
374
368
375
369
376
def url2uuid (url : str ) -> str :
@@ -425,19 +432,49 @@ def url2uuid(url: str) -> str:
425
432
gnotes = keep .all ()
426
433
427
434
i = 0
428
- for gnote in gnotes :
435
+ max_retries = 3 # Retry mechanism
436
+ retry_delay = 2
437
+ while i < 2056 :
438
+ gnote = gnotes [i ]
429
439
i += 1
430
- if isinstance (gnote , node .List ):
431
- if not config .import_todos :
432
- continue
433
- print (f'Importing TODO #{ i } : { gnote .title } ' )
434
- page = importPageWithCategories (notion , gnote , todos , categories )
435
- parseList (gnote , page )
436
- create_page (notion , page )
437
- else :
438
- if not config .import_notes :
439
- continue
440
- print (f'Importing note #{ i } : { gnote .title } ' )
441
- page = importPageWithCategories (notion , gnote , notes , categories )
442
- parseNote (gnote , page , keep , config )
443
- create_page (notion , page )
440
+ try :
441
+ if isinstance (gnote , node .List ):
442
+ if not config .import_todos :
443
+ continue
444
+ print (f'Importing TODO #{ i } : { gnote .title } ' )
445
+ page = importPageWithCategories (notion , gnote , todos , categories )
446
+ parseList (gnote , page )
447
+ create_page (notion , page )
448
+ else :
449
+ if not config .import_notes :
450
+ continue
451
+ print (f'Importing note #{ i } : { gnote .title } ' )
452
+ page = importPageWithCategories (notion , gnote , notes , categories )
453
+ parseNote (gnote , page , keep , config )
454
+ create_page (notion , page )
455
+ except errors .APIResponseError as e :
456
+ if e .code == 400 :
457
+ retries = 0
458
+ while retries < max_retries :
459
+ print (f"Retrying request after { retry_delay } seconds..." )
460
+ time .sleep (retry_delay )
461
+ try :
462
+ # Retry the request
463
+ if isinstance (gnote , node .List ):
464
+ page = importPageWithCategories (notion , gnote , todos , categories )
465
+ parseList (gnote , page )
466
+ create_page (notion , page )
467
+ else :
468
+ page = importPageWithCategories (notion , gnote , notes , categories )
469
+ parseNote (gnote , page , keep , config )
470
+ create_page (notion , page )
471
+ break # Exit the retry loop if successful
472
+ except errors .APIResponseError as e :
473
+ if e .code == 400 :
474
+ retries += 1
475
+ else :
476
+ raise # If the error is not a 400, raise it immediately
477
+ else :
478
+ raise # Raise the error if maximum retries are exceeded
479
+ else :
480
+ raise # If the error is not a 400, raise it immediately
0 commit comments