Skip to content

Instantly share code, notes, and snippets.

@felko
Last active May 2, 2020 20:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save felko/f71582747ea9bab8ef2f38e7730991b6 to your computer and use it in GitHub Desktop.
Save felko/f71582747ea9bab8ef2f38e7730991b6 to your computer and use it in GitHub Desktop.
Migrate neuron zettelkastens to the new hash ID format
#!/usr/bin/env python3.8
import re
import sys
import os
import uuid
from pathlib import Path
import glob
import time
import datetime
from collections import namedtuple
SRC_ZK, DEST_ZK = map(Path, sys.argv[1:])
Zettel = namedtuple('Zettel', ['id', 'date', 'content'])
SHORT_LINK = re.compile(r"<([A-Za-z-_0-9]+)>")
MARKDOWN_LINK = re.compile(r"\[([A-Z-a-z-_0-9]+)\]\(((?:z(?:cf)?).*?)\)")
# date-id => hash id
remap = {}
def generate_new_id():
zid = '0'
while zid.isdigit():
zid = str(uuid.uuid4())[:8]
return zid
def replace_links(md):
repl_short_link = lambda match: f"<{remap[match.group(1)]}>"
repl_markdown_link = lambda match: f"[{remap[match.group(1)]}]({match.group(2)})"
step1 = re.sub(SHORT_LINK, repl_short_link, md)
step2 = re.sub(MARKDOWN_LINK, repl_markdown_link, step1)
return step2
def migrate_zettel(zettel):
new_id = remap[zettel.id]
with (DEST_ZK / f"{new_id}.md").open('w') as file:
lines = replace_links(zettel.content).split('\n')
file.writelines('\n'.join(lines[:2]))
if zettel.date is not None:
file.write(f"\ndate: {zettel.date.strftime('%Y-%m-%d')}")
file.write('\n')
file.writelines('\n'.join(lines[2:]))
def make_zettel_from_path(path):
with (SRC_ZK / path).open() as file:
zid = path.stem
content = file.read()
# Extract date from ID
if re.match('\d{7}', zid):
date_id = zid[:4] + str(int(zid[4]) - 1)
date = datetime.datetime.strptime(date_id, "%y%W%w")
else:
date = None
return Zettel(zid, date, content)
def main():
zettels = []
for zettel_path in map(Path, glob.glob(str(SRC_ZK / f"[A-Za-z-_0-9]*.md"))):
zettel = make_zettel_from_path(zettel_path)
if zettel.date is not None:
remap[zettel.id] = generate_new_id()
else:
# Keep non-date IDs since they can be meaningful
remap[zettel.id] = zettel.id
print(f"{zettel.id:<10} => {remap[zettel.id]}")
zettels.append(zettel)
for zettel in zettels:
migrate_zettel(zettel)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment