Skip to main content

koesub

Fetch subtitles from YouTube or Bilibili, transcribe local audio/video with Whisper, and create black-background subtitled videos. Available as both a Python library and a command-line tool.

Requirements

  • Python 3.11 or newer.
  • FFmpeg and ffprobe on PATH for subtitle conversion, media decoding, duration checks, and video encoding.
  • Node.js on PATH for YouTube extraction with the configured yt-dlp runtime.
  • A local multilingual Whisper .pt checkpoint when transcription is needed. Models are not bundled with the package or downloaded automatically.

On macOS, install the external programs with:

brew install ffmpeg node

Transcription selects CUDA, MPS, or CPU according to PyTorch availability. The video renderer currently requires macOS because it uses the system Hiragino font at /System/Library/Fonts/ヒラギノ角ゴシック W3.ttc.

Installation

From a source checkout, install the project and its Python dependencies with uv:

uv sync
uv run koesub --help

For a standalone CLI installation from the checkout:

uv tool install .
koesub --help

To install the library into another virtual environment:

uv pip install /path/to/koesub

Use koesub COMMAND or python -m koesub COMMAND. The public Python API is under the koesub package. Installation includes yt-dlp, Whisper, PyTorch, and Pillow. External programs and model checkpoints remain separate requirements.

Fetch subtitles from a URL

uv run koesub fetch "https://www.youtube.com/watch?v=YE7VzlLtp-4" > subtitles.srt
uv run koesub fetch "https://www.bilibili.com/video/BV12N4y1M7rh?p=2" --lang zh-CN > subtitles.srt
uv run koesub fetch "VIDEO_URL" --lang ja \
    --model-path ~/.local/share/whisper/models/large-v3-turbo.pt > subtitles.srt

fetch accepts one YouTube or Bilibili video URL and writes complete, validated SRT content to stdout. Language/source reports, authentication retries, Whisper progress, and errors go to stderr. It returns 0 on success, nonzero on failure, and 130 on interruption. Failed fetches produce no SRT on stdout, although shell redirection may create an empty destination file.

Argument Behavior
URL Single YouTube/Bilibili video; Bilibili supports ?p=2.
--lang LANG, -l LANG Platform subtitle language and Whisper language hint. Default: prefer the original platform language, auto-detect during transcription.
--model-path PATH Local .pt checkpoint, or a directory containing exactly one checkpoint.
--chrome-profile PROFILE Chrome profile used during authentication retries.
--help, -h Show command help.

The default model directory is $XDG_DATA_HOME/whisper/models, or ~/.local/share/whisper/models when XDG_DATA_HOME is unset.

Platform captions are preferred, with manual captions preferred over automatic captions in the same language; identifiable automatic translations, danmaku, and chat are excluded. If valid captions cannot be obtained, including caption selection, download, conversion, or validation failures, the command automatically downloads audio and attempts local Whisper transcription. Audio-only formats are preferred; a single media file containing audio is used when necessary. Whisper is loaded only on this fallback path, and stderr identifies the successful source.

Each download starts anonymously. Explicit authentication errors trigger Safari, then Chrome retries. Cookie values and signed URLs are sanitized in diagnostics; cookies are not exported. Unsupported inputs are rejected before network access. Temporary captions and audio are cleaned up on success, failure, or interruption.

There is no --output-dir and no transcription opt-in flag. The caller owns final SRT persistence. Dialect/script hints such as zh-CN, zh-Hans, and en-GB map to zh and en for Whisper. The command transcribes speech without translating it, and recognition accuracy should be reviewed before relying on exact wording.

Transcribe a local file

uv run koesub transcribe audio.mp3 --language ja > subtitles.srt
uv run koesub transcribe video.mp4 > subtitles.srt

transcribe accepts exactly one local audio/video file. Whisper uses FFmpeg to decode its audio stream, so no separate audio-extraction step is needed. It writes SRT to stdout and diagnostics to stderr; empty subtitles or processing failures return a nonzero exit status without writing SRT.

Use --language LANG / -l LANG to set the audio language; the default is automatic detection. --model-path PATH / --model-dir PATH select a local checkpoint or single-checkpoint directory, with the same default model directory as fetch.

Create a subtitled video

uv run koesub make-video audio.mp3 --language ja
uv run koesub make-video first.mp3 second.flac --output-dir ./outputs
uv run koesub make-video audio.mp3 --audio-codec copy --container mkv

make-video creates a 1280×720, 25 fps video with a black background and white subtitles. It reads existing SRT from OUTPUT_DIR/srt/INPUT_STEM.srt, or transcribes missing subtitles in memory. Batch jobs reuse one Whisper model. Duplicate input stems are rejected before processing to prevent collisions within a batch.

Outputs are written to OUTPUT_DIR/CONTAINER/INPUT_STEM.CONTAINER; the default directory is ./outputs and the default format is H.264/AAC in MP4. Existing target videos are overwritten. Use --audio-codec, --video-codec, and --container to select available FFmpeg encoders and an output container (mp4, mkv, mov, avi, or ts). Automatic transcription accepts the same language/model options as transcribe.

The renderer requires non-overlapping captions and checks subtitle timing before encoding. Platform subtitle overlaps are preserved by fetch, so some fetched subtitles require editing before use by the renderer. Generated subtitles are not automatically persisted by make-video.

Python API

Fetch from a URL and receive an SRT string:

from koesub.fetch import fetch_srt

srt = fetch_srt("https://www.youtube.com/watch?v=YE7VzlLtp-4", language="en")

Reuse a loaded model for local files:

from koesub.transcription import load_model, transcribe_to_srt

model = load_model("/path/to/large-v3-turbo.pt")
first_srt = transcribe_to_srt(model, "first.mp3", language="ja")
second_srt = transcribe_to_srt(model, "second.flac", language="ja")

Library calls return strings and raise exceptions on failure. Callers control subtitle persistence and model reuse. Calls are sequential: inference diagnostics are redirected to stderr using process-wide stdout redirection.

Development and building

The project uses the native uv_build backend. Tests and the project skill are included in the source distribution; the wheel contains the koesub package, CLI entrypoint, README metadata, and MIT license.

uv sync
uv run python -m unittest discover -s tests -v
uv build --no-sources --clear
uvx twine check dist/*

Build artifacts are written to dist/ as a source distribution (.tar.gz) and an installable wheel (.whl). Building does not publish the package. Network and browser authentication tests use simulated services; they do not establish live YouTube/Bilibili availability.

Video subtitle analysis skill

The project skill is at skills/video-subtitles/SKILL.md, with UI metadata at skills/video-subtitles/agents/openai.yaml. It captures koesub's SRT stdout as a workspace artifact and guides timestamped analysis while identifying platform captions or local Whisper transcription.

Invoke it explicitly by providing the skill's path and a video URL:

Read and use /path/to/koesub/skills/video-subtitles/SKILL.md to fetch this video's subtitles and summarize its content with timestamps: VIDEO_URL

The repository skills/ folder is not automatically a globally registered skill. After installation in a supported discovery location, it can be invoked as $video-subtitles. Its policy allows automatic selection by default. The skill is included in the source archive and remains separate from wheel installation.

License

koesub is released under the MIT License. Third-party dependencies, model checkpoints, and system fonts retain their own licenses.

Metadata

Release files for koesub 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for koesub 0.1.0
File Size Uploaded
koesub-0.1.0.tar.gz 30.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for koesub 0.1.0
File Interpreter ABI Platform
koesub-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 53.9 kB

Release files / koesub-0.1.0.tar.gz

Download URL koesub-0.1.0.tar.gz
Size 30.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3589c6a8d06821c17f72cd773dd0b9ff8aaad3744f8ed44137010fb29e4eb445
BLAKE2b-256 checksum
How to use checksums
f8ed52c42a3b314599f2852b0f587c2bb2ee04b0372a4b1173167289a3262088
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / koesub-0.1.0-py3-none-any.whl

Download URL koesub-0.1.0-py3-none-any.whl
Size 23.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d4f256199755d51ff2f83dad1736c29fe07f2a9520ba370c70a726207cad009d
BLAKE2b-256 checksum
How to use checksums
1db187b6702c82858a4ba3493c674ca527f400477de7213469404c3796886843
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page