Skip to content

feat(logs): include on-error AVI clips in exports - #406

Open
tianguzhang wants to merge 1 commit into
MaaXYZ:mainfrom
tianguzhang:feat/on-error-video-export
Open

tianguzhang wants to merge 1 commit into
MaaXYZ:mainfrom
tianguzhang:feat/on-error-video-export

Conversation

@tianguzhang

@tianguzhang tianguzhang commented Oct 29, 2026 •

Copy link
Copy Markdown

Include AVI clips from debug/on_error in exported log archives, alongside the existing error screenshots. AVI extensions are matched case-insensitively; vision remains image-only and the existing filters for other debug files are unchanged.

The same modification-time ordering, archive splitting, and export retention rules apply. No encoder or new runtime dependency is introduced.

Validation: cargo check --locked --offline, cargo fmt --check, and a temporary Rust regression harness exercising the production collection and ZIP-writing functions. The harness first reproduced missing AVI files, then verified AVI inclusion, exclusions, ordering, retention, and two-volume ZIP splitting. A 30-second MJPEG AVI also survived a byte-identical ZIP round-trip and was checked with ffprobe. Temporary tests are not included in this PR.

Draft companion to MaaEnd/MaaEnd#6944 while the recorder implementation and end-to-end validation are in progress.

Sourcery 摘要

将发生错误时生成的 AVI 片段纳入导出的日志归档,同时不改变现有的调试文件筛选规则或导出行为。

新功能:

  • 将 debug/on_error 中的 AVI 片段与受支持的错误图像一同纳入导出的日志归档,并以不区分大小写的方式匹配扩展名。

改进:

  • 通用化调试文件收集,同时保留仅筛选视觉图像、按修改时间排序、拆分归档及保留策略。
Original summary in English

Summary by Sourcery

Include on-error AVI clips in exported log archives without changing existing debug-file filters or export behavior.

New Features:

  • Include AVI clips from debug/on_error in exported log archives alongside supported error images, with case-insensitive extension matching.

Enhancements:

  • Generalize debug artifact collection while preserving vision image-only filtering, modification-time ordering, archive splitting, and retention behavior.

@tianguzhang
tianguzhang marked this pull request as ready for review November 6, 2026 13:03
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-06T13:06:03.404805Z 5ff86c0 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copy link
Copy Markdown
Author

@MistEO 已取消草稿,麻烦有空帮忙审核一下日志导出这部分,重点看看文件收集、体积限制和兼容性。关联框架 PR:MaaXYZ/MaaFramework#1593,讨论:MaaXYZ/MaaFramework#1594。

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

你好 - 我发现了 3 个问题

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/file_ops.rs" line_range="662" />
<code_context>
+    let on_error_artifacts = collect_debug_artifacts(
+        &debug_dir.join("on_error"),
+        "on_error",
+        &["png", "jpg", "jpeg", "avi"],
+    );
+    let vision_images =
</code_context>
<issue_to_address>
**Large clips exhaust export memory**

When a large AVI reaches the capacity check and `pre_compress_measure` is called, `pre_compress_measure` buffers the entire deflated clip in a `Vec`, using memory proportional to the clip size and potentially exhausting memory and terminating the export or application.

Measure compressed size without retaining the entire compressed clip in memory.

Also at `src-tauri/src/commands/file_ops.rs:663`.
</issue_to_address>

### Comment 2
<location path="src-tauri/src/commands/file_ops.rs" line_range="662" />
<code_context>
+    let on_error_artifacts = collect_debug_artifacts(
+        &debug_dir.join("on_error"),
+        "on_error",
+        &["png", "jpg", "jpeg", "avi"],
+    );
+    let vision_images =
</code_context>
<issue_to_address>
**AVI clips exceed the volume limit**

When an AVI's compressed ZIP entry exceeds the remaining volume budget, including when it exceeds the limit in a fresh volume, the `wrote_any` guard skips the size check for an empty volume, and `add_file_to_zip` writes the AVI as one entry, producing a ZIP volume larger than `MAX_VOLUME_BYTES` while the export reports success.

Enforce the volume limit for the first entry too, and handle an AVI that cannot fit in an empty volume without writing an oversized volume.

Also at `src-tauri/src/commands/file_ops.rs:663`.
</issue_to_address>

### Comment 3
<location path="src-tauri/src/commands/file_ops.rs" line_range="557" />
<code_context>
-    let mut images: Vec<_> = rd.flatten().filter(|e| is_image_file(&e.path())).collect();
+    let mut artifacts: Vec<_> = rd
+        .flatten()
+        .filter(|e| e.path().is_file() && has_extension(&e.path(), extensions))
+        .collect();

</code_context>
<issue_to_address>
**Exports can contain incomplete clips**

When the recorder writes an AVI directly into `debug/on_error` while an export is collecting or copying it, `collect_debug_artifacts` accepts the live AVI path, and `add_file_to_zip` copies it without waiting for the recorder to finish; the ZIP captures a truncated or invalid clip, so the exported video cannot be played reliably.

Only export finalized clips, for example by writing to a temporary path and atomically renaming after the recorder closes the file, or by coordinating export with recorder finalization.
</issue_to_address>

Sourcery 对开源项目免费——如果你喜欢我们的评审,请考虑分享 ✨
Original comment in English

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/file_ops.rs" line_range="662" />
<code_context>
+    let on_error_artifacts = collect_debug_artifacts(
+        &debug_dir.join("on_error"),
+        "on_error",
+        &["png", "jpg", "jpeg", "avi"],
+    );
+    let vision_images =
</code_context>
<issue_to_address>
**Large clips exhaust export memory**

When a large AVI reaches the capacity check and `pre_compress_measure` is called, `pre_compress_measure` buffers the entire deflated clip in a `Vec`, using memory proportional to the clip size and potentially exhausting memory and terminating the export or application.

Measure compressed size without retaining the entire compressed clip in memory.

Also at `src-tauri/src/commands/file_ops.rs:663`.
</issue_to_address>

### Comment 2
<location path="src-tauri/src/commands/file_ops.rs" line_range="662" />
<code_context>
+    let on_error_artifacts = collect_debug_artifacts(
+        &debug_dir.join("on_error"),
+        "on_error",
+        &["png", "jpg", "jpeg", "avi"],
+    );
+    let vision_images =
</code_context>
<issue_to_address>
**AVI clips exceed the volume limit**

When an AVI's compressed ZIP entry exceeds the remaining volume budget, including when it exceeds the limit in a fresh volume, the `wrote_any` guard skips the size check for an empty volume, and `add_file_to_zip` writes the AVI as one entry, producing a ZIP volume larger than `MAX_VOLUME_BYTES` while the export reports success.

Enforce the volume limit for the first entry too, and handle an AVI that cannot fit in an empty volume without writing an oversized volume.

Also at `src-tauri/src/commands/file_ops.rs:663`.
</issue_to_address>

### Comment 3
<location path="src-tauri/src/commands/file_ops.rs" line_range="557" />
<code_context>
-    let mut images: Vec<_> = rd.flatten().filter(|e| is_image_file(&e.path())).collect();
+    let mut artifacts: Vec<_> = rd
+        .flatten()
+        .filter(|e| e.path().is_file() && has_extension(&e.path(), extensions))
+        .collect();

</code_context>
<issue_to_address>
**Exports can contain incomplete clips**

When the recorder writes an AVI directly into `debug/on_error` while an export is collecting or copying it, `collect_debug_artifacts` accepts the live AVI path, and `add_file_to_zip` copies it without waiting for the recorder to finish; the ZIP captures a truncated or invalid clip, so the exported video cannot be played reliably.

Only export finalized clips, for example by writing to a temporary path and atomically renaming after the recorder closes the file, or by coordinating export with recorder finalization.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

let on_error_artifacts = collect_debug_artifacts(
&debug_dir.join("on_error"),
"on_error",
&["png", "jpg", "jpeg", "avi"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 中等 · 大型片段会耗尽导出内存

当大型 AVI 触发容量检查并调用 pre_compress_measure 时,pre_compress_measure 会将整个压缩后的片段缓冲到一个 Vec 中,所需内存与片段大小成正比,可能导致内存耗尽并终止导出或应用程序。

请在测量压缩大小时避免将整个压缩后的片段保留在内存中。

另见 src-tauri/src/commands/file_ops.rs:663。

提供给 AI 代理的提示
在 `src-tauri/src/commands/file_ops.rs` 第 662 行:

**大型片段会耗尽导出内存**

当大型 AVI 触发容量检查并调用 `pre_compress_measure` 时,`pre_compress_measure` 会将整个压缩后的片段缓冲到一个 `Vec` 中,所需内存与片段大小成正比,可能导致内存耗尽并终止导出或应用程序。

请在测量压缩大小时避免将整个压缩后的片段保留在内存中。

另见 `src-tauri/src/commands/file_ops.rs:663`。
Original comment in English

🟡 Medium · Large clips exhaust export memory

When a large AVI reaches the capacity check and pre_compress_measure is called, pre_compress_measure buffers the entire deflated clip in a Vec, using memory proportional to the clip size and potentially exhausting memory and terminating the export or application.

Measure compressed size without retaining the entire compressed clip in memory.

Also at src-tauri/src/commands/file_ops.rs:663.

Prompt for AI agents
In `src-tauri/src/commands/file_ops.rs` at line 662:

**Large clips exhaust export memory**

When a large AVI reaches the capacity check and `pre_compress_measure` is called, `pre_compress_measure` buffers the entire deflated clip in a `Vec`, using memory proportional to the clip size and potentially exhausting memory and terminating the export or application.

Measure compressed size without retaining the entire compressed clip in memory.

Also at `src-tauri/src/commands/file_ops.rs:663`.

let on_error_artifacts = collect_debug_artifacts(
&debug_dir.join("on_error"),
"on_error",
&["png", "jpg", "jpeg", "avi"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 中等 · AVI 片段会超出卷大小限制

当 AVI 的压缩 ZIP 条目超出卷的剩余容量预算时(包括在新卷中超出限制的情况),wrote_any 守卫会跳过对空卷的大小检查,而 add_file_to_zip 会将 AVI 作为单个条目写入,导致 ZIP 卷超过 MAX_VOLUME_BYTES,但导出仍报告成功。

首个条目也应遵守卷大小限制;如果 AVI 无法放入空卷,请妥善处理,不要写出超限的卷。

另见 src-tauri/src/commands/file_ops.rs:663。

提供给 AI 代理的提示
在 `src-tauri/src/commands/file_ops.rs` 第 662 行:

**AVI 片段会超出卷大小限制**

当 AVI 的压缩 ZIP 条目超出卷的剩余容量预算时(包括在新卷中超出限制的情况),`wrote_any` 守卫会跳过对空卷的大小检查,而 `add_file_to_zip` 会将 AVI 作为单个条目写入,导致 ZIP 卷超过 `MAX_VOLUME_BYTES`,但导出仍报告成功。

首个条目也应遵守卷大小限制;如果 AVI 无法放入空卷,请妥善处理,不要写出超限的卷。

另见 `src-tauri/src/commands/file_ops.rs:663`。
Original comment in English

🟡 Medium · AVI clips exceed the volume limit

When an AVI's compressed ZIP entry exceeds the remaining volume budget, including when it exceeds the limit in a fresh volume, the wrote_any guard skips the size check for an empty volume, and add_file_to_zip writes the AVI as one entry, producing a ZIP volume larger than MAX_VOLUME_BYTES while the export reports success.

Enforce the volume limit for the first entry too, and handle an AVI that cannot fit in an empty volume without writing an oversized volume.

Also at src-tauri/src/commands/file_ops.rs:663.

Prompt for AI agents
In `src-tauri/src/commands/file_ops.rs` at line 662:

**AVI clips exceed the volume limit**

When an AVI's compressed ZIP entry exceeds the remaining volume budget, including when it exceeds the limit in a fresh volume, the `wrote_any` guard skips the size check for an empty volume, and `add_file_to_zip` writes the AVI as one entry, producing a ZIP volume larger than `MAX_VOLUME_BYTES` while the export reports success.

Enforce the volume limit for the first entry too, and handle an AVI that cannot fit in an empty volume without writing an oversized volume.

Also at `src-tauri/src/commands/file_ops.rs:663`.

let mut images: Vec<_> = rd.flatten().filter(|e| is_image_file(&e.path())).collect();
let mut artifacts: Vec<_> = rd
.flatten()
.filter(|e| e.path().is_file() && has_extension(&e.path(), extensions))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 中等 · 导出内容可能包含不完整的片段

当导出正在收集或复制 AVI 时,录制器直接将 AVI 写入 debug/on_error,collect_debug_artifacts 会接受这个仍在写入的 AVI 路径,而 add_file_to_zip 不会等待录制器完成就将其复制;因此 ZIP 中会包含被截断或无效的片段,导致导出的视频无法可靠播放。

只导出已完成的片段。例如,可以先写入临时路径,并在录制器关闭文件后原子重命名;也可以在导出与录制器完成写入之间进行协调。

提供给 AI 代理的提示
在 `src-tauri/src/commands/file_ops.rs` 第 557 行:

**导出内容可能包含不完整的片段**

当导出正在收集或复制 AVI 时,录制器直接将 AVI 写入 `debug/on_error`,`collect_debug_artifacts` 会接受这个仍在写入的 AVI 路径,而 `add_file_to_zip` 不会等待录制器完成就将其复制;因此 ZIP 中会包含被截断或无效的片段,导致导出的视频无法可靠播放。

只导出已完成的片段。例如,可以先写入临时路径,并在录制器关闭文件后原子重命名;也可以在导出与录制器完成写入之间进行协调。
Original comment in English

🟡 Medium · Exports can contain incomplete clips

When the recorder writes an AVI directly into debug/on_error while an export is collecting or copying it, collect_debug_artifacts accepts the live AVI path, and add_file_to_zip copies it without waiting for the recorder to finish; the ZIP captures a truncated or invalid clip, so the exported video cannot be played reliably.

Only export finalized clips, for example by writing to a temporary path and atomically renaming after the recorder closes the file, or by coordinating export with recorder finalization.

Prompt for AI agents
In `src-tauri/src/commands/file_ops.rs` at line 557:

**Exports can contain incomplete clips**

When the recorder writes an AVI directly into `debug/on_error` while an export is collecting or copying it, `collect_debug_artifacts` accepts the live AVI path, and `add_file_to_zip` copies it without waiting for the recorder to finish; the ZIP captures a truncated or invalid clip, so the exported video cannot be played reliably.

Only export finalized clips, for example by writing to a temporary path and atomically renaming after the recorder closes the file, or by coordinating export with recorder finalization.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant