Skip to content

Commit

Permalink
tiddlywiki: support single .tid files
Browse files Browse the repository at this point in the history
  • Loading branch information
marph91 committed Oct 21, 2024
1 parent 84eb61b commit e9b8a77
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 26 deletions.
11 changes: 7 additions & 4 deletions docs/formats/tiddlywiki.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ This page describes how to convert notes from TiddlyWiki to Markdown.
## General Information

- [Website](https://tiddlywiki.com/)
- Typical extension: `.json`
- Typical extension: `.json` or `.tid`

## Instructions

1. Export as described [at the website](https://tiddlywiki.com/static/How%2520to%2520export%2520tiddlers.html)
1. Choose json export
1. Choose "JSON file" if you want to export the complete wiki
2. Choose "TID text file" if you want to export a single tiddler only. Resources and internal links won't be converted in this case.
2. [Install jimmy](../index.md#installation)
3. Convert to Markdown. Example: `jimmy-cli-linux tiddlers.json --format tiddlywiki`
3. Convert to Markdown. Examples:
1. `jimmy-cli-linux tiddlers.json --format tiddlywiki`
2. `jimmy-cli-linux tiddlers.tid --format tiddlywiki`
4. [Import to your app](../import_instructions.md)

## Known Limitations

Note content is in TiddlyWiki's [WikiText format](https://tiddlywiki.com/#WikiText). It is converted, but Markdown supports only a subset.
Note content is in TiddlyWiki's [WikiText format](https://tiddlywiki.com/#WikiText). It is converted, but Markdown supports only a subset. For example Javascript functions won't work in the converted Markdown anymore.
66 changes: 45 additions & 21 deletions src/formats/tiddlywiki.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,32 @@ def split_tags(tag_string: str) -> list[str]:


class Converter(converter.BaseConverter):
accepted_extensions = [".json"]
accepted_extensions = [".json", ".tid"]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# we need a resource folder to avoid writing files to the source folder
self.resource_folder = common.get_temp_folder()

def convert(self, file_or_folder: Path):
file_dict = json.loads(Path(file_or_folder).read_text(encoding="utf-8"))
for note_tiddlywiki in file_dict:
title = note_tiddlywiki["title"]
def convert_json(self, file_or_folder: Path):
file_dict = json.loads(file_or_folder.read_text(encoding="utf-8"))
for tiddler in file_dict:
title = tiddler["title"]
self.logger.debug(f'Converting note "{title}"')

resources = []
mime = note_tiddlywiki.get("type", "")
mime = tiddler.get("type", "")
if mime == "image/svg+xml":
continue # TODO
if (
mime.startswith("image/")
or mime == "application/pdf"
or mime == "audio/mp3"
):
if (text_base64 := note_tiddlywiki.get("text")) is not None:
if (text_base64 := tiddler.get("text")) is not None:
# Use the original filename if possible.
# TODO: Files with same name are replaced.
resource_title = note_tiddlywiki.get("alt-text")
resource_title = tiddler.get("alt-text")
temp_filename = self.resource_folder / (
common.unique_title()
if resource_title is None
Expand All @@ -84,33 +84,57 @@ def convert(self, file_or_folder: Path):
temp_filename.write_bytes(base64.b64decode(text_base64))
body = f"![{temp_filename.name}]({temp_filename})"
resources.append(imf.Resource(temp_filename, body, resource_title))
elif (source := note_tiddlywiki.get("source")) is not None:
elif (source := tiddler.get("source")) is not None:
body = f"![{title}]({source})"
elif (uri := note_tiddlywiki.get("_canonical_uri")) is not None:
elif (uri := tiddler.get("_canonical_uri")) is not None:
body = f"[{title}]({uri})"
else:
body = wikitext_to_md(note_tiddlywiki.get("text", ""))
body = wikitext_to_md(tiddler.get("text", ""))
self.logger.warning(f"Unhandled attachment type {mime}")
elif mime == "application/json":
body = "```\n" + note_tiddlywiki.get("text", "") + "\n```"
body = "```\n" + tiddler.get("text", "") + "\n```"
else:
body = wikitext_to_md(note_tiddlywiki.get("text", ""))
body = wikitext_to_md(tiddler.get("text", ""))

note_imf = imf.Note(
title,
body,
author=note_tiddlywiki.get("creator"),
author=tiddler.get("creator"),
source_application=self.format,
# Tags don't have a separate id. Just use the name as id.
tags=[
imf.Tag(tag) for tag in split_tags(note_tiddlywiki.get("tags", ""))
],
tags=[imf.Tag(tag) for tag in split_tags(tiddler.get("tags", ""))],
resources=resources,
)
if "created" in note_tiddlywiki:
note_imf.created = tiddlywiki_to_datetime(note_tiddlywiki["created"])
if "modified" in note_tiddlywiki:
note_imf.updated = tiddlywiki_to_datetime(note_tiddlywiki["modified"])
if "created" in tiddler:
note_imf.created = tiddlywiki_to_datetime(tiddler["created"])
if "modified" in tiddler:
note_imf.updated = tiddlywiki_to_datetime(tiddler["modified"])
if any(t.reference_id.startswith("$:/tags/") for t in note_imf.tags):
continue # skip notes with special tags
self.root_notebook.child_notes.append(note_imf)

def convert_tid(self, file_or_folder: Path):
tiddler = file_or_folder.read_text(encoding="utf-8")
metadata_raw, body_wikitext = tiddler.split("\n\n", maxsplit=1)

metadata = {}
for line in metadata_raw.split("\n"):
key, value = line.split(": ", 1)
metadata[key] = value

note_imf = imf.Note(
metadata["title"],
wikitext_to_md(body_wikitext),
author=metadata.get("creator"),
source_application=self.format,
tags=[imf.Tag(tag) for tag in split_tags(metadata.get("tags", ""))],
created=tiddlywiki_to_datetime(metadata["created"]),
updated=tiddlywiki_to_datetime(metadata["modified"]),
)
self.root_notebook.child_notes.append(note_imf)

def convert(self, file_or_folder: Path):
if file_or_folder.suffix == ".json":
self.convert_json(file_or_folder)
else: # ".tid"
self.convert_tid(file_or_folder)
2 changes: 2 additions & 0 deletions test/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ def compare_dirs(dir1: Path, dir2: Path):
[["textbundle/test_4/Textbundle Example v1.textbundle"]],
[["textbundle/test_5/Textbundle Example v2.textbundle"]],
# [["tiddlywiki/test_1/tiddlers.json"]],
[["tiddlywiki/test_2/Deserializers.tid"]],
[["tiddlywiki/test_3/Plugins.tid"]],
[["tomboy_ng/test_1/gnote"]],
[["tomboy_ng/test_2/tomboy-ng"]],
[["turtl/test_1/turtl-backup.json"]],
Expand Down

0 comments on commit e9b8a77

Please sign in to comment.