- import os, json, datetime
-
- from dataclasses import dataclass
- from typing import List, Optional
-
- filepath = os.path.expanduser("~/Downloads/super-productivity-backup.json")
-
- with open(filepath) as f:
- data = json.loads(f.read())
-
- @dataclass
- class Task:
- id: str
- parent: Optional[str]
- title: str
- reminder: Optional[int]
- planned: Optional[int]
- tags: List[str]
- children: List[str]
- done: bool
-
- # reminder id to timestamp mapping
- reminders = {
- reminder["id"]: reminder["remindAt"] for reminder in data["reminders"]
- }
-
- # tag id to tag name mapping
- tags = {
- id: tag["title"] for id, tag in data["tag"]["entities"].items()
- }
-
- projects = {
- id: project["taskIds"] for id, project in data["project"]["entities"].items()
- }
-
- # task id to task object mapping
- tasks = {
- id: Task(
- id = id,
- parent = task["parentId"],
- title = task["title"],
- reminder = reminders[task["reminderId"]] if task["reminderId"] else None,
- planned = task["plannedAt"],
- tags = task["tagIds"],
- children = task["subTaskIds"],
- done = task["isDone"]
- ) for id, task in data["task"]["entities"].items()
- }
-
- # convert a task to org-mode according to its level
- def process_task(task: Task, level: int):
- asterisks = "*" * level
-
- tags_str = ":".join([tags[tag_id] for tag_id in task.tags])
- if tags_str:
- tags_str = f":{tags_str}:"
-
- status = "DONE" if task.done else "TODO"
-
- # print headline in a children aware way
- if task.children:
- total = len(task.children)
- done = sum(1 if task.done else 0 for task in (tasks[id] for id in task.children))
- print(f"{asterisks} {status} [{done}/{total}] {task.title} {tags_str}")
- else:
- print(f"{asterisks} {status} {task.title} {tags_str}")
-
- # print scheduled and deadline (if any)
- if task.planned:
- print(f"SCHEDULED: {timestamp_to_org(task.planned / 1000)} ", end="")
-
- if task.reminder:
- print(f"DEADLINE: {timestamp_to_org(task.reminder / 1000)}")
-
- print("")
- # now recursively handle all sub-tasks
- for child in task.children:
- process_task(tasks[child], level = level + 1)
-
-
- def timestamp_to_org(ts: int) -> str:
- return datetime.datetime.fromtimestamp(ts).strftime("<%Y-%m-%d %a %H:%M>")
-
- def main():
- # We start with iterating top-level tasks that have no parent
- for task in tasks.values():
- if task.parent == None:
- process_task(task, level = 1)
-
- # However if you prefer to start from Projects as top level headline instead,
- # Then comment out above part, and uncomment the below
- # for project, task_ids in projects.items():
- # print(f"* {project}\n")
- # for id in task_ids:
- # process_task(tasks[id], level = 2)
-
- main()