""" Super Productivity 数据解析工具 用于从 Super Productivity 导出的 JSON 中提取任务信息 """ import json from datetime import date from typing import List, Dict, Optional, Tuple class TaskEntry: """任务条目类""" def __init__( self, task_id: str, title: str, project_name: str, subtasks: Optional[List['TaskEntry']] = None, is_done: bool = False, time_spent: int = 0 ): self.id = task_id self.title = title self.project_name = project_name self.subtasks = subtasks or [] self.is_done = is_done self.time_spent = time_spent # 单位:毫秒 def __repr__(self): return f"TaskEntry(title='{self.title}', project='{self.project_name}', subtasks={len(self.subtasks)})" def get_time_spent_hours(self) -> float: """获取花费的时间(小时)""" return self.time_spent / 3600000.0 def parse_super_productivity_json(json_file_path: str) -> Tuple[Dict, Dict, Dict]: """ 解析 Super Productivity JSON 文件 Args: json_file_path: JSON 文件路径 Returns: (tasks, projects, tags) 元组 """ with open(json_file_path, 'r', encoding='utf-8') as f: data = json.load(f) tasks = data['mainModelData']['task']['entities'] projects = data['mainModelData']['project']['entities'] tags = data['mainModelData']['tag']['entities'] return tasks, projects, tags def get_project_name(projects: Dict, project_id: str) -> str: """获取项目名称""" if project_id in projects: return projects[project_id]['title'] return "Inbox" def parse_task_entry( task_id: str, tasks: Dict, projects: Dict ) -> Optional[TaskEntry]: """ 解析单个任务条目 Args: task_id: 任务 ID tasks: 所有任务字典 projects: 所有项目字典 Returns: TaskEntry 对象或 None """ task = tasks.get(task_id) if not task: return None # 获取基本信息 title = task.get('title', 'Untitled') project_id = task.get('projectId', 'INBOX_PROJECT') project_name = get_project_name(projects, project_id) is_done = task.get('isDone', False) time_spent = task.get('timeSpent', 0) # 解析子任务 subtask_ids = task.get('subTaskIds', []) subtasks = [] for subtask_id in subtask_ids: subtask = parse_task_entry(subtask_id, tasks, projects) if subtask: subtasks.append(subtask) return TaskEntry( task_id=task_id, title=title, project_name=project_name, subtasks=subtasks, is_done=is_done, time_spent=time_spent ) def get_today_tasks( json_file_path: str, target_date: Optional[date] = None, include_done: bool = False ) -> List[TaskEntry]: """ 获取今天 due 的任务 Args: json_file_path: JSON 文件路径 target_date: 目标日期,默认为今天 include_done: 是否包含已完成的任务 Returns: 今天的任务列表 """ if target_date is None: target_date = date.today() today_str = target_date.strftime('%Y-%m-%d') tasks, projects, _ = parse_super_productivity_json(json_file_path) today_tasks = [] for task_id, task in tasks.items(): # 检查是否是今天的任务 due_day = task.get('dueDay') # print(f'Task ID: {task_id}, Due Day: {due_day}, Today: {today_str}') # 调试输出 if due_day != today_str: continue # 检查是否已完成 if not include_done and task.get('isDone', False): continue # 只添加顶层任务(没有 parentId 的) if not task.get('parentId'): parsed_task = parse_task_entry(task_id, tasks, projects) if parsed_task: today_tasks.append(parsed_task) return today_tasks def get_tasks_by_tag( json_file_path: str, tag_name: str, include_done: bool = False ) -> List[TaskEntry]: """ 根据标签获取任务 Args: json_file_path: JSON 文件路径 tag_name: 标签名称(如 "TODAY") include_done: 是否包含已完成的任务 Returns: 带有该标签的任务列表 """ tasks, projects, tags = parse_super_productivity_json(json_file_path) # 查找标签 ID tag_id = None for tid, tag in tags.items(): if tag.get('title') == tag_name: tag_id = tid break if not tag_id: return [] # 获取带有该标签的任务 task_ids = tags[tag_id].get('taskIds', []) result_tasks = [] for task_id in task_ids: task = tasks.get(task_id) if not task: continue # 检查是否已完成 if not include_done and task.get('isDone', False): continue parsed_task = parse_task_entry(task_id, tasks, projects) if parsed_task: result_tasks.append(parsed_task) return result_tasks if __name__ == "__main__": """测试代码""" import sys if len(sys.argv) < 2: print("Usage: python super_productivity_utils.py ") sys.exit(1) json_file = sys.argv[1] # 获取今天的任务 print("=" * 60) print("📅 TODAY'S TASKS (with due date)") print("=" * 60) today_tasks = get_today_tasks(json_file) for task in today_tasks: print(f"\n📋 {task.title}") print(f" 📁 Project: {task.project_name}") if task.subtasks: print(f" └─ Subtasks ({len(task.subtasks)}):") for subtask in task.subtasks: status = "✓" if subtask.is_done else "○" print(f" {status} {subtask.title}") # 获取 TODAY 标签的任务 print("\n" + "=" * 60) print("🏷️ TASKS WITH 'TODAY' TAG") print("=" * 60) tagged_tasks = get_tasks_by_tag(json_file, "TODAY") for task in tagged_tasks: print(f"\n📋 {task.title}") print(f" 📁 Project: {task.project_name}") if task.time_spent > 0: print(f" ⏱️ Time spent: {task.get_time_spent_hours():.1f}h") print("\n" + "=" * 60) print(f"📊 Summary: {len(today_tasks)} due today, {len(tagged_tasks)} tagged TODAY") print("=" * 60)