Move output to output folder
This commit is contained in:
@ -3,13 +3,16 @@ import sys
|
||||
import json
|
||||
import time
|
||||
import getpass
|
||||
import shutil
|
||||
from collections import defaultdict
|
||||
import requests
|
||||
from datetime import datetime, timedelta
|
||||
from todoist_api_python.api import TodoistAPI
|
||||
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||
|
||||
ATTACHMENTS_DIR = "attachments"
|
||||
OUTPUT_DIR = "output"
|
||||
ATTACHMENTS_DIR = os.path.join(OUTPUT_DIR, "attachments")
|
||||
LEGACY_ATTACHMENTS_DIR = "attachments"
|
||||
TODOIST_API_TOKEN: str | None = None
|
||||
COMPLETED_HISTORY_FILE = "Todoist-Completed-History.json"
|
||||
|
||||
@ -49,9 +52,29 @@ def get_api_key():
|
||||
return key
|
||||
|
||||
|
||||
def ensure_output_dir():
|
||||
if not os.path.exists(OUTPUT_DIR):
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def ensure_attachments_dir():
|
||||
ensure_output_dir()
|
||||
if os.path.isdir(LEGACY_ATTACHMENTS_DIR) and LEGACY_ATTACHMENTS_DIR != ATTACHMENTS_DIR:
|
||||
try:
|
||||
if not os.path.exists(ATTACHMENTS_DIR):
|
||||
shutil.move(LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_DIR)
|
||||
else:
|
||||
for name in os.listdir(LEGACY_ATTACHMENTS_DIR):
|
||||
shutil.move(
|
||||
os.path.join(LEGACY_ATTACHMENTS_DIR, name),
|
||||
os.path.join(ATTACHMENTS_DIR, name),
|
||||
)
|
||||
os.rmdir(LEGACY_ATTACHMENTS_DIR)
|
||||
print(f"Moved legacy attachments into {ATTACHMENTS_DIR}")
|
||||
except (OSError, shutil.Error) as exc: # pylint: disable=broad-except
|
||||
print(f"Warning: failed to migrate legacy attachments: {exc}")
|
||||
if not os.path.exists(ATTACHMENTS_DIR):
|
||||
os.makedirs(ATTACHMENTS_DIR)
|
||||
os.makedirs(ATTACHMENTS_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def load_completed_history():
|
||||
@ -88,13 +111,23 @@ def save_completed_history(history):
|
||||
print(f"Warning: failed to write completed history ({exc}).")
|
||||
|
||||
|
||||
def normalize_timestamp(value):
|
||||
if not value:
|
||||
return ""
|
||||
if isinstance(value, datetime):
|
||||
return value.isoformat()
|
||||
return str(value)
|
||||
|
||||
|
||||
def merge_completed_lists(history_tasks, new_tasks):
|
||||
merged = []
|
||||
seen = set()
|
||||
|
||||
def make_key(task):
|
||||
task_id = str(task.get('id', ''))
|
||||
completed_at = task.get('completed_at') or task.get('updated_at') or ""
|
||||
completed_at = normalize_timestamp(task.get('completed_at'))
|
||||
if not completed_at:
|
||||
completed_at = normalize_timestamp(task.get('updated_at'))
|
||||
return (task_id, completed_at)
|
||||
|
||||
def add_task(task):
|
||||
@ -110,8 +143,8 @@ def merge_completed_lists(history_tasks, new_tasks):
|
||||
add_task(item)
|
||||
|
||||
def sort_key(task):
|
||||
completed_at = task.get('completed_at') or ""
|
||||
updated_at = task.get('updated_at') or ""
|
||||
completed_at = normalize_timestamp(task.get('completed_at'))
|
||||
updated_at = normalize_timestamp(task.get('updated_at'))
|
||||
return (completed_at, updated_at)
|
||||
|
||||
merged.sort(key=sort_key, reverse=True)
|
||||
@ -307,7 +340,7 @@ def process_task(task, comments_lookup):
|
||||
filename = att_dict.get('file_name') or os.path.basename(att_dict['file_url'])
|
||||
local_path = download_attachment(att_dict['file_url'], filename)
|
||||
if local_path:
|
||||
att_dict['local_file'] = os.path.relpath(local_path)
|
||||
att_dict['local_file'] = os.path.relpath(local_path, OUTPUT_DIR)
|
||||
attachments.append(att_dict)
|
||||
if attachments:
|
||||
task_dict['attachments'] = attachments
|
||||
@ -325,7 +358,7 @@ def process_task(task, comments_lookup):
|
||||
filename = attachment_dict.get("file_name") or os.path.basename(file_url)
|
||||
local_path = download_attachment(file_url, filename)
|
||||
if local_path:
|
||||
attachment_dict['local_file'] = os.path.relpath(local_path)
|
||||
attachment_dict['local_file'] = os.path.relpath(local_path, OUTPUT_DIR)
|
||||
comment_dict['attachment'] = attachment_dict
|
||||
serialized_comments.append(comment_dict)
|
||||
task_dict['comments'] = serialized_comments
|
||||
@ -459,9 +492,10 @@ def main():
|
||||
# Write JSON
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
json_filename = f"Todoist-Actual-Backup-{today}.json"
|
||||
with open(json_filename, "w", encoding="utf-8") as f:
|
||||
json_output_path = os.path.join(OUTPUT_DIR, json_filename)
|
||||
with open(json_output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2, default=json_serial)
|
||||
print(f"Exported data to {json_filename}")
|
||||
print(f"Exported data to {json_output_path}")
|
||||
# Write HTML
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(os.path.dirname(__file__)),
|
||||
@ -475,9 +509,10 @@ def main():
|
||||
env.filters['markdown'] = lambda text: text or ""
|
||||
template = env.get_template("todoist_backup_template.html")
|
||||
html_filename = f"Todoist-Actual-Backup-{today}.html"
|
||||
with open(html_filename, "w", encoding="utf-8") as f:
|
||||
html_output_path = os.path.join(OUTPUT_DIR, html_filename)
|
||||
with open(html_output_path, "w", encoding="utf-8") as f:
|
||||
f.write(template.render(projects=data, date=today))
|
||||
print(f"Generated HTML backup at {html_filename}")
|
||||
print(f"Generated HTML backup at {html_output_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
Reference in New Issue
Block a user