Files
Inkycal/inkycal/modules/super_productivity_utils.py

242 lines
6.5 KiB
Python
Raw Permalink Normal View History

2025-11-30 21:17:02 +01:00
"""
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 <json_file_path>")
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)