Skip to content

Instantly share code, notes, and snippets.

@Schaka
Created January 22, 2026 21:36
Show Gist options
  • Select an option

  • Save Schaka/7d7baa2f7cd5fe38632a785958fd82b2 to your computer and use it in GitHub Desktop.

Select an option

Save Schaka/7d7baa2f7cd5fe38632a785958fd82b2 to your computer and use it in GitHub Desktop.
Convert SRT to ASS with black bar
import os
import re
# CONFIGURATION
# ------------------------------------------------------------------
PLAY_RES_X = 3840
PLAY_RES_Y = 2160
# Styles provided in your original script
STYLES_BLOCK = """[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Background,Arial,48,&H00000000,&H00000000,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,7,10,10,10,1
Style: Default,Arial,72,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,240,1
"""
# The drawing code for your background box
BG_DRAWING = r"{\pos(800,1820)\p1}m 0 0 l 2200 0 l 2200 140 l 0 140{\p0}"
# SEGMENTATION SETTING
# 1000 centiseconds = 10 seconds.
# Shorter segments fix "disappearing" backgrounds when skipping in MKVs.
SEGMENT_DURATION_CS = 1000
# ------------------------------------------------------------------
def srt_to_cs(srt_time):
"""Converts SRT time (00:00:01,000) to total centiseconds."""
h, m, s_ms = srt_time.split(':')
s, ms = s_ms.split(',')
return (int(h) * 360000) + (int(m) * 6000) + (int(s) * 100) + (int(ms) // 10)
def cs_to_ass(total_cs):
"""Converts total centiseconds to ASS timestamp (H:MM:SS.cs)."""
if total_cs < 0: total_cs = 0
h = total_cs // 360000
rem = total_cs % 360000
m = rem // 6000
rem = rem % 6000
s = rem // 100
cs = rem % 100
return f"{h}:{m:02d}:{s:02d}.{cs:02d}"
def process_conversion():
# Get all .srt files in current directory
files = [f for f in os.listdir('.') if f.lower().endswith('.srt')]
if not files:
print("No .srt files found in this directory.")
return
for filename in files:
base_name = os.path.splitext(filename)[0]
ass_filename = f"{base_name}.ass"
try:
with open(filename, 'r', encoding='utf-8-sig') as f:
content = f.read()
except Exception as e:
print(f"Could not read {filename}: {e}")
continue
# Regex to find SRT blocks
pattern = re.compile(r'(\d+)\n(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})\n((?:.|\n)*?)(?=\n\d+\n|\Z)', re.MULTILINE)
parsed_events = []
min_cs = float('inf')
max_cs = 0
for match in pattern.finditer(content):
start_cs = srt_to_cs(match.group(2))
end_cs = srt_to_cs(match.group(3))
text = match.group(4).strip().replace('\n', '\\N')
parsed_events.append({
'start': start_cs,
'end': end_cs,
'text': text
})
# Identify the total range of the subtitles
if start_cs < min_cs: min_cs = start_cs
if end_cs > max_cs: max_cs = end_cs
if not parsed_events:
print(f"Skipping {filename}: No subtitle entries found.")
continue
# Header Construction
ass_lines = [
"[Script Info]",
f"Title: {base_name}",
"ScriptType: v4.00+",
f"PlayResX: {PLAY_RES_X}",
f"PlayResY: {PLAY_RES_Y}",
"ScaledBorderAndShadow: yes",
"",
STYLES_BLOCK,
"",
"[Events]",
"Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"
]
# 1. GENERATE 10-SECOND BACKGROUND SEGMENTS
# This spans from the very first subtitle to the very last.
current_chunk_start = min_cs
while current_chunk_start < max_cs:
current_chunk_end = min(current_chunk_start + SEGMENT_DURATION_CS, max_cs)
t_start = cs_to_ass(current_chunk_start)
t_end = cs_to_ass(current_chunk_end)
# Layer 0 ensures background is behind text
bg_line = f"Dialogue: 0,{t_start},{t_end},Background,,0,0,0,,{BG_DRAWING}"
ass_lines.append(bg_line)
current_chunk_start = current_chunk_end
# 2. ADD DIALOGUE EVENTS
for event in parsed_events:
t_start = cs_to_ass(event['start'])
t_end = cs_to_ass(event['end'])
# Layer 1 ensures text is on top of the background
line = f"Dialogue: 1,{t_start},{t_end},Default,,0,0,0,,{event['text']}"
ass_lines.append(line)
# Write to file
with open(ass_filename, 'w', encoding='utf-8') as out:
out.write('\n'.join(ass_lines))
print(f"Done: {filename} -> {ass_filename}")
print(f" Background segmented every 10s from {cs_to_ass(min_cs)} to {cs_to_ass(max_cs)}")
if __name__ == "__main__":
process_conversion()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment