Skip to content

feat(tools): 新增开场视频与曲目伪装的编辑工具 - #78

Merged
clansty merged 6 commits into
MuNET-OSS:mainfrom
HuimanQAQ:feat/intro-movie-camouflage
Oct 28, 2026
Merged

clansty merged 6 commits into
MuNET-OSS:mainfrom
HuimanQAQ:feat/intro-movie-camouflage

Conversation

@HuimanQAQ

@HuimanQAQ HuimanQAQ commented Oct 28, 2026 •

Copy link
Copy Markdown

概述

配合 AquaMai 的 Fancy.CustomIntroCinematic / Fancy.TrackCamouflage,在「工具」页新增编辑工具:

  • 开场视频:为指定乐曲设置 LocalAssets/IntroMovies/Enter_<id>.mp4(或 _L/_R 分屏),并自动生成 Enter_<id>.acb / .awb
  • 曲目伪装:编辑 LocalAssets/Camouflages/<id>.toml 与 <id>_jacket.*,含封面预览

后端 Controllers/Tools/FancyToolController.cs

  • 开场视频:GetIntroMovie / GetIntroMovieFile(PhysicalFile + Range)/ GetIntroMovieList / SetIntroMovie / DeleteIntroMovie
  • 上传视频统一转 H.264 MP4,只留画面(与游戏内一致:AquaMai 的 VideoPlayer 不输出视频音轨)
  • 音轨自动抽成 Enter_<id>.acb / .awb(复用 Audio.ExtractAudioFromMp4 + Audio.ConvertToMai),游戏里由它们发声
  • 支持「左右屏同一视频(单文件)」与「左右分开」,替换单侧时自动补齐另一侧
  • 开场音频单独替换:SetIntroAudio / DeleteIntroAudio
  • 音频预览:GetIntroAudioFile 把 acb/awb 解成 wav(按 acb mtime 缓存、支持 Range),供前端试听
  • 曲目伪装:GetCamouflage / GetCamouflageJacket / GetCamouflageList / SetCamouflage(Tomlyn + 原子写入)/ SetCamouflageJacket / DeleteCamouflage
  • 删除/覆盖统一走 DeleteFilesWithRetry / MoveFileWithRetry:文件被占用(例如还在预览)时先探测再重试并最终兜底,不会卡死也不会误报成功

VideoConvert(新增可选参数,其他调用方行为不变)

  • KeepAudio:是否保留音轨(默认丢弃)
  • ExtraArgs + H264QualityArgs(codec):按编码器给画质参数。本机探测到 h264_mf,默认设置码率极低(720×720 仅 1.0 Mbps),加参数后同源 1280×1280 可到 13 Mbps

前端 views/Tools/IntroCamouflageModal.tsx

  • 全部使用 MuNET-UI 组件(Tabs / Select / TextInput / CheckBox / Button / Modal),曲目选择 = 搜索框 + Select
  • 左右分屏用 1:2 并排预览;视频一律 muted,声音只播一路解码后的音频,播放/暂停/拖动进度与画面双向同步,避免重声
  • 未选择乐曲时所有输入与按钮禁用
  • 已有列表显示真实曲名(开场视频用 L=R / L / R 标记),载入时清空搜索并定位到该曲目
  • 替换封面只刷新封面状态,不会冲掉尚未保存的表单内容
  • 删除/覆盖前主动释放播放器句柄,避免 Windows 因占用删不掉文件

测试

  • dotnet build -c Crack、pnpm typecheck、pnpm build 全部通过
  • 实测:带音轨 mp4 → 输出只有 video 流,自动生成 acb(6688B)+awb;无音轨 mp4 → 清掉旧 acb/awb;side=L/R 分别写入并补齐另一侧;mp3 替换音频正常;GetIntroAudioFile 200/206 正常
  • 文件被占用时删除返回 delete-failed(约 3s),解锁后正常删除

View guided diff

Sourcery 摘要

在工具页加入开场视频与曲目伪装的完整编辑工作流,并将相关媒体处理能力整合到后端与前端。

新功能:

  • 在工具页新增开场视频编辑功能,支持上传、预览、替换和删除单视频或左右分屏视频,并自动管理独立的游戏音频文件。
  • 新增曲目伪装编辑功能,可配置曲名、曲师、谱师、解锁条件及封面。

错误修复:

  • 改进媒体文件的覆盖和删除流程,减少因播放器占用而导致操作失败或误报成功的情况。

改进:

  • 增强视频转换选项,支持控制是否保留音轨,并根据编码器应用画质参数。
  • 提供支持 Range 的媒体预览、音频试听和前端播放同步,并补充简体中文、繁体中文及英文界面文案。

日常维护:

  • 为新增的工具接口生成前端 API 类型和客户端调用代码。
Original summary in English

Sourcery 摘要

在 Tools 页面中集成 AquaMai 自定义内容的片头影片和曲目伪装编辑器。

新功能:

  • 在 Tools 页面中添加 AquaMai 片头影片编辑流程,支持单画面或分屏视频、独立音频、预览、替换和删除。
  • 添加曲目伪装编辑功能,可编辑元数据和封面图,并支持预览和保存。

错误修复:

  • 当活动预览导致文件仍被锁定时,确保媒体替换和删除操作能够可靠地报告失败。

增强功能:

  • 改进视频转换的质量控制,同时确保片头视频不含声音,并单独管理音频。
  • 支持可启用范围选择的媒体预览、同步分屏播放以及本地化 UI 文本。

测试:

  • 验证后端构建,以及新工具流程的前端类型检查和构建。

杂项:

  • 为新的 Fancy Tool 端点生成类型化前端 API 模型和客户端方法。
Original summary in English

Sourcery 总结

在工具页集成 AquaMai 开场视频与曲目伪装的完整编辑工作流。

新功能:

  • 在工具页新增 AquaMai 开场视频编辑,支持单视频或左右分屏视频、独立音频、预览、替换和删除。
  • 新增曲目伪装编辑,支持修改曲名、曲师、谱师、解锁条件及封面并提供预览。

问题修复:

  • 改进媒体文件覆盖和删除流程,在文件被预览占用时可靠地重试并报告失败。

功能增强:

  • 增强视频转换能力,支持按编码器应用画质参数,并将开场视频音频独立管理。
  • 提供支持 Range 的媒体预览、分屏播放同步和独立音频试听。

文档:

  • 补充开场视频与曲目伪装功能的简体中文、繁体中文和英文界面文案。

测试:

  • 验证后端构建及前端类型检查和构建。

杂项:

  • 为新增 Fancy Tool 接口生成类型化前端 API 模型和客户端方法。
Original summary in English

Sourcery 总结

将 AquaMai 开场影片和曲目伪装编辑功能集成到 Tools 页面。

新功能:

  • 在 Tools 页面中新增 AquaMai 开场影片管理工作流,支持共用视频或分屏视频、独立音频、预览、替换和删除。
  • 新增曲目伪装编辑功能,支持编辑元数据、解锁条件和封面图,并支持预览和移除。

错误修复:

  • 当预览播放器仍占用文件时,媒体替换和删除操作现在可以可靠地报告失败。

增强功能:

  • 改进视频转换功能,支持显式选择视频流、配置编码器质量设置,以及添加额外的输出参数。
  • 提供支持范围选择的媒体预览、同步分屏播放、独立音频预览,以及本地化的用户界面文本。

构建:

  • 为新增的 Fancy Tool 端点生成类型化前端 API 模型和客户端方法。

测试:

  • 验证后端编译、前端类型检查和生产构建。
Original summary in English

Sourcery 摘要

将 AquaMai 片头影片和曲目伪装编辑功能集成到 Tools 页面。

新功能:

  • 在 Tools 页面中添加 AquaMai 片头影片管理工作流,支持单画面或分屏视频、独立音频、预览、替换和删除。
  • 添加曲目伪装编辑功能,支持编辑元数据、解锁条件和封面图,并提供预览和移除功能。

错误修复:

  • 当预览播放器仍在占用文件时,确保媒体替换和删除操作能够可靠地报告失败。

增强功能:

  • 改进视频转换质量控制,并使片头视频的音频与视频流分离。
  • 提供同步分屏播放、支持范围选择的媒体预览,以及本地化的 UI 文案。

构建:

  • 为新增的 Fancy Tool 端点生成带类型的前端 API 模型和客户端方法。

测试:

  • 验证后端编译、前端类型检查和生产构建。
Original summary in English

Summary by Sourcery

Integrate AquaMai intro movie and track camouflage editing into the Tools page.

New Features:

  • Add Tools-page workflows for managing AquaMai intro movies, including single or split-screen videos, independent audio, previews, replacement, and deletion.
  • Add track camouflage editing for metadata, unlock conditions, and jacket artwork with preview and removal support.

Bug Fixes:

  • Make media replacement and deletion report failures reliably when preview players still hold files open.

Enhancements:

  • Improve video conversion quality controls and keep intro video audio separate from the video stream.
  • Provide synchronized split-screen playback, range-enabled media previews, and localized UI text.

Build:

  • Generate typed frontend API models and client methods for the new Fancy Tool endpoints.

Tests:

  • Validate backend compilation and frontend type checking and production builds.

- 后端新增 FancyToolController,配合 AquaMai 的 Fancy.CustomIntroCinematic / Fancy.TrackCamouflage:
  - 开场视频:GetIntroMovie / GetIntroMovieFile(支持 Range)/ GetIntroMovieList / SetIntroMovie / DeleteIntroMovie
  - 上传视频统一转 H.264 MP4,并按当前编码器给画质参数(h264_mf 默认画质极低,实测同源 2.86 Mbps → 13 Mbps)
  - 支持左右屏同一视频(L=R)与左右分开;替换单侧时自动补齐另一侧
  - 音轨自动抽取成 Enter_<id>.acb / .awb(游戏里由 acb/awb 发声);另提供 SetIntroAudio / DeleteIntroAudio 单独替换音频
  - 曲目伪装:GetCamouflage / GetCamouflageJacket / GetCamouflageList / SetCamouflage(Toml)/ SetCamouflageJacket / DeleteCamouflage
  - 删除与覆盖统一走占用重试(DeleteFilesWithRetry / MoveFileWithRetry),文件被占用时不会卡死或误报成功
- VideoConvert 新增 KeepAudio / ExtraArgs 选项与 H264QualityArgs,其他调用方行为不变
- 前端:工具页新增入口 + IntroCamouflageModal
  - 使用 MuNET-UI 的 Tabs / Select / TextInput / CheckBox,曲目选择带搜索框过滤
  - 左右分屏 1:2 预览,播放/暂停/拖动进度双向同步,显示实际分辨率与文件路径
  - 未选择乐曲时所有输入与按钮禁用
  - 已有列表显示真实曲名,载入时清空搜索并定位到该曲目
- 预览里左右两个 <video> 都带音轨时会同时出声(重声)。现在视频一律 muted,
  声音只播一路:新增 GetIntroAudioFileApi 把 Enter_<id>.acb/.awb 解成 wav
  (按 acb 修改时间缓存到临时目录,支持 Range),前端用隐藏的 <audio> 与视频
  同步播放/暂停/拖动进度
- SetIntroMovie 不再保留视频音轨(KeepAudio=false),mp4 回归纯画面,
  与游戏内一致(AquaMai 的 VideoPlayer 本来就不输出视频音轨)
- 重新生成 apiGen
@sourcery-ai

sourcery-ai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

审阅者指南

本 PR 在工具页新增开场视频与曲目伪装编辑能力:后端负责媒体转换、音频封装、TOML/封面文件管理及占用重试,前端通过统一弹窗提供曲目选择、分屏同步预览、编辑上传和删除,并同步扩展视频转换器与 API/多语言支持。

开场视频上传与音频提取时序图

sequenceDiagram
    participant User
    participant Modal as IntroCamouflageModal
    participant API as FancyToolController
    participant Converter as VideoConvert
    participant Audio as Audio
    participant Assets as IntroMovies

    User->>Modal: chooseIntroMovie()
    Modal->>API: SetIntroMovie(id, side, file)
    API->>Converter: ConvertVideo(KeepAudio=false, ExtraArgs)
    Converter-->>API: silent H.264 MP4
    API->>Audio: ExtractAudioFromMp4(inputPath, wavPath)
    Audio-->>API: extracted WAV
    API->>Audio: ConvertToMai(wavPath, acbPath)
    Audio-->>API: ACB and AWB
    API->>Assets: MoveFileWithRetry(video, target)
    API->>Assets: MoveFileWithRetry(acb, awb)
    API-->>Modal: FancyToolResult
    Modal->>API: GetIntroMovie(id)
    API-->>Modal: video and audio availability
Loading

开场视频同步预览时序图

sequenceDiagram
    participant User
    participant Modal as IntroCamouflageModal
    participant VideoL as Left video
    participant VideoR as Right video
    participant Audio as Decoded WAV audio

    User->>VideoL: play or pause
    VideoL->>VideoR: syncPlay()
    VideoL->>Audio: playAudio()
    User->>VideoL: seek
    VideoL->>VideoR: syncSeek()
    VideoL->>Audio: syncAudioSeek()
    User->>VideoR: play or pause
    VideoR->>VideoL: syncPlay()
    VideoR->>Audio: playAudio()
Loading

AquaMai 本地资源实体关系图

erDiagram
    INTRO_MOVIE {
        int id PK
        file single_mp4
        file left_mp4
        file right_mp4
        file acb
        file awb
    }
    CAMOUFLAGE {
        int id PK
        string toml
        string name
        string artist
        string noteDesigner
        boolean hideNoteDesigner
        double unlockScore
        file jacket
    }
    INTRO_MOVIE ||--|| CAMOUFLAGE : "may share track id"
Loading

文件级变更

变更 详情 文件
新增开场视频与独立音频的完整文件管理和转换后端。
  • 提供视频查询、列表、Range 预览、上传、覆盖及删除接口。
  • 将视频统一转换为静音 H.264 MP4,并从源文件提取音频生成 ACB/AWB;支持单文件及左右分屏模式。
  • 支持独立音频替换、删除和 WAV 预览缓存。
  • 通过重试、文件占用探测和原子/临时文件处理降低覆盖删除失败及音画不一致风险。
MaiChartManager/Controllers/Tools/FancyToolController.cs
新增曲目伪装配置与封面管理 API。
  • 读写 TOML 中的曲名、曲师、谱师、隐藏谱师和解锁成绩字段。
  • 支持 JPG/PNG 封面预览、替换、列表查询和删除,并在替换时清理其他扩展名。
  • 采用原子写入配置文件并返回统一错误结果。
MaiChartManager/Controllers/Tools/FancyToolController.cs
扩展视频转换能力并为 H.264 编码器提供质量参数。
  • 增加 KeepAudio 和 ExtraArgs 选项,同时保持默认丢弃音轨的既有行为。
  • 按 libx264、Media Foundation、NVENC、QSV 等编码器追加画质参数。
  • 调整流映射以支持可选音频轨及 AAC 输出。
MaiChartManager/Utils/VideoConvert.cs
新增前端开场视频与曲目伪装编辑弹窗及工具入口。
  • 使用 MuNET-UI 提供曲目搜索选择、Tab 切换、表单编辑、上传、保存和删除操作。
  • 实现单视频及左右分屏预览,并同步播放、暂停和进度;视频静音且单独播放解码后的音频。
  • 在上传或删除前释放媒体句柄,刷新封面时保留未保存的表单内容,并展示真实曲名及视频侧别。
MaiChartManager/Front/src/views/Tools/IntroCamouflageModal.tsx
MaiChartManager/Front/src/views/Tools/index.tsx
为新增后端接口生成前端 API 类型和客户端方法。
  • 增加开场视频、音频和曲目伪装 DTO 类型。
  • 生成查询、上传、删除及列表接口的 FormData/JSON 客户端调用。
MaiChartManager/Front/src/client/apiGen.ts
补充新工具的多语言界面文案。
  • 新增英文、简体中文和繁体中文的工具标题、操作提示、错误信息及确认文案。
MaiChartManager/Front/src/locales/en.yaml
MaiChartManager/Front/src/locales/zh.yaml
MaiChartManager/Front/src/locales/zh-TW.yaml

提示与命令

与 Sourcery 交互

  • 触发新一轮审阅: 在拉取请求中评论 @sourcery-ai review。
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 根据审阅评论创建 GitHub issue: 回复审阅评论,请 Sourcery 根据该评论创建 issue。也可以回复审阅评论并发送 @sourcery-ai issue 来创建 issue。
  • 生成拉取请求标题: 在拉取请求标题中的任意位置输入 @sourcery-ai,即可随时生成标题。也可以在拉取请求中评论 @sourcery-ai title,随时重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中想要生成摘要的位置输入 @sourcery-ai summary,即可随时在该位置生成 PR 摘要。也可以在拉取请求中评论 @sourcery-ai summary,随时重新生成摘要。
  • 生成审阅者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时重新生成审阅者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这个功能会很有用。
  • 忽略所有 Sourcery 审阅: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审阅。如果你想从头开始进行新一轮审阅,这尤其有用——别忘了评论 @sourcery-ai review 来触发新一轮审阅!

自定义使用体验

访问你的控制面板来:

  • 启用或停用审阅功能,例如 Sourcery 生成的拉取请求摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

本 PR 在工具页新增开场视频与曲目伪装编辑能力:后端负责媒体转换、音频封装、TOML/封面文件管理及占用重试,前端通过统一弹窗提供曲目选择、分屏同步预览、编辑上传和删除,并同步扩展视频转换器与 API/多语言支持。

Sequence diagram for intro video upload and audio extraction

sequenceDiagram
    participant User
    participant Modal as IntroCamouflageModal
    participant API as FancyToolController
    participant Converter as VideoConvert
    participant Audio as Audio
    participant Assets as IntroMovies

    User->>Modal: chooseIntroMovie()
    Modal->>API: SetIntroMovie(id, side, file)
    API->>Converter: ConvertVideo(KeepAudio=false, ExtraArgs)
    Converter-->>API: silent H.264 MP4
    API->>Audio: ExtractAudioFromMp4(inputPath, wavPath)
    Audio-->>API: extracted WAV
    API->>Audio: ConvertToMai(wavPath, acbPath)
    Audio-->>API: ACB and AWB
    API->>Assets: MoveFileWithRetry(video, target)
    API->>Assets: MoveFileWithRetry(acb, awb)
    API-->>Modal: FancyToolResult
    Modal->>API: GetIntroMovie(id)
    API-->>Modal: video and audio availability
Loading

Sequence diagram for synchronized intro preview

sequenceDiagram
    participant User
    participant Modal as IntroCamouflageModal
    participant VideoL as Left video
    participant VideoR as Right video
    participant Audio as Decoded WAV audio

    User->>VideoL: play or pause
    VideoL->>VideoR: syncPlay()
    VideoL->>Audio: playAudio()
    User->>VideoL: seek
    VideoL->>VideoR: syncSeek()
    VideoL->>Audio: syncAudioSeek()
    User->>VideoR: play or pause
    VideoR->>VideoL: syncPlay()
    VideoR->>Audio: playAudio()
Loading

Entity relationship diagram for AquaMai local assets

erDiagram
    INTRO_MOVIE {
        int id PK
        file single_mp4
        file left_mp4
        file right_mp4
        file acb
        file awb
    }
    CAMOUFLAGE {
        int id PK
        string toml
        string name
        string artist
        string noteDesigner
        boolean hideNoteDesigner
        double unlockScore
        file jacket
    }
    INTRO_MOVIE ||--|| CAMOUFLAGE : "may share track id"
Loading

File-Level Changes

Change Details Files
新增开场视频与独立音频的完整文件管理和转换后端。
  • 提供视频查询、列表、Range 预览、上传、覆盖及删除接口。
  • 将视频统一转换为静音 H.264 MP4,并从源文件提取音频生成 ACB/AWB;支持单文件及左右分屏模式。
  • 支持独立音频替换、删除和 WAV 预览缓存。
  • 通过重试、文件占用探测和原子/临时文件处理降低覆盖删除失败及音画不一致风险。
MaiChartManager/Controllers/Tools/FancyToolController.cs
新增曲目伪装配置与封面管理 API。
  • 读写 TOML 中的曲名、曲师、谱师、隐藏谱师和解锁成绩字段。
  • 支持 JPG/PNG 封面预览、替换、列表查询和删除,并在替换时清理其他扩展名。
  • 采用原子写入配置文件并返回统一错误结果。
MaiChartManager/Controllers/Tools/FancyToolController.cs
扩展视频转换能力并为 H.264 编码器提供质量参数。
  • 增加 KeepAudio 和 ExtraArgs 选项,同时保持默认丢弃音轨的既有行为。
  • 按 libx264、Media Foundation、NVENC、QSV 等编码器追加画质参数。
  • 调整流映射以支持可选音频轨及 AAC 输出。
MaiChartManager/Utils/VideoConvert.cs
新增前端开场视频与曲目伪装编辑弹窗及工具入口。
  • 使用 MuNET-UI 提供曲目搜索选择、Tab 切换、表单编辑、上传、保存和删除操作。
  • 实现单视频及左右分屏预览,并同步播放、暂停和进度;视频静音且单独播放解码后的音频。
  • 在上传或删除前释放媒体句柄,刷新封面时保留未保存的表单内容,并展示真实曲名及视频侧别。
MaiChartManager/Front/src/views/Tools/IntroCamouflageModal.tsx
MaiChartManager/Front/src/views/Tools/index.tsx
为新增后端接口生成前端 API 类型和客户端方法。
  • 增加开场视频、音频和曲目伪装 DTO 类型。
  • 生成查询、上传、删除及列表接口的 FormData/JSON 客户端调用。
MaiChartManager/Front/src/client/apiGen.ts
补充新工具的多语言界面文案。
  • 新增英文、简体中文和繁体中文的工具标题、操作提示、错误信息及确认文案。
MaiChartManager/Front/src/locales/en.yaml
MaiChartManager/Front/src/locales/zh.yaml
MaiChartManager/Front/src/locales/zh-TW.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@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.

嗨——我已审阅你的更改,整体看起来很棒!

Sourcery 评估

需要人工审核。 替换片头视频或封面会覆盖现有的游戏文件,而删除操作可能会移除这些资源及其配置;回滚应用程序并不能恢复之前的文件。影响仅限于所选曲目,但恢复可能需要使用备份或重新创建这些资源。


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

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. Replacing an intro video or jacket overwrites existing game files, and the delete actions can remove those assets and their configuration; reverting the application will not restore the previous files. The impact is limited to the selected track, but recovery may require a backup or recreating the assets.


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

@cubic-dev-ai cubic-dev-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.

All reported issues were addressed across 8 files

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread MaiChartManager/Utils/VideoConvert.cs Resolved
Comment thread MaiChartManager/Utils/VideoConvert.cs Resolved
- VideoConvert:删除 KeepAudio 选项(IVF/USM 放不下音频,正数 Padding 路径也会忽略它),
  恢复统一的 -map 0:0;RunConcatenate 的输出参数也带上 ExtraArgs
- FancyToolController:
  - 开场音频 acb/awb 成对替换:先备份旧文件,任一移动失败就回滚
  - SetIntroMovie 先清理与新布局冲突的旧文件,清理失败直接返回 delete-failed,
    避免单文件与 L/R 同时存在
  - SetCamouflageJacket 先写临时文件再覆盖目标,写入失败不会破坏已有封面
  - Delete* 接口补 EnsureGamePath 守卫,避免 GamePath 为空时删到工作目录下的相对路径
- 前端 IntroCamouflageModal:
  - 替换音频后 bump previewToken,避免 <audio> 继续用旧 URL 播缓存
  - loadIntroMovie / loadCamouflage / refreshCamouflageJacket 加竞态保护,丢弃过期响应
- en.yaml:pickMusicFirst 改为 Select a song first,camoUnlockScore 明确为 Score

@cubic-dev-ai cubic-dev-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.

All reported issues were addressed across 4 files (changes from recent commits).

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.

View guided diff | Re-trigger cubic

Comment thread MaiChartManager/Utils/VideoConvert.cs Resolved
- SetIntroMovie 把「转码 → 清理旧布局 → 落地新视频 → 落地音频」做成一个事务:
  操作前备份 Enter_<id>.mp4 / _L / _R / .acb / .awb,任一步失败整体回滚,
  不会出现「新音频配旧画面」「旧布局已删但新视频没落地」这类半状态
- 抽出 BuildIntroAudio(只生成到临时目录)与 IntroFileTransaction,
  SetIntroAudio 复用同一套事务;删除不再需要的 CreateIntroAudio / RestoreOrDelete
- VideoConvert:-map 0:0 改为 -map 0:v:0,避免「第 0 个流其实是音频」的容器选错流导致转换失败

@cubic-dev-ai cubic-dev-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.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

- 新增按 id 的 SemaphoreSlim(IntroFileGates):SetIntroMovie / SetIntroAudio 与
  DeleteIntroMovie / DeleteIntroAudio / DeleteCamouflage 都先拿锁再执行,finally 释放,
  不同曲目互不阻塞
- 原因:上传视频时会顺带重写 acb/awb,两个并发请求交错提交可能出现
  「mp4 来自请求 A、acb/awb 来自请求 B」的音画不匹配;事务本身无法防止交错

@cubic-dev-ai cubic-dev-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.

All reported issues were addressed across 1 file (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

- 用固定 64 条 SemaphoreSlim 的分段锁替换按 id 建字典的 IntroFileGates:
  内存恒定、不需要回收,id 校验也提前到加锁之前
- DeleteIntroMovie / DeleteIntroAudio / DeleteCamouflage 改为 async action +
  await WaitAsync(),避免转码长时间持锁时阻塞线程池线程
- SetCamouflage / SetCamouflageJacket 也拿同一把锁(按 id),
  删除不会再与伪装配置 / 封面上传交错,留下不完整的伪装文件

@cubic-dev-ai cubic-dev-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.

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

View guided diff | Re-trigger cubic

@clansty
clansty merged commit 5d56bf0 into MuNET-OSS:main Oct 28, 2026
3 checks passed
@HuimanQAQ
HuimanQAQ deleted the feat/intro-movie-camouflage branch October 28, 2026 20:33
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.

2 participants