Created
March 24, 2024 10:42
-
-
Save DavideWiest/96c39de773cdee369c2d42298963dc10 to your computer and use it in GitHub Desktop.
Markdown Tasks to Taskpaper (Obsidian Tasks Syntax)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import glob | |
| import os | |
| import sys | |
| import re | |
| import urllib.parse | |
| # sorted by priority | |
| markdown_priorities = [ | |
| "highest", "high", "medium", "low", "lowest" | |
| ] | |
| use_tabs_as_indetation_primarily = True | |
| keep_indentation = True | |
| replace_tag_slash_with_dash = True | |
| date_as_due_else_date = True | |
| remove_insertion_strings = True | |
| replace_obsidian_links_with_url = True | |
| obsidian_vault_name = "V-1.2" | |
| obsidian_base_subdir = "K - Projektinhalte" | |
| obsidian_url = "obsidian://vault/" + urllib.parse.quote(obsidian_vault_name) + "/" + urllib.parse.quote(obsidian_base_subdir) | |
| remove_leftover_symbols = True | |
| def convert_md_to_taskpaper(fileContents, file_path): | |
| taskpaper = "" | |
| lines = fileContents.split("\n") | |
| for line in lines: | |
| # count indentation level | |
| if use_tabs_as_indetation_primarily: | |
| line = line.replace("\t", " ") | |
| indentation = line.count(" ") | |
| line = line.strip() | |
| print(indentation) | |
| if line.startswith("- ["): | |
| is_done = line[3] == "X" | |
| task = line[5:] | |
| task = task.strip() | |
| task = " ".join(task.split()) | |
| task = task.replace(":: ", "::") | |
| task = task.replace(" ::", "::") | |
| # remove insertion strings | |
| if remove_insertion_strings: | |
| task = re.sub(r"\{\{.*?\}\}", "", task) | |
| # replace obsidian links | |
| if replace_obsidian_links_with_url: | |
| task = task.replace("]]", f"]({obsidian_url})").replace("[[", "[") | |
| # replace priority | |
| for priority in markdown_priorities: | |
| task = task.replace(f"[priority::{priority}]", f"@priorty({markdown_priorities.index(priority)+1})") | |
| # replace date | |
| date = [i.split("::")[1].strip() for i in task.split(" ") if i.startswith("[due::") or i.startswith("[start::") or i.startswith("[scheduled::")] | |
| date = [i.replace("]", "") for i in date if i != ""] | |
| task = " ".join([i for i in task.split(" ") if not (i.startswith("[due::") or i.startswith("[start::") or i.startswith("[scheduled::") or i.startswith("[completion::]"))]) | |
| if date != []: | |
| if date_as_due_else_date: | |
| task += f" @due({date[0]})" | |
| else: | |
| task += f" @date({date[0]})" | |
| # replace tags | |
| tags = [i[1:] for i in task.split(" ") if i.startswith("#")] | |
| if replace_tag_slash_with_dash: | |
| tags = [i.replace("/", "-") for i in tags] | |
| task = " ".join([i for i in task.split(" ") if not i.startswith("#")]) | |
| for tag in tags: | |
| task += f" @{tag}" | |
| if is_done: | |
| task += " @done" | |
| # remove leftover symbols | |
| if remove_leftover_symbols: | |
| task = " " + task + " " | |
| for symbol in [":", ".", ",", ";", "-"]: | |
| task = task.replace(symbol, "") | |
| task = task.strip() | |
| if keep_indentation: | |
| indent = ("\t" if use_tabs_as_indetation_primarily else " ") * indentation | |
| else: | |
| indent = "" | |
| taskpaper += indent + "- " + task + "\n" | |
| else: | |
| taskpaper += line + "\n" | |
| return taskpaper | |
| def getFileTuples(fileOrFolder, outputLocation = None): | |
| path = fileOrFolder | |
| fileContents = [] | |
| if outputLocation is None: | |
| outputLocation = fileOrFolder | |
| if os.path.isfile(path): | |
| fileContents.append((path, open(path, "r", encoding="utf-8").read(), outputLocation.replace(".md", ".taskpaper"))) | |
| elif os.path.isdir(path): | |
| for filePath in glob.glob(os.path.join(path, "*.md")): | |
| file = os.path.basename(filePath) | |
| fileContents.append((filePath, open(filePath, "r", encoding="utf-8").read(), os.path.join(outputLocation, file.replace(".md", ".taskpaper")))) | |
| else: | |
| print("Please provide a valid file or folder as a command line argument.") | |
| sys.exit(1) | |
| return fileContents | |
| if __name__ == "__main__": | |
| # extract parameters file or folder | |
| # Check if a file or folder is provided as a command line argument | |
| if len(sys.argv) == 2: | |
| fileContents = getFileTuples(sys.argv[1]) | |
| elif len(sys.argv) > 2: | |
| fileContents = getFileTuples(sys.argv[1], sys.argv[2]) | |
| else: | |
| print("Please provide a file or folder as a command line argument.") | |
| sys.exit(1) | |
| for (filePath, fileContents, outputLocation) in fileContents: | |
| taskpaper = convert_md_to_taskpaper(fileContents, filePath) | |
| # Create directory if it doesn't exist | |
| if not os.path.exists(outputLocation.rsplit("/", 1)[0]): | |
| os.makedirs(outputLocation.rsplit("/", 1)[0]) | |
| # Write taskpaper to file | |
| with open(outputLocation, "w", encoding="utf-8") as f: | |
| f.write(taskpaper) | |
Author
Author
Configuration
markdown_priorities = ["highest", "high", "medium", "low", "lowest"]
use_tabs_as_indetation_primarily = True
keep_indentation = True
replace_tag_slash_with_dash = True
date_as_due_else_date = True
remove_insertion_strings = True
replace_obsidian_links_with_url = True
obsidian_vault_name = "MyVault"
obsidian_base_subdir = "Templates"
obsidian_url = "obsidian://vault/" + urllib.parse.quote(obsidian_vault_name) + "/" + urllib.parse.quote(obsidian_base_subdir)
remove_leftover_symbols = True
- if
replace_obsidian_links_with_url´ is set to true, it's recommended to changeobsidian_vault_nameandobsidian_base_subdir`
Author
Use Case
- Migrate from markdown tasks to taskpaper
- Migrate from markdown tasks to Todoist (over the taskbone integration)
- Migrate from obsidian tasks to Todoist (see 2.)
- Obsidian link conversion is supported
- Obsidian Tasks syntax conversion is fully supported
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Examples
python md_to_taskpaper.py myfile.md: Convert a single Markdown file (myfile.md) to TaskPaper (same directory)python md_to_taskpaper.py myfile.md output_folder: Convert a single Markdown file (myfile.md) to TaskPaper (different output directory)python md_to_taskpaper.py myfolder output_folder: Convert all Markdown files in a folder (myfolder) to TaskPaper (other directory)python md_to_taskpaper.py myfolder: Convert all Markdown files in a folder (myfolder) to TaskPaper (same directory)python md_to_taskpaper.py myfile.txt: Convert a non-standard Markdown file (myfile.txt) to TaskPaper (optionally add an output path)