| 123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- """阅读日志服务 —— 论文阅读时间记录、阅读日历数据生成与统计."""
- from __future__ import annotations
- import datetime as _dt, sqlite3, time
- from ...utils.common import exec_sql
- def ensure_tables(db_path: str) -> None:
- exec_sql(db_path,
- """CREATE TABLE IF NOT EXISTS paper_reading_sessions (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- paper_id INTEGER NOT NULL, duration_sec INTEGER NOT NULL,
- day_key TEXT NOT NULL, created_at INTEGER NOT NULL)""",
- "CREATE INDEX IF NOT EXISTS idx_prs_day ON paper_reading_sessions(day_key, created_at)",
- "CREATE INDEX IF NOT EXISTS idx_prs_paper ON paper_reading_sessions(paper_id, created_at)")
- def append_session(db_path: str, *, paper_id: int, duration_sec: int, client_ts: int | None = None) -> None:
- if not db_path or int(duration_sec or 0) <= 0:
- return
- ensure_tables(db_path)
- dur = min(int(duration_sec), 86400)
- ts = int(client_ts) if client_ts else int(time.time())
- day = _dt.datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
- conn = sqlite3.connect(db_path)
- try:
- conn.execute("INSERT INTO paper_reading_sessions(paper_id,duration_sec,day_key,created_at) VALUES(?,?,?,?)",
- (int(paper_id), dur, day, int(time.time())))
- conn.commit()
- finally:
- conn.close()
- def list_daily_aggregate(db_path: str, *, days: int = 180) -> list[dict[str, int | str]]:
- if not db_path:
- return []
- ensure_tables(db_path)
- d = max(7, min(int(days or 180), 366))
- start = _dt.datetime.fromtimestamp(int(time.time()) - (d - 1) * 86400).strftime("%Y-%m-%d")
- conn = sqlite3.connect(db_path)
- conn.row_factory = sqlite3.Row
- try:
- rows = conn.execute(
- "SELECT day_key, SUM(duration_sec) AS seconds, COUNT(*) AS sessions FROM paper_reading_sessions WHERE day_key>=? GROUP BY day_key ORDER BY day_key",
- (start,)).fetchall()
- return [{"date": r["day_key"], "seconds": int(r["seconds"] or 0), "sessions": int(r["sessions"] or 0)} for r in rows]
- finally:
- conn.close()
|