# AI Video Editor · محرر فيديو

`03 · ai-video-editor · R&D`

محرر فيديو محلي كـ MCP-style substrate — file-level tool API مع hash-verified diffs وaudit trails. Timeline وscripts وasync TTS ككود، وGemini كـ orchestrator.

**النطاق:** Solo · 3 أسابيع  
**الدور:** Local Remotion IDE

**الفيديو:** [YouTube](https://www.youtube.com/watch?v=re_wOoERPjE) · [RuTube](https://rutube.ru/video/private/f9d43170e4449b1dad0d638335fd054d/?p=Z2DwdK3LsCf7CUnt60CnEw)

## شرح الفيديو

محرر فيديو AI محلي مبني كقاعدة لسير عمل تقوده الوكلاء — التايملاين، المعاينات، السكربتات والمهام غير المتزامنة كلها تعيش داخل الكود، فيقدر الـ agent يقرأها، يعدلها ويرجعها سطرا بسطر عبر changesets متحققة بالهاش. تايملاين مخصص بزوم من الفريم إلى الساعات، محرر سكربت بأربع نوافذ CodeMirror، خط async للصوت؛ كل شيء يشتغل محلياً.

محرر فيديو AI محلي: مبني كقاعدة لسير عمل تقوده الوكلاء. التايملاين، المعاينات، السكربتات والمهام غير المتزامنة كلها تعيش داخل الكود نفسه، عشان الـ Agent يقدر يقرأها، يعدلها، ويرجعها سطر بسطر.

التايملاين مصمم خصيصاً: سحب، قص بالشفرة، magnet snap، وزوم من مستوى الفريم إلى ساعات.

محرر السكربت يفتح أي ملف Markdown أو JSON من شجرة المشروع، لحد أربعة نوافذ CodeMirror جنب بعض.

اطلب من الـ Agent يعيد صياغة فقرة، والمحرر يتحدث مباشرة قدامك. كل تعديل هو changeset متحقق بالهاش: طبقه، ارجعه، أو افتح الفرق وشوفه قبل ما يلمس الدسك. واطلب منه يقص ويعيد ترتيب التايملاين، والحركات تنعرض خطوة بخطوة.

توليد الصوت هو أول async pipeline مركّب. الكليب نفسه يعرض التقدم أثناء تشغيل المهمة.

كل شيء يشتغل محلياً. القاعدة جاهزة، والباقي يتركب فوقها.

---

## السياق

> Timeline في الكود — وإلا يبقى agent مجرد نافذة chat.

قيادة timeline فيديو برمجيا من خارج محرر تجاري سطحها ضيق. Premiere Pro ExtendScript يكشف import/export وعمليات timeline أساسية، لكن السطح أضيق من workflow حقيقي يحتاجه agent يولد ويعيد قص المحتوى. DaVinci scripting نظيف وموثق، لكنه في النسخة المدفوعة؛ بقية السوق مغلق أو prototype.

الفيديو scripted يصبح كودا. Remotion compositions هي TSX. السيناريوهات والتوقيتات تعيش في markdown وJSON. عندما يعني التحرير نقل السطور وإعادة قص timing، يستطيع AI coauthor استخدام أدوات المطور نفسها — read slice، replace line range، diff، revert — إذا عامل المحرر script كملف لا كtranscript chat.

## حقائق

| | |
|---|---|
| **النطاق** | 21 يوما solo |
| **الأسطح** | Browser editor + local FastAPI media-service · monorepo + docker-compose · local |
| **Timeline** | Zoom 0.01×–50× · magnet snap · blade · undo/redo |
| **Composition** | Remotion 4.0 · Babel-standalone on-demand compile · per-clip error overlay |
| **AI agent** | Gemini 3 + 2.5 · audit-first changesets · sha256 apply/revert · SSE |
| **Audio** | Async TTS pipeline · queue + state machine على clip · two-speaker dialogue · scenario versioning |
| **الحالة** | Substrate مبني end-to-end · script edits وasync TTS live · agent-orchestrator/export لاحقا |

## المعمارية

### دورة حياة تعديل AI

```text
 1  User                          Type message + Enter
        │
 2  Frontend
        │  POST /ai/chat                       [threadId, model, system_instr]
        ▼
 3  media_service  (FastAPI)
        │  insert thread + message + run[pending]
        │  ThreadPoolExecutor.submit(run_chat_job)
        ▼
 4  run_chat_job  (worker thread)
        │  client.generate_stream(model, contents, tools, config)
        ▼
 5  Gemini  ──►  text  /  thought  /  functionCall
                │
                ▼
              tool_call  (file_read_slices, text_replace_lines, …)
                │
                ▼
              text_tools  ──►  audit  {before, after, meta}
        │
 6  agent_changes_v2
        │  append_file_change · sha256 base/after · unified diff
        ▼
 7  Frontend  ◄── SSE /ai/chat/{run_id}/stream      [streaming|tools|done]
        │
 8  apply_changeset(forward)
        │  verify sha256(file) == base_hash  →  write OR 409 hash_mismatch
        ▼
 9  File written  ·  changeset.status = applied
```

**Audit-payload دائما.** كل tool call يعيد audit payload حتى عند apply=false. Backend يحفظ before/after وsha256 وunified diff في SQLite قبل لمس الملف.

**Hash-verification.** Forward apply يقارن sha256(file) مع base_hash؛ reverse مع after_hash. mismatch يعطي 409 مع expected/actual/direction.

**SSE لا WebSocket.** Endpoint SSE واحد يبث running/streaming/tools/complete/error. sessionStorage يحتفظ بـ run_id لإعادة الاتصال بعد refresh.

### تخطيط المكونات

```text
   Browser                       Local services            Storage
   ───────                       ──────────────            ───────
   Frontend  (Vite · React)      media_service             /projects/<id>/
        │                        (FastAPI :8000)              │
        Zustand · PlaybackStore        │                      ├ project.json
        Remotion Player                ▼                      ├ assets/<sha>.<ext>
        CodeMirror             ┌──────────────────┐           ├ previews/  proxies/
        │                      │  routes (~50)    │           ├ remotion/<aid>/
        │  HTTPS  /api/*       │  ThreadPool(5)   │           │     manifest.json
        ├─────────────────────►│  asyncio.Sem.    │           └ scripts/
        ◄──── SSE stream ──────┤  ffmpeg subproc  │             ├ *.md  /  *.json
                               │  google-genai    │             ├ workflows/*.json
                               └────┬─────────────┘             └ Scenario_TTS.json
                                    │
                                    ▼
                          SQLite (WAL · 11 tables)         External
                          ────────────────────────         ────────
                          threads · messages · runs        Gemini API
                          usage_records · tool_events      google-cloud-speech
                          changesets_v2 + file_changes_v2
                          tts_jobs · stt_jobs
```

**خدمتان، بلا broker.** Frontend + media_service في docker-compose واحد مع /projects volume. لا Redis ولا Celery — SQLite WAL + ThreadPool تقوم بدور queue.

**المشروع يعيش على FS.** project.json هو source of truth. assets content-addressable. عند restart يعيد media_service بناء runtime state من FS + SQLite.

**External provider-agnostic.** الحالي يستخدم google-genai وgoogle-cloud-speech؛ تبديل model يعني إضافة worker لا إعادة كتابة substrate.

### نموذج المشروع والحالة

```text
PROJECT (project.json)             RUNTIME STATE (in-memory)
──────────────────────             ─────────────────────────
Project                            Zustand store
  ├── Asset (×N)                     ├── project        (committed)
  │     · type:                      ├── editorState    (committed playhead)
  │       video|audio|image|         ├── history.past   (≤20 snapshots)
  │       remotion|text|callout      └── openTextContents
  │     · hash · originalPath
  │     · audio.{generationStage,    PlaybackStore  (mini-store, not Zustand)
  │              progress, error}      ├── status   playing|paused|buffering
  │                                    ├── timeSeconds  (live, every frame)
  ├── Folder (×N)                      ├── frame        (live)
  │                                    └── lastUpdateTs  (poller fallback)
  ├── Track (×M)
  │     ├── kind  Video | Audio
  │     └── Clip (×K)
  │           · type  Media | Text | Remotion
  │           · trackId · start · duration
  │           · linkedClipId   (V↔A pair)
  │           · transform      (overlay state)
  │
  └── EditorState
         · playhead    (committed, paused position)
         · zoom · tool · selectedClipIds


SQLITE  (usage.sqlite · WAL · 11 tables)
─────────────────────────────────────────
threads          messages          runs               usage_records
   └── usage           └── status       └── thinking_     └── prompt/output/
       totals              run_id           preset            cached/thought

agent_changesets_v2 ──┬── agent_file_changes_v2
                      │      · seq · path
                      │      · base_hash · after_hash
                      │      · before_text · after_text · patch_text
                      │      · status  pending|ready|applied|reverted
                      │
tool_events           tts_jobs           stt_jobs
   · run_id · seq        · status           · status
   · payload_json        · result_json      · result_json
```

**متجران، cadenceان.** Zustand يحمل committed state؛ PlaybackStore يحمل live time. live updates لا تصل إلى Zustand حتى لا يعيد parent tree حول Remotion Player render كل frame.

**linkedClipId.** عند إسقاط فيديو مع audio، importer يفصل audio asset ويربط clipين عبر linkedClipId. cut/move/delete تتسلسل على الزوج.

**Audit trail في SQLite.** كل AI tool call يكتب changesets_v2 + file_changes_v2 قبل لمس الملف. status هو timeline التعديل forward/reverse.

## قرارات هندسية رئيسية

### 01 · Changesets audit-first مع hash-verification

**القرار.** كل AI tool call يحفظ before/after وhashes وdiff في SQLite؛ apply يقارن current hash ويرفض 409 عند drift.

**لماذا.** AI يكتب ملفات = race condition افتراضيا. hash verification يجعل السباق مرئيا ويعطي preview يدوي للـ prompts غير الموثوقة.

**الكلفة.** عمل إضافي لكل tool call وجداول أكثر ومعاملات apply/revert عبر N ملفات.

### 02 · Committed playhead في store، والـ live playback في ticker جانبي

**القرار.** editorState.playhead في Zustand للـ paused/scrub فقط؛ live time في PlaybackStore خارجي يحدث كل frame.

**لماذا.** تحديث Zustand كل frame يعيد render حول Remotion Player 60 مرة/ثانية ويسبب micro-resyncs. فصل committed/live يحافظ على player.

**الكلفة.** مصدران للوقت وPlaybackController يتوسط كل play/pause/seek.

### 03 · Babel-standalone عند الطلب لـ Remotion clips

**القرار.** Remotion clip مخزن كcode ويترجم runtime عبر @babel/standalone مع React وRemotion API محدود injected.

**لماذا.** المستخدم يعدل في CodeMirror ويحفظ، والإطار التالي يعكس التغيير. dependency lazy-loaded فقط عند أول Remotion clip.

**الكلفة.** Babel chunk كبير وPRELUDE محدود؛ production متعدد المستخدمين يحتاج Worker isolation.

### 04 · System prompts كملفات project live

**القرار.** Prompts في scripts/text-editor/workflows/*.json وتعدل عبر CodeMirror نفسه. كل run يحفظ prompt id/path/name.

**لماذا.** Prompts artifacts مثل بقية ملفات المشروع؛ versioning وanalytics تصبح طبيعية.

**الكلفة.** قراءة من disk لكل request ولا schema validation مخصص للـ workflow JSON.

### 05 · SQLite + ThreadPool كqueue، لا Celery + Redis

**القرار.** AI runs وTTS/STT jobs rows في SQLite مع atomic claim؛ workers ThreadPool/Semaphores داخل FastAPI.

**لماذا.** المنتج single-machine وحمله صغير. broker سيضيف خدمات وفشل تشغيلي بلا قيمة.

**الكلفة.** لا scale أفقي ولا Flower dashboard؛ visibility hand-rolled وmigrations غائبة.

## التقنيات

| | |
|---|---|
| **Frontend** | React 18 · Vite · TypeScript · Zustand+Immer · Remotion 4 · CodeMirror · Tailwind · shadcn/ui |
| **Backend** | Python · FastAPI · pydantic · sqlite3 (raw SQL · WAL) · ffmpeg subprocess |
| **AI** | Gemini 3 (pro/flash preview) + 2.5 · google-genai 1.55 · streaming · thinking · tools · TTS · STT (google-cloud-speech) |
| **Composition** | Remotion 4.0 · @babel/standalone (lazy) · per-clip error overlay |
| **Concurrency** | ThreadPoolExecutor(5) · asyncio.Semaphore(10/6) · ffmpeg sem (global=6, per-asset=3) · LRU caches |
| **Scale** | ~30K LOC TS — 3K timeline + 2.4K AI panel + 2K media + 2.3K properties (each a domain-rich UI surface) · ~8K LOC Py · 16 docs · ~50 routes · 11 SQLite tables |

## الدروس والحالة

### ما سأحمله للأمام

- Audit-first changesets — كل prompt سيئ عاد في click واحد دون خسارة العمل السابق.
- فصل committed/live playhead — pattern صالح لأي player ثقيل parent.
- Geometry في shared utils — preview وbbox يستخدمان نفس normalize/resolve، بلا drift.
- SQLite + ThreadPool كqueue — خلال ثلاثة أسابيع يومية لم أحتج Celery.
- تحيز نحو open code surfaces — Remotion TSX، scenarios markdown/JSON، workflow prompts JSON؛ agent يستطيع authoring لكل طبقة.

### ما سأغيره

- Vitest أزيل مبكرا — لن أكرر ذلك. Babel runtime compilation وhash changesets يحتاجان harness.
- schema يعاد بناؤه عند startup بلا migrations. مقبول لـ solo R&D، لكنه blocker للتسليم.
- TTS long-polls بينما chat SSE؛ transportان حيث كان واحد يكفي. SSE عام للـ background jobs كان سيجعل pipelines اللاحقة مجانية.

R&D · substrate مبني end-to-end · يعمل محليا في Docker. script edits وasync TTS live؛ agent-as-orchestrator وexport هما الشرائح التالية.

---

المصدر: https://ilyadev.xyz/cases/ai-video-editor (HTML) · /cases/ai-video-editor.ar.md (هذا الملف)
السابق: 02 — Restaurant Stock AI Agent · مخزون المطاعم → https://ilyadev.xyz/cases/ai-warehouse.ar.md
التالي: 04 — Bullet Reign · Roblox → https://ilyadev.xyz/cases/roblox-game.ar.md
الفهرس: https://ilyadev.xyz/llms-ar.txt — قائمة دراسات الحالة الكاملة
المؤلف: إليا كازانتسيف — https://ilyadev.xyz/index.ar.md
