From e9b8a77f4367d621f406b55fcb2b951197f9c4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B6rfelt?= Date: Mon, 21 Oct 2024 18:17:51 +0200 Subject: [PATCH] tiddlywiki: support single .tid files --- docs/formats/tiddlywiki.md | 11 ++++--- src/formats/tiddlywiki.py | 66 ++++++++++++++++++++++++++------------ test/data | 2 +- test/test_convert.py | 2 ++ 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/docs/formats/tiddlywiki.md b/docs/formats/tiddlywiki.md index 56992aca..17c287e7 100644 --- a/docs/formats/tiddlywiki.md +++ b/docs/formats/tiddlywiki.md @@ -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. diff --git a/src/formats/tiddlywiki.py b/src/formats/tiddlywiki.py index e3eba1bb..47a4b235 100644 --- a/src/formats/tiddlywiki.py +++ b/src/formats/tiddlywiki.py @@ -50,21 +50,21 @@ 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 ( @@ -72,10 +72,10 @@ def convert(self, file_or_folder: Path): 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 @@ -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) diff --git a/test/data b/test/data index e25dbd44..a5ebd459 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit e25dbd447fb611d0375f05231154fdfb3344a1aa +Subproject commit a5ebd459ff395a919375f0b3c3dbac9da8f931c7 diff --git a/test/test_convert.py b/test/test_convert.py index a82bf98d..2b9d4324 100644 --- a/test/test_convert.py +++ b/test/test_convert.py @@ -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"]],