import os from styles import STYLES def seconds_to_ass_time(seconds): """Converts seconds (float) to 0:00:00.00 format""" mins, secs = divmod(seconds, 60) hours, mins = divmod(mins, 60) cs = int((secs - int(secs)) * 100) return f"{int(hours)}:{int(mins):02d}:{int(secs):02d}.{cs:02d}" def generate_ass(transcript, style_name="hormozi", output_file="subs.ass"): """ Generates an .ass file from a transcript list. transcript: [{'text': 'Hello', 'start': 0.0, 'end': 0.5}, ...] """ config = STYLES.get(style_name, STYLES["hormozi"]) header = f"""[Script Info] ScriptType: v4.00+ PlayResX: 1280 PlayResY: 720 [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: Default,{config['Fontname']},{config['Fontsize']},{config['PrimaryColour']},{config['PrimaryColour']},{config['OutlineColour']},{config['BackColour']},{config['Bold']},{config['Italic']},0,0,100,100,0,0,{config['BorderStyle']},{config['Outline']},{config['Shadow']},{config['Alignment']},{config['MarginL']},{config['MarginR']},{config['MarginV']},1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text """ # We need to group words into "Phrases" (Lines) to avoid flickering # For simplicity, we will put roughly 3-4 words per line, or use the provided breaks if advanced. # Here we assume the transcript IS the phrasing (chunks of words). # If transcript is just words, we might want to group them. # Let's assume input is a list of WORDS for "Karaoke" style effect. # We will group them into chunks of ~1.5 - 2 seconds. lines = [] current_chunk = [] chunk_start = 0.0 chunk_duration = 0.0 events_str = "" # Simple Logic: 1 line = 1 transcript item (assuming transcript handles grouping) # OR Logic: Input is single words, we must group. # Let's code for: Input is BLOCKS of words (Phrases), loop through them. # If the user sends single words, this will visualize strictly one word at a time. for item in transcript: start = seconds_to_ass_time(item['start']) end = seconds_to_ass_time(item['end']) # Apply Active Style # If the text has multiple words, we treat the whole block as 'Active' # To do word-by-word karaoke, we'd need nested logic. text = item['text'] style_code = config['active_anim'] # Apply the "active" look to this chunk # Simple line: line_str = f"Dialogue: 0,{start},{end},Default,,0,0,0,,{style_code}{text}" events_str += line_str + "\n" with open(output_file, "w", encoding="utf-8") as f: f.write(header + events_str) return output_file