Skip to content

Instantly share code, notes, and snippets.

@terbo
Last active July 16, 2025 02:39
Show Gist options
  • Save terbo/f87a137a13af3d12806795c19fd796d8 to your computer and use it in GitHub Desktop.
Save terbo/f87a137a13af3d12806795c19fd796d8 to your computer and use it in GitHub Desktop.
# Original code from https://github.com/usememos/memos/issues/4425
# Imports google keep notes from a takeout into Memos (usememos.com)
# TODO: Add tags from labels/title [x]
# Add creation/update time [x]
# Import images
# Add HTML/Markdown
import os, requests, json
from datetime import datetime
# Konfiguration
MEMOS_API_URL = "http://localhost:5230/api/v1/memos" #correct url to your memos
AUTH_TOKEN = "" #memos api token
TAKEOUT_FOLDER = "/home/user/Downloads/Takeout/Keep/" #path to your backup
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Bearer {AUTH_TOKEN}"
}
# create notes from takeout files
def upload_takeout_notes():
memo_ids = []
for filename in os.listdir(TAKEOUT_FOLDER):
if filename.endswith(".json"):
filepath = os.path.join(TAKEOUT_FOLDER, filename)
with open(filepath, "r", encoding="utf-8") as file:
data = json.load(file)
text = data.get("textContent", "").strip()
timestamp_usec = data.get("createdTimestampUsec", 0)
edited_usec = data.get("userEditedTimestampUsec", 0)
labels = data.get('labels',[])
title = data.get('title','')
filepath = data.get("filePath", '')
is_pinned = data.get("isPinned", False) # Prüfe, ob die Notiz gepinnt ist
if timestamp_usec:
if labels:
labeltext = ''
for label in labels:
labeltext += '#' + label['name'].replace(' ','_').lower() + ' '
text += '\n\n' + labeltext
if title:
titletext = f'### {title}\n'
text = titletext + text
if text:
data_payload = {"content": text, "visibility": "PRIVATE", "pinned": is_pinned}
else: # FIX: image only post
continue
# data_payload = {"resources": [{'filename':filepath}], "visibility": "PRIVATE", "pinned": is_pinned}
response = requests.post(MEMOS_API_URL, headers=HEADERS, json=data_payload)
if response.status_code == 200:
memo_id = response.json().get("name", "").replace("memos/", "")
memo_ids.append((memo_id, timestamp_usec, edited_usec, is_pinned))
print(f"New Memo: {filename} (ID: {memo_id}, Pinned: {is_pinned})")
else:
print(f"Error: {filename}, Status: {response.status_code}, Antwort: {response.text}")
return memo_ids
# update notes with correct date and pinned status
def update_memo_dates(memo_ids):
for memo_id, timestamp_usec, update_usec, is_pinned in memo_ids:
iso_time = datetime.utcfromtimestamp(timestamp_usec / 1e6).isoformat() + "Z"
up_time = datetime.utcfromtimestamp(update_usec / 1e6).isoformat() + "Z"
update_url = f"{MEMOS_API_URL}/{memo_id}"
data = {
"name": f"memos/{memo_id}",
"create_time": iso_time,
"update_time": up_time,
"pinned": is_pinned
}
response = requests.patch(update_url, headers=HEADERS, json=data)
print(f"Update {memo_id}: {response.status_code} - {response.text}")
# Hauptlogik
memo_ids = upload_takeout_notes()
if memo_ids:
update_memo_dates(memo_ids)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment