split render, prepare for single video
This commit is contained in:
parent
48ab9cf951
commit
6b40002528
3 changed files with 199 additions and 327 deletions
159
render_utils.py
Normal file
159
render_utils.py
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
import re
|
||||
import os
|
||||
|
||||
import lxml.etree
|
||||
|
||||
from .render_kdenlive melt_xml, get_melt
|
||||
|
||||
|
||||
def parse_lang(lang):
|
||||
if lang and "," in lang:
|
||||
lang = lang.split(',')
|
||||
if isinstance(lang, list):
|
||||
tlang = lang[1:]
|
||||
lang = lang[0]
|
||||
else:
|
||||
tlang = None
|
||||
if lang == "en":
|
||||
lang = None
|
||||
return lang, tlang
|
||||
|
||||
def random_int(seq, length):
|
||||
n = n_ = length - 1
|
||||
#print('len', n)
|
||||
if n == 0:
|
||||
return n
|
||||
r = seq() / 9 * 10
|
||||
base = 10
|
||||
while n > 10:
|
||||
n /= 10
|
||||
r += seq() / 9 * 10
|
||||
base += 10
|
||||
r = int(round(n_ * r / base))
|
||||
return r
|
||||
|
||||
def random_choice(seq, items, pop=False):
|
||||
n = random_int(seq, len(items))
|
||||
if pop:
|
||||
return items.pop(n)
|
||||
return items[n]
|
||||
|
||||
def chance(seq, chance):
|
||||
return (seq() / 10) < chance
|
||||
|
||||
def get_clip_by_seqid(clips, seqid):
|
||||
selected = None
|
||||
for i, clip in enumerate(clips):
|
||||
if clip['seqid'] == seqid:
|
||||
selected = i
|
||||
break
|
||||
if selected is not None:
|
||||
return clips.pop(i)
|
||||
return None
|
||||
|
||||
|
||||
def get_scene_duration(scene):
|
||||
if isinstance(scene, str):
|
||||
with open(scene) as fd:
|
||||
scene = json.load(fd)
|
||||
duration = 0
|
||||
for key, value in scene.items():
|
||||
for name, clips in value.items():
|
||||
for clip in clips:
|
||||
duration += int(clip['duration'] * 24)
|
||||
return duration / 24
|
||||
|
||||
|
||||
def get_offset_duration(prefix):
|
||||
duration = 0
|
||||
for root, folders, files in os.walk(prefix):
|
||||
for f in files:
|
||||
if f == 'scene.json':
|
||||
duration += get_scene_duration(scene)
|
||||
return duration
|
||||
|
||||
|
||||
def get_track_duration(scene, k, n):
|
||||
duration = 0
|
||||
for key, value in scene.items():
|
||||
if key == k:
|
||||
for name, clips in value.items():
|
||||
if name == n:
|
||||
for clip in clips:
|
||||
duration += int(clip['duration'] * 24)
|
||||
return duration / 24
|
||||
|
||||
def get_project_duration(file):
|
||||
out = melt_xml(file)
|
||||
chain = lxml.etree.fromstring(out).xpath('producer')[0]
|
||||
duration = int(chain.attrib['out']) + 1
|
||||
return duration
|
||||
|
||||
def fix_overlaps(data):
|
||||
previous = None
|
||||
for sub in data:
|
||||
if previous is None:
|
||||
previous = sub
|
||||
else:
|
||||
if sub['in'] < previous['out']:
|
||||
previous['out'] = sub['in'] - 0.001
|
||||
previous = sub
|
||||
return data
|
||||
|
||||
def shift_clips(data, offset):
|
||||
for clip in data:
|
||||
clip['in'] += offset
|
||||
clip['out'] += offset
|
||||
return data
|
||||
|
||||
def ass_encode(subs, options):
|
||||
if "lang" in options:
|
||||
langs = options["lang"].split(',')
|
||||
else:
|
||||
langs = list(subs[0]["values"])
|
||||
#print('ass_encode', langs, options)
|
||||
#print(subs)
|
||||
|
||||
header = '''[Script Info]
|
||||
ScriptType: v4.00+
|
||||
PlayResX: 1920
|
||||
PlayResY: 1080
|
||||
ScaledBorderAndShadow: yes
|
||||
YCbCr Matrix: None
|
||||
|
||||
[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
|
||||
'''
|
||||
ass = header
|
||||
offset = options.get("sub_margin", 10)
|
||||
spacing = options.get("sub_spacing", 20)
|
||||
height = 42
|
||||
styles = []
|
||||
for lang in reversed(langs):
|
||||
if isinstance(options.get("font"), list) and lang in options["font"]:
|
||||
font = options["font"][lang]
|
||||
else:
|
||||
font = 'SimHei' if lang in ('zh', 'jp') else 'Menlo'
|
||||
if isinstance(options.get("font_size"), list) and lang in options["font_size"]:
|
||||
size = options["font_size"][lang]
|
||||
else:
|
||||
size = 46 if font == 'SimHei' else 42
|
||||
|
||||
styles.append(
|
||||
f'Style: {lang},{font},{size},&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,{offset},1'
|
||||
)
|
||||
offset += size + spacing
|
||||
ass += '\n'.join(reversed(styles)) + '\n'
|
||||
events = [
|
||||
'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text'
|
||||
]
|
||||
for sub in subs:
|
||||
start = ox.format_timecode(sub['in']).rstrip('0')
|
||||
stop = ox.format_timecode(sub['out']).rstrip('0')
|
||||
for lang in reversed(langs):
|
||||
value = sub['values'][lang]
|
||||
event = f'Dialogue: 0,{start},{stop},{lang},,0,0,0,,{value}'
|
||||
events.append(event)
|
||||
ass += '\n\n[Events]\n' + '\n'.join(events) + '\n'
|
||||
return ass
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue