dotfiles/writing/papis/scripts/papis-marvin
Marty Oehme 85c152a07c
writing: Restructure module layout per-program
Similarly to the qutebrowser module we change the layout to have a
program name at the top-level and all required files for that specific
program within, whether they reside within .config, .local or anywhere
else.
We use dotter mappings to achieve this.
2024-09-18 16:43:15 +02:00

163 lines
4.3 KiB
Python
Executable file

#!/usr/bin/env python
# papis-short-help: Import iOS Marvin exported csv annotations
#
# This script can be used to import your highlights and notes from
# the iOS application 'Marvin Reader'. In the app, export your
# annotations as 'csv' format and then point the script to the
# resulting file.
# https://git.martyoeh.me/Marty/papis-marvin
import os
import sys
import re
import logging
from typing import Dict
import papis.api
import papis.pick
import papis.format
import papis.commands.edit
import papis.commands.list
import papis.commands.add
import papis.notes
import papis.config
import papis.database
import isbnlib
import papis.isbn
logger = logging.getLogger("marvin")
logger.setLevel(logging.DEBUG)
DEFAULT_CSV_PATH = "/home/marty/Nextcloud/Personal/Backups/Journal.csv"
def main(fpath, db):
with open(fpath) as f:
import csv
csv = csv.DictReader(f)
notes = get_all_annotations(db, csv)
write_to_files(notes)
def get_all_annotations(db, csv) -> Dict:
notes = {}
note_file = ""
for row in csv:
# switch to next book
if not is_same_book(row["Title"]):
doc = get_document(db, row["Author"], row["Title"])
if not doc:
continue
note_file = get_notefile(db, doc)
text = format_entry(row)
if note_file and text:
if note_file not in notes.keys():
notes[note_file] = []
notes[note_file].append(text)
return notes
def get_document(db, author, title):
res = query_document(db, author, title)
if not res:
add_to_database(author, title)
res = query_document(db, author, title)
if not res:
logger.warning(f"Nothing found for {author}: {title}.\nPlease create manually.")
return
return res
# TODO warn user/ let him pick with picker if multiple docs found
def query_document(db, author, title):
title = strip_string(title)
for query in [f"author:({author}) title:({title})"]:
print(f"query: {query}")
res = db.query(query)
if len(res) >= 1:
return res[0]
def add_to_database(author, title, confirm=True, edit=False):
logger.info(f"Searching - '{title} {author}'")
data = None
try:
data = papis.isbn.get_data(f"{title}")
except isbnlib.ISBNLibException as e:
logger.error(e)
else:
logger.warning(f"Found: {data}")
if data:
papis_data = papis.isbn.data_to_papis(data[0])
papis.commands.add.run([], data=papis_data, confirm=confirm, edit=edit)
def get_notefile(db, document) -> str | None:
if not document.has("notes"):
notes_name = papis.config.getstring("notes-name")
document["notes"] = papis.format.format(notes_name, document)
document.save()
db.update(document)
notes_path = os.path.join(str(document.get_main_folder()), document["notes"])
if not os.path.exists(notes_path):
# TODO reimplement logger: logger.debug("Creating '%s'", notes_path)
papis.notes.notes_path_ensured(document)
return notes_path
# TODO implement custom formatting (akin to pubs-extract)
def format_entry(row) -> str:
text = f"> {row['HighlightText']}"
if row["EntryText"]:
if text:
text += "\n"
else:
text = "> "
text += f"{row['EntryText']}"
return text
_old_title = ""
def is_same_book(title):
global _old_title
same = _old_title == title
_old_title = title
if same:
return True
return False
def write_to_files(notes: Dict):
# write to notes
for f, entries in notes.items():
if f:
with open(f, "a") as note:
logger.info(f"Editing {f}...")
num_added = 0
for entry in entries:
with open(f) as noteread:
if entry not in noteread.read():
note.write(f"{entry}\n\n")
num_added += 1
logger.info(f"Added {num_added} entries to it.")
strip_pattern = re.compile(r"([^\s\w]|_)+\w*")
def strip_string(title) -> str:
return strip_pattern.sub("", title)
if __name__ == "__main__":
# use argument passed to command as file or default file here
fpath = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_CSV_PATH
main(fpath, papis.database.get())