Giter VIP home page Giter VIP logo

gkeep2notion's Introduction

Google Keep -> Notion

Exports notes and lists from Google Keep and imports them into your Notion.

Features

Supports exporting:

  • Notes
  • TODO lists
  • Images and audio (unsupported in recent Notion API versions, stay tuned for updates)
  • Categorization via labels

Installation

This script requires Python 3.9+, https://github.com/kiwiz/gkeepapi, https://github.com/ramnes/notion-sdk-py, and a couple more libraries to run. Install the pre-requisite libraries via Pip3:

pip3 install -r requirements.txt

Optional: make the script executable:

chmod +x gkeep2notion.py

Preventing "Authentication failed" on some systems


Running inside of a Docker Container

In order to use the gkeepapi dependency, you'll need to run it inside of a docker container that is compatible with it. Otherwise you'll most likely run into an "Authentication failed" error.

  1. Build the Docker Image
docker build -t gkeep2notion_image .
  1. Run the Docker Container
docker run -it --name gkeep2notion_container gkeep2notion_image /bin/bash
  1. Now you should be inside the container and the rest of the guide should work

On some systems the authentication fails even with valid credentials. This may happen because of three reasons:

  1. You have enabled 2FA on your account
  2. Google issues a CAPTCHA for your IP address
  3. SSL certificate validation fails.

To fix the 2FA problem:

You need to create an app specific password for the script.

  1. Go to https://myaccount.google.com/apppasswords
  2. Login to your account
  3. Under the Select the app and device you want to generate the app password for. section:
    1. Select Other(Custom name) from the Select app dropdown
    2. Enter some name like gkeep2notion and click on Generate button
    3. Copy password from the popup and click Done
  4. Use this copied password in your terminal when script prompts for password

To fix the CAPTCHA problem:

Try using the Unlock CAPTCHA link before retrying login.

To try fixing the SSL problem:*

Revert to an older version of the following library:

pip3 install requests==2.23.0

Configuration

Before use, copy config.example.ini to config.ini and edit its contents. See configuration explanation below:

[gkeep]
email[email protected] # Your Google account
import_notes=true # Set to false if you don't want to import notes
import_todos=true # Set to false if you don't want to import TODO lists
import_media=true # Set to false if you don't need to import images and audio

[notion]
token=Copy it from your Notion integratin # See documentation below
root_url=https://notion.so/PAGE-ID Create a root url in your Notion # See documentation below

Obtaining Notion token

The importer needs to access your Notion account and it needs to know the root URL in which to import all the Google Keep contents.

To get a Notion authentication token:

  1. Go to your Notion integrations
  2. Click "Create new integration"
  3. Enter any name, e.g. gkeep2notion. As per Integration type, choose Internal integration. In the Capabilities make sure this integration can Read, Update, and Insert content.
  4. After creating the integration copy the "Internal Integration Token" value to the token in your config.ini.

Configuring the root_url

This script imports all the content under a certain page in Notion that has to exist already. It is recommended to create a special page for the imported content, and then migrate it to your regular Notion structure from there.

  1. Create a new page in Notion e.g. "Google Keep import"
  2. Click on ••• button on top right of the page and select "Add Connections" (at the bottom) from the menu.
  3. Search for your integration name and select it. You should press "Confirm" on the dialog that will appear. This will make the page accessible to your integration.
  4. Copy the URL of the page in the address bar or use "Copy link" in the context menu of the navigation bar
  5. Paste that link to root_url in the config.ini.

Usage

Google authentication

The first time you run gkeep2notion it will ask for your Google Account's password to authenticate into your Google Keep account. After obtaining an authentication token, gkeep2notion saves it in your system's keyring. Next time you won't need to enter the password again.

Import everything

Note: export/import takes a considerable amount of time. Especially when working with notes containing media files. So you may want to try importing a subset of your records before importing everything.

By default gkeep2notion exports everything in your Google Keep account and imports it into Notion. It can be done as simple as:

./gkeep2notion.py

Google Keep search query

You can use the search function built into Google Keep to import notes matching a search query:

./gkeep2notion.py -q 'Orange apple'

Import specific labels

You can import notes and tasklists containing specific label(s) in Google Keep using the -l option.

An example with one label:

./gkeep2notion.py -l cooking

An example with multiple labels, comma separated:

./gkeep2notion.py -l 'work, business, management'

Credits

This tool uses the unofficial Google Keep API for Python by kiwiz. Google Keep is of course a registered trademark of Google and neither the API nor this script are affiliated with Google, Inc.

