#!/usr/bin/env python3 import sys import os from optparse import OptionParser import json import math import shutil import tempfile import time import urllib.error import urllib.parse import urllib.request import uuid 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 %(uuid)s ''' fcp_header = ''' ''' fcp_footer = '''''' sequence_template = ''' %(uuid)s 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 = 1920 - 240 font = os.path.join(base, 'DejaVuSansCondensedBold.ttf') if not os.path.exists(font): 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' gid = 0 def __init__(self, size=None, font=None): if size is not None: self.fontsize = size if font is not None: self.font = font 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], 'uuid': str(uuid.uuid1()).upper(), 'duration': duration, 'subs': '\n'.join([self.sub(*s) for s in subs]) }) def sub(self, start, end, text): self.gid += 1 text = xml.sax.saxutils.escape('\n'.join(text).strip()).replace('\n', ' ') return generator_template % { 'id': self.gid, 'uuid': str(uuid.uuid1()).upper(), '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") parser.add_option('-s', '--size', dest='size', help='font size, default=18', type=int, default=18) parser.add_option('-f', '--font', dest='font', help='font name, default="Courier New"', type=str, default='Courier New') (opts, args) = parser.parse_args() if not args: parser.print_help() sys.exit() srt = args[0] output = srt.replace('.srt', '') + '.xml' fcp = Fcp(font=opts.font, size=int(opts.size)) fcp.add_srt(srt, opts.wrap) fcp.save(output)