LCYT Python - Live Captions for Youtube Live
Send live captions to YouTube Live streams using Google's official HTTP ingestion url. For more details, see ../README.md.
Installation
pip install lcyt
Or install from source:
pip install .
Quick Start
from lcyt import YoutubeLiveCaptionSender
sender = YoutubeLiveCaptionSender(stream_key="YOUR_STREAM_KEY")
sender.start()
# Send a caption
sender.send("Hello, world!")
sender.end()
API Reference
YoutubeLiveCaptionSender
The main class for sending captions to YouTube.
Constructor
sender = YoutubeLiveCaptionSender(
stream_key="YOUR_KEY", # YouTube stream key (cid value)
base_url="http://...", # Base ingestion URL (optional)
ingestion_url="http://...", # Full URL (overrides stream_key/base_url)
region="reg1", # Region identifier (default: reg1)
cue="cue1", # Cue identifier (default: cue1)
use_region=False, # Include region/cue in body (optional)
sequence=0, # Starting sequence number
verbose=False, # Enable debug logging
)
| Parameter | Type | Default | Description |
|---|---|---|---|
stream_key |
str | None | YouTube stream key (cid value) |
base_url |
str | http://upload.youtube.com/closedcaption |
Base ingestion URL |
ingestion_url |
str | None | Full pre-built URL (overrides stream_key/base_url) |
region |
str | reg1 |
Region identifier |
cue |
str | cue1 |
Cue identifier |
use_region |
bool | False | Include region/cue in caption body |
sequence |
int | 0 | Starting sequence number |
verbose |
bool | False | Enable verbose logging |
Methods
start()
Initialize the sender. Must be called before sending captions.
sender.start()
send(text, timestamp=None)
Send a single caption.
result = sender.send("Hello, world!")
result = sender.send("Custom timestamp", "2024-01-15T12:00:00.000")
# Returns SendResult with:
# - sequence: int
# - status_code: int
# - response: str
# - server_timestamp: str | None
construct(text, timestamp=None)
Queue a caption for batch sending.
sender.construct("First caption")
sender.construct("Second caption")
sender.construct("Third caption", "2024-01-15T12:00:01.000")
print(len(sender.get_queue())) # 3
send_batch(captions=None)
Send multiple captions in a single POST request. If no list is provided, sends the internal queue built with construct().
from lcyt import Caption
# Option 1: Pass list directly
result = sender.send_batch([
Caption(text="Caption 1"),
Caption(text="Caption 2", timestamp="2024-01-15T12:00:00.500"),
])
# Option 2: Use construct() then send_batch()
sender.construct("Caption 1")
sender.construct("Caption 2")
result = sender.send_batch() # Sends queue and clears it
# Returns SendResult with:
# - sequence: int
# - count: int
# - status_code: int
# - response: str
# - server_timestamp: str | None
heartbeat()
Send an empty POST to verify connection. Can be used for clock synchronization.
result = sender.heartbeat()
print(f"Server time: {result.server_timestamp}")
end()
Stop the sender and cleanup.
sender.end()
get_queue() / clear_queue()
Manage the caption queue.
queue = sender.get_queue() # Returns list of Caption objects
cleared = sender.clear_queue() # Returns count of cleared captions
get_sequence() / set_sequence(seq)
Get or set the current sequence number.
seq = sender.get_sequence()
sender.set_sequence(100)
Configuration Management
LCYT provides utilities for managing configuration:
from lcyt import LCYTConfig, load_config, save_config, get_default_config_path
# Load config from default path (~/.lcyt-config.json)
config = load_config()
# Load from custom path
config = load_config("/path/to/config.json")
# Create and save config
config = LCYTConfig(
stream_key="YOUR_KEY",
sequence=42,
)
save_config(config)
# Get default config path
path = get_default_config_path() # ~/.lcyt-config.json
Error Handling
LCYT provides custom exception classes:
from lcyt import (
LCYTError, # Base exception
ConfigError, # Configuration errors
NetworkError, # HTTP/network errors (has status_code attribute)
ValidationError, # Input validation errors (has field attribute)
)
try:
sender.send("Hello")
except ConfigError as e:
print(f"Configuration error: {e}")
except NetworkError as e:
print(f"Network error: {e}, status: {e.status_code}")
except ValidationError as e:
print(f"Validation error: {e}, field: {e.field}")
Data Classes
Caption
from lcyt import Caption
caption = Caption(
text="Hello, world!",
timestamp="2024-01-15T12:00:00.000", # Optional
)
SendResult
Returned by send(), send_batch(), and heartbeat():
from lcyt import SendResult
# Fields:
# - sequence: int
# - status_code: int
# - response: str
# - server_timestamp: str | None
# - timestamp: str | None (for send())
# - count: int | None (for send_batch())
Google Caption Format
LCYT implements Google's official YouTube Live caption format:
Request Format
- Method: POST
- Content-Type:
text/plain - URL params:
cid=<stream_key>&seq=N
Body Format
YYYY-MM-DDTHH:MM:SS.mmm
CAPTION TEXT
YYYY-MM-DDTHH:MM:SS.mmm
ANOTHER CAPTION
With region (when use_region=True):
YYYY-MM-DDTHH:MM:SS.mmm [region:reg1#cue1]
CAPTION TEXT
Important Requirements
- Timestamps must be within 60 seconds of the server's current time
- Body must end with a trailing newline (
\n) - Region/cue identifier after timestamp is optional
Line Breaks
Use <br> within caption text for line breaks:
sender.send("Line one<br>Line two")
YouTube Setup
To get your YouTube Live caption ingestion URL and key:
- Go to YouTube Studio
- Click Create → Go Live
- Set up your stream settings
- Look for Closed captions in the stream settings
- Enable POST captions to URL
- Copy the ingestion URL and stream key
License
MIT
Metadata
Release files for lcyt 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lcyt-1.1.1.tar.gz | 24.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lcyt-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.3 kB
Release files / lcyt-1.1.1.tar.gz
| Download URL | lcyt-1.1.1.tar.gz |
|---|---|
| Size | 24.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3703bda0c8d3b58f681d081a297299dff2a99434d001174ff58ddc3b18d4c3cd
|
|
BLAKE2b-256 checksum How to use checksums |
6a7b4fcc8bfc4609139fd464dd3dcaacee60800d254ba2ea07a835e69fb60ee8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / lcyt-1.1.1-py3-none-any.whl
| Download URL | lcyt-1.1.1-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb6d0ce6f50863baf7d38ab21f2f0aded20898bcad6f1e22daabd0603bfd5130
|
|
BLAKE2b-256 checksum How to use checksums |
f5a6e2b6f10b627ce56dfdfadbce0313d994c5efe61e27c9922ee65c0c794500
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|