Files
verdande/tools/pak-noter-i-portioner.py
T

89 lines
3.2 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Pakker en Apple Noter-eksport i portioner, der kan importeres.
Eksporten af tolv hundrede noter fylder knap to hundrede megabyte, og næsten
alt sammen er billeder: teksten selv er under fire. Importen tager 64 MB ad
gangen, og tunnelen foran den tager mindre — så det skal deles.
Delt efter hvad en note *vejer med sine billeder*, ikke efter antal. De fleste
noter har ingen, så de fylder én portion til sammen; de få med et fotoalbum i
får hver deres. En note og dens billeder ligger altid i samme portion, for
linkene i teksten er relative, og en note, hvis billeder kom med i næste
portion, ville pege på ingenting.
./pak-noter-i-portioner.py ~/Desktop/apple-noter [MB]
"""
import os
import re
import sys
import zipfile
# Under importens 64 MB og under det, en tunnel plejer at tage. Hellere en
# portion mere end en, der ryger på målstregen.
DEFAULT_LIMIT_MB = 40
LINK = re.compile(r"!\[[^\]]*\]\((vedhaeftninger/[^)]+)\)")
def main() -> int:
src = os.path.expanduser(sys.argv[1] if len(sys.argv) > 1 else "~/Desktop/apple-noter")
limit = int(float(sys.argv[2] if len(sys.argv) > 2 else DEFAULT_LIMIT_MB) * 1024 * 1024)
out_dir = src.rstrip("/") + "-portioner"
os.makedirs(out_dir, exist_ok=True)
notes = sorted(f for f in os.listdir(src) if f.endswith(".md"))
if not notes:
print(f"Ingen .md-filer i {src}")
return 1
# Hvad hver note vejer, og hvad den trækker med sig.
weighed = []
for name in notes:
path = os.path.join(src, name)
text = open(path, encoding="utf-8", errors="replace").read()
files = []
size = os.path.getsize(path)
for rel in LINK.findall(text):
f = os.path.join(src, rel)
if os.path.exists(f):
files.append(rel)
size += os.path.getsize(f)
weighed.append((name, files, size))
# En note, der alene er større end grænsen, får sin egen portion frem for at
# blive sprunget over: den skal med, og en portion på 25 MB er stadig en, der
# kan sendes.
batches, current, current_size = [], [], 0
for item in weighed:
if current and current_size + item[2] > limit:
batches.append(current)
current, current_size = [], 0
current.append(item)
current_size += item[2]
if current:
batches.append(current)
print(f"{len(notes)} noter → {len(batches)} portioner\n")
for i, batch in enumerate(batches, start=1):
zip_path = os.path.join(out_dir, f"noter-{i:02d}.zip")
seen = set()
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as z:
for name, files, _ in batch:
z.write(os.path.join(src, name), name)
for rel in files:
if rel in seen:
continue
seen.add(rel)
z.write(os.path.join(src, rel), rel)
mb = os.path.getsize(zip_path) / 1024 / 1024
print(f" {os.path.basename(zip_path)} {len(batch):4d} noter {len(seen):3d} bilag {mb:6.1f} MB")
print(f"\nLigger i:\n {out_dir}")
print("\nImportér én ad gangen under Indstillinger → Data → Noter.")
return 0
if __name__ == "__main__":
sys.exit(main())