Skip to content

feat(export): add batch export feature for all Gemini conversations#235

Draft
chengyongru wants to merge 4 commits intoNagi-ovo:mainfrom
chengyongru:main
Draft

feat(export): add batch export feature for all Gemini conversations#235
chengyongru wants to merge 4 commits intoNagi-ovo:mainfrom
chengyongru:main

Conversation

@chengyongru
Copy link

@chengyongru chengyongru commented Feb 3, 2026

添加了批量导出功能, 只支持导出json,最终打包为zip保存由于gemini的懒加载,需要手动翻到会话话列表的最下面,否则只能导出已加载的会话列表

导出过程比较慢,会从第一个会话开始一个个往下翻,然后在每个会话内部会自动定位到timeline起点

image image image
Open with Devin

Add comprehensive batch export functionality that automatically traverses
and exports all conversations as a ZIP file containing individual JSON files.

Core Features:
- Automatic conversation traversal and sequential loading
- Lazy loading trigger to capture complete conversation history
- Progress tracking with success/failure reporting
- ZIP file generation with timestamped filenames
- Reuses proven collectChatPairs() for content extraction

UI Changes:
- Add "Batch Export" button to export dialog
- Include batch export description in dialog UI
- Support for all 9 languages (en, zh, zh_CN, zh_TW, ja, fr, es, pt, ar, ru)

Technical Implementation:
- BatchExportService: Handles automated conversation navigation
- DOM fingerprinting for lazy loading detection
- Recursive history loading with stabilization checks
- Export result tracking with detailed error reporting

Files Added:
- src/features/export/services/BatchExportService.ts

Files Modified:
- src/features/export/ui/ExportDialog.ts (batch export button)
- src/pages/content/export/index.ts (lazy loading integration)
- src/locales/*/messages.json (translations for all languages)
Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View issues and 5 additional flags in Devin Review.

Open in Devin Review

Comment on lines 132 to 135
const warningElement = dialog.querySelector('.gv-export-dialog-warning');
if (warningElement) {
warningElement.after(batchDesc);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Batch export description never inserted due to querying element before it's appended to DOM

The batch export description element is never inserted into the dialog because the code queries for .gv-export-dialog-warning before the warning element is appended to the dialog.

Click to expand

Root Cause

At line 132, the code tries to find the warning element:

const warningElement = dialog.querySelector('.gv-export-dialog-warning');

However, the warning element is only appended to dialog later at line 142:

dialog.appendChild(warning);

This means warningElement will always be null, and the batchDesc element created at lines 127-129 will never be inserted into the dialog.

Impact

The batch export description text ("Export all conversations as individual JSON files (ZIP)") will never be displayed to users, even though the translation is provided. This is a UI bug that affects user experience but doesn't break functionality.

Expected vs Actual

  • Expected: The batch export description should appear in the dialog after the warning message
  • Actual: The description is never shown because the insertion fails silently

Recommendation: Move the batch export description insertion logic to after the dialog elements are assembled (after line 144), or directly use the warning variable reference instead of querying for it: warning.after(batchDesc);

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@chengyongru chengyongru marked this pull request as draft February 3, 2026 09:44
chengyongru and others added 2 commits February 3, 2026 18:06
Fix two bugs identified by Devin AI code review:

1. 🔴 Critical: Stale topNode reference causing incomplete lazy loading
   - Root cause: recursivelyLoadHistory reused the same topNode reference
     across recursive calls, but Gemini prepends new messages making
     the old reference point to a middle element
   - Fix: Re-fetch the top user element on each recursive attempt
   - Added getTopUserElement() helper method that filters for top-level
     user elements (not nested)
   - Aligns with the proven pattern in executeExportSequence (index.ts:608)

2. 🟡 UI bug: Batch export description never displayed
   - Root cause: querySelector executed before warning element was
     appended to DOM, always returning null
   - Fix: Move dialog assembly before batch export button creation,
     use warning variable directly instead of querying
   - Description now correctly appears in export dialog

Impact:
- Long conversations will now export completely instead of truncating
- Users will see the batch export description text in the UI
- No breaking changes to existing functionality

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…lector

Address Devin AI review feedback about duplicate code between BatchExportService
and index.ts. The ConversationCollector object was specifically exported for
BatchExportService to use, but it wasn't being utilized.

Changes:
1. Fixed index.ts recursivelyLoadHistory to re-fetch topNode on each attempt
   - Resolves the same stale reference bug we fixed in BatchExportService
   - Ensures complete lazy loading for all conversation history

2. Refactored BatchExportService to use ConversationCollector
   - Removed 243 lines of duplicate code
   - Changed import from collectChatPairs to ConversationCollector
   - Replaced triggerLazyLoading() with ConversationCollector.triggerLazyLoad()
   - Replaced collectChatPairs() with ConversationCollector.collectCurrentPairs()
   - Deleted redundant methods:
     * recursivelyLoadHistory()
     * getTopUserElement()
     * computeFingerprint()
     * hashString()
     * waitForFingerprintChange()
     * waitForAnyElement()

Benefits:
- Single source of truth for lazy loading logic
- Consistent selector management across export features
- Future selector updates only need to be made in one place
- Reduced code from 536 lines to 332 lines (-204 lines)

Impact:
- All export features (single and batch) now share identical lazy loading
  behavior, ensuring consistent data collection
- No functional changes - same behavior with less code duplication
@Nagi-ovo
Copy link
Owner

Nagi-ovo commented Feb 3, 2026

@chengyongru Hi, 感谢你的 PR!如果你准备好了 code review 请 @ 我一下!

@Nagi-ovo Nagi-ovo added the enhancement New feature or request label Feb 3, 2026
@chengyongru
Copy link
Author

@Nagi-ovo 通过这种方案批量导出的速度过慢,pr暂时不具备实用价值,可以先留着给有需要的人自己 pull下去打包使用。

实际测试中几十条对话还行,上千的话就有点捉急了,我有时间再研究研究能不能直接用接口,可能不是很快。

@ypwcharles
Copy link
Contributor

这样不如用google takeout导出再做数据清理来的方便了

@chengyongru
Copy link
Author

@ypwcharles 我试过takeout 只能导出 gem这些prompt啥的,你有测试过如何导出全部对话吗?

@Nagi-ovo
Copy link
Owner

Nagi-ovo commented Feb 6, 2026

@chengyongru @ypwcharles 勾选活动记录的话应该可以导出对话,但我刚尝试了一下,发现导出来的完全就是活动记录里那种碎片化的方式,好乱啊

@ypwcharles
Copy link
Contributor

@ypwcharles 我试过takeout 只能导出 gem这些prompt啥的,你有测试过如何导出全部对话吗?

有试过,在活动记录里面选gemini可以导出全部的对话记录。你可以问一下gemini具体怎么操作

@ypwcharles
Copy link
Contributor

@chengyongru @ypwcharles 勾选活动记录的话应该可以导出对话,但我刚尝试了一下,发现导出来的完全就是活动记录里那种碎片化的方式,好乱啊

是的很乱,而且它是单条的对话记录,要写程序清理然后重新分组才是原来的对话记录。不过对话是全的

@chengyongru
Copy link
Author

@ypwcharles 测试了一下发现活动记录导出的json没有会话信息,是按时间组织的,这就比较恼火了,虽然可以简单按时间窗口做个聚类,或者按机器学习的方法聚类一下,但是没办法做到完美的把所有对话正确组织成和网页一样的顺序。

但是从另一个角度考虑,之所以要把所有数据都拿到本地其实是为了知识管理,可能找个嵌入模型把这些文本转换成向量做聚类,再用时间做个排序,可能比完美恢复对话顺序更有实际意义一点。

@ypwcharles
Copy link
Contributor

ypwcharles commented Feb 8, 2026 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments