def shift(input_file, output_file, shift_by, shift_start, shift_end, multiplier): """Shift all lines in a script by defined amount and/or change speed. \b You can use one of the following formats to specify the time for shift: - "1.5s" or just "1.5" means 1 second 500 milliseconds - "150ms" means 150 milliseconds - "1:7:12.55" means 1 hour, 7 minutes, 12 seconds and 550 milliseconds. All parts are optional. Every format allows a negative sign before the value, which means "shift back", like "-12s" \b Optionally, specify multiplier to change speed: - 1.2 makes subs 20% faster - 7/8 makes subs 12.5% slower \b To shift both start end end time by one minute and 15 seconds: $ prass shift input.ass --by 1:15 -o output.ass To shift only start time by half a second back: $ prass shift input.ass --start --by -0.5s -o output.ass """ if not shift_start and not shift_end: shift_start = shift_end = True shift_ms = parse_shift_string(shift_by) multiplier = parse_fps_string(multiplier) if multiplier < 0: raise PrassError('Speed multiplier should be a positive number') script = AssScript.from_ass_stream(input_file) script.shift(shift_ms, shift_start, shift_end, multiplier) script.to_ass_stream(output_file)
def copy_styles(dst_file, src_file, output_file, clean, resample, forced_resolution): """Copy styles from one ASS script to another, write the result as a third script. You always have to provide the "from" argument, "to" defaults to stdin and "output" defaults to stdout. \b Simple usage: $ prass copy-styles --from template.ass --to unstyled.ass -o styled.ass With pipes: $ cat unstyled.ass | prass copy-styles --from template.ass | prass cleanup --comments -o out.ass """ src_script = AssScript.from_ass_stream(src_file) dst_script = AssScript.from_ass_stream(dst_file) if forced_resolution: forced_resolution = parse_resolution_string(forced_resolution) dst_script.append_styles(src_script, clean, resample, forced_resolution) dst_script.to_ass_stream(output_file)
def tpp(input_file, output_file, styles, lead_in, lead_out, max_overlap, max_gap, adjacent_bias, keyframes_path, timecodes_path, fps, kf_before_start, kf_after_start, kf_before_end, kf_after_end): """Timing post-processor. It's a pretty straightforward port from Aegisub so you should be familiar with it. You have to specify keyframes and timecodes (either as a CFR value or a timecodes file) if you want keyframe snapping. All parameters default to zero so if you don't want something - just don't put it in the command line. \b To add lead-in and lead-out: $ prass tpp input.ass --lead-in 50 --lead-out 150 -o output.ass To make adjacent lines continuous, with 80% bias to changing end time of the first line: $ prass tpp input.ass --overlap 50 --gap 200 --bias 80 -o output.ass To snap events to keyframes without a timecodes file: $ prass tpp input.ass --keyframes kfs.txt --fps 23.976 --kf-before-end 150 --kf-after-end 150 --kf-before-start 150 --kf-after-start 150 -o output.ass """ if fps and timecodes_path: raise PrassError( 'Timecodes file and fps cannot be specified at the same time') if fps: timecodes = Timecodes.cfr(parse_fps_string(fps)) elif timecodes_path: timecodes = Timecodes.from_file(timecodes_path) elif any((kf_before_start, kf_after_start, kf_before_end, kf_after_end)): raise PrassError( 'You have to provide either fps or timecodes file for keyframes processing' ) else: timecodes = None if timecodes and not keyframes_path: raise PrassError( 'You have to specify keyframes file for keyframes processing') keyframes_list = parse_keyframes( keyframes_path) if keyframes_path else None actual_styles = [] for style in styles: actual_styles.extend(x.strip() for x in style.split(',')) script = AssScript.from_ass_stream(input_file) script.tpp(actual_styles, lead_in, lead_out, max_overlap, max_gap, adjacent_bias, keyframes_list, timecodes, kf_before_start, kf_after_start, kf_before_end, kf_after_end) script.to_ass_stream(output_file)
def cleanup(input_file, output_file, drop_comments, drop_empty_lines, drop_unused_styles, drop_actors, drop_effects, drop_spacing, drop_sections): """Remove junk data from ASS script \b To remove commented and empty lines plus clear unused styles: $ prass cleanup input.ass --comments --empty-lines --styles output.ass """ sections_map = { "fonts": "[Fonts]", "graphics": "[Graphics]", "aegi": "[Aegisub Project Garbage]", "extradata": "[Aegisub Extradata]" } drop_sections = [sections_map[x] for x in drop_sections] script = AssScript.from_ass_stream(input_file) script.cleanup(drop_comments, drop_empty_lines, drop_unused_styles, drop_actors, drop_effects, drop_spacing, drop_sections) script.to_ass_stream(output_file)
def tpp(input_file, output_file, styles, lead_in, lead_out, max_overlap, max_gap, adjacent_bias, keyframes_path, timecodes_path, fps, kf_before_start, kf_after_start, kf_before_end, kf_after_end): """Timing post-processor. It's a pretty straightforward port from Aegisub so you should be familiar with it. You have to specify keyframes and timecodes (either as a CFR value or a timecodes file) if you want keyframe snapping. All parameters default to zero so if you don't want something - just don't put it in the command line. \b To add lead-in and lead-out: $ prass tpp input.ass --lead-in 50 --lead-out 150 -o output.ass To make adjacent lines continuous, with 80% bias to changing end time of the first line: $ prass tpp input.ass --overlap 50 --gap 200 --bias 80 -o output.ass To snap events to keyframes without a timecodes file: $ prass tpp input.ass --keyframes kfs.txt --fps 23.976 --kf-before-end 150 --kf-after-end 150 --kf-before-start 150 --kf-after-start 150 -o output.ass """ if fps and timecodes_path: raise PrassError('Timecodes file and fps cannot be specified at the same time') if fps: timecodes = Timecodes.cfr(parse_fps_string(fps)) elif timecodes_path: timecodes = Timecodes.from_file(timecodes_path) elif any((kf_before_start, kf_after_start, kf_before_end, kf_after_end)): raise PrassError('You have to provide either fps or timecodes file for keyframes processing') else: timecodes = None if timecodes and not keyframes_path: raise PrassError('You have to specify keyframes file for keyframes processing') keyframes_list = parse_keyframes(keyframes_path) if keyframes_path else None actual_styles = [] for style in styles: actual_styles.extend(x.strip() for x in style.split(',')) script = AssScript.from_ass_stream(input_file) script.tpp(actual_styles, lead_in, lead_out, max_overlap, max_gap, adjacent_bias, keyframes_list, timecodes, kf_before_start, kf_after_start, kf_before_end, kf_after_end) script.to_ass_stream(output_file)
def sort_script(input_file, output_file, sort_by, descending): """Sort script by one or more parameters. \b Sorting by time: $ prass sort input.ass --by time -o output.ass Sorting by time and then by layer, both in descending order: $ prass sort input.ass --by time --by layer --desc -o output.ass """ script = AssScript.from_ass_stream(input_file) attrs_map = { "start": "start", "time": "start", "end": "end", "style": "style", "actor": "actor", "effect": "effect", "layer": "layer" } getter = attrgetter(*[attrs_map[x] for x in sort_by]) script.sort_events(getter, descending) script.to_ass_stream(output_file)
def shift(input_file, output_file, shift_by, shift_start, shift_end): """Shift all lines in a script by defined amount. \b You can use one of the following formats to specify the time: - "1.5s" or just "1.5" means 1 second 500 milliseconds - "150ms" means 150 milliseconds - "1:7:12.55" means 1 hour, 7 minutes, 12 seconds and 550 milliseconds. All parts are optional. Every format allows a negative sign before the value, which means "shift back", like "-12s" \b To shift both start end end time by one minute and 15 seconds: $ prass shift input.ass --by 1:15 -o output.ass To shift only start time by half a second back: $ prass shift input.ass --start --by -0.5s -o output.ass """ if not shift_start and not shift_end: shift_start = shift_end = True shift_ms = parse_shift_string(shift_by) script = AssScript.from_ass_stream(input_file) script.shift(shift_ms, shift_start, shift_end) script.to_ass_stream(output_file)