diff --git a/weread-sync/sync.py b/weread-sync/sync.py index 7cfa015..1b6baa2 100755 --- a/weread-sync/sync.py +++ b/weread-sync/sync.py @@ -28,6 +28,7 @@ REPO_DIR = os.path.expanduser("~/weread-notes") SKILL_VERSION = "1.0.3" OUTPUT_DIR = os.path.join(REPO_DIR, "notes") + # ─── API 调用 ───────────────────────────────────────── def call_weread(api_name, **params): @@ -73,10 +74,43 @@ def get_notebooks(): "title": book.get("title", "未知书名"), "author": book.get("author", ""), "reviewCount": b.get("reviewCount", 0), + "noteCount": b.get("noteCount", 0), + "readingProgress": b.get("readingProgress", 0), }) return result +def get_book_info(book_id): + """获取书籍详细信息""" + data = call_weread("/book/info", bookId=book_id) + if not data: + return {} + return { + "cover": data.get("cover", ""), + "translator": data.get("translator", ""), + "publisher": data.get("publisher", ""), + "isbn": data.get("isbn", ""), + "category": data.get("category", ""), + "intro": data.get("intro", ""), + "publishTime": data.get("publishTime", ""), + } + + +def get_book_progress(book_id): + """获取阅读进度""" + data = call_weread("/book/getprogress", bookId=book_id) + if not data: + return {} + book = data.get("book", {}) + return { + "progress": book.get("progress", 0), + "readingTime": book.get("readingTime", 0), + "startReadingTime": book.get("startReadingTime", 0), + "updateTime": book.get("updateTime", 0), + "chapterIdx": book.get("chapterIdx", 0), + } + + def get_bookmarks(book_id): """获取一本书的划线""" data = call_weread("/book/bookmarklist", bookId=book_id) @@ -129,15 +163,84 @@ def format_time(ts): return datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M") -def generate_markdown(book, bookmarks, reviews): - """生成一本书的笔记 Markdown""" +def format_duration(minutes): + """分钟 → 可读时长""" + if not minutes: + return "—" + h = minutes // 60 + m = minutes % 60 + if h > 0: + return f"{h}小时{m}分钟" + return f"{m}分钟" + + +def generate_header(book, book_info, progress): + """生成书籍信息头部""" lines = [] lines.append(f"# {book['title']}") - if book.get("author"): - lines.append(f"> 作者:{book['author']}") lines.append("") - lines.append(f"> 同步时间:{format_time(time.time())}") + + # 封面图(居中显示,宽350px) + cover = book_info.get("cover", "") + if cover: + lines.append('

') + lines.append(f' ') + lines.append('

') + lines.append("") + + # 基本信息表(居中) + lines.append('
') lines.append("") + lines.append("| | |") + lines.append("|:---|:---|") + lines.append(f"| **作者** | {book.get('author', '—')} |") + if book_info.get("translator"): + lines.append(f"| **译者** | {book_info['translator']} |") + if book_info.get("publisher"): + lines.append(f"| **出版社** | {book_info['publisher']} |") + if book_info.get("category"): + lines.append(f"| **分类** | {book_info['category']} |") + if book_info.get("isbn"): + lines.append(f"| **ISBN** | {book_info['isbn']} |") + if book_info.get("publishTime"): + lines.append(f"| **出版时间** | {book_info['publishTime']} |") + + # 阅读进度 + pct = progress.get("progress", 0) + read_minutes = progress.get("readingTime", 0) + start_ts = progress.get("startReadingTime", 0) + update_ts = progress.get("updateTime", 0) + + lines.append(f"| **阅读进度** | {pct}% |") + if read_minutes: + lines.append(f"| **阅读时长** | {format_duration(read_minutes)} |") + if start_ts: + lines.append(f"| **开始阅读** | {format_time(start_ts)} |") + if update_ts: + lines.append(f"| **最近阅读** | {format_time(update_ts)} |") + + lines.append(f"| **划线数量** | {book.get('noteCount', '—')} 条 |") + lines.append("") + lines.append('
') + lines.append("") + + # 简介 + intro = book_info.get("intro", "") + if intro: + # 取前 200 字作为摘要 + short_intro = intro[:200] + ("..." if len(intro) > 200 else "") + lines.append("> " + short_intro) + lines.append("") + + return lines + + +def generate_markdown(book, bookmarks, reviews, book_info, progress): + """生成一本书的笔记 Markdown""" + lines = [] + + # 书籍信息头部 + lines.extend(generate_header(book, book_info, progress)) # 划线 if bookmarks: @@ -145,40 +248,48 @@ def generate_markdown(book, bookmarks, reviews): lines.append("## 划线笔记") lines.append("") current_chapter = None + first = True for bm in bookmarks: + if not first: + lines.append("---") + first = False if bm["chapter"] != current_chapter: lines.append(f"### {bm['chapter']}") lines.append("") current_chapter = bm["chapter"] lines.append(f"> {bm['text']}") if bm["time"]: - lines.append(f"> [{format_time(bm['time'])}]") + lines.append(f"> 🕐 {format_time(bm['time'])}") lines.append("") # 想法 if reviews: lines.append("---") - lines.append("## 笔记/想法") + lines.append("## 💬 笔记/想法") lines.append("") current_chapter = None + first = True for r in reviews: + if not first: + lines.append("---") + first = False # 按章节分组(跳过空章节名) chapter = r.get("chapter", "").strip() if chapter and chapter != current_chapter: - if current_chapter is not None: - lines.append("") lines.append(f"### {chapter}") lines.append("") current_chapter = chapter elif not chapter: current_chapter = None - # 原文 + 想法组合展示 + # 原文在引用框内,想法在引用框外(加粗) if r.get("abstract"): lines.append(f"> {r['abstract']}") - lines.append(">") - lines.append(f"> {r['content']}") - if r["time"]: - lines.append(f"> [{format_time(r['time'])}]") + if r["time"]: + lines.append(f"> 🕐 {format_time(r['time'])}") + lines.append("") + lines.append(f"💬 **{r['content']}**") + if r["time"] and not r.get("abstract"): + lines.append(f"🕐 {format_time(r['time'])}") lines.append("") return "\n".join(lines) @@ -221,7 +332,7 @@ def main(): print(f" 找到 {len(books)} 本书") # 2. 逐本获取笔记 - print("\n[2/3] 拉取笔记...") + print("\n[2/3] 拉取笔记 + 书籍信息...") total_bookmarks = 0 total_reviews = 0 os.makedirs(OUTPUT_DIR, exist_ok=True) @@ -230,6 +341,11 @@ def main(): bid = book["bookId"] title = book["title"] print(f" [{i+1}/{len(books)}] {title}...", end=" ") + sys.stdout.flush() + + # 获取书籍信息 + book_info = get_book_info(bid) + progress = get_book_progress(bid) # 获取划线 bookmarks, _ = get_bookmarks(bid) @@ -242,7 +358,8 @@ def main(): # 生成 Markdown safe_title = title.replace("/", "_").replace("\\", "_").replace(":", "_") - md = generate_markdown(book, bookmarks, reviews) + safe_title = safe_title.replace("(", "(").replace(")", ")").replace("[", "【").replace("]", "】") + md = generate_markdown(book, bookmarks, reviews, book_info, progress) filepath = os.path.join(OUTPUT_DIR, f"{safe_title}.md") with open(filepath, "w", encoding="utf-8") as f: f.write(md) @@ -257,11 +374,12 @@ def main(): print("\n[3/3] 生成索引...") index_lines = ["# 微信读书笔记索引", "", "| 书名 | 作者 | 划线 | 想法 | 最后同步 |", "|:---|:---|:---:|:---:|:---:|"] for book in books: - safe_title = book['title'].replace('/','_').replace('\\','_').replace(':','_') + safe_title = book['title'].replace('/', '_').replace('\\', '_').replace(':', '_') + safe_title = safe_title.replace('(', '(').replace(')', ')').replace('[', '【').replace(']', '】') md_file = os.path.join(OUTPUT_DIR, f"{safe_title}.md") if os.path.exists(md_file): - index_lines.append(f"| [{book['title']}](notes/{os.path.basename(md_file)}) | {book.get('author','')} | {book.get('reviewCount',0)} | — | {format_time(time.time())} |") - + index_lines.append(f"| [{book['title']}](notes/{os.path.basename(md_file)}) | {book.get('author', '')} | {book.get('noteCount', 0)} | {book.get('reviewCount', 0)} | {format_time(time.time())} |") + index_path = os.path.join(REPO_DIR, "README.md") with open(index_path, "w", encoding="utf-8") as f: f.write("\n".join(index_lines))