Skip to content

Commit

Permalink
add support for tomboy-ng
Browse files Browse the repository at this point in the history
  • Loading branch information
marph91 committed Jun 24, 2024
1 parent 498740a commit 0ee9aa3
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/formats/tomboy_ng.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
- [Website](https://wiki.gnome.org/Apps/Tomboy/tomboy-ng)
- Typical extension: Folder with `.note` files

## Import to Joplin

Example:

- `jimmy-cli-linux ~/.local/share/tomboy-ng/ --format tomboy_ng`
- `jimmy-cli-linux tomboy-ng/5E74990A-E93E-4A11-AEA2-0814A37FEE1A.note --format tomboy_ng`

## Known limitations

- Note links are not exported.
- Multiple formats are not converted properly.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ nav:
- Tiddlywiki: formats/tiddlywiki.md
- Todo.txt: formats/todo.txt.md
- Todoist: formats/todoist.md
- Tomboy-ng: formats/tomboy_ng.md
- Toodledo: formats/toodledo.md
- xit: formats/xit.md
- Zoho Notebook: formats/zoho_notebook.md
Expand Down
97 changes: 97 additions & 0 deletions src/formats/tomboy_ng.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""Convert tomboy-ng notes to the intermediate format."""

from pathlib import Path
import logging
import xml.etree.ElementTree as ET # noqa: N817

import common
import converter
import intermediate_format as imf


LOGGER = logging.getLogger("jimmy")


class Converter(converter.BaseConverter):
accepted_extensions = [".note"]
accept_folder = True

def parse_content(self, node):
# TODO
# pylint: disable=too-many-branches

# https://stackoverflow.com/a/26870728
md_content = [node.text] if node.text is not None else []
for child_index, child in enumerate(node):
# match case doesn't work with fstrings
if child.tag.endswith("bold"):
md_content.append(f"**{child.text}**")
elif child.tag.endswith("highlight"):
md_content.append(child.text) # TODO
elif child.tag.endswith("italic"):
md_content.append(f"*{child.text}*")
elif child.tag.endswith("list"):
for item in child:
if item.tag.endswith("list-item"):
md_content.append(f"- {item.text}")
else:
LOGGER.warning(f"ignoring list tag {item.tag}")
elif child.tag.endswith("monospace"):
md_content.append(f"`{child.text}`")
elif child.tag.endswith("strikeout"):
md_content.append(f"~~{child.text}~~")
elif child.tag.endswith("underline"):
if child_index != 0:
# Don't put note title again in the note body.
md_content.append(f"++{child.text}++")
elif (
child.tag.endswith("small")
or child.tag.endswith("large")
or child.tag.endswith("huge")
):
md_content.append(child.text) # TODO
else:
LOGGER.warning(f"ignoring tag {child.tag}")
if child.tail is not None:
md_content.append(child.tail)
if node.tail is not None:
md_content.append(node.tail)
return "".join(md_content).strip()

def convert_note(self, note_file: Path):
# Format: https://wiki.gnome.org/Apps/Tomboy/NoteXmlFormat
root_node = ET.parse(note_file).getroot()

# There seems to be no simple solution of ignoring the namespace.
# So we need to use the wildcard always: https://stackoverflow.com/q/13412496
# TODO: are these tags or folders?
tags_element = root_node.find("{*}tags")
if tags_element is None:
tags = []
else:
tags = [tag.text for tag in tags_element.findall("{*}tag")]
if "system:template" in tags:
return # ignore templates

content = root_node.find("{*}text/{*}note-content")
body = self.parse_content(content)

note_data = {"body": body}
if (title := root_node.find("{*}title")) is not None:
note_data["title"] = title.text
else:
note_data["title"] = body.split("\n", 1)[0]
if (date_ := root_node.find("{*}create-date")) is not None:
note_data["user_created_time"] = common.iso_to_unix_ms(str(date_.text))
if (date_ := root_node.find("{*}last-change-date")) is not None:
note_data["user_updated_time"] = common.iso_to_unix_ms(str(date_.text))
self.root_notebook.child_notes.append(
imf.Note(note_data, tags=[imf.Tag({"title": tag}) for tag in tags])
)

def convert(self, file_or_folder: Path):
if file_or_folder.is_dir():
for note in file_or_folder.glob("*.note"):
self.convert_note(note)
else:
self.convert_note(file_or_folder)
1 change: 1 addition & 0 deletions test/example_commands.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ $EXECUTABLE "$CACHE/textbundle/example.textpack" --format textbundle
# $EXECUTABLE "$CACHE/tiddlywiki/tiddlyhost.json" --format tiddlywiki
$EXECUTABLE "$CACHE/todo_txt/examples_from_readme.txt" --format todo_txt
$EXECUTABLE "$CACHE/todoist/Privates.csv" --format todoist
$EXECUTABLE "$CACHE/tomboy-ng/tomboy-ng/" --format tomboy_ng
$EXECUTABLE "$CACHE/toodledo/toodledo_completed_240427.csv" --format toodledo
$EXECUTABLE "$CACHE/toodledo/toodledo_current_240427.csv" --format toodledo
$EXECUTABLE "$CACHE/toodledo/toodledo_notebook_240427.csv" --format toodledo
Expand Down

0 comments on commit 0ee9aa3

Please sign in to comment.