CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pysrt

SubRip (.srt) subtitle parser and writer for Python

Pending
Overview
Eval results
Files

subtitle-files.mddocs/

Subtitle Files

File-level operations for SubRip subtitle files, including parsing, saving, batch operations, and file format handling. The SubRipFile class provides a list-like interface for managing collections of subtitles.

Capabilities

File Creation and Loading

Create new subtitle files or load existing ones with automatic encoding detection.

class SubRipFile:
    def __init__(self, items=None, eol=None, path=None, encoding='utf-8'):
        """
        Create a new SubRipFile instance.
        
        Args:
            items (list, optional): List of SubRipItem instances
            eol (str, optional): End of line character (defaults to os.linesep)
            path (str, optional): File path for saving
            encoding (str): File encoding (default: 'utf-8')
        """

    @classmethod
    def open(cls, path='', encoding=None, error_handling=0):
        """
        Open and parse a SubRip file from filesystem.
        
        Args:
            path (str): Path to subtitle file
            encoding (str, optional): File encoding (auto-detected if None)
            error_handling (int): Error handling mode (ERROR_PASS/ERROR_LOG/ERROR_RAISE)
            
        Returns:
            SubRipFile: Parsed subtitle file
        """

    @classmethod
    def from_string(cls, source, **kwargs):
        """
        Create SubRipFile from string content.
        
        Args:
            source (str): Subtitle content as string
            **kwargs: Additional arguments passed to constructor
            
        Returns:
            SubRipFile: Parsed subtitle file
        """

File Saving and Output

Save subtitle files with encoding and format control.

def save(self, path=None, encoding=None, eol=None):
    """
    Save subtitles to file.
    
    Args:
        path (str, optional): Output path (uses instance path if None)
        encoding (str, optional): Output encoding (uses instance encoding if None)
        eol (str, optional): End of line character (uses instance eol if None)
    """

def write_into(self, output_file, eol=None):
    """
    Write subtitles to file-like object.
    
    Args:
        output_file: Any object with write() method
        eol (str, optional): End of line character
    """

Streaming Parser

Stream subtitles as they are parsed without storing them in memory.

@classmethod
def stream(cls, source_file, error_handling=0):
    """
    Generator that yields SubRipItem instances as they are parsed.
    
    Args:
        source_file: Iterable yielding unicode strings (file-like object)
        error_handling (int): Error handling mode
        
    Yields:
        SubRipItem: Parsed subtitle items
    """

def read(self, source_file, error_handling=0):
    """
    Parse subtitles from file-like object and add to current instance.
    
    Args:
        source_file: Iterable yielding unicode strings
        error_handling (int): Error handling mode
        
    Returns:
        SubRipFile: Self for method chaining
    """

Time-based Filtering

Filter subtitles based on timing constraints.

def slice(self, starts_before=None, starts_after=None, ends_before=None, ends_after=None):
    """
    Filter subtitles by time constraints.
    
    Args:
        starts_before: SubRipTime or coercible - filter items starting before this time
        starts_after: SubRipTime or coercible - filter items starting after this time
        ends_before: SubRipTime or coercible - filter items ending before this time
        ends_after: SubRipTime or coercible - filter items ending after this time
        
    Returns:
        SubRipFile: New instance with filtered subtitles (references original items)
    """

def at(self, timestamp=None, **kwargs):
    """
    Get subtitles visible at specific timestamp.
    
    Args:
        timestamp: SubRipTime or coercible, or None to use kwargs
        **kwargs: Time components (hours, minutes, seconds, milliseconds)
        
    Returns:
        SubRipFile: New instance with subtitles visible at timestamp
    """

Batch Operations

Apply operations to all subtitles in the file.

def shift(self, *args, **kwargs):
    """
    Shift timing of all subtitles.
    
    Args:
        *args: Positional time arguments (hours, minutes, seconds, milliseconds)
        **kwargs: Named time arguments or ratio for proportional scaling
        
    Supported kwargs:
        hours (int): Hours to add
        minutes (int): Minutes to add  
        seconds (int): Seconds to add
        milliseconds (int): Milliseconds to add
        ratio (float): Multiply all times by this ratio
    """

def clean_indexes(self):
    """
    Sort subtitles by start time and renumber sequentially.
    Should be called after operations that may disorder subtitles.
    """

Properties

Access file-level information and computed properties.

@property
def text(self):
    """
    Combined text content of all subtitles.
    
    Returns:
        str: All subtitle text joined with newlines
    """

@property  
def eol(self):
    """
    End of line character used in file.
    
    Returns:
        str: EOL character (\\n, \\r\\n, or \\r)
    """

@property
def path(self): 
    """File path if set during creation or opening."""

@property
def encoding(self):
    """File encoding used for reading/writing."""

List Interface

SubRipFile inherits from UserList and supports standard list operations.

# Indexing and slicing
item = subs[0]                    # Get first subtitle
items = subs[1:5]                 # Get range of subtitles

# Iteration  
for sub in subs:                  # Iterate over all subtitles
    print(sub.text)

# Length and membership
count = len(subs)                 # Number of subtitles
has_item = item in subs           # Check if item is in file

# Modification
subs.append(new_item)             # Add subtitle to end
subs.extend(more_items)           # Add multiple subtitles
subs.insert(0, first_item)        # Insert at specific position
subs.remove(item)                 # Remove specific item
del subs[0]                       # Delete by index

# Sorting
subs.sort()                       # Sort by start time (default)
subs.reverse()                    # Reverse order

Constants

ERROR_PASS: int = 0               # Ignore parsing errors
ERROR_LOG: int = 1                # Log parsing errors to stderr  
ERROR_RAISE: int = 2              # Raise exceptions on parsing errors
DEFAULT_ENCODING: str = 'utf_8'   # Default file encoding

Usage Examples

Basic File Operations

import pysrt

# Load subtitle file
subs = pysrt.open('movie.srt')
print(f"Loaded {len(subs)} subtitles")

# Handle encoding explicitly
subs = pysrt.open('movie.srt', encoding='latin1')

# Error handling
try:
    subs = pysrt.open('malformed.srt', error_handling=pysrt.ERROR_RAISE)
except pysrt.Error as e:
    print(f"Parsing error: {e}")

Time Manipulation

# Shift all subtitles 2.5 seconds forward
subs.shift(seconds=2, milliseconds=500)

# Convert framerate from 23.976 to 25 fps
subs.shift(ratio=25/23.976)

# Get subtitles visible at 1 minute mark
minute_subs = subs.at(minutes=1)

# Get subtitles in first 30 seconds
early_subs = subs.slice(ends_before={'seconds': 30})

File Processing

# Stream processing for large files
for subtitle in pysrt.stream(open('large_movie.srt', 'r', encoding='utf-8')):
    if 'profanity' in subtitle.text.lower():
        subtitle.text = '[CENSORED]'
    print(subtitle)

# Create from string content  
srt_content = """1
00:00:01,500 --> 00:00:05,000
Hello, World!

2
00:00:06,000 --> 00:00:10,000
Welcome to PySRT!
"""
subs = pysrt.from_string(srt_content)

Batch Processing

# Clean up subtitle file
subs = pysrt.open('messy_subtitles.srt')
subs.clean_indexes()           # Sort and renumber
subs.shift(milliseconds=500)   # Fine-tune timing
subs.save('clean_subtitles.srt')

# Split subtitles into multiple files
full_movie = pysrt.open('full_movie.srt')
first_half = full_movie.slice(ends_before={'minutes': 60})
second_half = full_movie.slice(starts_after={'minutes': 60})
second_half.shift(minutes=-60)  # Reset timing for second part
first_half.save('part1.srt')
second_half.save('part2.srt')

Install with Tessl CLI

npx tessl i tessl/pypi-pysrt

docs

command-line.md

index.md

subtitle-files.md

subtitle-items.md

time-handling.md

tile.json