Files
momentry_playground/AGENTS.md

6.6 KiB
Raw Blame History

MoMentry Playground - AGENTS.md

概述

MoMentry Playground 是一個整合式桌面應用程式,提供:

  • 多格式媒體播放(視頻、音頻、圖片)
  • Markdown/PDF/HTML 檢視
  • Frame-精確的視頻控制
  • 與 momentry_core 處理模組的進度監控
  • Database 查詢功能

技術棧

元件 技術
語言 Rust 2021
桌面框架 tao + wry
視頻播放 SDL2 + FFmpeg-sidecar
前端 HTML/CSS/JS (WebView)
後端接口 HTTP API (momentry_core port 3002)
數據庫 PostgreSQL, MongoDB, Qdrant (via API)

構建/測試/代碼質量命令

構建

# Debug 構建
cargo build

# Release 構建
cargo build --release

# 運行
cargo run

# 指定功能運行
cargo run --features "youtube,cloud"

測試

# 運行所有測試
cargo test

# 運行單個測試
cargo test test_name

# 運行並顯示輸出
cargo test -- --nocapture

# 運行 doc tests
cargo test --doc

代碼質量

# 格式化代碼
cargo fmt

# 檢查格式化
cargo fmt -- --check

# Lint + 自動修復
cargo clippy --fix --allow-dirty --allow-staged

# Lint 檢查
cargo clippy

# 類型檢查
cargo check

# 完整檢查(相當於所有以上)
cargo build --all-targets

WASM 目標(如使用 Yew

# 添加 WASM 目標
rustup target add wasm32-unknown-unknown

# 使用 Trunk 開發
trunk serve

# Production 構建
trunk build --release

代碼風格指南

格式規範

  • 最大行長: 100 字符
  • 縮進: 4 空格(使用 rustfmt 自動處理)
  • 換行: Unix 風格 (\n)

命名慣例

// 類型/結構體/枚舉: PascalCase
struct VideoPlayer;
enum PlaybackState;
trait MediaViewer;

// 函數/方法/變量: snake_case
fn play_video();
let current_frame = 0;
let is_playing = true;

// 常量: SCREAMING_SNAKE_CASE
const MAX_FRAME_BUFFER: usize = 10;
const SEEK_DELAY_MS: u64 = 500;

// 模塊: snake_case
mod video_player;
pub mod ffmpeg;

// 公開 API: 完整單詞
fn get_playback_position() -> Duration;
fn set_volume() -> Result<(), PlayerError>;

錯誤處理

// 使用 anyhow 進行應用級錯誤處理
use anyhow::{Context, Result, anyhow};

fn load_video(path: &str) -> Result<VideoFile> {
    let file = File::open(path)
        .with_context(|| format!("Failed to open video: {}", path))?;
    // ...
}

// 定義專用錯誤枚舉
#[derive(Debug, thiserror::Error)]
pub enum PlayerError {
    #[error("Codec not supported: {0}")]
    UnsupportedCodec(String),
    
    #[error("Seek failed: {0}")]
    SeekFailed(String),
    
    #[error("FFmpeg error: {stderr}")]
    FFmpegError { stderr: String },
}

模塊結構

// src/lib.rs - 庫入口
pub mod player;
pub mod ui;
pub mod viewer;
pub mod api;

// 每個模塊的組織
mod player {
    pub mod video;    // 公開子模塊
    mod controls;     // 私有實現
    
    pub use video::{VideoPlayer, VideoEvent};
}

並發安全

// 使用 Arc<Mutex<T>> 共享狀態
let player = Arc::new(Mutex::new(VideoPlayer::new()));

// 在多線程間共享 Frame buffer
type FrameBuffer = Arc<Mutex<VecDeque<Frame>>>;

// Spawn 線程時克隆 Arc
let player_clone = Arc::clone(&player);
std::thread::spawn(move || {
    // ...
});

文檔注釋

/// 視頻播放器核心結構
///
/// # Example
/// ```
/// let player = VideoPlayer::new();
/// player.open("video.mp4")?;
/// player.play()?;
/// ```
pub struct VideoPlayer {
    // ...
}

/// 播放事件
#[derive(Debug, Clone, PartialEq)]
pub enum PlayEvent {
    /// 播放開始
    Play,
    /// 播放暫停
    Pause,
    /// 進度更新 (當前幀, 總幀數)
    Progress(u64, u64),
    /// 播放結束
    End,
}

依賴管理

# 明確版本範圍
[dependencies]
anyhow = "1.0"
serde = { version = "1.0", features = ["derive"] }

# 避免使用 * 導入
# 錯誤: use std::collections::*;
# 正確: use std::collections::{HashMap, HashSet};

API 設計

// 使用 Result 明確錯誤
fn command(&self, cmd: &str) -> Result<String>;

// 公開方法要有文檔
/// 發送播放命令
///
/// # Arguments
/// * `cmd` - 命令字串 ("play", "pause", "seek <time>")
///
/// # Errors
/// 返回無效命令或播放錯誤
pub fn command(&self, cmd: &str) -> Result<String> {
    // ...
}

WebView 前端規範

HTML 結構

<div id="app">
  <div id="toolbar"><!-- 控制工具欄 --></div>
  <div id="input-area"><!-- 命令輸入 --></div>
  <div id="media-viewport"><!-- 媒體顯示 --></div>
  <div id="controls"><!-- 播放控制 --></div>
  <div id="status-bar"><!-- 狀態信息 --></div>
  <div id="output-log"><!-- 日誌輸出 --></div>
</div>

JS 命令接口

// 發送命令到 Rust 後端
function sendCommand(cmd) {
    window.momentry_command(cmd);
}

// 接收後端事件
window.momentry_on_event = function(event) {
    console.log('Event:', event);
};

CSS 樣式

:root {
    --bg-primary: #1e1e1e;
    --bg-secondary: #2d2d2d;
    --text-primary: #ffffff;
    --accent: #007acc;
    --error: #f44747;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; }

外部依賴

FFmpeg (必需)

# macOS
brew install ffmpeg

# Linux
sudo apt install ffmpeg

# 驗證
ffmpeg -version
ffprobe -version

yt-dlp (YouTube 支援)

brew install yt-dlp  # macOS
pip install yt-dlp    # pip

環境變量

# API 服務地址
export MOMENTRY_API_URL=http://localhost:3002

# 數據庫連接
export DATABASE_URL=postgresql://user:pass@localhost:5432/momentry
export QDRANT_URL=http://localhost:6333

# 輸出目錄
export MOMENTRY_OUTPUT_DIR=./output

# 日誌級別
export RUST_LOG=debug

開發工作流

1. 創建功能分支

git checkout -b feature/video-controls

2. 開發與測試

cargo test feature_name
cargo clippy --fix
cargo fmt
cargo build --release

3. 提交使用Conventional Commits

git commit -m "feat(player): add frame-precise seeking"
git commit -m "fix(controls): correct volume sync"
git commit -m "docs: update AGENTS.md"

4. 推送與 PR

git push -u origin feature/video-controls
# 在 Gitea 創建 PR → main

常見問題

Q: FFmpeg 路徑找不到

// 在代碼中指定路徑
let ffmpeg_path = std::path::Path::new("/opt/homebrew/bin/ffmpeg");
VideoDecoder::new(ffmpeg_path)

Q: WebView 不顯示

確保 index.html 在正確的資源路徑,或使用 include_bytes! 嵌入。

Q: 編譯緩慢

# 使用 sccache
cargo install sccache
export RUSTC_WRAPPER=sccache