flake8 code cleanup, minor fixes
This commit is contained in:
parent
b9eb2d234e
commit
43f08547f0
4 changed files with 606 additions and 583 deletions
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
|
||||
import subprocess
|
||||
import renderlib
|
||||
|
@ -15,179 +16,185 @@ from xml.sax.saxutils import escape as xmlescape
|
|||
|
||||
# Parse arguments
|
||||
parser = argparse.ArgumentParser(
|
||||
description='C3VOC Intro-Outro-Generator - Variant to use with apple Motion Files',
|
||||
usage="./make.py gpn17/Intro.motn https://url/to/schedule.xml",
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
description='C3VOC Intro-Outro-Generator - Variant to use with apple Motion Files',
|
||||
usage="./make.py gpn17/Intro.motn https://url/to/schedule.xml",
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
|
||||
parser.add_argument('motn', action="store", metavar='Motion-File', type=str, help='''
|
||||
Path to your Motion-File .motn-File
|
||||
''')
|
||||
parser.add_argument('schedule', action="store", metavar='Schedule-URL', type=str, nargs='?', help='''
|
||||
URL or Path to your schedule.xml
|
||||
''')
|
||||
Path to your Motion-File .motn-File
|
||||
''')
|
||||
parser.add_argument('schedule', action="store", metavar='Schedule-URL', type=str, nargs='?', help='''
|
||||
URL or Path to your schedule.xml
|
||||
''')
|
||||
|
||||
parser.add_argument('--debug', action="store_true", default=False, help='''
|
||||
Run script in debug mode and render with placeholder texts,
|
||||
not parsing or accessing a schedule. Schedule-URL can be left blank when
|
||||
used with --debug
|
||||
This argument must not be used together with --id
|
||||
Usage: ./make.py yourproject/ --debug
|
||||
''')
|
||||
Run script in debug mode and render with placeholder texts,
|
||||
not parsing or accessing a schedule. Schedule-URL can be left blank when
|
||||
used with --debug
|
||||
This argument must not be used together with --id
|
||||
Usage: ./make.py yourproject/ --debug
|
||||
''')
|
||||
|
||||
parser.add_argument('--id', dest='ids', nargs='+', action="store", type=int, help='''
|
||||
Only render the given ID(s) from your projects schedule.
|
||||
This argument must not be used together with --debug
|
||||
Usage: ./make.py yourproject/ --id 4711 0815 4223 1337
|
||||
''')
|
||||
Only render the given ID(s) from your projects schedule.
|
||||
This argument must not be used together with --debug
|
||||
Usage: ./make.py yourproject/ --id 4711 0815 4223 1337
|
||||
''')
|
||||
|
||||
parser.add_argument('--exclude-id', dest='exclude_ids', nargs='+', action="store", type=int, help='''
|
||||
Do not render the given ID(s) from your projects schedule.
|
||||
Usage: ./make.py yourproject/ --exclude-id 1 8 15 16 23 42
|
||||
''')
|
||||
Do not render the given ID(s) from your projects schedule.
|
||||
Usage: ./make.py yourproject/ --exclude-id 1 8 15 16 23 42
|
||||
''')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def headline(str):
|
||||
print("##################################################")
|
||||
print(str)
|
||||
print("##################################################")
|
||||
print()
|
||||
print("##################################################")
|
||||
print(str)
|
||||
print("##################################################")
|
||||
print()
|
||||
|
||||
|
||||
def error(str):
|
||||
headline(str)
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
headline(str)
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if not args.motn:
|
||||
error("The Motion-File is a rquired argument")
|
||||
error("The Motion-File is a rquired argument")
|
||||
|
||||
if not args.debug and not args.schedule:
|
||||
error("Either specify --debug or supply a schedule")
|
||||
error("Either specify --debug or supply a schedule")
|
||||
|
||||
if args.debug:
|
||||
persons = ['Arnulf Christl', 'Astrid Emde', 'Dominik Helle', 'Till Adams']
|
||||
events = [{
|
||||
'id': 3773,
|
||||
'title': 'Was ist Open Source, wie funktioniert das?',
|
||||
'subtitle': 'Die Organisation der Open Geo- und GIS-Welt. Worauf man achten sollte.',
|
||||
'persons': persons,
|
||||
'personnames': ', '.join(persons),
|
||||
'room': 'Großer Saal',
|
||||
}]
|
||||
persons = ['Arnulf Christl', 'Astrid Emde', 'Dominik Helle', 'Till Adams']
|
||||
events = [{
|
||||
'id': 3773,
|
||||
'title': 'Was ist Open Source, wie funktioniert das?',
|
||||
'subtitle': 'Die Organisation der Open Geo- und GIS-Welt. Worauf man achten sollte.',
|
||||
'persons': persons,
|
||||
'personnames': ', '.join(persons),
|
||||
'room': 'Großer Saal',
|
||||
}]
|
||||
|
||||
else:
|
||||
events = list(renderlib.events(args.schedule))
|
||||
events = list(renderlib.events(args.schedule))
|
||||
|
||||
|
||||
def describe_event(event):
|
||||
return "#{}: {}".format(event['id'], event['title'])
|
||||
return "#{}: {}".format(event['id'], event['title'])
|
||||
|
||||
|
||||
def event_print(event, message):
|
||||
print("{} – {}".format(describe_event(event), message))
|
||||
print("{} – {}".format(describe_event(event), message))
|
||||
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory()
|
||||
print('working in '+tempdir.name)
|
||||
print('working in ' + tempdir.name)
|
||||
|
||||
|
||||
def fmt_command(command, **kwargs):
|
||||
args = {}
|
||||
for key, value in kwargs.items():
|
||||
args[key] = shlex.quote(value)
|
||||
args = {}
|
||||
for key, value in kwargs.items():
|
||||
args[key] = shlex.quote(value)
|
||||
|
||||
command = command.format(**args)
|
||||
return shlex.split(command)
|
||||
|
||||
command = command.format(**args)
|
||||
return shlex.split(command)
|
||||
|
||||
def run(command, **kwargs):
|
||||
return subprocess.check_call(
|
||||
fmt_command(command, **kwargs))
|
||||
return subprocess.check_call(
|
||||
fmt_command(command, **kwargs))
|
||||
|
||||
|
||||
def run_output(command, **kwargs):
|
||||
return subprocess.check_output(
|
||||
fmt_command(command, **kwargs),
|
||||
encoding='utf-8',
|
||||
stderr=subprocess.STDOUT)
|
||||
return subprocess.check_output(
|
||||
fmt_command(command, **kwargs),
|
||||
encoding='utf-8',
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
|
||||
def enqueue_job(event):
|
||||
event_id = str(event['id'])
|
||||
work_doc = os.path.join(tempdir.name, event_id+'.motn')
|
||||
intermediate_clip = os.path.join(tempdir.name, event_id+'.mov')
|
||||
event_id = str(event['id'])
|
||||
work_doc = os.path.join(tempdir.name, event_id + '.motn')
|
||||
intermediate_clip = os.path.join(tempdir.name, event_id + '.mov')
|
||||
|
||||
with open(args.motn, 'r') as fp:
|
||||
xmlstr = fp.read()
|
||||
with open(args.motn, 'r') as fp:
|
||||
xmlstr = fp.read()
|
||||
|
||||
for key, value in event.items():
|
||||
xmlstr = xmlstr.replace("$"+str(key), xmlescape(str(value)))
|
||||
for key, value in event.items():
|
||||
xmlstr = xmlstr.replace("$" + str(key), xmlescape(str(value)))
|
||||
|
||||
with open(work_doc, 'w') as fp:
|
||||
fp.write(xmlstr)
|
||||
with open(work_doc, 'w') as fp:
|
||||
fp.write(xmlstr)
|
||||
|
||||
compressor_info = run_output(
|
||||
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath apple-prores-4444.cmprstng -locationpath {locationpath}',
|
||||
batchname=describe_event(event),
|
||||
jobpath=work_doc,
|
||||
locationpath=intermediate_clip)
|
||||
compressor_info = run_output(
|
||||
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath apple-prores-4444.cmprstng -locationpath {locationpath}',
|
||||
batchname=describe_event(event),
|
||||
jobpath=work_doc,
|
||||
locationpath=intermediate_clip)
|
||||
|
||||
match = re.search("<jobID ([A-Z0-9\-]+) ?\/>", compressor_info)
|
||||
if not match:
|
||||
event_print(event, "unexpected output from compressor: \n"+compressor_info)
|
||||
return
|
||||
match = re.search(r"<jobID ([A-Z0-9\-]+) ?\/>", compressor_info)
|
||||
if not match:
|
||||
event_print(event, "unexpected output from compressor: \n" + compressor_info)
|
||||
return
|
||||
|
||||
return match.group(1)
|
||||
|
||||
return match.group(1)
|
||||
|
||||
def fetch_job_status():
|
||||
compressor_status = run_output('/Applications/Compressor.app/Contents/MacOS/Compressor -monitor')
|
||||
job_status_matches = re.finditer("<jobStatus (.*) \/jobStatus>", compressor_status)
|
||||
compressor_status = run_output('/Applications/Compressor.app/Contents/MacOS/Compressor -monitor')
|
||||
job_status_matches = re.finditer(r"<jobStatus (.*) \/jobStatus>", compressor_status)
|
||||
|
||||
status_dict = {}
|
||||
for match in job_status_matches:
|
||||
lexer = shlex.shlex(match.group(1), posix=True)
|
||||
lexer.wordchars += "="
|
||||
|
||||
job_status = dict(word.split("=", maxsplit=1) for word in lexer)
|
||||
job_id = job_status['jobid']
|
||||
status_dict[job_id] = job_status
|
||||
|
||||
return status_dict
|
||||
status_dict = {}
|
||||
for match in job_status_matches:
|
||||
lexer = shlex.shlex(match.group(1), posix=True)
|
||||
lexer.wordchars += "="
|
||||
|
||||
job_status = dict(word.split("=", maxsplit=1) for word in lexer)
|
||||
job_id = job_status['jobid']
|
||||
status_dict[job_id] = job_status
|
||||
|
||||
return status_dict
|
||||
|
||||
|
||||
def filter_finished_jobs(active_jobs):
|
||||
job_status = fetch_job_status()
|
||||
job_status = fetch_job_status()
|
||||
|
||||
new_active_jobs = []
|
||||
finished_jobs = []
|
||||
for job_id, event in active_jobs:
|
||||
if job_id not in job_status:
|
||||
status = 'Processing'
|
||||
else:
|
||||
status = job_status[job_id]['status']
|
||||
new_active_jobs = []
|
||||
finished_jobs = []
|
||||
for job_id, event in active_jobs:
|
||||
if job_id not in job_status:
|
||||
status = 'Processing'
|
||||
else:
|
||||
status = job_status[job_id]['status']
|
||||
|
||||
if status == 'Processing':
|
||||
new_active_jobs.append((job_id, event))
|
||||
continue
|
||||
elif status == 'Successful':
|
||||
finished_jobs.append((job_id, event))
|
||||
else:
|
||||
event_print(event, "failed with staus="+status+" – removing from postprocessing queue")
|
||||
if status == 'Processing':
|
||||
new_active_jobs.append((job_id, event))
|
||||
continue
|
||||
elif status == 'Successful':
|
||||
finished_jobs.append((job_id, event))
|
||||
else:
|
||||
event_print(event, "failed with staus=" + status + " – removing from postprocessing queue")
|
||||
|
||||
return new_active_jobs, finished_jobs
|
||||
return new_active_jobs, finished_jobs
|
||||
|
||||
|
||||
def finalize_job(job_id, event):
|
||||
event_id = str(event['id'])
|
||||
intermediate_clip = os.path.join(tempdir.name, event_id+'.mov')
|
||||
final_clip = os.path.join(os.path.dirname(args.motn), event_id+'.ts')
|
||||
copy_clip = os.path.join(os.path.dirname(args.motn), event_id+'.mov')
|
||||
event_id = str(event['id'])
|
||||
intermediate_clip = os.path.join(tempdir.name, event_id + '.mov')
|
||||
final_clip = os.path.join(os.path.dirname(args.motn), event_id + '.ts')
|
||||
copy_clip = os.path.join(os.path.dirname(args.motn), event_id + '.mov')
|
||||
|
||||
shutil.copy(intermediate_clip, copy_clip)
|
||||
shutil.copy(intermediate_clip, copy_clip)
|
||||
|
||||
run('ffmpeg -y -hide_banner -loglevel error -i "{input}" -map 0:v -c:v mpeg2video -q:v 0 -aspect 16:9 -map 0:a -map 0:a -map 0:a -map 0:a -shortest -f mpegts "{output}"',
|
||||
input=intermediate_clip,
|
||||
output=final_clip)
|
||||
|
||||
event_print(event, "finalized intro to "+final_clip)
|
||||
run('ffmpeg -y -hide_banner -loglevel error -i {input} -f lavfi -i anullsrc -ar 48000 -ac 2 -map 0:v -c:v mpeg2video -q:v 0 -aspect 16:9 -map 1:a -map 1:a -map 1:a -map 1:a -shortest -f mpegts {output}',
|
||||
input=intermediate_clip,
|
||||
output=final_clip)
|
||||
|
||||
event_print(event, "finalized intro to " + final_clip)
|
||||
|
||||
|
||||
active_jobs = []
|
||||
|
@ -199,25 +206,25 @@ filtered_events = list(filtered_events)
|
|||
|
||||
print("enqueuing {} jobs into compressor".format(len(filtered_events)))
|
||||
for event in filtered_events:
|
||||
job_id = enqueue_job(event)
|
||||
if not job_id:
|
||||
event_print(event, "job was not enqueued successfully, skipping postprocessing")
|
||||
continue
|
||||
job_id = enqueue_job(event)
|
||||
if not job_id:
|
||||
event_print(event, "job was not enqueued successfully, skipping postprocessing")
|
||||
continue
|
||||
|
||||
event_print(event, "enqueued as "+job_id)
|
||||
active_jobs.append((job_id, event))
|
||||
event_print(event, "enqueued as " + job_id)
|
||||
active_jobs.append((job_id, event))
|
||||
|
||||
print("waiting for rendering to complete")
|
||||
|
||||
while len(active_jobs) > 0:
|
||||
time.sleep(15)
|
||||
active_jobs, finished_jobs = filter_finished_jobs(active_jobs)
|
||||
time.sleep(15)
|
||||
active_jobs, finished_jobs = filter_finished_jobs(active_jobs)
|
||||
|
||||
print("{} jobs in queue, {} ready to finalize".format(len(active_jobs), len(finished_jobs)))
|
||||
for job_id, event in finished_jobs:
|
||||
event_print(event, "finalizing job")
|
||||
finalize_job(job_id, event)
|
||||
print("{} jobs in queue, {} ready to finalize".format(len(active_jobs), len(finished_jobs)))
|
||||
for job_id, event in finished_jobs:
|
||||
event_print(event, "finalizing job")
|
||||
finalize_job(job_id, event)
|
||||
|
||||
|
||||
print('all done, cleaning up '+tempdir.name)
|
||||
print('all done, cleaning up ' + tempdir.name)
|
||||
tempdir.cleanup()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue