Skip to main content

Send live captions to YouTube streams

Project description

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:

  1. Go to YouTube Studio
  2. Click CreateGo Live
  3. Set up your stream settings
  4. Look for Closed captions in the stream settings
  5. Enable POST captions to URL
  6. Copy the ingestion URL and stream key

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lcyt-1.1.0.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lcyt-1.1.0-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

File details

Details for the file lcyt-1.1.0.tar.gz.

File metadata

  • Download URL: lcyt-1.1.0.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for lcyt-1.1.0.tar.gz
Algorithm Hash digest
SHA256 694aff33c75904ee64bbf8357edccd02d4843eafa80cf62c3a79286c41a31483
MD5 4c5404d7224330224071b2ac447ec6bc
BLAKE2b-256 4511ef8dc2d0056a9488384194e0177c173dd2efde59bc65ceec99b0650937d4

See more details on using hashes here.

File details

Details for the file lcyt-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: lcyt-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for lcyt-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 14bd2661cf4be59f4bdbd75f710d7c84bdb715049463376e758d692b098a7f41
MD5 c62652c395483157d7c2999952f83baf
BLAKE2b-256 b84e3326b33650069a5e6b455cee04b25aaa9e273b7a8ec16b305578034f05fe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page