split render_utils
This commit is contained in:
parent
a65ab31595
commit
12613d7393
2 changed files with 155 additions and 150 deletions
151
render.py
151
render.py
|
|
@ -15,40 +15,7 @@ import lxml.etree
|
||||||
|
|
||||||
from .pi import random
|
from .pi import random
|
||||||
from .render_kdenlive import KDEnliveProject, _CACHE, melt_xml, get_melt
|
from .render_kdenlive import KDEnliveProject, _CACHE, melt_xml, get_melt
|
||||||
|
from .render_utils import *
|
||||||
|
|
||||||
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 write_if_new(path, data, mode=''):
|
def write_if_new(path, data, mode=''):
|
||||||
|
|
@ -342,35 +309,6 @@ def compose(clips, target=150, base=1024, voice_over=None, options=None):
|
||||||
print(scene['audio-center']['A1'][-1])
|
print(scene['audio-center']['A1'][-1])
|
||||||
return scene, used
|
return scene, used
|
||||||
|
|
||||||
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_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 write_subtitles(data, folder, options):
|
def write_subtitles(data, folder, options):
|
||||||
data = fix_overlaps(data)
|
data = fix_overlaps(data)
|
||||||
path = folder / "front.srt"
|
path = folder / "front.srt"
|
||||||
|
|
@ -439,12 +377,6 @@ def render(root, scene, prefix='', options=None):
|
||||||
files.append(path)
|
files.append(path)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
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 get_fragments(clips, voice_over, prefix):
|
def get_fragments(clips, voice_over, prefix):
|
||||||
import itemlist.models
|
import itemlist.models
|
||||||
import item.models
|
import item.models
|
||||||
|
|
@ -496,19 +428,6 @@ def get_fragments(clips, voice_over, prefix):
|
||||||
fragments.sort(key=lambda f: ox.sort_string(f['name']))
|
fragments.sort(key=lambda f: ox.sort_string(f['name']))
|
||||||
return fragments
|
return fragments
|
||||||
|
|
||||||
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 render_all(options):
|
def render_all(options):
|
||||||
options = load_defaults(options)
|
options = load_defaults(options)
|
||||||
prefix = options['prefix']
|
prefix = options['prefix']
|
||||||
|
|
@ -861,23 +780,6 @@ def get_srt(sub, offset, lang, tlang):
|
||||||
sdata["out"] += offset
|
sdata["out"] += offset
|
||||||
return sdata
|
return sdata
|
||||||
|
|
||||||
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 scene_subtitles(scene, options):
|
def scene_subtitles(scene, options):
|
||||||
import item.models
|
import item.models
|
||||||
offset = 0
|
offset = 0
|
||||||
|
|
@ -939,57 +841,6 @@ def update_subtitles(options):
|
||||||
subs = scene_subtitles(scene, options)
|
subs = scene_subtitles(scene, options)
|
||||||
write_subtitles(subs, folder, options)
|
write_subtitles(subs, folder, options)
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def update_m3u(render_prefix, exclude=[]):
|
def update_m3u(render_prefix, exclude=[]):
|
||||||
files = ox.sorted_strings(glob(render_prefix + "*/*/back.mp4"))
|
files = ox.sorted_strings(glob(render_prefix + "*/*/back.mp4"))
|
||||||
for ex in exclude:
|
for ex in exclude:
|
||||||
|
|
|
||||||
154
render_utils.py
Normal file
154
render_utils.py
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
from .render_kdenlive import melt_xml
|
||||||
|
|
||||||
|
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