Skip to content

Repository files navigation

Leg2Sub


Leg2Sub


AboutFeaturesGPU / CUDAInstallationArchitectureDevelopmentLicense

Electron 39 React 19 Vite 7 Python core CUDA optional License


Leg2Sub - screenshot placeholder


📖 About

Leg2Sub transcribes, translates and subtitles videos locally, with optional GPU acceleration (NVIDIA/CUDA) or CPU fallback. It is a desktop app (Electron + Vite + React) with a Python core (WhisperX) serving the interface, rather than the other way around — there is no HTTP server, no web UI and no Docker: everything runs as a local process on your machine.


✨ Features

Screen Input Output
Subtitle Videos MP4/MOV/AVI SRT + MP4 with softsub and/or hardsub
Translate Subtitles SRT/VTT Translated SRT (Google Translate)
Transcribe Videos MP4/MOV/AVI Transcribed text + SRT
Colorize Subtitles SRT Styled ASS (color, font size, outline and box background)

Transcription engines: WhisperX (with word-level alignment) or Whisper. Device: GPU (CUDA), CPU or automatic.


⚙️ GPU / CUDA

  • The Settings screen shows the real GPU: its name, VRAM and driver come from nvidia-smi (detection independent of torch), so a physical GPU appears as "DETECTED" even before the environment is ready.
  • uv.lock resolves CPU-only torch on Windows (the CUDA deps are gated to Linux). So when setting up the environment, if there is an NVIDIA GPU the app automatically installs the CUDA torch build on top of uv sync (from the download.pytorch.org/whl/cuXXX index), enabling real acceleration. The CUDA version lives in the CUDA_INDEX_URL constant in src/main/pythonEnv.ts. Because the CPU and CUDA wheels share the same version string (2.8.0 vs 2.8.0+cu126), the reinstall is forced with --reinstall-package — otherwise uv would treat the requirement as already satisfied and CUDA would never install.
  • If you had the environment in CPU mode and then added/enabled a GPU, click Check again in Settings — torch is reinstalled with CUDA support.
  • The Whisper models (large-v3, large-v3-turbo, ...) are not downloaded during environment setup; they are fetched automatically on first use, depending on the chosen model, and cached in the user home directory (~/.cache/huggingface and ~/.cache/whisper).

⚙️ Requirements

  • Node.js 20+
  • uv and Git on PATH — uv provisions Python and installs the WhisperX fork via git
  • An NVIDIA GPU + CUDA driver are optional — without them the app runs on CPU

🚀 Installation

git clone https://github.com/Paulogb98/Leg2Sub.git
cd Leg2Sub

npm install
npm run dev

On the first run, open Settings → Set up environment inside the app so Electron runs uv sync in core/ and creates the venv (includes torch and the WhisperX fork — a several-GB download; larger in CUDA mode).


🏗️ Architecture

Everything lives at the repository root (the Electron app is the root — there is no desktop/ subfolder):

Leg2Sub/
├── core/               # Python engine: WhisperX (fork github.com/Paulogb98/whisperX) + ffmpeg
│   ├── worker.py           # single entry point called by the app: 1 JSON job via stdin, NDJSON progress via stdout
│   ├── system_info.py      # reports python/torch/CUDA/GPU/ffmpeg as JSON (Settings screen)
│   ├── utils/              # library: whisperx/whisper, ffmpeg, subtitles (SRT/ASS/VTT), translation, color styling
│   └── pyproject.toml      # dependencies managed via uv (uv.lock pins the versions)
├── src/main/           # main process: window, IPC, managed Python venv, job spawning
├── src/preload/        # contextIsolation bridge (window.api)
├── src/renderer/src/   # React UI (screens, components, zustand store)
└── src/shared/         # TypeScript types shared across main/preload/renderer

How the desktop talks to the core

No HTTP server: the Electron main process manages its own Python venv (created in userData/pyenv on first run, via Settings → "Set up environment", using uv sync) and, for each job, spawns python core/worker.py, sends the job description as JSON over stdin and reads NDJSON progress events from stdout:

{"type":"progress","step":1,"stepLabel":"Transcribing with WHISPERX","totalSteps":4,"progressPct":42,"elapsedS":12.4}
{"type":"done","outputs":{"srt":"...","softsub":"...","hardsub":"..."}}
{"type":"error","message":"..."}

The 4 job kinds (subtitle, translate, transcribe, colorize) map 1:1 to the app screens and to the handlers in core/worker.py.


🛠️ Development

npm run dev         # electron-vite dev server + Electron window
npm run typecheck   # tsc --noEmit for main/preload and renderer
npm run lint        # eslint
npm run build:win   # or build:mac / build:linux — packaged installer

electron-builder.yml copies the whole core/ as an extra package resource (extraResources), so the packaged app loads the same Python code used in development. Tested only on Windows so far; mac/linux builds have not been validated.

Runtime locations (outside the repository)

  • Python venv: userData/pyenv (Windows: %APPDATA%\Leg2Sub\pyenv). Ready marker: pyenv/.ready.
  • User settings: userData/settings.json.
  • Model cache: ~/.cache/huggingface and ~/.cache/whisper (several GB — relevant when uninstalling/cleaning).

🤝 Contributing

git checkout -b feature/YourFeature
# ... your changes ...
git commit -m 'feat: add YourFeature'
git push origin feature/YourFeature

📄 License

GPLv3 — see LICENSE.


🙏 Acknowledgments

  • 🎙️ WhisperX — transcription with word-level alignment (fork used: Paulogb98/whisperX)
  • 🗣️ OpenAI Whisper
  • 🎬 LeGen — original reference for the subtitling pipeline
  • ⚛️ Electron · React · Vite — the desktop shell and UI

About

Desktop app that transcribes, translates, and subtitles videos locally using AI (WhisperX/Whisper) — optional GPU (CUDA) acceleration, no cloud, no Docker.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages