Skip to content

Instantly share code, notes, and snippets.

@m4rkk
Last active May 15, 2025 21:06
Show Gist options
  • Select an option

  • Save m4rkk/4ff0052c2572114ee5ea38a09f8ddc88 to your computer and use it in GitHub Desktop.

Select an option

Save m4rkk/4ff0052c2572114ee5ea38a09f8ddc88 to your computer and use it in GitHub Desktop.
Publish MarkDown document to a Notion page. I used ChatGPTExporter to export threads to .MD files manually; then post process with this to fix up code blocks and push it to Notion.
#!/usr/bin/env bash
#
# md2n.sh — Move MarkDown document into notion.
#
# DESCRIPTION:
# Preserves code blocks and provides a copy button on each block.
# Yaml blocks are suspect, so patch them up with pandoc.
#
# DEPENDENCIES:
# - Pandoc - tried and true document converter tool.
# - fix-yaml.lua; this simple lua parser is expected at ~/bin/fix-yaml.lua,
# it depends on pandoc to do the work once a block is identified.
# - Python - pushes to Notion.
# - API keys, Notion User Token V2, and parent page ID expected to be found
# in a .env file in your ~/secrets/notion_keys.env.
# - ChatGPTExport or some other tool to generate the MarkDown file from threads.
#
# USAGE:
# md2n.sh <markdown-file> [page-title]
#
# AUTHOR:
# m4rkk
#
set -euo pipefail
# Load environment variables from well-known locations
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/secrets}"
for envfile in "$PWD/.env" "$CONFIG_DIR/notion_keys.env"; do
if [ -f "$envfile" ]; then
echo "Loading environment from $envfile"
set -o allexport
# shellcheck disable=SC1091
source "$envfile"
set +o allexport
break
fi
done
usage() {
echo "Usage: $(basename "$0") <markdown-file> [page-title]"
exit 1
}
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
usage
fi
SRC="$1"
# Derive title from filename if not provided
title_param="${2:-}"
TITLE="${title_param:-$(basename "$SRC" .md)}"
TMP="$(mktemp /tmp/fixed.XXXXXX).md"
# Verify required environment variables
: "${NOTION_TOKEN_V2:?Environment variable NOTION_TOKEN_V2 must be set (or defined in .env)}"
: "${NOTION_PARENT_PAGE_ID:?Environment variable NOTION_PARENT_PAGE_ID must be set (or defined in .env)}"
# 1) Fix YAML fences
pandoc -f markdown -t gfm+yaml_metadata_block --lua-filter=$HOME/bin/fix-yaml.lua \
-o "$TMP" "$SRC"
# 2) Import into Notion with custom title
PARENT_URL="https://www.notion.so/${NOTION_PARENT_PAGE_ID}"
python3 - <<EOF
import os
from notion.client import NotionClient
from notion.block import PageBlock
from md2notion.upload import upload
token = os.environ['NOTION_TOKEN_V2']
parent_url = "$PARENT_URL"
title = "$TITLE"
file_path = "$TMP"
client = NotionClient(token_v2=token)
parent = client.get_block(parent_url)
# Create a new child page with the given title
new_page = parent.children.add_new(PageBlock, title=title)
# Upload markdown content into that new page
with open(file_path, "r", encoding="utf-8") as mdFile:
upload(mdFile, new_page)
EOF
# Clean up
echo -e "\nImported to Notion under parent ${NOTION_PARENT_PAGE_ID} with title \"${TITLE}\""
rm "$TMP"
-- fix-yaml.lua
-- Part of the md2n.sh solution to publish ChatGPT threads as Notion pages. See md2n.sh for details.
-- Author: m4rkk
function CodeBlock(el)
-- if it was a fenced block with no info-string…
if #el.classes == 0 then
-- and the first line looks like YAML key:value…
local first = el.text:match("([^\n]+)")
if first and first:match("^%s*[%w_%-]+%s*:%s*.+") then
return pandoc.CodeBlock(el.text, {class="yaml"})
end
end
return el
end
@m4rkk
Copy link
Copy Markdown
Author

m4rkk commented May 15, 2025

It's a little wonky - need to finish this when time permits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment