# revfactory/subtitle-pro architecture

> Architecture diagram of the GitHub repository revfactory/subtitle-pro, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-03). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/revfactory/subtitle-pro
- Repository: https://github.com/revfactory/subtitle-pro

## Overview

#### Purpose and Entry Points
Subtitle Pro is a Next.js web service that generates Korean subtitles for YouTube videos, then synchronizes them as an in-player overlay. The landing flow begins at `app/page.tsx`; direct viewing uses `/watch?v=VIDEO_ID` via `app/watch/page.tsx`. Server work is initiated and polled through `app/api/subtitles/route.ts`.

#### Application Boundary
The project uses Next.js 16 App Router, React 19, and TypeScript. Browser components own YouTube playback, job polling, and subtitle rendering; server-side API/pipeline code owns media processing and third-party API access. The shared boundary contract is `types/subtitle.ts`, defining cues, job states, and job payloads. Cue timestamps are seconds, matching YouTube Player `getCurrentTime()`.

#### Job API and State Lifecycle
`app/api/subtitles/route.ts` exposes POST job creation and GET job-status polling. It coordinates with the in-memory job registry in `lib/job-store.ts`; this registry tracks stages such as extracting, transcribing, translating, done, and failures. `hooks/use-subtitle-job.ts` repeatedly queries the API and supplies status/results to the watch UI.

#### Subtitle Generation Pipeline
`lib/pipeline.ts` orchestrates the sequential generation flow:
1. Extract audio from a YouTube video.
2. Transcribe audio into timestamped source-language segments.
3. Batch/parallel translate segments to Korean.
4. Persist and return finalized subtitle cues.

It composes `lib/extract.ts`, `lib/transcribe.ts`, and `lib/translate.ts`. Pipeline behavior—including cache, model, and batching settings—is centralized in `lib/config.ts`.

#### External Processing and Persistence
Audio extraction invokes local `yt-dlp` and `ffmpeg`, requiring both as host-installed system tools. `lib/transcribe.ts` calls AssemblyAI for speech-to-text; `lib/translate.ts` calls Anthropic Claude for Korean translation. API credentials are environment-provided (`ASSEMBLYAI_API_KEY`, `ANTHROPIC_API_KEY`). Completed subtitles are cached on local disk under `.cache/`, keyed by video ID; job state itself is process-local and is not durable across server restarts.

#### Watch and Playback Composition
`components/watch-view.tsx` assembles the viewing experience. `components/youtube-player.tsx` integrates the YouTube IFrame Player and emits playback time. `components/subtitle-overlay.tsx` selects and displays the active cue for that time, while `components/subtitle-controls.tsx` and `lib/overlay-settings.ts` manage presentation preferences. `hooks/use-fullscreen.ts` handles fullscreen behavior around the player/overlay boundary.

#### Input and Navigation Flow
`components/video-id-form.tsx` accepts a YouTube URL or ID and routes the user to the watch page. `lib/youtube.ts` normalizes or validates YouTube identifiers before pipeline usage. The resulting control flow is: user input or direct watch URL → watch UI starts/polls subtitle job → server pipeline creates/caches cues → player time drives overlay selection.

Main entry points: [`lib/pipeline.ts`](https://github.com/revfactory/subtitle-pro/blob/main/lib/pipeline.ts) (Subtitle pipeline), [`app/api/subtitles/route.ts`](https://github.com/revfactory/subtitle-pro/blob/main/app/api/subtitles/route.ts) (Subtitle job API), [`components/watch-view.tsx`](https://github.com/revfactory/subtitle-pro/blob/main/components/watch-view.tsx) (Watch view), [`types/subtitle.ts`](https://github.com/revfactory/subtitle-pro/blob/main/types/subtitle.ts) (Subtitle contract)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_browser["Browser UI"]
  node_landing["Landing page<br/>Next.js route<br/>[page.tsx]"]
  node_video_form["Video ID form<br/>React component<br/>[video-id-form.tsx]"]
  node_watch_page["Watch page<br/>Next.js route<br/>[page.tsx]"]
  node_watch_view["Watch view<br/>React composition<br/>[watch-view.tsx]"]
  node_subtitle_job_hook["Subtitle job hook<br/>React hook"]
  node_youtube_player["YouTube player<br/>React component<br/>[youtube-player.tsx]"]
  node_subtitle_overlay["Subtitle overlay<br/>React component"]
  node_subtitle_controls["Subtitle controls<br/>React component"]
  node_overlay_settings["Overlay settings<br/>client state"]
end

subgraph group_server["Server generation"]
  node_subtitle_api{{"Subtitle job API<br/>App Router API<br/>[route.ts]"}}
  node_job_store[("In-memory job registry<br/>process-local state<br/>[job-store.ts]")]
  node_pipeline["Subtitle pipeline<br/>orchestrator<br/>[pipeline.ts]"]
  node_youtube_validation["YouTube ID validation<br/>[youtube.ts]"]
  node_subtitle_contract["Subtitle contract<br/>TypeScript types<br/>[subtitle.ts]"]
  node_audio_extraction["Audio extraction<br/>pipeline stage<br/>[extract.ts]"]
  node_transcription["Speech transcription<br/>pipeline stage<br/>[transcribe.ts]"]
  node_translation["Korean translation<br/>pipeline stage<br/>[translate.ts]"]
  node_pipeline_config["Pipeline configuration<br/>configuration module<br/>[config.ts]"]
end

subgraph group_external["External dependencies"]
  node_media_tools{{"yt-dlp and ffmpeg<br/>host-installed tools"}}
  node_assemblyai{{"AssemblyAI<br/>speech-to-text API"}}
  node_claude{{"Anthropic Claude<br/>translation API"}}
  node_subtitle_cache[("Local subtitle cache<br/>disk cache")]
end

node_landing -->|"renders"| node_video_form
node_video_form -->|"navigates with video ID"| node_watch_page
node_watch_page -->|"renders"| node_watch_view
node_watch_view -->|"starts and reads jobs"| node_subtitle_job_hook
node_subtitle_job_hook -->|"POST / GET polling"| node_subtitle_api
node_watch_view -->|"hosts"| node_youtube_player
node_youtube_player -->|"playback time in seconds"| node_subtitle_overlay
node_watch_view -->|"renders"| node_subtitle_controls
node_subtitle_controls -->|"updates preferences"| node_overlay_settings
node_overlay_settings -->|"presentation settings"| node_subtitle_overlay
node_subtitle_api -->|"creates and reads state"| node_job_store
node_subtitle_api -->|"runs generation"| node_pipeline
node_subtitle_api -->|"validates video ID"| node_youtube_validation
node_subtitle_api -->|"job payloads"| node_subtitle_contract
node_pipeline -->|"reads and writes completed cues"| node_subtitle_cache
node_pipeline -->|"1. extract audio"| node_audio_extraction
node_audio_extraction -->|"invokes"| node_media_tools
node_pipeline -->|"2. transcribe"| node_transcription
node_transcription -->|"speech-to-text request"| node_assemblyai
node_pipeline -->|"3. translate"| node_translation
node_translation -->|"Korean translation request"| node_claude
node_pipeline -->|"uses settings"| node_pipeline_config
node_pipeline -->|"finalizes cues"| node_subtitle_contract
node_subtitle_job_hook -->|"consumes status and cues"| node_subtitle_contract
node_subtitle_overlay -->|"selects active cue"| node_subtitle_contract

click node_landing "https://github.com/revfactory/subtitle-pro/blob/main/app/page.tsx"
click node_video_form "https://github.com/revfactory/subtitle-pro/blob/main/components/video-id-form.tsx"
click node_watch_page "https://github.com/revfactory/subtitle-pro/blob/main/app/watch/page.tsx"
click node_watch_view "https://github.com/revfactory/subtitle-pro/blob/main/components/watch-view.tsx"
click node_subtitle_job_hook "https://github.com/revfactory/subtitle-pro/blob/main/hooks/use-subtitle-job.ts"
click node_youtube_player "https://github.com/revfactory/subtitle-pro/blob/main/components/youtube-player.tsx"
click node_subtitle_overlay "https://github.com/revfactory/subtitle-pro/blob/main/components/subtitle-overlay.tsx"
click node_subtitle_controls "https://github.com/revfactory/subtitle-pro/blob/main/components/subtitle-controls.tsx"
click node_overlay_settings "https://github.com/revfactory/subtitle-pro/blob/main/lib/overlay-settings.ts"
click node_subtitle_api "https://github.com/revfactory/subtitle-pro/blob/main/app/api/subtitles/route.ts"
click node_job_store "https://github.com/revfactory/subtitle-pro/blob/main/lib/job-store.ts"
click node_pipeline "https://github.com/revfactory/subtitle-pro/blob/main/lib/pipeline.ts"
click node_youtube_validation "https://github.com/revfactory/subtitle-pro/blob/main/lib/youtube.ts"
click node_subtitle_contract "https://github.com/revfactory/subtitle-pro/blob/main/types/subtitle.ts"
click node_audio_extraction "https://github.com/revfactory/subtitle-pro/blob/main/lib/extract.ts"
click node_transcription "https://github.com/revfactory/subtitle-pro/blob/main/lib/transcribe.ts"
click node_translation "https://github.com/revfactory/subtitle-pro/blob/main/lib/translate.ts"
click node_pipeline_config "https://github.com/revfactory/subtitle-pro/blob/main/lib/config.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_landing,node_video_form,node_watch_page,node_watch_view,node_subtitle_job_hook,node_youtube_player,node_subtitle_overlay,node_subtitle_controls,node_overlay_settings toneBlue
class node_subtitle_api,node_job_store,node_pipeline,node_youtube_validation,node_subtitle_contract,node_audio_extraction,node_transcription,node_translation,node_pipeline_config toneAmber
class node_media_tools,node_assemblyai,node_claude,node_subtitle_cache toneMint
```

## Components

### Browser UI

Client-side viewing, playback, and job polling.

- [Landing page](https://github.com/revfactory/subtitle-pro/blob/main/app/page.tsx): Next.js route · `app/page.tsx`
- [Video ID form](https://github.com/revfactory/subtitle-pro/blob/main/components/video-id-form.tsx): React component · Accepts a YouTube URL or video ID and navigates to watch. · `components/video-id-form.tsx`
- [Watch page](https://github.com/revfactory/subtitle-pro/blob/main/app/watch/page.tsx): Next.js route · Direct entry point for /watch?v=VIDEO_ID. · `app/watch/page.tsx`
- [Watch view](https://github.com/revfactory/subtitle-pro/blob/main/components/watch-view.tsx): React composition · Combines playback, job status, and subtitle presentation. · `components/watch-view.tsx`
- [Subtitle job hook](https://github.com/revfactory/subtitle-pro/blob/main/hooks/use-subtitle-job.ts): React hook · Creates jobs and polls status. · `hooks/use-subtitle-job.ts`
- [YouTube player](https://github.com/revfactory/subtitle-pro/blob/main/components/youtube-player.tsx): React component · Emits YouTube playback time. · `components/youtube-player.tsx`
- [Subtitle overlay](https://github.com/revfactory/subtitle-pro/blob/main/components/subtitle-overlay.tsx): React component · Selects the active cue from playback time. · `components/subtitle-overlay.tsx`
- [Subtitle controls](https://github.com/revfactory/subtitle-pro/blob/main/components/subtitle-controls.tsx): React component · `components/subtitle-controls.tsx`
- [Overlay settings](https://github.com/revfactory/subtitle-pro/blob/main/lib/overlay-settings.ts): client state · Stores subtitle presentation preferences. · `lib/overlay-settings.ts`

### Server generation

API, job lifecycle, and subtitle pipeline.

- [Subtitle job API](https://github.com/revfactory/subtitle-pro/blob/main/app/api/subtitles/route.ts): App Router API · POST creates generation jobs; GET returns job status. · `app/api/subtitles/route.ts`
- [In-memory job registry](https://github.com/revfactory/subtitle-pro/blob/main/lib/job-store.ts): process-local state · Tracks extracting, transcribing, translating, done, and failures. · `lib/job-store.ts`
- [Subtitle pipeline](https://github.com/revfactory/subtitle-pro/blob/main/lib/pipeline.ts): orchestrator · Sequentially extracts, transcribes, translates, and returns cues. · `lib/pipeline.ts`
- [YouTube ID validation](https://github.com/revfactory/subtitle-pro/blob/main/lib/youtube.ts): utility · Normalizes and validates video identifiers. · `lib/youtube.ts`
- [Subtitle contract](https://github.com/revfactory/subtitle-pro/blob/main/types/subtitle.ts): TypeScript types · Defines cues, job states, and payloads; timestamps use seconds. · `types/subtitle.ts`
- [Audio extraction](https://github.com/revfactory/subtitle-pro/blob/main/lib/extract.ts): pipeline stage · Downloads and converts video audio. · `lib/extract.ts`
- [Speech transcription](https://github.com/revfactory/subtitle-pro/blob/main/lib/transcribe.ts): pipeline stage · Produces timestamped source-language segments. · `lib/transcribe.ts`
- [Korean translation](https://github.com/revfactory/subtitle-pro/blob/main/lib/translate.ts): pipeline stage · Batch-translates segments to Korean. · `lib/translate.ts`
- [Pipeline configuration](https://github.com/revfactory/subtitle-pro/blob/main/lib/config.ts): configuration module · Centralizes cache, model, and batching behavior. · `lib/config.ts`

### External dependencies

Host tools, AI services, and local cache.

- **yt-dlp and ffmpeg**: host-installed tools · Required local executables for audio extraction.
- **AssemblyAI**: speech-to-text API · Authenticated with ASSEMBLYAI_API_KEY.
- **Anthropic Claude**: translation API · Authenticated with ANTHROPIC_API_KEY.
- **Local subtitle cache**: disk cache · Completed cues under .cache/, keyed by video ID.

## Connections

- Landing page → Video ID form: renders
- Video ID form → Watch page: navigates with video ID
- Watch page → Watch view: renders
- Watch view → Subtitle job hook: starts and reads jobs
- Subtitle job hook → Subtitle job API: POST / GET polling
- Watch view → YouTube player: hosts
- YouTube player → Subtitle overlay: playback time in seconds
- Watch view → Subtitle controls: renders
- Subtitle controls → Overlay settings: updates preferences
- Overlay settings → Subtitle overlay: presentation settings
- Subtitle job API → In-memory job registry: creates and reads state
- Subtitle job API → Subtitle pipeline: runs generation
- Subtitle job API → YouTube ID validation: validates video ID
- Subtitle job API → Subtitle contract: job payloads
- Subtitle pipeline → Local subtitle cache: reads and writes completed cues
- Subtitle pipeline → Audio extraction: 1. extract audio
- Audio extraction → yt-dlp and ffmpeg: invokes
- Subtitle pipeline → Speech transcription: 2. transcribe
- Speech transcription → AssemblyAI: speech-to-text request
- Subtitle pipeline → Korean translation: 3. translate
- Korean translation → Anthropic Claude: Korean translation request
- Subtitle pipeline → Pipeline configuration: uses settings
- Subtitle pipeline → Subtitle contract: finalizes cues
- Subtitle job hook → Subtitle contract: consumes status and cues
- Subtitle overlay → Subtitle contract: selects active cue
