Dukou

版本历史

Version History

Dukou 每个版本的变化。

What changed in each version of Dukou.

Version 0.1.14

Current Version

Build 15 ·

New

  • Dukou now also sits in the Dock; click its icon to open Settings. Turn it off in General if you prefer the menu bar only.

Fixes

  • Fixed "Choose in Finder…" doing nothing on macOS 27.
  • Fixed blank strips above and below the Settings window and the setup guide on macOS 27.

Version 0.1.14

当前版本

Build 15 ·

新功能

  • Dukou 现在也显示在程序坞里,点图标即可打开设置;不需要的话可以在「通用」里关掉。

修复

  • 修复 macOS 27 上「手动从访达中选择…」点击后没有反应的问题。
  • 修复 macOS 27 上设置窗口和设置向导上下多出空白的问题。

Build 14 ·

  • The quick forward pages are laid out afresh: tighter options, and the Start button stays at the bottom of the window.
  • New: Resume. Sending the same chat again asks for only the messages after the last export, and each chat can remember its own prompt.
  • Saving a quick WeChat forward to a folder can produce Markdown: a note with its attachments, ready for an Obsidian vault.

Build 14 ·

  • 快捷转发页重新排版:选项更紧凑,「开始」按钮固定在窗口底部。
  • 新增续聊:同一个群再次发送时,自动提示只处理上次之后的新消息;每个群可以记住自己的 Prompt。
  • 快捷微信转发存到文件夹时可选 Markdown,得到笔记加附件的文件夹,可直接放进 Obsidian。

Build 13 ·

  • Quick WeChat forward can now leave out photos and videos: turn off Save photos or Save videos and the export keeps the chat text without those files.
  • Fixed "This batch could not be selected accurately" when exporting a group with many photos.

Build 13 ·

  • 快捷微信转发新增「保存图片」「保存视频」开关,关掉后导出只保留文字记录,不带对应的图片或视频文件。
  • 修复图片较多的群导出时报「无法准确选中这一批消息」的问题。

Build 12 ·

  • Quick WeChat forward can now include an HTML preview. Tick it and the ZIP gains an index.html: unpack the whole ZIP, open it, and read the chat as bubbles — search by sender or text, jump by date, zoom images, play audio and video inline.
  • Your own messages are placed on the right automatically, and there is a picker in the top corner when they cannot be detected.

Build 12 ·

  • 快捷微信转发新增「HTML 预览」。勾选后,导出的 ZIP 里会多一个 index.html,完整解压后双击就能像聊天界面一样看记录:搜索昵称和正文、按日期跳转、放大图片、直接播放音视频。
  • 预览会自动把你自己的消息放在右侧;认不出来时,可以在右上角手动选。

Build 11 ·

  1. A sponsored post no longer ends the whole export. An ad has no author the way an ordinary post does, so reading one raised the author error — the deliberate refusal to guess, which is right for a post whose author failed to load and wrong for one that never had an author. A single ad anywhere in the requested range meant nothing was exported. Ads are now skipped and the run continues. The ad badge is absent from the accessibility tree, so the evidence is the ad's own popover: both the 赞助商提供的广告信息 notice and the 关闭该广告 button must be present, in those roles, before anything is treated as an ad — a post that merely mentions ads is not dropped from your export. The probe happens before the avatar is touched, since an ad's avatar navigates to the advertiser's site, and the popover is always dismissed with Esc, never by pressing 关闭该广告, which would remove the ad from your own feed.

Build 11 ·

  1. 朋友圈里的广告不再让整轮导出失败。广告帖没有正常的作者,Dukou 读到它就会按「读不到作者就停下、不猜」的规则中断——那条规则对加载失败的帖子是对的,对本来就没有作者的广告则不然,结果是范围内只要有一条广告就一条都导不出来。现在遇到广告会跳过它继续往下读。广告标记在辅助功能树里根本不存在,所以判断依据是它自己的弹窗:必须同时有「赞助商提供的广告信息」这段说明和「关闭该广告」这个按钮,才算广告——只是正文里提到广告的帖子不会被误删。探测在点头像之前进行(广告的头像会跳去广告主网站),弹窗一律用 ESC 关掉,绝不会去点「关闭该广告」,那会把广告从你自己的朋友圈里移除。

Build 10 ·

  1. Quick Moments forward (experimental). Choose how many recent posts to export, with photos and videos as separate options. Authors, the times WeChat displays and the full text go into a chronological TXT, with the media in a media/ folder inside one ZIP, pasted into an app or saved to a folder. A post whose author cannot be read stops the run rather than being guessed at — a wrong attribution is worse than a missing post — and anything that could not be loaded is written into the text instead of quietly dropped. Photos and videos have to be opened and downloaded one at a time, which is slow, so leave the computer alone while it runs; ESC stops it. The clipboard is borrowed during collection and is not restored over anything you copied in the meantime.
  2. Either quick forward can now land in a folder. Pasting into an app was the only ending, which ruled out the case where the export itself is the point — an archive you keep, hand to someone, or feed to something that reads a directory. A destination is now an app or a folder, picked the same way; folders open after saving, and a name collision is worked around rather than overwritten.
  3. No cap on the message count, and batches can be merged. Batches of 100 export back to back and the pane estimates five seconds per hundred. A run can extract those batches and repack them as a single ZIP, which is offered past 500 messages — the point where handing an app many files starts failing on its own. The original ZIPs stay in history if merging or delivery stops.
  4. One naming scheme. Chat and Moments exports are both named by source, the span the content covers and the count. Only a range with both endpoints describes content; anything else is dated by export time, which is all a Moments post with a relative timestamp can honestly claim.
  5. A shorter README. The build commands and source tree are gone, and what remains is written for people who do not read Swift.

Build 10 ·

  1. 新增「快捷朋友圈转发」(实验)。填要导出的条数,图片和视频可以分别选。Dukou 把作者、微信显示的时间和完整正文按时间线整理成 TXT,媒体放进同一个 ZIP 的 media/ 文件夹,粘给应用或存进文件夹。读不到作者时会停下来,不猜——记错人比少一条更糟;没能加载的内容会写进 TXT,而不是悄悄丢掉。图片和视频要逐个打开再下载,速度很慢,这段时间请不要碰电脑,按 ESC 可以中断。采集媒体时会临时借用剪贴板,结束后如果你已经复制了新东西,就不再覆盖。
  2. 两种快捷转发都能直接存进文件夹。以前只能粘给应用,导出本身是目的时(留档、转给别人、喂给读目录的工具)没法用。现在目标是应用或文件夹,同一个选择器里挑;存完自动打开目录,重名不覆盖而是改名。
  3. 消息条数不再有上限,可以合并成一个 ZIP。每 100 条一批连续导出,界面按每 100 条约 5 秒预估耗时;可以把多批解压后重新打包成一个 ZIP,向应用转发超过 500 条时会主动建议——那正是一次粘贴很多文件开始出问题的地方。合并或交付中断时原始 ZIP 仍留在记录里。
  4. 文件名统一。聊天记录和朋友圈都按「来源 + 内容时间范围 + 条数」命名。只有起止都拿得到时才用内容时间;否则按导出时间标注——朋友圈只有「3 小时前」这种相对时间时,能诚实说的只有这个。
  5. README 精简。删掉了构建命令、目录结构这些开发内容,剩下的说明也改成不写代码的人能看懂的话。

Build 9 ·

  1. A right-click that does not take no longer ends the run. Just after a scroll settles, WeChat sometimes shows the context menu without the click having actually landed on the message; and because Qt's menu items expose no AXPress, the press has to be a synthetic click, which misses while the popup's coordinates are still moving. The whole right-click → 多选 → 合并转发 transition now retries — up to four times, alternating between the two click points on the bubble and re-locating the anchor row from the current geometry each time — and a menu item is only clicked once two consecutive scans agree on where it is.

Build 9 ·

  1. 右键那一下没生效不再让整轮转发失败。滚动刚停下时右键,微信有时会把菜单弹出来,但这一下并没有真的选中消息;而 Qt 的菜单项不提供 AXPress,只能合成点击,弹窗坐标还在动的时候点下去就会落空。现在「右键 → 多选 → 合并转发」整段都会重试,最多四次,消息气泡的左右两个落点轮着来,每次重试都按当前的行位置重新定位锚点;菜单项也要连续两次扫描位置一致,才会被点。

Build 8 ·

  1. A message arriving mid-run no longer stops the forward. The tracker assumed the list only moves when it is scrolled: an arrival adds or pushes out visible rows and can reverse the direction things moved in, and any of that used to end the run — in an active group that is the normal case, not an edge one. It now re-locates itself by the longest stretch of messages the two snapshots still share, falling back to whichever position is nearest the previous one when repeated rows make that ambiguous.

Build 8 ·

  1. 转发途中群里来新消息不再中断。以前的定位逻辑假设聊天列表只在被滚动时才会变:新消息一到,可见的消息行增减、位置反向移动,就会被判成「跟不上了」而停下——活跃的群里这不是偶发,是常态。现在改成按两次快照之间仍然相同的那段消息来重新定位,重复内容分不清时就取离原位置最近的那个。

Build 7 ·

  1. An unrecognised message kind no longer aborts a forward. Each exported record used to be compared against the message it was supposed to be, and that comparison had to know the kind first — red packets, Channels cards, merged chat-record cards, labeled stickers, video calls each needed their own rule, every one of them written after a run had already failed on it. Any kind not yet accounted for stopped the forward, for messages WeChat had exported perfectly well. The native ZIP is now delivered as-is.
  2. The archive is still checked for integrity: every entry goes through the same CRC check, and an empty or unreadable one is refused with the file kept.
  3. The count is now shown as "about N": it comes from parsing the transcript, so it is an estimate and no longer presented as exact.

Build 7 ·

  1. 不再因为「没见过的消息类型」中断转发。以前会把微信导出的每条记录和界面上的消息逐条比对,可这个比对得先认识消息类型——红包、视频号、合并的聊天记录卡片、带名字的表情、视频通话,每一种都要单独写规则,而且都是先失败过一次才补上的。没补到的类型就直接中止,哪怕微信已经正确导出了。现在直接交付微信导出的原始 ZIP。
  2. 仍然校验文件完整:每个条目照常做 CRC 校验,空的或读不完整的会拒绝并保留文件。
  3. 条数改为显示「约 N 条」:条数来自解析聊天记录文本,属于估算,界面上不再说得像精确值。

Build 6 ·

  1. History loads faster: each page of history used to be confirmed by travelling back to the newest message. The pass now reads how much arrived from where the keyboard focus moved, and returns to the bottom only once at the end.
  2. Fixed: a run could stall when the last row was a timestamp or a 拍了拍 notice. Neither is a message, and the list was judged not to have reached the bottom when it already had.
  3. Fixed: these message kinds stopped a forward — merged chat-record cards, labeled animated stickers, video calls, red packets and videos. WeChat's exported text describes them differently from the interface, and the mismatch used to abort the run.

Build 6 ·

  1. 加载历史更快:以前每翻一页历史都要跑回最新消息确认一次;现在通过焦点位置的变化直接判断加载了多少,全程只在最后回来一次。
  2. 修复:最后一条是时间戳或「拍了拍」时会卡住。这类提示不是消息,以前会被误判成没能回到最新消息而中止。
  3. 修复:以下消息类型会导致转发中止——合并转发的聊天记录卡片、带名字的动画表情、视频通话记录、红包、视频。这些消息在微信导出的文本里和界面上写法不同,以前会被当成对不上。

Build 5 ·

  1. Quick WeChat forward is much faster: about 20 seconds for 500 messages (the previous release took about 30 seconds for 300). It used to scroll the wheel a screen at a time and stop after each one to work out where it had landed. It now uses the message list's own keyboard navigation — Home crosses the entire loaded history in one step, and an arrow key moves exactly one message. The keys go to WeChat directly rather than through the global event stream.
  2. Messages taller than the window are handled correctly: an image or a long text bubble taller than a screen could not be stepped over by the wheel. One arrow key crosses it.
  3. Channels cards pass verification: accessibility exposes such a card's author but not its video URL, so these messages used to be read as a mismatch and stop the run.

Build 5 ·

  1. 快捷微信转发快了一大截:500 条消息全程约 20 秒(上个版本 300 条约 30 秒)。以前是用滚轮一屏一屏往上翻,每翻一次都得停下来看看落到哪了;现在直接用微信消息列表自带的键盘导航——Home 一下就跨过整段已加载的记录,方向键一次稳稳走一条消息。按键只发给微信,不经过全局输入。
  2. 超高的消息也能正确选中:比一屏还高的图片或长文本,以前滚轮跨不过去,现在一个方向键就过。
  3. 视频号卡片能通过校验:这类消息的作者名辅助功能能读到、视频链接读不到,以前会被当成对不上而中止。

Build 4 ·

  1. Forwarding several hundred WeChat messages no longer gives up halfway: WeChat reads a conversation off disk as you scroll into it — measured at about 64 rows per second over history it already holds and about 8 over history it does not. Every batch of 100 used to hit that boundary again, and the third or fourth would simply time out. A request past 100 now loads the whole stretch once before selecting anything, and it reads WeChat's own count first: if the history is already in memory, the pass costs nothing.
  2. A long-standing bug fixed: returning to the newest message used one enormous scroll gesture, which WeChat clamps to about 50 points. It only ever appeared to work because the list is normally already at the newest message — scroll up first and it could not get back.
  3. Forward to Other Apps is found on every Mac: WeChat stacks a promotion above that row for each companion app installed (企业微信, WorkBuddy), so it sits in one of three places. Clicking a fixed position happened to match a machine with exactly one promotion; on macOS 26 with none, the click landed in the recipient list. It is now located by structure — promotions and the tab row have no name, every contact does — and verified on both macOS 15 and macOS 26, with no screen-recording permission involved.
  4. Escape stops a forward immediately: the automation owns the pointer while it runs, so Cancel has to be aimed at. Escape does not.
  5. The message count takes only digits: the field was free text until it lost focus, so an input method could leave "②00" sitting in it. Non-digits are now refused as typed, and digits in any form (②00, 200) fold to 200.

Build 4 ·

  1. 一次几百条的微信转发不再中途失败:微信的聊天记录是用到才从磁盘读的,越往上翻越慢——实测已加载的部分每秒能过 64 条,没加载的只有 8 条。以前每一批 100 条都要重新撞上这道坎,第三、四批往往直接超时告败。现在超过 100 条会先把整段历史一次性拉到内存里再开始选,而且它会读微信自己的账:已经加载够了就直接跳过,一秒都不多花。
  2. 修好一处一直存在的问题:回到最新消息用的是一个过大的滚动手势,微信会把它压成每次约 50 点。它一直「有效」只是因为列表通常本来就停在最新消息处——你要是先往上翻过一段再执行,它就回不去了。
  3. 「转发到其他应用」在各种电脑上都能找到:这一行上方会为装了的企业微信、WorkBuddy 各留一条推广位,所以它的位置有三种可能。以前按固定位置去点,装了一个推广位的机器碰巧对得上,macOS 26 上没有推广位时那一下会点进联系人列表里。现在按结构定位——推广位和标签行没有名字、每个联系人都有名字,那一行就在第一个有名字的行上面。macOS 15 与 macOS 26 均已验证,不需要屏幕录制权限。
  4. 按 Esc 立即中断转发:执行期间鼠标被自动化占着,「取消」得瞄准了点;Esc 在哪儿都能按。
  5. 条数只能输入数字:这个框在失焦前是自由文本,输入法给的「②00」能原样停在里面。现在非数字当场被拒,各种写法的数字(②00、200)都会折成 200。

Build 3 ·

  1. Quick WeChat forward reaches apps that are not in front: it used to fail whenever the destination was behind another window or minimised. Dukou now brings the app forward, restoring a minimised window, before it pastes.
  2. A status capsule while it runs: it floats in the corner, names the step it is on, asks you to keep your hands off the mouse and keyboard, and cancels on one click. A failure is said there too, with a button back to Settings — by then Settings is usually buried behind WeChat.
  3. A third less waiting: the scroll now steps by the height of the visible list instead of crawling, and paces itself to what WeChat can keep up with. 120 messages went from 17.3 s to 11.2 s; 300 take about 30 s.
  4. The Send to Custom picker opens next to the pointer: it used to sit in the shelf's corner, which on a multi-display Mac was often the wrong screen. It now appears beside the click that raised it, on that screen.
  5. A redrawn DMG background: six Dukou bubble stickers ring the drag lane in the middle, every pointer aimed at the Applications folder.

Build 3 ·

  1. 快捷微信转发能送到不在最前面的应用:以前目标 App 只要被挡住或最小化就一定失败。现在 Dukou 会先把它带到前台,最小化的窗口也还原回来,再粘贴。
  2. 执行期间有一枚状态条:浮在屏幕角落,说明进行到哪一步、提醒完成前别碰鼠标和键盘,随时可以点「取消」。失败也说在这里,并带一个直接跳回设置的按钮——出错时设置窗口通常已经被微信盖住了。
  3. 等待时间少了三分之一:滚动改成按可见列表的高度一步跨过去,并按微信跟得上的节奏自己调速。120 条消息从 17.3 秒降到 11.2 秒,300 条全程约 30 秒。
  4. 「发送到自定义」的选择卡片改在鼠标旁边弹出:以前固定在暂存架的角落——多显示器上那往往是另一块屏幕。现在它跟着你点击的位置出现,就在同一块屏幕上。
  5. DMG 安装背景重画:六枚渡口气泡贴纸围着中间的拖拽通道,每个指针都朝向 Applications 文件夹。

Build 2 ·

  1. The guide opens on first launch: open Dukou after installing and the setup guide is there; a launch from WeChat's forward menu stays silent as before.
  2. The guide ends in Settings: the last step has a single Done button that opens Settings → General.
  3. Sharp DMG background: a Retina sticker sheet on white replaces the blurry artwork.

Build 2 ·

  1. 首次启动直接进入设置向导:装好后打开 Dukou 就会看到向导;由微信转发菜单在后台拉起时仍保持安静。
  2. 向导结束自动打开设置:最后一步只剩「完成」,点击后直接进入设置 → 通用。
  3. DMG 安装背景改为 Retina 清晰版:白底加渡口气泡贴纸,不再模糊。

Build 1 ·

  1. Five forward-menu entries: Stash in Dukou / Send to Codex / Send to Claude / Copy to Clipboard / Send to Custom appear in WeChat's "forward to other apps" menu, each switchable in Settings.
  2. A share extension with no interface: nothing appears on screen; the files land before the system reclaims its temporary copy, committed as one atomic batch.
  3. A Dropover-style shelf: docked to the corner you chose, consumed when dragged out, gone when empty; files stay in History and age out on schedule.
  4. Send to any app: your own list of targets — one goes straight through, several get a picker; terminal-like apps can receive quoted paths instead of files.
  5. Attached prompt: a prompt of your own is pasted ahead of the files; keep up to three and switch between them.
  6. Quick WeChat forward (experimental): name a group and a message count; Dukou drives WeChat through Accessibility, verifies the exported ZIP and pastes it into the target app.
  7. Secure distribution: the Universal 2 app and DMG are Developer ID-signed, Apple-notarized and stapled, with an EdDSA-signed Sparkle update feed.

Build 1 ·

  1. 五条转发入口:微信「转发到其他应用」里出现 暂存到渡口 / 发给 Codex / 发给 Claude / 复制到剪贴板 / 发送到自定义,在设置里逐条开关。
  2. 无界面的分享扩展:点完入口不出现任何面板,文件在系统回收临时文件前落盘,整批原子提交。
  3. Dropover 式暂存架:常驻所选屏幕角落,拖出去就送达,全拖完自动消失;文件留在「记录」里,到期自动清理。
  4. 发到任何 App:自定义应用清单,一个直接发、多个弹卡片选;终端类应用可只粘贴带引号的文件路径。
  5. 附加 Prompt:转发时先粘一条写好的 Prompt 再粘文件,最多保存 3 条随时切换。
  6. 快捷微信转发(实验):填群名和条数,通过辅助功能在微信里多选、合并转发,校验导出的 ZIP 后粘贴到目标 App。
  7. 安全分发:Universal 2 应用与 DMG 均已完成 Developer ID 签名、Apple 公证和票据装订,并提供 Sparkle EdDSA 签名更新源。