CastScribe downloads subtitles or media from YouTube, Bilibili, Xiaoyuzhou, Apple Podcasts, playlists, feeds, and channel URLs, then writes transcript files.
It first tries subtitles. If subtitles are unavailable, it downloads audio. If audio-only download is unavailable, it downloads the lowest quality combined audio/video format and transcribes that.
CastScribe can download media and convert existing subtitles on any system that supports Python and yt-dlp.
Local speech transcription depends on the operating system:
- macOS 26 or later: local transcription uses Apple's
yapcommand. - macOS before 26: use a cloud backend, or use
faster-whisperby running on another supported Python environment. - Linux and Windows: local transcription uses
faster-whisper.
Cloud transcription backends are available on macOS, Linux, and Windows when the matching cloud SDK and credentials are configured.
- Python 3.10+
yt-dlpPython package, installed automatically when installing this project- Or
yt-dlpCLI available onPATH - optional cloud transcription SDKs:
castscribe[azure],castscribe[aws],castscribe[google], orcastscribe[cloud]
CastScribe first tries downloaded subtitles. These local transcription requirements apply only when no subtitle is available and CastScribe must transcribe audio.
CastScribe uses yap for the default local backend.
Install yap with Homebrew:
brew install yapOr install it with Mint:
mint install finnvoor/yapEnable Dictation and install the language assets before long runs:
- Open System Settings.
- Go to Keyboard.
- Enable Dictation.
- Add the language you plan to use, for example English -> United States.
yap does not provide speaker diarization. Use --backend google, --backend azure, or --backend aws when you need speaker labels.
CastScribe uses faster-whisper for the default local backend outside yap environments.
Install it through CastScribe's Whisper extra:
python3 -m pip install -e '.[whisper]'Or install faster-whisper directly:
python3 -m pip install faster-whisperThe --model value is passed to faster-whisper; common choices are tiny, base, small, medium, and large-v3.
Install from GitHub:
python3 -m pip install "castscribe @ git+https://github.com/longbai/CastScribe.git"Or install from a local checkout:
python3 -m pip install -e .Then run:
castscribe --helpYou can also run without installing:
PYTHONPATH=src python3 -m castscribe --helpThe old script entry remains available for compatibility:
PYTHONPATH=src python3 media_to_text.py --helpSingle or multiple remote URLs:
castscribe "https://www.youtube.com/watch?v=..."
castscribe "https://space.bilibili.com/..." "https://www.xiaoyuzhoufm.com/episode/..."URL file:
castscribe --input urls.txtChannel or playlist URL:
castscribe --output transcripts "https://www.youtube.com/@channel/videos"
castscribe --output transcripts "https://www.youtube.com/playlist?list=..."
castscribe --locale en_US --output transcripts "https://podcasts.apple.com/cn/podcast/the-economics-of-everyday-things/id1666678354"Local files, file:// URLs, and local directories:
castscribe ./audio.mp3
castscribe file:///Users/me/Downloads/captions.vtt
castscribe --output transcripts ./podcast-downloadsSRT output:
castscribe --format srt ./audio.mp3
castscribe --format srt --output transcripts "https://www.youtube.com/watch?v=..."YouTube or Bilibili may require cookies when they show bot, sign-in, or HTTP 412 checks:
castscribe --cookies-from-browser chrome "https://www.youtube.com/shorts/JLV1YqS445I"
castscribe --cookies cookies.txt "https://www.youtube.com/watch?v=HjDsO0RHQHg&t=303s"
castscribe --cookies-from-browser chrome "https://space.bilibili.com/266765166/lists/2621160?type=season"Limit a channel, playlist, or podcast feed while testing:
castscribe --playlist-items 1:2 --locale en_US --output transcripts "https://podcasts.apple.com/cn/podcast/the-economics-of-everyday-things/id1666678354"CastScribe only calls a transcription backend when it cannot use downloaded subtitles. The default backend is local.
Install optional cloud SDKs:
python3 -m pip install -e '.[azure]'
python3 -m pip install -e '.[aws]'
python3 -m pip install -e '.[google]'
python3 -m pip install -e '.[cloud]'Azure Speech uses environment variables named SPEECH_KEY and ENDPOINT:
castscribe --backend azure --language en-US ./meeting.wavAWS Transcribe uses the normal boto3 credential chain. The first version expects the media file to already be available in S3:
castscribe \
--backend aws \
--cloud-region us-west-2 \
--cloud-uri s3://your-bucket/path/audio.mp3 \
--language en-US \
./audio.mp3Google Cloud Speech-to-Text uses Application Default Credentials:
castscribe --backend google --language en-US --min-speakers 2 --max-speakers 6 ./meeting.wavTencent Cloud and Alibaba Cloud are selectable but not implemented yet:
castscribe --backend tencent ./meeting.wav
castscribe --backend aliyun ./meeting.wavCloud credentials must not be committed to the repository. Do not pass access keys on the command line; use the provider's environment variables or default credential chain.
The program first tries subtitles, preferring zh-Hans, zh-CN, zh, then en.
Apple Podcasts show pages are resolved through Apple's lookup API to their RSS feed before downloading episodes.
Local subtitle files are converted directly to .txt or .srt. Local media files are transcribed directly. Local directories are scanned recursively for supported subtitle and media files.
Output rules:
- Without
--output, each output is written next to the source or downloaded file with the same basename, ending in.txtor.srt. - With
--output DIR, all transcript files are written directly intoDIR. - Remote downloads use
DIR/downloadswhen--output DIRis set. Without--output, downloads are written under the current directory using theyt-dlpfilename template. - Existing
.txtor.srtfiles are skipped, so channel and playlist downloads can be rerun after interruption.
Run tests:
python3 -m unittest discover -s testsBuild a wheel and source distribution:
python3 -m pip install -e '.[build]'
python3 -m build
python3 -m twine check dist/*Install the built wheel locally:
python3 -m pip install dist/castscribe-*.whlPackages are published by GitHub Actions when a GitHub Release is published.
Create a GitHub Release in the browser with tag v0.1.1.
Do not push a separate release tag when publishing from the GitHub Release UI; the release event triggers the publish workflow.
PyPI publishing uses Trusted Publishing. Configure the PyPI project with:
- Owner:
longbai - Repository:
CastScribe - Workflow:
publish.yml - Environment:
pypi
No PyPI token is stored in the repository.