#!/usr/bin/env python3 import sys import os from optparse import OptionParser import tempfile import shutil import math import time import json import urllib.request import urllib.parse import urllib.error import xml.sax.saxutils import ox from PIL import Image base = os.path.abspath(os.path.dirname(__file__)) generator_template = ''' Text 3000 FALSE 25 0 %(duration)s %(start)s %(end)s TRUE FALSE black Text Text Text generator video str Text %(text)s fontname Font %(font)s fontsize Size 0 1000 %(fontsize)s fontstyle Style 1 4 Plain 1 Bold 2 Italic 3 Bold/Italic 4 1 fontalign Alignment 1 3 Left 1 Center 2 Right 3 1 fontcolor Font Color 255 255 255 255 origin Origin -0.402778 -0.217014 fonttrack Tracking -200 200 1 leading Leading -100 100 0 aspect Aspect 0.1 5 1 autokern Auto Kerning TRUE subpixel Use Subpixel TRUE Basic Motion basic motion motion video center Center 0 -0.00315457 video BAA51DEC-ECB0-4879-9910-8E83B0EF7C1B ''' fcp_header = ''' ''' fcp_footer = '''''' sequence_template = ''' 72DC4146-6224-4400-BAAC-2AB6E0D3D292 add %(id)s %(duration)s FALSE 25 FALSE 25 01:00:00:00 90000 source NDF -1 -1 FALSE ''' def wrap_text(start, end, text, fontsize=30): margin = 40 width = 640 #font = os.path.join(base, 'DejaVuSansCondensedBold.ttf') font = '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono-Bold.ttf' n = 10 alltxt = [] text = ox.strip_tags(ox.decode_html(text)) for t in text.strip().split('\n'): lines = ox.wrapText(t, width - 2 * margin, 20, font, fontsize) for line in lines: alltxt.append(line) alltxt.append('') pages = int(math.ceil(len(alltxt) / n)) lines_per_page = int(math.ceil(len(alltxt) / pages)) frames_per_page = int((end - start) / pages) pos = start r = [] for p in range(0, len(alltxt), lines_per_page): txt = alltxt[p:p+lines_per_page] r.append((pos, pos+frames_per_page, txt)) pos += frames_per_page return r class Fcp: sequences = [] fps = 25 fontsize = 18 font = 'Courier New' #font = 'Lucida Grande' def __init__(self): pass def add_srt(self, srt, wrap=True): data = ox.srt.load(srt) #info = api.get(id=item_id, keys=['layers']) subs = [] #for s in info['data']['layers']['transcripts']: duration = -1 for s in data: value = s['value'].replace('
', '\n').replace('
', '\n') value = ox.strip_tags(value) start = int(s['in'] * fcp.fps) end = int(s['out'] * fcp.fps) if start < duration: print("warning", start, '<', duration, value) start = duration duration = end if wrap: for t in wrap_text(start, end, value, self.fontsize): subs.append(t) else: subs.append((start, end, value.split('\n'))) self.sequences.append(sequence_template % { 'id': os.path.splitext(os.path.basename(srt))[0], 'duration': duration, 'subs': '\n'.join([self.sub(*s) for s in subs]) }) def sub(self, start, end, text): text = xml.sax.saxutils.escape('\n'.join(text).strip()).replace('\n', ' ') return generator_template % { 'start': start, 'end': end, 'duration': end-start, 'text': text, 'fontsize': self.fontsize, 'font': self.font, } def save(self, output): with open(output, 'w') as f: f.write(fcp_header) for s in self.sequences: f.write(s) f.write(fcp_footer) if __name__ == '__main__': usage = "usage: %prog srtfile" parser = OptionParser(usage=usage) parser.add_option('-w', '--wrap', dest='wrap', help='rewrap text', action="store_true") (opts, args) = parser.parse_args() if not args: parser.print_help() sys.exit() srt = args[0] output = srt.replace('.srt', '') + '.xml' fcp = Fcp() fcp.add_srt(srt, opts.wrap) fcp.save(output)