diff --git a/booklist_parse.py b/booklist_parse.py index 5080704..6e536cd 100644 --- a/booklist_parse.py +++ b/booklist_parse.py @@ -51,6 +51,7 @@ class BookListManager: notes = annotations.get(bk_id, {}) day_notes = {} # 收集每本书所有笔记的创建时间,按天分组 + # day_notes: {date对象: [datetime对象, ...]},便于后续统计每天的阅读行为 for uuid, note in notes.items(): raw_date = note.get('creationdate') try: @@ -64,58 +65,78 @@ class BookListManager: # 获取该书的打开时间戳(ZLASTOPENDATE),用于判断无笔记时是否有打开过书籍 open_info = books_open.get(bk_id, {}) last_open_ts = open_info.get('last_open') - # 生成最近30天的阅读时长列表 + # 生成最近30天的阅读时长列表(readtime30d),索引0为今天,索引29为30天前 readtime30d = [] for i in range(30): day = today - datetime.timedelta(days=i) times = day_notes.get(day, []) + # 统计当天阅读时长 if not times: + # 没有笔记,判断当天是否有打开过书籍 opened = False if last_open_ts: open_dt = datetime.datetime(2001, 1, 1) + datetime.timedelta(seconds=last_open_ts) if open_dt.date() == day: opened = True + # 无笔记但当天有打开书籍,阅读时间设为READ_TIME_OPEN_DAY readtime = READ_TIME_OPEN_DAY if opened else 0 elif len(times) == 1: + # 只有一条笔记,设为最小阅读时长 readtime = READ_TIME_DAY else: + # 多条笔记,统计相邻笔记时间差(仅累加小于3小时的部分,单位分钟) times_sorted = sorted(times) total_minutes = 0 for idx in range(1, len(times_sorted)): delta = (times_sorted[idx] - times_sorted[idx-1]).total_seconds() / 60 + # 只统计相邻笔记间隔小于等于180分钟的部分 if 0 < delta <= 180: total_minutes += int(delta) + # 如果没有有效时间差,则用最小阅读时长 readtime = total_minutes if total_minutes > 0 else READ_TIME_DAY readtime30d.append(readtime) + # 保存每本书的30天阅读时长列表 booksinfo[bk_id]['readtime30d'] = readtime30d - # 新增:统计今年每个月的阅读时长和年总阅读时长(遍历今年每一天) - readtime12m = [0] * 12 # 今年每月阅读时长 - readtime_year = 0 # 今年总阅读时长 + # 新增:统计今年每月和全年阅读时长(遍历今年每一天,更精确) + # readtime12m: 今年每月阅读时长列表(索引0为1月,索引11为12月) + # readtime_year: 今年总阅读时长(分钟) + readtime12m = [0] * 12 + readtime_year = 0 first_day = datetime.date(this_year, 1, 1) days_in_year = (today - first_day).days + 1 for i in range(days_in_year): day = first_day + datetime.timedelta(days=i) times = day_notes.get(day, []) + # 统计当天阅读时长,逻辑与readtime30d一致 if not times: + # 无笔记,判断当天是否有打开过书籍 opened = False if last_open_ts: open_dt = datetime.datetime(2001, 1, 1) + datetime.timedelta(seconds=last_open_ts) if open_dt.date() == day: opened = True + # 无笔记但当天有打开书籍,阅读时间设为READ_TIME_OPEN_DAY readtime = READ_TIME_OPEN_DAY if opened else 0 elif len(times) == 1: + # 只有一条笔记,设为最小阅读时长 readtime = READ_TIME_DAY else: + # 多条笔记,统计相邻笔记时间差(仅累加小于3小时的部分,单位分钟) times_sorted = sorted(times) total_minutes = 0 for idx in range(1, len(times_sorted)): delta = (times_sorted[idx] - times_sorted[idx-1]).total_seconds() / 60 + # 只统计相邻笔记间隔小于等于180分钟的部分 if 0 < delta <= 180: total_minutes += int(delta) + # 如果没有有效时间差,则用最小阅读时长 readtime = total_minutes if total_minutes > 0 else READ_TIME_DAY + # 按月累计到readtime12m readtime12m[day.month-1] += readtime + # 全年累计到readtime_year readtime_year += readtime + # 保存到booksinfo booksinfo[bk_id]['readtime12m'] = readtime12m booksinfo[bk_id]['readtime_year'] = readtime_year except Exception as e: diff --git a/detaildesign.md b/detaildesign.md index 03f5f8b..38b9c6a 100644 --- a/detaildesign.md +++ b/detaildesign.md @@ -1,3 +1,24 @@ +# 2025年阅读统计功能设计补充 + +## 书籍阅读时长统计 + +1. `readtime30d`:每本书最近30天每天的阅读时长(分钟),索引0为今天,索引29为30天前。 +2. `readtime12m`:每本书今年每月的累计阅读时长(分钟),索引0为1月,索引11为12月。统计逻辑为遍历今年每一天,按月累计。 +3. `readtime_year`:每本书今年总阅读时长(分钟),为`readtime12m`各月之和。 +4. 支持无笔记但当天有打开书籍时,阅读时长设为`READ_TIME_OPEN_DAY`(config.py配置,默认30分钟)。 +5. 多条笔记时,统计相邻笔记时间差(仅累加小于3小时的部分),更真实反映实际阅读行为。 + +## 全局统计函数 + +1. `get_total_readtime_year()`:返回全年所有书的累计阅读时间(分钟)。 +2. `get_total_readtime12m()`:返回全年所有书的月度累计阅读时间(长度12的列表,单位:分钟)。 +3. `get_total_readtime(days=30)`:返回最近days天每天所有书籍的总阅读时间(分钟),索引0为今天。 + +## 设计说明 + +- 所有统计均以“分钟”为单位,便于可视化和分析。 +- 年度统计遍历今年每一天,保证月度和年度数据完整。 +- 统计逻辑与实际阅读行为高度贴合,支持无笔记但有打开书籍的场景。 # iBooks 笔记导出工具 详细设计文档 ## 1. 概述