Compare commits

...

22 commits

Author SHA1 Message Date
j
c8991438bb group fixes 2024-09-10 13:03:49 +01:00
j
45e2acbbb8 avoid recursion 2024-09-10 12:46:47 +01:00
j
e221626191 sync group 2024-09-10 12:42:16 +01:00
j
9021131e8d newline 2024-08-29 17:36:30 +02:00
j
44bd62897c avoid double 2024-08-29 17:36:18 +02:00
j
793da444ad fix subtitle import 2024-04-30 16:44:35 +01:00
j
4f57230996 increase the melody version of Bani's singing by 0.5 db 2024-04-14 10:36:13 +01:00
j
1ac5574bfc reset tick 2024-04-04 23:37:29 +01:00
j
3c9f200fdd don't reset player if its paused 2024-04-04 23:24:56 +01:00
j
569c72ee8b skip folders without scene.json 2024-04-02 12:37:17 +02:00
j
7654fc7d6c sub border color 2024-04-02 12:35:01 +02:00
j
f8bb75cd5b duration not needed for subtitle updates 2024-04-02 11:30:46 +02:00
j
8268166b77 load player config from file 2024-04-01 12:08:21 +02:00
j
6cdbf4f1b9 forward pause/play to peers 2024-03-23 10:00:47 +01:00
j
a6479d1746 fix seek in sax 2024-03-22 14:51:08 +01:00
j
19b54d57cb include sound adjustments
Front L & R: +3.0
Centre: -14.0
Rear: L & R +3.0
Wall (Back): L & R -8.0 (These is the stereo pair attached to the "original" clips)
2024-03-22 14:25:13 +01:00
j
d72bf343e3 adjust levels
- Melody (Ban's vocals) (+ 1 db)
- Ashley (Ban's vocals) (- 0.75 db)
2024-03-22 14:13:16 +01:00
j
ed03c7026a sync to hour, play sax inline, add s/p keybindings 2024-03-22 14:10:07 +01:00
j
438108a8f9 fix update_subtitles 2024-03-22 12:29:11 +01:00
j
3782ca6721 multiple languages 2024-03-22 11:33:39 +01:00
j
80db2f0255 import/export subtitles 2024-03-22 10:56:50 +01:00
j
01f669b61d better way to calculate remove 2024-03-19 11:48:36 +01:00
9 changed files with 345 additions and 47 deletions

View file

@ -2,24 +2,43 @@ import json
import os import os
import subprocess import subprocess
import ox
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.conf import settings from django.conf import settings
from ...render import add_translations
class Command(BaseCommand): class Command(BaseCommand):
help = 'export all subtitles for translations' help = 'export all subtitles for translations'
def add_arguments(self, parser): def add_arguments(self, parser):
pass parser.add_argument('--lang', action='store', dest='lang', default=None, help='subtitle language')
def handle(self, **options): def handle(self, **options):
import annotation.models import annotation.models
import item.models import item.models
lang = options["lang"]
if lang:
lang = lang.split(',')
tlang = lang[1:]
lang = lang[0]
else:
tlang = None
if lang == "en":
lang = None
for i in item.models.Item.objects.filter(data__type__contains='Voice Over').order_by('sort__title'): for i in item.models.Item.objects.filter(data__type__contains='Voice Over').order_by('sort__title'):
print("## %s %s" % (i.get("title"), i.public_id)) print("## %s %s" % (i.get("title"), i.public_id))
for sub in i.annotations.all().filter(layer='subtitles').exclude(value='').order_by("start"): for sub in i.annotations.all().filter(layer='subtitles').exclude(value='').filter(languages=lang).order_by("start"):
if not sub.languages: if tlang:
print(sub.value.strip() + "\n") value = add_translations(sub, tlang)
value = ox.strip_tags(value)
else:
value = sub.value.replace('<br/>', '<br>').replace('<br>\n', '\n').replace('<br>', '\n').strip()
if sub.languages:
value = ox.strip_tags(value)
print(value.strip() + "\n")
print("\n\n\n") print("\n\n\n")

View file

@ -28,10 +28,20 @@ class Command(BaseCommand):
help = 'generate symlinks to clips and clips.json' help = 'generate symlinks to clips and clips.json'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--lang', action='store', dest='lang', default=None, help='subtitle language')
parser.add_argument('--prefix', action='store', dest='prefix', default="/srv/t_for_time", help='prefix to build clips in') parser.add_argument('--prefix', action='store', dest='prefix', default="/srv/t_for_time", help='prefix to build clips in')
def handle(self, **options): def handle(self, **options):
prefix = options['prefix'] prefix = options['prefix']
lang = options["lang"]
if lang:
lang = lang.split(',')
tlang = lang[1:]
lang = lang[0]
else:
tlang = None
if lang == "en":
lang = None
clips = [] clips = []
for i in item.models.Item.objects.filter(sort__type='original'): for i in item.models.Item.objects.filter(sort__type='original'):
qs = item.models.Item.objects.filter(data__title=i.data['title']).exclude(id=i.id) qs = item.models.Item.objects.filter(data__title=i.data['title']).exclude(id=i.id)
@ -102,8 +112,8 @@ class Command(BaseCommand):
os.unlink(target) os.unlink(target)
os.symlink(src, target) os.symlink(src, target)
subs = [] subs = []
for sub in vo.annotations.filter(layer="subtitles").exclude(value="").order_by("start"): for sub in vo.annotations.filter(layer="subtitles", languages=lang).exclude(value="").order_by("start"):
sdata = get_srt(sub) sdata = get_srt(sub, lang=tlang)
subs.append(sdata) subs.append(sdata)
voice_over[fragment_id][batch] = { voice_over[fragment_id][batch] = {
"src": target, "src": target,

View file

@ -0,0 +1,109 @@
import json
import os
import subprocess
import ox
from django.core.management.base import BaseCommand
from django.conf import settings
from item.models import Item
from annotation.models import Annotation
class Command(BaseCommand):
help = 'export all subtitles for translations'
def add_arguments(self, parser):
parser.add_argument('--lang', action='store', dest='lang', default=None, help='subtitle language')
parser.add_argument('--test', action='store_true', dest='test', default=False, help='test run')
parser.add_argument('args', metavar='args', type=str, nargs='*', help='file or url')
def handle(self, filename, **options):
if not options["lang"]:
print("--lang is required")
return
lang = options["lang"]
if filename.startswith("http"):
data = ox.net.read_url(filename).decode()
else:
with open(filename) as fd:
data = fd.read()
data = ('\n' + data.strip()).split('\n## ')[1:]
invalid = []
valid = []
for block in data:
title, block = block.split('\n', 1)
block = block.strip()
title = title.strip()
item_id = title.split(' ')[-1]
item = Item.objects.get(public_id=item_id)
subtitles_en = item.annotations.filter(layer="subtitles", languages=None).exclude(value='')
lines = block.split('\n\n')
if len(lines) != subtitles_en.count():
print('%s: number of subtitles does not match, en: %s vs %s: %s' % (title, subtitles_en.count(), lang, len(lines)))
if options["test"]:
print(json.dumps(lines, indent=2, ensure_ascii=False))
print(json.dumps([s.value for s in subtitles_en.order_by('start')], indent=2, ensure_ascii=False))
continue
if options["test"]:
print('%s: valid %s subtitles' % (title, len(lines)))
else:
n = 0
item.annotations.filter(layer="subtitles", languages=lang).delete()
for sub_en in subtitles_en.order_by('start'):
sub = Annotation()
sub.item = sub_en.item
sub.user = sub_en.user
sub.layer = sub_en.layer
sub.start = sub_en.start
sub.end = sub_en.end
sub.value = '<span lang="%s">%s</span>' % (lang, lines[n])
sub.save()
n += 1
'''
srt = 'vocals_txt/%s/%s' % (title[0], title.replace('.wav', '.srt'))
filename = 'vocals_txt/%s/%s' % (title[0], title.replace('.wav', '.' + lang + '.srt'))
folder = os.path.dirname(filename)
if not os.path.exists(folder):
os.makedirs(folder)
data = json.load(open(srt + '.json'))
subs = block.replace('\n\n', '\n').split('\n')
if len(data) != len(subs):
print('invalid', title, 'expected', len(data), 'got', len(subs))
invalid.append('## %s\n\n%s' % (title, block))
valid.append('## %s\n\n%s' % (title, '\n\n'.join([d['value'] for d in data])))
continue
for i, sub in enumerate(data):
sub['value'] = subs[i]
kodata = ox.srt.encode(data)
current = None
if os.path.exists(filename):
with open(filename, 'rb') as fd:
current = fd.read()
if current != kodata:
print('update', title, filename)
with open(filename, 'wb') as fd:
fd.write(kodata)
with open(filename + '.json', 'w') as fd:
ko = [{
'in': s['in'],
'out': s['out'],
'value': s['value'],
} for s in data]
json.dump(ko, fd, ensure_ascii=False, indent=4)
if invalid:
with open('invalid_%s_subtitles.txt' % lang, 'w') as fd:
fd.write('\n\n\n\n'.join(invalid))
with open('invalid_%s_subtitles_en.txt' % lang, 'w') as fd:
fd.write('\n\n\n\n'.join(valid))
'''

View file

@ -13,8 +13,8 @@ class Command(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--prefix', action='store', dest='prefix', default="/srv/t_for_time", help='prefix to build clips in') parser.add_argument('--prefix', action='store', dest='prefix', default="/srv/t_for_time", help='prefix to build clips in')
parser.add_argument('--duration', action='store', dest='duration', default="3600", help='target duration of all fragments in seconds')
parser.add_argument('--offset', action='store', dest='offset', default="1024", help='inital offset in pi') parser.add_argument('--offset', action='store', dest='offset', default="1024", help='inital offset in pi')
parser.add_argument('--lang', action='store', dest='lang', default=None, help='subtitle language')
def handle(self, **options): def handle(self, **options):
update_subtitles(options) update_subtitles(options)

View file

@ -8,6 +8,7 @@ import time
from threading import Thread from threading import Thread
from datetime import datetime from datetime import datetime
import ox
import mpv import mpv
@ -19,10 +20,17 @@ SYNC_GRACE_TIME = 5
SYNC_JUMP_AHEAD = 1 SYNC_JUMP_AHEAD = 1
PORT = 9067 PORT = 9067
DEBUG = False DEBUG = False
FONT = 'Menlo'
FONT_SIZE = 30 CONFIG = {
FONT_BORDER = 4 "font": "Menlo",
SUB_MARGIN = 2 * 36 + 6 "font_size": 30,
"font_border": 4,
"sub_border_color": "0.0/0.0/0.0/0.75",
"sub_margin": 2 * 36 + 6,
"sub_spacing": 0,
"vf": None,
"sync_group": None,
}
def hide_gnome_overview(): def hide_gnome_overview():
@ -44,6 +52,7 @@ class Main:
class Sync(Thread): class Sync(Thread):
active = True active = True
is_main = True is_main = True
is_paused = False
ready = False ready = False
destination = "255.255.255.255" destination = "255.255.255.255"
reload_check = None reload_check = None
@ -53,32 +62,52 @@ class Sync(Thread):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.is_main = kwargs.get('mode', 'main') == 'main' self.is_main = kwargs.get('mode', 'main') == 'main'
self.start_at_hour = kwargs.get("hour", False)
self.sock = self.init_socket() self.sock = self.init_socket()
self.main = Main() self.main = Main()
if self.is_main: if self.is_main:
self.socket_enable_broadcast() self.socket_enable_broadcast()
if kwargs.get("sax"):
self.sax = mpv.MPV(
log_handler=mpv_log, input_default_bindings=True,
input_vo_keyboard=True,
)
self.sax.loop_file = True
self.sax.play("/srv/t_for_time/render/Saxophone-5.1.mp4")
else:
self.sax = None
if mpv.MPV_VERSION >= (2, 2): if mpv.MPV_VERSION >= (2, 2):
self.mpv = mpv.MPV( self.mpv = mpv.MPV(
log_handler=mpv_log, input_default_bindings=True, log_handler=mpv_log, input_default_bindings=True,
input_vo_keyboard=True, input_vo_keyboard=True,
sub_font_size=FONT_SIZE, sub_font=FONT, sub_font_size=CONFIG["font_size"], sub_font=CONFIG["font"],
sub_border_size=FONT_BORDER, sub_border_size=CONFIG["font_border"],
sub_margin_y=SUB_MARGIN, sub_border_color=CONFIG["sub_border_color"],
sub_margin_y=CONFIG["sub_margin"],
sub_ass_line_spacing=CONFIG["sub_spacing"],
) )
else: else:
self.mpv = mpv.MPV( self.mpv = mpv.MPV(
log_handler=mpv_log, input_default_bindings=True, log_handler=mpv_log, input_default_bindings=True,
input_vo_keyboard=True, input_vo_keyboard=True,
sub_text_font_size=FONT_SIZE, sub_text_font=FONT, sub_text_font_size=CONFIG["font_size"], sub_text_font=CONFIG["font"],
sub_border_size=FONT_BORDER, sub_border_size=CONFIG["font_border"],
sub_margin_y=SUB_MARGIN, sub_border_color=CONFIG["sub_border_color"],
sub_margin_y=CONFIG["sub_margin"],
sub_ass_line_spacing=CONFIG["sub_spacing"],
) )
if CONFIG.get("vf"):
self.mpv.vf = CONFIG["vf"]
self.mpv.observe_property('time-pos', self.time_pos_cb) self.mpv.observe_property('time-pos', self.time_pos_cb)
self.mpv.fullscreen = kwargs.get('fullscreen', False) self.mpv.fullscreen = kwargs.get('fullscreen', False)
self.mpv.loop_file = False self.mpv.loop_file = False
self.mpv.loop_playlist = True self.mpv.loop_playlist = True
self.mpv.register_key_binding('q', self.q_binding) self.mpv.register_key_binding('q', self.q_binding)
self.mpv.register_key_binding('s', self.s_binding)
self.mpv.register_key_binding('p', self.p_binding)
self.mpv.register_key_binding('SPACE', self.space_binding)
self.playlist = kwargs['playlist'] self.playlist = kwargs['playlist']
self.playlist_mtime = os.stat(self.playlist).st_mtime self.playlist_mtime = os.stat(self.playlist).st_mtime
self.mpv.loadlist(self.playlist) self.mpv.loadlist(self.playlist)
@ -90,6 +119,31 @@ class Sync(Thread):
time.sleep(0.1) time.sleep(0.1)
self.mpv.pause = True self.mpv.pause = True
self.sync_to_main() self.sync_to_main()
elif self.start_at_hour:
self.mpv.pause = True
fmt = '%Y-%m-%d %H'
now = datetime.now()
offset = (now - datetime.strptime(now.strftime(fmt), fmt)).total_seconds()
if self.sax:
self.sax.wait_until_playing()
self.sax.seek(offset, 'absolute', 'exact')
self.sax.pause = True
position = 0
for idx, item in enumerate(self.mpv.playlist):
duration = ox.avinfo(item['filename'])['duration']
if position + duration > offset:
pos = offset - position
self.mpv.playlist_play_index(idx)
self.mpv.pause = False
self.mpv.wait_until_playing()
self.mpv.seek(pos, 'absolute', 'exact')
time.sleep(0.1)
break
else:
position += duration
if self.sax:
self.sax.pause = False
self.ready = True self.ready = True
Thread.__init__(self) Thread.__init__(self)
self.start() self.start()
@ -106,16 +160,45 @@ class Sync(Thread):
else: else:
self.read_position_main() self.read_position_main()
self.reload_playlist() self.reload_playlist()
if self._tick and abs(time.time() - self._tick) > 60: if not self.is_paused and self._tick and abs(time.time() - self._tick) > 60:
logger.error("player is stuck") logger.error("player is stuck")
self._tick = 0 self._tick = 0
self.stop() self.stop()
self.mpv.stop() self.mpv.stop()
def q_binding(self, *args): def q_binding(self, *args):
if args[0] != 'd-':
return
self.stop() self.stop()
self.mpv.stop() self.mpv.stop()
def space_binding(self, *args):
if args[0] != 'd-':
return
if self.mpv.pause:
self.p_binding(*args)
else:
self.s_binding(*args)
def s_binding(self, *args):
if args[0] != 'd-':
return
self.is_paused = True
self.mpv.pause = True
if self.sax:
self.sax.pause = True
self.send_playback_state()
def p_binding(self, *args):
if args[0] != 'd-':
return
self.is_paused = False
self._tick = 0
self.mpv.pause = False
if self.sax:
self.sax.pause = False
self.send_playback_state()
def stop(self, *args): def stop(self, *args):
self.active = False self.active = False
if self.sock: if self.sock:
@ -195,6 +278,8 @@ class Sync(Thread):
"%0.4f %s" "%0.4f %s"
% (self.mpv.time_pos, self.mpv.playlist_current_pos) % (self.mpv.time_pos, self.mpv.playlist_current_pos)
).encode() ).encode()
if CONFIG.get("sync_group"):
msg = ("%s " % CONFIG["sync_group"]).encode() + msg
except: except:
return return
try: try:
@ -202,18 +287,47 @@ class Sync(Thread):
except socket.error as e: except socket.error as e:
logger.error("send failed: %s", e) logger.error("send failed: %s", e)
def send_playback_state(self):
state = 'pause' if self.mpv.pause else 'play'
msg = ("%s -1" % state).encode()
try:
self.sock.send(msg)
except socket.error as e:
logger.error("send failed: %s", e)
# #
# follower specific # follower specific
# #
_last_ping = None
def read_position_main(self): def read_position_main(self):
self.sock.settimeout(5) self.sock.settimeout(5)
try: while True:
data = self.sock.recvfrom(1024)[0].decode().split(" ", 1) try:
except socket.timeout: data = self.sock.recvfrom(1024)[0].decode().split(" ", 1)
logger.error("failed to receive data from main") except socket.timeout:
except OSError: if self._last_ping != "pause":
logger.error("socket closed") logger.error("failed to receive data from main")
return
except OSError:
logger.error("socket closed")
return
if CONFIG.get("sync_group"):
if data[0] == str(CONFIG["sync_group"]):
data = data[1].split(" ", 1)
break
else:
break
self._last_ping = data[0]
if data[0] == "pause":
self.is_paused = True
self.mpv.pause = True
elif data[0] == "play":
self.is_paused = False
self._tick = 0
self.mpv.pause = False
else: else:
self.main.time_pos = float(data[0]) self.main.time_pos = float(data[0])
self.main.playlist_current_pos = int(data[1]) self.main.playlist_current_pos = int(data[1])
@ -302,16 +416,23 @@ def main():
parser.add_argument('--prefix', help='video location', default=prefix) parser.add_argument('--prefix', help='video location', default=prefix)
parser.add_argument('--window', action='store_true', help='run in window', default=False) parser.add_argument('--window', action='store_true', help='run in window', default=False)
parser.add_argument('--debug', action='store_true', help='debug', default=False) parser.add_argument('--debug', action='store_true', help='debug', default=False)
parser.add_argument('--hour', action='store_true', help='hour', default=False)
parser.add_argument('--sax', action='store_true', help='hour', default=False)
parser.add_argument('--config', help='config', default=None)
args = parser.parse_args() args = parser.parse_args()
DEBUG = args.debug DEBUG = args.debug
if DEBUG: if DEBUG:
log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s' log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s'
logging.basicConfig(level=logging.DEBUG, format=log_format) logging.basicConfig(level=logging.DEBUG, format=log_format)
if args.config:
with open(args.config) as fd:
CONFIG.update(json.load(fd))
base = os.path.dirname(os.path.abspath(__file__)) base = os.path.dirname(os.path.abspath(__file__))
#os.chdir(base) #os.chdir(base)
player = Sync(mode=args.mode, playlist=args.playlist, fullscreen=not args.window) player = Sync(mode=args.mode, playlist=args.playlist, fullscreen=not args.window, hour=args.hour, sax=args.sax)
while player.active: while player.active:
try: try:
player.mpv.wait_for_playback() player.mpv.wait_for_playback()

View file

@ -132,17 +132,17 @@ def compose(clips, target=150, base=1024, voice_over=None):
subs = [] subs = []
for vo in voice_overs: for vo in voice_overs:
voc = vo.copy() voc = vo.copy()
a, b = '3', '-6' a, b = '-11', '-3'
if 'Whispered' in voc['src']: if 'Whispered' in voc['src']:
a, b = '6', '-3' a, b = '-8', '0'
elif 'Read' in voc['src']: elif 'Read' in voc['src']:
a, b = '6.25', '-2.75' a, b = '-7.75', '0.25'
elif 'Free' in voc['src']: elif 'Free' in voc['src']:
a, b = '5.2', '-3.8' a, b = '-8.8', '-0.8'
elif 'Ashley' in voc['src']: elif 'Ashley' in voc['src']:
a, b = '3.75', '-5.25' a, b = '-9.5', '-1.50'
elif 'Melody' in voc['src']: elif 'Melody' in voc['src']:
a, b = '4.25', '-4.75' a, b = '-5.25', '-0.25'
voc['filter'] = {'volume': a} voc['filter'] = {'volume': a}
scene['audio-center']['A1'].append(voc) scene['audio-center']['A1'].append(voc)
vo_low = vo.copy() vo_low = vo.copy()
@ -282,10 +282,10 @@ def compose(clips, target=150, base=1024, voice_over=None):
scene['audio-back']['A1'].append({ scene['audio-back']['A1'].append({
'duration': clip['duration'], 'duration': clip['duration'],
'src': clip['original'], 'src': clip['original'],
'filter': {'volume': '+0.2'}, 'filter': {'volume': '-8.2'},
}) })
# TBD: Foley # TBD: Foley
cf_volume = '-5.5' cf_volume = '-2.5'
scene['audio-front']['A2'].append({ scene['audio-front']['A2'].append({
'duration': clip['duration'], 'duration': clip['duration'],
'src': foley, 'src': foley,
@ -308,6 +308,16 @@ def get_scene_duration(scene):
duration += clip['duration'] duration += clip['duration']
return duration return duration
def get_offset_duration(prefix):
duration = 0
for root, folders, files in os.walk(prefix):
for f in files:
if f == 'scene.json':
path = os.path.join(root, f)
scene = json.load(open(path))
duration += get_scene_duration(scene)
return duration
def render(root, scene, prefix=''): def render(root, scene, prefix=''):
fps = 24 fps = 24
files = [] files = []
@ -343,6 +353,7 @@ def render(root, scene, prefix=''):
files.append(path) files.append(path)
return files return files
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
@ -541,7 +552,7 @@ def render_all(options):
shutil.move(fragment_prefix / "front-5.1.mp4", fragment_prefix / "front.mp4") shutil.move(fragment_prefix / "front-5.1.mp4", fragment_prefix / "front.mp4")
for fn in ( for fn in (
"audio-5.1.mp4", "audio-5.1.mp4",
"audio-center.wav", "audio-rear.wav", "audio-center.wav", "audio-center.wav", "audio-rear.wav",
"audio-front.wav", "audio-back.wav", "back-audio.mp4", "audio-front.wav", "audio-back.wav", "back-audio.mp4",
"fl.wav", "fr.wav", "fc.wav", "lfe.wav", "bl.wav", "br.wav", "fl.wav", "fr.wav", "fc.wav", "lfe.wav", "bl.wav", "br.wav",
): ):
@ -555,9 +566,26 @@ def render_all(options):
json.dump(_CACHE, fd) json.dump(_CACHE, fd)
def get_srt(sub, offset=0): def add_translations(sub, lang):
value = sub.value.replace('<br/>', '<br>').replace('<br>\n', '\n').replace('<br>', '\n').strip()
if sub.languages:
value = ox.strip_tags(value)
if lang:
for slang in lang:
if slang == "en":
slang = None
for tsub in sub.item.annotations.filter(layer="subtitles", start=sub.start, end=sub.end, languages=slang):
tvalue = tsub.value.replace('<br/>', '<br>').replace('<br>\n', '\n').replace('<br>', '\n').strip()
if tsub.languages:
tvalue = ox.strip_tags(tvalue)
value += '\n' + tvalue
return value
def get_srt(sub, offset=0, lang=None):
sdata = sub.json(keys=['in', 'out', 'value']) sdata = sub.json(keys=['in', 'out', 'value'])
sdata['value'] = sdata['value'].replace('<br/>', '<br>').replace('<br>\n', '\n').replace('<br>', '\n') sdata['value'] = sdata['value'].replace('<br/>', '<br>').replace('<br>\n', '\n').replace('<br>', '\n').strip()
if lang:
sdata['value'] = add_translations(sub, lang)
if offset: if offset:
sdata["in"] += offset sdata["in"] += offset
sdata["out"] += offset sdata["out"] += offset
@ -578,8 +606,17 @@ def update_subtitles(options):
import item.models import item.models
prefix = Path(options['prefix']) prefix = Path(options['prefix'])
duration = int(options['duration'])
base = int(options['offset']) base = int(options['offset'])
lang = options["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
_cache = os.path.join(prefix, "cache.json") _cache = os.path.join(prefix, "cache.json")
if os.path.exists(_cache): if os.path.exists(_cache):
@ -589,7 +626,10 @@ def update_subtitles(options):
base_prefix = prefix / 'render' / str(base) base_prefix = prefix / 'render' / str(base)
for folder in os.listdir(base_prefix): for folder in os.listdir(base_prefix):
folder = base_prefix / folder folder = base_prefix / folder
with open(folder / "scene.json") as fd: scene_json = folder / "scene.json"
if not os.path.exists(scene_json):
continue
with open(scene_json) as fd:
scene = json.load(fd) scene = json.load(fd)
offset = 0 offset = 0
subs = [] subs = []
@ -599,8 +639,8 @@ def update_subtitles(options):
vo = item.models.Item.objects.filter(data__batch__icontains=batch, data__title__startswith=fragment_id + '_').first() vo = item.models.Item.objects.filter(data__batch__icontains=batch, data__title__startswith=fragment_id + '_').first()
if vo: if vo:
#print("%s => %s %s" % (clip['src'], vo, vo.get('batch'))) #print("%s => %s %s" % (clip['src'], vo, vo.get('batch')))
for sub in vo.annotations.filter(layer="subtitles").exclude(value="").order_by("start"): for sub in vo.annotations.filter(layer="subtitles").filter(languages=lang).exclude(value="").order_by("start"):
sdata = get_srt(sub, offset) sdata = get_srt(sub, offset, tlang)
subs.append(sdata) subs.append(sdata)
else: else:
print("could not find vo for %s" % clip['src']) print("could not find vo for %s" % clip['src'])
@ -656,8 +696,8 @@ def render_infinity(options):
if f.isdigit() and os.path.isdir(render_prefix + f) and state["offset"] > int(f) >= 100 if f.isdigit() and os.path.isdir(render_prefix + f) and state["offset"] > int(f) >= 100
] ]
if len(current) > state["max-items"]: if len(current) > state["max-items"]:
current = list(reversed(ox.sorted_strings(current))) current = ox.sorted_strings(current)
remove = list(reversed(current[-state["max-items"]:])) remove = current[:-state["max-items"]]
update_m3u(render_prefix, exclude=remove) update_m3u(render_prefix, exclude=remove)
for folder in remove: for folder in remove:
folder = render_prefix + folder folder = render_prefix + folder

View file

@ -554,7 +554,6 @@ class KDEnliveProject:
] + value) ] + value)
] ]
def properties(self, *props): def properties(self, *props):
return [ return [
self.get_element("property", attrib={"name": name}, text=str(value) if value is not None else value) self.get_element("property", attrib={"name": name}, text=str(value) if value is not None else value)

6
sax.py
View file

@ -31,7 +31,7 @@ reverb = {
"src": reverb_wav, "src": reverb_wav,
"duration": 3600.0, "duration": 3600.0,
"filter": { "filter": {
"volume": "0.5" "volume": "3.5"
}, },
} }
@ -39,14 +39,14 @@ long = {
"src": long_wav, "src": long_wav,
"duration": 3600.0, "duration": 3600.0,
"filter": { "filter": {
"volume": "-4" "volume": "-1"
}, },
} }
noise = { noise = {
"src": nois_wav, "src": nois_wav,
"duration": 3600.0, "duration": 3600.0,
"filter": { "filter": {
"volume": "4.75" "volume": "7.75"
}, },
} }

BIN
title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB