34c3 mods

This commit is contained in:
Peter Körner 2017-12-27 15:07:46 +01:00
parent b0ac0b83f4
commit 04a66cb90c
3 changed files with 2692 additions and 110 deletions

2536
GPN17-Fahrplan.XML Executable file

File diff suppressed because it is too large Load diff

View file

@ -14,14 +14,14 @@ from xml.sax.saxutils import escape as xmlescape
# Parse arguments # Parse arguments
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='C3VOC Intro-Outro-Generator - Variant to use with apple Motion Files', description='C3VOC Intro-Outro-Generator - Variant to use with apple Motion Files',
usage="./make.py gpn17/Intro.motn https://url/to/schedule.xml", usage="./make.py gpn17/Intro.motn https://url/to/schedule.xml",
formatter_class=argparse.RawTextHelpFormatter) formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('motn', action="store", metavar='Motion-File', type=str, help=''' parser.add_argument('motn', action="store", metavar='Motion-File', type=str, help='''
Path to your Motion-File .motn-File Path to your Motion-File .motn-File
''') ''')
parser.add_argument('schedule', action="store", metavar='Schedule-URL', type=str, nargs='?', help=''' parser.add_argument('schedule', action="store", metavar='Schedule-URL', type=str, nargs='?', help='''
URL or Path to your schedule.xml URL or Path to your schedule.xml
''') ''')
@ -41,172 +41,217 @@ parser.add_argument('--id', dest='ids', nargs='+', action="store", type=int, hel
args = parser.parse_args() args = parser.parse_args()
def headline(str): def headline(str):
print("##################################################") print("##################################################")
print(str) print(str)
print("##################################################") print("##################################################")
print() print()
def error(str): def error(str):
headline(str) headline(str)
parser.print_help() parser.print_help()
sys.exit(1) sys.exit(1)
if not args.motn: 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: 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: if args.debug:
persons = ['Arnulf Christl', 'Astrid Emde', 'Dominik Helle', 'Till Adams'] persons = ['Arnulf Christl', 'Astrid Emde', 'Dominik Helle', 'Till Adams']
events = [{ events = [{
'id': 3773, 'id': 3773,
'title': 'Was ist Open Source, wie funktioniert das?', 'title': 'Was ist Open Source, wie funktioniert das?',
'subtitle': 'Die Organisation der Open Geo- und GIS-Welt. Worauf man achten sollte.', 'subtitle': 'Die Organisation der Open Geo- und GIS-Welt. Worauf man achten sollte.',
'persons': persons, 'persons': persons,
'personnames': ', '.join(persons), 'personnames': ', '.join(persons),
'room': 'Großer Saal', 'room': 'Großer Saal',
}] }]
else: else:
events = list(renderlib.events(args.schedule)) events = list(renderlib.events(args.schedule))
def describe_event(event): def describe_event(event):
return "#{}: {}".format(event['id'], event['title']) return "#{}: {}".format(event['id'], event['title'])
def event_print(event, message): 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) tempdir = '/Users/pkoerner/VOC/34c3_intro_bix'
print('working in ' + tempdir)
def fmt_command(command, **kwargs): def fmt_command(command, **kwargs):
args = {} args = {}
for key, value in kwargs.items(): for key, value in kwargs.items():
args[key] = shlex.quote(value) 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): def run(command, **kwargs):
return subprocess.check_call( return subprocess.check_call(
fmt_command(command, **kwargs)) fmt_command(command, **kwargs))
def run_output(command, **kwargs): def run_output(command, **kwargs):
return subprocess.check_output( return subprocess.check_output(
fmt_command(command, **kwargs), fmt_command(command, **kwargs),
encoding='utf-8', encoding='utf-8',
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
def enrich_event(event):
print(event)
result = {}
result.update(event)
art = {"red":"1", "green":"1", "blue":"0.20000000298023224"}
ccc = {"red":"0.60000002384185791", "green":"0.80000001192092896", "blue":"0"}
entertainment = ccc
ethics = {"red":"1", "green":"0.20000000298023224", "blue":"1"}
hardware = {"red":"1", "green":"0.40000000596046448", "blue":"0"}
resilience = {"red":"0.64313727617263794", "green":"0.10980392247438431", "blue":"0.19215686619281769"}
science = {"red":"1", "green":"0.40000000596046448", "blue":"0"}
security = {"red":"0.4117647111415863", "green":"0", "blue":"0.82745099067687988"}
if "Art" in event['track']:
result.update(art)
elif "CCC" in event['track']:
result.update(ccc)
elif "Entertainment" in event['track']:
result.update(entertainment)
elif "Ethics" in event['track']:
result.update(ethics)
elif "Hardware" in event['track']:
result.update(hardware)
elif "Resilience" in event['track']:
result.update(resilience)
elif "Science" in event['track']:
result.update(science)
elif "Security" in event['track']:
result.update(security)
else:
print("Found unrecognized track name %s, assuming CCC track colour" % (event['track']))
result.update(ccc)
return result
def enqueue_job(event): def enqueue_job(event):
event_id = str(event['id']) event_id = str(event['id'])
work_doc = os.path.join(tempdir.name, event_id+'.motn') work_doc = os.path.join(tempdir, event_id + '.motn')
intermediate_clip = os.path.join(tempdir.name, event_id+'.mov') intermediate_clip = os.path.join(tempdir, event_id + '.mov')
with open(args.motn, 'r') as fp: with open(args.motn, 'r') as fp:
xmlstr = fp.read() xmlstr = fp.read()
for key, value in event.items(): for key, value in event.items():
xmlstr = xmlstr.replace("$"+str(key), xmlescape(str(value))) xmlstr = xmlstr.replace("$" + str(key), xmlescape(str(value)))
with open(work_doc, 'w') as fp: with open(work_doc, 'w') as fp:
fp.write(xmlstr) fp.write(xmlstr)
compressor_info = run_output( compressor_info = run_output(
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath apple-prores-4444.cmprstng -locationpath {locationpath}', '/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath apple-prores-4444.cmprstng -locationpath {locationpath}',
batchname=describe_event(event), batchname=describe_event(event),
jobpath=work_doc, jobpath=work_doc,
locationpath=intermediate_clip) locationpath=intermediate_clip)
match = re.search("<jobID ([A-Z0-9\-]+) ?\/>", compressor_info) match = re.search("<jobID ([A-Z0-9\-]+) ?\/>", compressor_info)
if not match: if not match:
event_print(event, "unexpected output from compressor: \n"+compressor_info) event_print(event, "unexpected output from compressor: \n" + compressor_info)
return return
return match.group(1)
return match.group(1)
def fetch_job_status(): def fetch_job_status():
compressor_status = run_output('/Applications/Compressor.app/Contents/MacOS/Compressor -monitor') compressor_status = run_output('/Applications/Compressor.app/Contents/MacOS/Compressor -monitor')
job_status_matches = re.finditer("<jobStatus (.*) \/jobStatus>", compressor_status) job_status_matches = re.finditer("<jobStatus (.*) \/jobStatus>", compressor_status)
status_dict = {} status_dict = {}
for match in job_status_matches: for match in job_status_matches:
lexer = shlex.shlex(match.group(1), posix=True) lexer = shlex.shlex(match.group(1), posix=True)
lexer.wordchars += "=" 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
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): def filter_finished_jobs(active_jobs):
job_status = fetch_job_status() job_status = fetch_job_status()
new_active_jobs = [] new_active_jobs = []
finished_jobs = [] finished_jobs = []
for job_id, event in active_jobs: for job_id, event in active_jobs:
if job_id not in job_status: if job_id not in job_status:
status = 'Processing' status = 'Processing'
else: else:
status = job_status[job_id]['status'] status = job_status[job_id]['status']
if status == 'Processing': if status == 'Processing':
new_active_jobs.append((job_id, event)) new_active_jobs.append((job_id, event))
continue continue
elif status == 'Successful': elif status == 'Successful':
finished_jobs.append((job_id, event)) finished_jobs.append((job_id, event))
else: else:
event_print(event, "failed with staus="+status+" removing from postprocessing queue") 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): def finalize_job(job_id, event):
event_id = str(event['id']) event_id = str(event['id'])
intermediate_clip = os.path.join(tempdir.name, event_id+'.mov') intermediate_clip = os.path.join(tempdir, event_id + '.mov')
final_clip = os.path.join(os.path.dirname(args.motn), event_id+'.ts') final_clip = os.path.join(os.path.dirname(args.motn), event_id + '.mov')
run('ffmpeg -y -hide_banner -loglevel error -i "{input}" -ar 48000 -ac 1 -f s16le -i /dev/zero -map 0:v -c:v mpeg2video -q:v 0 -aspect 16:9 -map 1:0 -map 1:0 -map 1:0 -map 1:0 -shortest -f mpegts "{output}"', # run('ffmpeg -y -hide_banner -loglevel error -i "{input}" -ar 48000 -ac 1 -f s16le -i /dev/zero -map 0:v -c:v mpeg2video -q:v 0 -aspect 16:9 -map 1:0 -map 1:0 -map 1:0 -map 1:0 -shortest -f mpegts "{output}"',
input=intermediate_clip, # input=intermediate_clip,
output=final_clip) # output=final_clip)
run('mv "{input}" "{output}"',
event_print(event, "finalized intro to "+final_clip) input=intermediate_clip,
output=final_clip)
event_print(event, "finalized intro to " + final_clip)
active_jobs = [] active_jobs = []
print("enqueuing {} jobs into compressor".format(len(events))) print("enqueuing {} jobs into compressor".format(len(events)))
for event in events: for event in events:
if args.ids and event['id'] not in args.ids: if args.ids and event['id'] not in args.ids:
continue continue
job_id = enqueue_job(event) event = enrich_event(event)
if not job_id:
event_print(event, "job was not enqueued successfully, skipping postprocessing")
continue
event_print(event, "enqueued as "+job_id) job_id = enqueue_job(event)
active_jobs.append((job_id, 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))
print("waiting for rendering to complete") print("waiting for rendering to complete")
while len(active_jobs) > 0: while len(active_jobs) > 0:
time.sleep(60) time.sleep(60)
active_jobs, finished_jobs = filter_finished_jobs(active_jobs) active_jobs, finished_jobs = filter_finished_jobs(active_jobs)
print("{} jobs in queue, {} ready to finalize".format(len(active_jobs), len(finished_jobs))) print("{} jobs in queue, {} ready to finalize".format(len(active_jobs), len(finished_jobs)))
for job_id, event in finished_jobs: for job_id, event in finished_jobs:
event_print(event, "finalizing job") event_print(event, "finalizing job")
finalize_job(job_id, event) finalize_job(job_id, event)
print('all done, cleaning up ' + tempdir)
print('all done, cleaning up '+tempdir.name) #tempdir.cleanup()
tempdir.cleanup()

View file

@ -223,6 +223,7 @@ def events(scheduleUrl, titlemap={}):
'persons': personnames, 'persons': personnames,
'personnames': ', '.join(personnames), 'personnames': ', '.join(personnames),
'room': room.attrib['name'], 'room': room.attrib['name'],
'track': event.find('track').text.split(', '),
} }
try: try: