diff --git a/export_todoist.py b/export_todoist.py index 5938a85..735663e 100644 --- a/export_todoist.py +++ b/export_todoist.py @@ -9,6 +9,7 @@ from todoist_api_python.api import TodoistAPI from jinja2 import Environment, FileSystemLoader, select_autoescape ATTACHMENTS_DIR = "attachments" +TODOIST_API_TOKEN: str | None = None def usage(): @@ -38,19 +39,66 @@ def ensure_attachments_dir(): os.makedirs(ATTACHMENTS_DIR) +def _file_looks_like_html(path): + try: + with open(path, 'rb') as handle: + prefix = handle.read(256) + except OSError: + return False + if not prefix: + return True + snippet = prefix.lstrip().lower() + return snippet.startswith(b"Todoist Backup - {{ date }}

Todoist Backup ({{ date }})

- + + {% macro render_task(task, level=0) %} +
+ {{ task.content | markdown | safe }}
+ {% if task.description %} +
{{ task.description | markdown | safe }}
+ {% endif %} + + {% set meta_fields = [] %} + {% if task.id is not none %} + {% set _ = meta_fields.append('ID: ' ~ task.id) %} + {% endif %} + {% if task.due and task.due.date %} + {% set due_dt = task.due.date %} + {% if due_dt.__class__.__name__ == 'datetime' or due_dt.__class__.__name__ == 'date' %} + {% set due_fmt = due_dt.strftime('%Y-%m-%d') %} + {% else %} + {% set due_str = due_dt|string %} + {% if 'T' in due_str %} + {% set due_fmt = due_str[:10] %} + {% else %} + {% set due_fmt = due_str %} + {% endif %} + {% endif %} + {% set _ = meta_fields.append('Due: ' ~ due_fmt) %} + {% endif %} + {% if task.due and task.due.is_recurring %} + {% if task.due.string %} + {% set _ = meta_fields.append('Recurring: ' ~ task.due.string) %} + {% endif %} + {% endif %} + {% if task.priority is not none %} + {% set _ = meta_fields.append('Priority: ' ~ task.priority) %} + {% endif %} + {{ meta_fields|join(' | ') }} +
+ {% if task.attachments %} +
+ Attachments: + +
+ {% endif %} + {% if task.comments %} +
+ Comments: + +
+ {% endif %} + {% if task.subtasks %} +
+ {% for child in task.subtasks %} + {{ render_task(child, level + 1) }} + {% endfor %} +
+ {% endif %} +
+ {% endmacro %} + + {% for project in projects %}

{{ project.name }} {% if project.is_archived %}[Archived]{% endif %}

ID: {{ project.id }} | Color: {{ project.color }} | Created: {{ project.created_at }}
+

Active Tasks

{% for task in project.tasks %} -
-
{{ task.content | markdown | safe }}
+ {{ render_task(task, 0) }} + {% else %} +

No active tasks.

+ {% endfor %} +
+ +

Completed Tasks

+
+ {% for task in project.completed_tasks %} +
+ {{ task.content | markdown | safe }}
{% if task.description %} -
{{ task.description | markdown | safe }}
+
{{ task.description | markdown | safe }}
{% endif %} -
+ {% set meta_fields = [] %} {% if task.id is not none %} {% set _ = meta_fields.append('ID: ' ~ task.id) %} @@ -72,66 +177,6 @@ {% if task.priority is not none %} {% set _ = meta_fields.append('Priority: ' ~ task.priority) %} {% endif %} - {{ meta_fields|join(' | ') }} -
- {% if task.attachments %} -
- Attachments: - -
- {% endif %} - {% if task.comments %} -
- Comments: -
    - {% for comment in task.comments %} -
  • {{ comment.content }} ({{ comment.posted_at }})
  • - {% endfor %} -
-
- {% endif %} -
- {% endfor %} -
-

Completed Tasks

-
- {% for task in project.completed_tasks %} -
-
{{ task.content | markdown | safe }}
- {% if task.description %} -
{{ task.description | markdown | safe }}
- {% endif %} -
- {% set meta_fields = [] %} - {% if task.id is not none %} - {% set _ = meta_fields.append('ID: ' ~ task.id) %} - {% endif %} - {% if task.due and task.due.date %} - {% set due_dt = task.due.date %} - {% if due_dt.__class__.__name__ == 'datetime' or due_dt.__class__.__name__ == 'date' %} - {% set due_fmt = due_dt.strftime('%Y-%m-%d %H:%M') if due_dt.__class__.__name__ == 'datetime' else due_dt.strftime('%Y-%m-%d 00:00') %} - {% else %} - {% set due_str = due_dt|string %} - {% if 'T' in due_str %} - {% set due_fmt = due_str[:16].replace('T', ' ') %} - {% else %} - {% set due_fmt = due_str %} - {% endif %} - {% endif %} - {% set _ = meta_fields.append('Due: ' ~ due_fmt) %} - {% endif %} - {% if task.due and task.due.is_recurring %} - {% if task.due.string %} - {% set _ = meta_fields.append('Recurring: ' ~ task.due.string) %} - {% endif %} - {% endif %} - {% if task.priority is not none %} - {% set _ = meta_fields.append('Priority: ' ~ task.priority) %} - {% endif %} {% if task.completed_at %} {% if task.completed_at.__class__.__name__ == 'datetime' or task.completed_at.__class__.__name__ == 'date' %} {% set completed_fmt = task.completed_at.strftime('%Y-%m-%d') %} @@ -146,7 +191,10 @@ {% set _ = meta_fields.append('Completed: ' ~ completed_fmt) %} {% endif %} {{ meta_fields|join(' | ') }} -
+
+ {% if task.parent_task %} +
Parent task: {{ task.parent_task.content | markdown | safe }}
+ {% endif %} {% if task.attachments %}
Attachments: @@ -159,15 +207,31 @@ {% endif %} {% if task.comments %}
- Comments: + Comments:
    {% for comment in task.comments %} -
  • {{ comment.content }} ({{ comment.posted_at }})
  • +
  • + {{ comment.content | markdown | safe }} + ({{ comment.posted_at }}) + {% set attachment = comment.attachment %} + {% if attachment and (attachment.local_file or attachment.file_url) %} +
    + Attachment: + {% if attachment.local_file %} + {{ attachment.file_name or attachment.local_file }} + {% elif attachment.file_url %} + {{ attachment.file_name or attachment.file_url }} + {% endif %} +
    + {% endif %} +
  • {% endfor %}
{% endif %}
+ {% else %} +

No completed tasks in this period.

{% endfor %}