Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
3f67254
feat(media): folder browsing in media panel (#58)
cuic19053-hue Jun 22, 2026
116c97c
feat(settings): 7-pane sidebar layout + MCP Instructions pane; home 1…
cuic19053-hue Jun 22, 2026
76f9b0b
feat(media): extract audio track to local file (star export on media …
cuic19053-hue Jun 22, 2026
2a0bf5e
feat(#93): add clip right-click context menu
cuic19053-hue Jun 23, 2026
45ae2a2
feat(timeline): copy / cut / paste clips (⌘C / ⌘X / ⌘V) (#94)
cuic19053-hue Jun 23, 2026
3192a2e
fix(#94): rebase onto main + linkGroup re-mapping + empty-clipboard t…
cuic19053-hue Jun 23, 2026
4cb8ec3
feat(timeline): 吸附迟滞+多探针 / 链接 offset 角标 / 音量橡皮筋 (#99)
cuic19053-hue Jun 23, 2026
1278015
feat(swap-media): 实现 SwapMedia 编辑命令,支持替换 clip 媒体 (#101)
cuic19053-hue Jun 23, 2026
0e702a1
feat(inspector): live sampling + missing fields (crop/fade/flip) (#97)
cuic19053-hue Jun 23, 2026
8b2dd4e
feat(timeline): drag-drop new track + Option/Alt-drag duplicate (#98)
cuic19053-hue Jun 23, 2026
15a5869
style: fix cargo fmt import in command.rs (#97)
cuic19053-hue Jun 23, 2026
91abbb4
style: fix cargo fmt in command.rs and tests (#101)
cuic19053-hue Jun 23, 2026
bc0ae4c
style: fix cargo fmt in duplicate.rs (#98)
cuic19053-hue Jun 23, 2026
6e31aae
fix: correct cargo fmt in command_apply.rs (#101)
cuic19053-hue Jun 23, 2026
595c9c8
fix: add ..Default::default() for new ClipProperties fields (#97)
cuic19053-hue Jun 23, 2026
5d614f0
fix: correct cargo fmt in duplicate.rs - split long assert lines (#98)
cuic19053-hue Jun 23, 2026
e54a8e1
fix: align trailing comment with 43 spaces (#101)
cuic19053-hue Jun 23, 2026
26718b0
fix: split long assert/assert_eq lines for cargo fmt (#98)
cuic19053-hue Jun 23, 2026
79770aa
fix: compile errors - rotation_track type + borrow conflict (#98)
cuic19053-hue Jun 23, 2026
839a8e8
style: fix cargo fmt - import wrap + assert_eq single line (#98)
cuic19053-hue Jun 23, 2026
8bbf618
style: fix import wrapping for cargo fmt (#98)
cuic19053-hue Jun 23, 2026
25ca9e1
fix: clippy errors - remove redundant clone on Copy types (#98)
cuic19053-hue Jun 23, 2026
35d9eab
fix(preview): align playback audio routing
Jun 24, 2026
6aa297b
Merge remote-tracking branch 'origin/main' into codex/pr-78-fix-20260624
Jun 24, 2026
b6018a0
Merge remote-tracking branch 'origin/main' into codex/pr-121-fix-2026…
Jun 24, 2026
eae2fe3
Merge remote-tracking branch 'origin/main' into codex/pr-122-fix-2026…
Jun 24, 2026
e1883a7
Merge remote-tracking branch 'origin/main' into codex/pr-77-fix-20260624
Jun 24, 2026
3363fb7
Merge remote-tracking branch 'origin/main' into codex/pr-108-fix-2026…
Jun 24, 2026
abb74ba
chore: trim playback whitespace
Jun 24, 2026
92e8a54
chore: trim playback whitespace
Jun 24, 2026
59a47a6
chore: trim playback whitespace
Jun 24, 2026
2acd161
Merge remote-tracking branch 'origin/main' into codex/pr-105-fix-2026…
Jun 24, 2026
9a3301d
Merge remote-tracking branch 'origin/main' into codex/pr-120-fix-2026…
Jun 24, 2026
b2358b6
Merge remote-tracking branch 'origin/main' into codex/pr-123-fix-2026…
Jun 24, 2026
2d655b9
Merge remote-tracking branch 'origin/main' into codex/pr-79-fix-20260624
Jun 24, 2026
df1e318
fix(media): import folder tile icon
Jun 24, 2026
a61b8a8
fix(timeline): remove duplicate context menu handler
Jun 24, 2026
ee17867
Merge branch 'codex/pr-78-fix-20260624' into codex/integration-20260624
Jun 24, 2026
f2b0c95
Merge branch 'codex/pr-121-fix-20260624' into codex/integration-20260624
Jun 24, 2026
3339289
Merge branch 'codex/pr-122-fix-20260624' into codex/integration-20260624
Jun 24, 2026
92e61ff
Merge branch 'codex/pr-105-fix-20260624' into codex/integration-20260624
Jun 24, 2026
e2f5a9b
Merge branch 'codex/pr-108-fix-20260624' into codex/integration-20260624
Jun 24, 2026
270feb1
Merge branch 'codex/pr-120-fix-20260624' into codex/integration-20260624
Jun 24, 2026
587df36
Merge branch 'codex/pr-123-fix-20260624' into codex/integration-20260624
Jun 24, 2026
5cad5b8
Merge branch 'codex/pr-77-fix-20260624' into codex/integration-20260624
Jun 24, 2026
65b7411
Merge branch 'codex/pr-79-fix-20260624' into codex/integration-20260624
Jun 24, 2026
0c9af64
fix(preview): prevent playback resume flash and scrub overflow
Jun 24, 2026
e59c7b1
fix(timeline): correct trackpad zoom direction
Jun 24, 2026
abab0c0
fix(editing): drop-at-cursor + reliable delete + blue selection + res…
Jun 24, 2026
48c080d
fix(preview/editing): pause no longer jumps back, scrub no longer stu…
Jun 24, 2026
2975dca
fix(ipc): camelCase per-variant serde so delete/split/inspector/etc. …
Jun 24, 2026
7b4e41e
docs(preview): mark two-surface playback for rewrite per #142 (upstre…
Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ OpenTake 是 Palmier Pro 的跨平台社区分支:Rust core(Tauri 2 + React
```
PRIMARY-CN/
├── palmier-pro-upstream/ # 上游只读参考(Swift macOS 视频编辑器,GPL-3.0)
│ └── Sources/PalmierPro/ # 209 .swift,~43K 行,编辑逻辑的真理来源
└── OpenTake/ # 本项目
├── docs/ # 架构 / 路线图 / 模块移植规格
│ └── Sources/PalmierPro/ # 上游编辑逻辑的真理来源
└── OpenTake/ # 本项目(当前工作仓库)
├── assets/ # 品牌图标与静态资源
├── crates/ # Rust workspace(domain / ops / project / media / render / agent / gen / core)
├── docs/ # 架构 / 路线图 / 规格 / 上游拆解
│ └── _analysis/ # 上游拆解报告(4 份横切分析)
├── crates/ # Rust workspace(待创建)
├── src-tauri/ # Tauri 2 桌面壳(待创建)
├── web/ # React + TypeScript 前端(待创建)
└── services/ # 可选后端服务(待创建)
├── src-tauri/ # Tauri 2 桌面壳
└── web/ # React + TypeScript 前端
```

## 从何处开始
Expand Down Expand Up @@ -46,9 +46,10 @@ PRIMARY-CN/
| 桌面壳 | Tauri 2 |
| 前端 | React + TypeScript + Vite |
| 状态管理 | Zustand(前端只读镜像) |
| 编解码 | ffmpeg-next(libav*) |
| 编解码 | ffmpeg-sidecar(调用系统 ffmpeg/ffprobe) |
| 帧合成 | wgpu(自写合成器) |
| 音频播放 | cpal |
| 语义搜索 | ort + SigLIP2(tokenizers 预处理) |
| MCP server | rmcp(streamable-http-server) |

## 移植法则
Expand All @@ -75,7 +76,7 @@ PRIMARY-CN/
- 所有数值常量走 `AppTheme`,不硬编码。
- 悬停态用 CSS `:hover` + 圆角背景,图标用 lucide-react。

## 构建(Phase 0 完成后)
## 构建

```bash
# Rust core
Expand All @@ -90,7 +91,7 @@ cd web && pnpm install && pnpm build
cargo tauri dev
```

当前状态:**设计阶段**,代码尚未产生。ROADMAP Phase 0 为工程脚手架
当前状态:核心实现已落地,Rust workspace、Tauri 壳、React 前端、MCP/Agent 层和主要文档都在仓库中;ROADMAP 继续追踪剩余的高风险差距和后续阶段

## 上游参考

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

## 0. 项目身份
- OpenTake = [palmier-io/palmier-pro](https://github.com/palmier-io/palmier-pro)(Swift 原生 macOS 视频编辑器,GPL-3.0)的**跨平台社区分支**。**忠实 1:1 复刻其编辑逻辑与 UI**(用户反复强调:别自己发明,照上游源码复刻;除登录/账号外都对齐),再加更强 Agent 能力。
- 栈:Tauri 2 + Rust workspace + React/TS;媒体 = FFmpeg(sidecar)+ wgpu(合成)+ cpal + whisper-rs + candle/ort。
- 栈:Tauri 2 + Rust workspace + React/TS;媒体 = ffmpeg-sidecar + wgpu(合成)+ cpal + whisper-rs + ort/SigLIP2
- GitHub `appergb/OpenTake`(Public,main 受保护)。许可 GPL-3.0。

## 1. 目录
Expand Down
2 changes: 1 addition & 1 deletion DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ PRIMARY-CN/
| 整体架构 | **Tauri 2**(Rust core + Web 前端) | 与 Rust 核心天然契合;二进制小;一套代码覆盖三桌面平台 |
| 核心语言 | **Rust** | 领域模型 / 编辑操作 / 工程格式 / 媒体管线 / MCP server |
| 前端 | **React + TypeScript** | 生态最全,AI/人协作最顺,契合既有 web 规则 |
| 媒体引擎 | **FFmpeg 绑定**(`ffmpeg-next` 等) | 替代 AVFoundation:解码/合成/导出/缩略图/波形;LGPL/GPL 与本项目 GPL-3.0 兼容 |
| 媒体引擎 | **FFmpeg 调用层**(`ffmpeg-sidecar`, 调用系统 `ffmpeg`/`ffprobe`) | 替代 AVFoundation:解码/合成/导出/缩略图/波形;LGPL/GPL 与本项目 GPL-3.0 兼容 |
| 目标平台 | **桌面优先**:macOS / Windows / Linux | 先把跨平台桌面做扎实(已实现"让 mac 用户也能用 + 扩到 Win/Linux") |
| 生成式 AI | **自建后端 / BYOK** | 上游 genAI 闭源(Convex+Clerk),代码不在仓库,必须新建:轻量代理对接 fal.ai/Replicate/各厂商 API |

Expand Down
8 changes: 4 additions & 4 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ OpenTake は CapCut / DaVinci Resolve / Final Cut Pro の代替品ではあり

| 機能 | 技術 |
|:--|:--|
| コーデック | FFmpeg (`ffmpeg-next`) |
| コーデック | ffmpeg-sidecar(システムの ffmpeg/ffprobe を呼び出し) |
| コンポジター | wgpu カスタムコンポジター |
| 音声再生 | cpal |
| 文字起こし | whisper-rs |
| 意味検索 | candle / ort + SigLIP2 |
| 意味検索 | ort + SigLIP2 + tokenizers |

### 🌐 BYOK AI生成

Expand Down Expand Up @@ -233,15 +233,15 @@ cd web && pnpm install && pnpm build
cd .. && cargo tauri dev
```

> ⚠️ **現在の状態**: 初期設計段階。アーキテクチャ、ロードマップ、モジュール移植マップは完了。コード実装中
> ⚠️ **現在の状態**: Rustワークスペース、Tauriシェル、React UI、MCP/Agent層、主要ドキュメントは揃っており、ROADMAP は残るギャップと高リスク項目を追跡しています

---

## 📋 バージョン履歴

| バージョン | 日付 | マイルストーン |
|:--|:--|:--|
| `0.1.0-dev` | 2026-06 | Phase 0+1: Cargo workspace + Domain models + Edit ops |
| `0.1.0-dev` | 2026-06 | 開発中スナップショット: ワークスペース、主要 crate、Tauri シェル、React UI、MCP/Agent 層 |
| *(planned)* `1.0.0` | TBD | Phase 10: フルリリース |

📖 [完全なロードマップ](docs/ROADMAP.md)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ Built-in Agent chat panel shares tool definitions and system prompt with MCP.

| Capability | Technology |
|:--|:--|
| Codec | FFmpeg (`ffmpeg-next`) — battle-tested Rust bindings |
| Codec | ffmpeg-sidecar (system ffmpeg/ffprobe) |
| Compositor | wgpu custom compositor — multi-track layering + per-frame property sampling + affine/crop/blend |
| Audio Playback | cpal |
| Transcription | whisper-rs (word/segment timestamps) |
| Semantic Search | candle / ort + SigLIP2 dual-encoder |
| Semantic Search | ort + SigLIP2 + tokenizers |

### 🌐 BYOK AI Generation

Expand Down Expand Up @@ -273,7 +273,7 @@ cd web && pnpm install && pnpm build
cd .. && cargo tauri dev
```

> ⚠️ **Current Status**: Early design phase. Architecture, roadmap, and module port maps are complete; code implementation in progress.
> ⚠️ **Current Status**: Active implementation. The Rust workspace, Tauri shell, React UI, MCP/Agent layer, and core docs are in place; the roadmap now tracks the remaining parity gaps and hard blockers.

The sibling directory `palmier-pro-upstream/` contains upstream Swift sources for reference during porting.

Expand All @@ -283,7 +283,7 @@ The sibling directory `palmier-pro-upstream/` contains upstream Swift sources fo

| Version | Date | Milestone |
|:--|:--|:--|
| `0.1.0-dev` | 2026-06 | Phase 0+1: Cargo workspace + Domain models + Edit ops + Tauri scaffold |
| `0.1.0-dev` | 2026-06 | Active development snapshot: workspace, core crates, Tauri shell, React UI, and MCP/Agent surface |
| *(planned)* `0.2.0` | TBD | Phase 2: Persistence + Media import + Thumbnails + Waveform |
| *(planned)* `0.3.0` | TBD | Phase 3: Timeline UI + Preview + MCP Server |
| *(planned)* `0.4.0` | TBD | Phase 4: GPU Compositor (wgpu) + Text rasterization |
Expand Down
8 changes: 4 additions & 4 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ Agent 操作时间线时,每次工具返回附带 `context_signal`:

| 能力 | 技术 |
|:--|:--|
| 编解码 | FFmpeg (`ffmpeg-next`) — 成熟 Rust 绑定 |
| 编解码 | ffmpeg-sidecar(调用系统 ffmpeg/ffprobe) |
| 帧合成 | wgpu 自写合成器 — 多轨叠加 + 逐帧属性采样 + 仿射/裁剪/混合 |
| 音频播放 | cpal |
| 语音转写 | whisper-rs (word/segment 时间戳) |
| 语义搜索 | candle / ort + SigLIP2 图文双编码器 |
| 语义搜索 | ort + SigLIP2 + tokenizers |

### 🌐 BYOK 生成式 AI

Expand Down Expand Up @@ -251,15 +251,15 @@ cd web && pnpm install && pnpm build
cd .. && cargo tauri dev
```

> ⚠️ **当前状态**: 早期设计阶段。架构设计、路线图、模块移植地图已完成,代码正在落地中
> ⚠️ **当前状态**: 核心实现已落地,Rust 工作空间、Tauri 壳、React UI、MCP/Agent 层和核心文档都已就位;路线图现在主要追踪剩余的对齐差距和高风险阻塞点

---

## 📋 版本历史

| 版本 | 日期 | 里程碑 |
|:--|:--|:--|
| `0.1.0-dev` | 2026-06 | Phase 0+1: Cargo workspace + Domain models + Edit ops + Tauri scaffold |
| `0.1.0-dev` | 2026-06 | 进行中的开发快照:工作空间、核心 crate、Tauri 壳、React UI 与 MCP/Agent 层 |
| *(planned)* `0.2.0` | TBD | Phase 2: Persistence + Media import + Thumbnails + Waveform |
| *(planned)* `0.3.0` | TBD | Phase 3: Timeline UI + Preview + MCP Server |
| *(planned)* `0.4.0` | TBD | Phase 4: GPU Compositor (wgpu) + Text rasterization |
Expand Down
1 change: 1 addition & 0 deletions crates/opentake-agent/src/mcp/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ impl Dispatcher {
opacity: a.opacity,
transform: a.transform.map(transform_from_arg),
text_content: a.content.clone(),
..Default::default()
};
let res = self.apply(EditCommand::SetClipProperties {
clip_ids,
Expand Down
59 changes: 59 additions & 0 deletions crates/opentake-media/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,65 @@ impl MediaEngine {
pub fn export_pause(&self) -> ExportPause {
self.export_pause.clone()
}

/// Extract the audio track from `input` into `output` as a self-contained
/// audio file. The container/codec is picked from the output extension:
/// `.m4a` → AAC in MP4, `.mp3` → libmp3lame, `.wav` → PCM s16le. Video is
/// dropped (`-vn`). Streams the mux directly (input file → output file),
/// never holding the full audio in memory — suitable for long sources.
///
/// Returns the output path on success. Errors bubble up as `MediaError::Ffmpeg`
/// when ffmpeg is missing, exits non-zero, or the extension is unsupported.
pub fn extract_audio(&self, input: &Path, output: &Path) -> Result<std::path::PathBuf> {
extract_audio_file(input, output).map(|_| output.to_path_buf())
}
}

/// Run `ffmpeg -y -i <input> -vn <codec args> <output>` to mux the audio track
/// into a standalone file. Codec is selected by `output`'s extension so the
/// caller just picks a save-path filter in the native dialog and the right
/// encoder falls out. `-y` overwrites (the save dialog already confirmed).
fn extract_audio_file(input: &Path, output: &Path) -> Result<()> {
let codec_args: Vec<&str> = match output.extension().and_then(|e| e.to_str()) {
Some("m4a") | Some("m4r") | Some("aac") => vec!["-c:a", "aac", "-b:a", "192k"],
Some("mp3") => vec!["-c:a", "libmp3lame", "-b:a", "192k"],
Some("wav") => vec!["-c:a", "pcm_s16le"],
Some(ext) => {
return Err(MediaError::Ffmpeg(format!(
"unsupported audio extension: .{ext} (use m4a, mp3, or wav)"
)));
}
None => {
return Err(MediaError::Ffmpeg(
"output path has no extension (use .m4a, .mp3, or .wav)".into(),
));
}
};

let mut cmd = std::process::Command::new(ff::ffmpeg_path());
cmd.arg("-y")
.arg("-i")
.arg(input)
.arg("-vn")
.args(&codec_args)
.arg(output);

let out = cmd
.output()
.map_err(|e| MediaError::Ffmpeg(format!("ffmpeg spawn: {e}")))?;
if !out.status.success() {
let stderr = String::from_utf8_lossy(&out.stderr);
return Err(MediaError::Ffmpeg(format!(
"ffmpeg exited {}{}",
out.status,
if stderr.trim().is_empty() {
String::new()
} else {
format!(": {}", stderr.trim())
}
)));
}
Ok(())
}

#[cfg(test)]
Expand Down
Loading
Loading