Thanks to ramnes for the unofficial Notion Python SDK. Neither that API nor this script are affiliated with Notion. Notion is a trademark of Notion Labs, Inc.

gkeep2notion's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

gkeep2notion's Issues

Authentication failed on MacOS

Hi, I am getting the following on my terminal every time I run the script:

Loading access token from keyring
Logging into Google Keep
Password: 
Authenticating, this may take a while...
Authentication failed
https://accounts.google.com/signin/continue?sarp=1&scc=1&continue=https://accounts.google.com/o/android/auth?hl%3Den_us%26xoauth_display_name%3DAndroid%2BLogin%2BService%26source%3DAndroid%2BLogin&plt=AKgnsbv2PzW992JO0Ygp_gcBHiGvEDnE2z169EY8XgaXv-SQCBWSEfd_w-4BdTVXtE2YzVwpZ8LuVKgOvFvGvM-j-vWrhHncj73BOQeoe6wjzhAJD4GOHl_1QRfj9b_Lyi-FPXVxUHfr

I am using python version: Python 3.10.6 and running it on MacOS Monterey version: 12.5.1

('NeedsBrowser', 'To access your account, you must sign in on the web. Touch Next to start browser sign-in.')

Getting the following error:

Loading access token from keyring
Logging into Google Keep
Password:
Authenticating, this may take a while...
Authentication failed
('NeedsBrowser', 'To access your account, you must sign in on the web. Touch Next to start browser sign-in.')

I had a working Google Keep export script from another Github project and it's also giving me the same error. Generated new app password code and tried that, same issue.

Root URL couldnt be found i guess

Logging into Notion
Traceback (most recent call last):
File "c:\Users\thush\Downloads\gkeep2notion-main\gkeep2notion.py", line 214, in
root = client.get_block(config.root_url)
File "C:\Python310\lib\site-packages\notion\client.py", line 169, in get_block
block = self.get_record_data("block", block_id, force_refresh=force_refresh)
File "C:\Python310\lib\site-packages\notion\client.py", line 162, in get_record_data
return self._store.get(table, id, force_refresh=force_refresh)
File "C:\Python310\lib\site-packages\notion\store.py", line 184, in get
self.call_load_page_chunk(id)
File "C:\Python310\lib\site-packages\notion\store.py", line 286, in call_load_page_chunk
recordmap = self._client.post("loadPageChunk", data).json()["recordMap"]
File "C:\Python310\lib\site-packages\notion\client.py", line 260, in post
raise HTTPError(
requests.exceptions.HTTPError: Invalid input.

Links are not converted properly

After switch from notion-client to notion-sdk the Markdown-based link formatting is gone. I'll need to figure out a replacement.

Authentication failed - MacOS - After following "Preventing "Authentication failed" on some systems" recommendations

Hi, thank you for your work!
I'm getting the following error after following the instructions.

Loading access token from keyring Logging into Google Keep Password: Authenticating, this may take a while... Authentication failed ('BadAuthentication', None)

The 'pip3 install -r requirements.txt' command leads to the following:
'ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
notion-sdk-py 0.0.1 requires chardet==4.0.0, but you have chardet 3.0.4 which is incompatible.
notion-sdk-py 0.0.1 requires requests==2.25.1, but you have requests 2.23.0 which is incompatible.
notion-sdk-py 0.0.1 requires urllib3==1.26.4, but you have urllib3 1.25.11 which is incompatible.
Successfully installed chardet-3.0.4 urllib3-1.25.11
WARNING: Skipping /usr/local/lib/python3.11/site-packages/certifi-2023.7.22-py3.11.egg-info due to invalid metadata entry 'name'
WARNING: Skipping /usr/local/lib/python3.11/site-packages/certifi-2023.7.22-py3.11.egg-info due to invalid metadata entry 'name''

So there might be a conflict in dependencies. However installing chardet==4.0.0, requests==2.25.1 and urllib3==1.26.4, doesn't fix it. The warning on certifi stays as well.

Aside from these, the solution concerning the CAPTCHA problem leads to a dead google link. I'm not certain why, can it be that CAPTCHA authentication is outdated for google accounts?

notion_client.errors.RequestTimeoutError: Request to Notion API has timed out

Notion is not longer allowing API usage outside their apps?

output:

D:\Program** Files\Python\gkeep2notion-main>gkeep2notion.py
Loading access token from keyring
Authorization, this may take a while...
Logging into Notion
Traceback (most recent call last):
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_exceptions.py", line 10, in map_exceptions
    yield
  File "D:\Program Files\Python39\lib\site-packages\httpcore\backends\sync.py", line 62, in start_tls
    raise exc
  File "D:\Program Files\Python39\lib\site-packages\httpcore\backends\sync.py", line 57, in start_tls
    sock = ssl_context.wrap_socket(
  File "D:\Program Files\Python39\lib\ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "D:\Program Files\Python39\lib\ssl.py", line 1040, in _create
    self.do_handshake()
  File "D:\Program Files\Python39\lib\ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
socket.timeout: _ssl.c:1112: The handshake operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Program Files\Python39\lib\site-packages\httpx\_transports\default.py", line 60, in map_httpcore_exceptions
    yield
  File "D:\Program Files\Python39\lib\site-packages\httpx\_transports\default.py", line 218, in handle_request
    resp = self._pool.handle_request(req)
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_sync\connection_pool.py", line 253, in handle_request
    raise exc
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_sync\connection_pool.py", line 237, in handle_request
    response = connection.handle_request(request)
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_sync\http_proxy.py", line 261, in handle_request
    connect_response = self._connection.handle_request(
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_sync\connection.py", line 86, in handle_request
    raise exc
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_sync\connection.py", line 63, in handle_request
    stream = self._connect(request)
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_sync\connection.py", line 150, in _connect
    stream = stream.start_tls(**kwargs)
  File "D:\Program Files\Python39\lib\site-packages\httpcore\backends\sync.py", line 62, in start_tls
    raise exc
  File "D:\Program Files\Python39\lib\contextlib.py", line 137, in __exit__
    self.gen.throw(typ, value, traceback)
  File "D:\Program Files\Python39\lib\site-packages\httpcore\_exceptions.py", line 14, in map_exceptions
    raise to_exc(exc)
httpcore.ConnectTimeout: _ssl.c:1112: The handshake operation timed out

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "D:\Program Files\Python39\lib\site-packages\notion_client\client.py", line 189, in request
    response = self.client.send(request)
  File "D:\Program Files\Python39\lib\site-packages\httpx\_client.py", line 908, in send
    response = self._send_handling_auth(
  File "D:\Program Files\Python39\lib\site-packages\httpx\_client.py", line 936, in _send_handling_auth
    response = self._send_handling_redirects(
  File "D:\Program Files\Python39\lib\site-packages\httpx\_client.py", line 973, in _send_handling_redirects
    response = self._send_single_request(request)
  File "D:\Program Files\Python39\lib\site-packages\httpx\_client.py", line 1009, in _send_single_request
    response = transport.handle_request(request)
  File "D:\Program Files\Python39\lib\site-packages\httpx\_transports\default.py", line 218, in handle_request
    resp = self._pool.handle_request(req)
  File "D:\Program Files\Python39\lib\contextlib.py", line 137, in __exit__
    self.gen.throw(typ, value, traceback)
  File "D:\Program Files\Python39\lib\site-packages\httpx\_transports\default.py", line 77, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.ConnectTimeout: _ssl.c:1112: The handshake operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Program Files\Python\gkeep2notion-main\gkeep2notion.py", line 372, in <module>
    create_page(notion, notes)
  File "D:\Program Files\Python\gkeep2notion-main\gkeep2notion.py", line 168, in create_page
    notion_page = notion.pages.create(parent=page.parent,
  File "D:\Program Files\Python39\lib\site-packages\notion_client\api_endpoints.py", line 197, in create
    return self.parent.request(
  File "D:\Program Files\Python39\lib\site-packages\notion_client\client.py", line 191, in request
    raise RequestTimeoutError()
notion_client.errors.RequestTimeoutError: Request to Notion API has timed out

body.children[9].bulleted_list_item.rich_text[0].text.content.length should be ≤ `2000`, instead was `2174`.

Hello!

First of all, thanks for developing this.

I have encountered this issue, after successfully importing 15 notes. Could you check it out? 🥺

Importing note #14:
Parsing 9 blocks
Importing note #15:
Parsing 3 blocks
Importing note #16:
Parsing 31 blocks
Traceback (most recent call last):
File "/Users/marinucs/Library/Python/3.11/lib/python/site-packages/notion_client/client.py", line 118, in _parse_response
response.raise_for_status()
File "/Users/marinucs/Library/Python/3.11/lib/python/site-packages/httpx/_models.py", line 749, in raise_for_status
raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://api.notion.com/v1/pages'
For more information check: https://httpstatuses.com/400

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/marinucs/Downloads/gkeep2notion/./gkeep2notion.py", line 440, in
create_page(notion, page)
File "/Users/marinucs/Downloads/gkeep2notion/./gkeep2notion.py", line 189, in create_page
notion_page = notion.pages.create(parent=page.parent,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/marinucs/Library/Python/3.11/lib/python/site-packages/notion_client/api_endpoints.py", line 199, in create
return self.parent.request(
^^^^^^^^^^^^^^^^^^^^
File "/Users/marinucs/Library/Python/3.11/lib/python/site-packages/notion_client/client.py", line 194, in request
return self._parse_response(response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/marinucs/Library/Python/3.11/lib/python/site-packages/notion_client/client.py", line 126, in _parse_response
raise APIResponseError(response, body["message"], code)
notion_client.errors.APIResponseError: body failed validation: body.children[9].bulleted_list_item.rich_text[0].text.content.length should be ≤ 2000, instead was 2174.

Error during export

Interface of Notion's share form doesn't allow to choose Integration as client.
So I create Global Web Share Link for Root page and specify it
https://rain-puppy-6dd.notion.site/Root-Page-ID

Script output:

Loading access token from keyring
Logging into Google Keep
Password:
Authenticating, this may take a while...
Authentication is successful, saving token in keyring
Token saved. Have fun with other commands!
Logging into Notion
Traceback (most recent call last):
  File "C:\Users\Sergey\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\notion_client\client.py", line 116, in _parse_response
    response.raise_for_status()
  File "C:\Users\Sergey\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\httpx\_models.py", line 749, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://api.notion.com/v1/pages'
For more information check: https://httpstatuses.com/400

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Sergey\Downloads\gkeep2notion-main\gkeep2notion-main\gkeep2notion.py", line 372, in <module>
    create_page(notion, notes)
  File "C:\Users\Sergey\Downloads\gkeep2notion-main\gkeep2notion-main\gkeep2notion.py", line 168, in create_page
    notion_page = notion.pages.create(parent=page.parent,
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Sergey\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\notion_client\api_endpoints.py", line 197, in create
    return self.parent.request(
           ^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Sergey\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\notion_client\client.py", line 192, in request
    return self._parse_response(response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Sergey\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\notion_client\client.py", line 124, in _parse_response
    raise APIResponseError(response, body["message"], code)
notion_client.errors.APIResponseError: body failed validation. Fix one:
body.parent.database_id should be defined, instead was `undefined`.
body.parent.page_id should be a valid uuid, instead was `""`.

Add an instruction for generating app password for google acc

I have 2-step verification in my google account so I was always getting an error "Authentication failed" even after applying both advises in 'Preventing "Authentication failed" on some systems' section.
I solved this issue by generating app password for google account using this instruction and putting generated password into script's prompt.
I think it might be good to add this advice to readme.

ModuleNotFoundError: No module named 'urllib3.packages.six.moves'

i did manage to get passed the part where i give it my password & it saves it, when i run the script again however, it doesnt seem to be running properly

Traceback (most recent call last):
  File "/Users/wisnet/Downloads/GKN/gkeep2notion-main/./gkeep2notion.py", line 11, in <module>
    from gkeepapi import Keep, node
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/gkeepapi/__init__.py", line 15, in <module>
    import gpsoauth
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/gpsoauth/__init__.py", line 9, in <module>
    import requests
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/requests/__init__.py", line 43, in <module>
    import urllib3
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/urllib3/__init__.py", line 7, in <module>
    from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/urllib3/connectionpool.py", line 11, in <module>
    from .exceptions import (
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/urllib3/exceptions.py", line 2, in <module>
    from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead
ModuleNotFoundError: No module named 'urllib3.packages.six.moves'

im on mac OS btw.

`notion_client.errors.APIResponseError: body failed validation`

I was following the README step by step and ended up the following error:

Traceback (most recent call last):
  File "/private/var/folders/nq/vxjjn3311fg4q263qsxrghpcpzgp66/T/tmp.H2EvgEH7/gkeep2notion/gkeep2notion.py", line 372, in <module>
    create_page(notion, notes)
  File "/private/var/folders/nq/vxjjn3311fg4q263qsxrghpcpzgp66/T/tmp.H2EvgEH7/gkeep2notion/gkeep2notion.py", line 168, in create_page
    notion_page = notion.pages.create(parent=page.parent,
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/notion_client/api_endpoints.py", line 199, in create
    return self.parent.request(
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/notion_client/client.py", line 194, in request
    return self._parse_response(response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/notion_client/client.py", line 126, in _parse_response
    raise APIResponseError(response, body["message"], code)
notion_client.errors.APIResponseError: body failed validation. Fix one:
body.parent.database_id should be defined, instead was `undefined`.
body.parent.page_id should be a valid uuid, instead was `""`.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.