Skip to content

Instantly share code, notes, and snippets.

@flablog
Created July 19, 2018 08:12
Show Gist options
  • Save flablog/58dddc550bb1d049c985e720ea6ab0ac to your computer and use it in GitHub Desktop.
Save flablog/58dddc550bb1d049c985e720ea6ab0ac to your computer and use it in GitHub Desktop.
Play : simple command line to play shots as sequences
#!/usr/bin/python
'''This scripts reads CSVs prepared from a XML edit export,
and prepares a Melt command to play shots as a sequence
https://mltframework.org/twiki/bin/view/MLT/MltMelt
'''
import argparse
import os
import sys
import glob
from pprint import pprint
project = "Dilili"
parser = argparse.ArgumentParser()
parser.add_argument("episode", type=str,
default="DIL",
help="episode name")
parser.add_argument("seq", type=int,
help="sequence number (without S)")
parser.add_argument("shots",
type=int,
action='store',
nargs='*',
help="shot number(s), without P")
parser.add_argument("-r", "--range",
type=str,
help="range start:end :end (from beginning to the end) start: (from start to the end)")
parser.add_argument("-rv", help="play in rv instead of melt",
action="store_true")
parser.add_argument("-dj", help="play one shot in djv_view",
action="store_true")
parser.add_argument("-v", '--verbose', help="verbose mode",
action="store_true")
parser.add_argument('--list-only', help="activate verbose mode and does not execute the commad at the end",
action="store_true")
parser.add_argument("-compo", help="play compo OUT image sequence instead of movie preview",
action="store_true")
args = parser.parse_args()
if args.list_only:
args.verbose = True
start = 0
end = 999999
# If a range is specified
if args.range and ":" not in args.range:
print("range invalid, should be start:end or :end or start:")
elif args.range and ":" in args.range:
s, e = args.range.split(":")
if s and s.isdigit():
start = int(s)
if e and e.isdigit():
end = int(e)
# If not argument provided
if len(sys.argv) < 2:
print("Provide a least a sequence number to play > ex: play 2")
sys.exit()
root = "/u/production/%s/%s/" % (project, episode)
seq = "S%02i" % args.seq
wip = args.wip
compo = args.compo
# Checking if episode or sequence exists
if not os.path.exists(root):
print("Episode %s DOES NOT EXISTS" % root)
sys.exit()
if not os.path.exists(root + seq):
print("SEQUENCE DOES NOT EXISTS IN %s" % root)
sys.exit()
# Checking if there is a CSV file available for that sequence
current = root + seq + "/EDIT/current/"
EDL_path = root + seq + "/EDIT/EDL/*.csv"
EDLs = glob.glob(EDL_path)
if not EDLs:
print("NO EDL (CSV) FILE FOUND ON : %s" % EDL_path)
sys.exit()
# Grabbing the last version :
EDLs.sort()
last_EDL = EDLs[-1]
if args.verbose:
print("Using following EDL : %s" % last_EDL)
# Parsing the EDL file and listing all the shots
shots = []
f = open(last_EDL, 'r')
lines = f.readlines()
f.close()
if args.verbose:
if args.range:
print("Range set : %i:%i" % (start, end))
else:
print("default range : %i:%i" % (start, end))
in_range = False
start_consumed = False
for l in lines:
if not l or l.startswith('#') or ',' not in l:
print("skipped : %s" % l)
continue
shot = l.split(',')[0]
if shot.startswith(episode):
if args.range:
shot_id = int(shot.split("_")[-1].split("P")[1])
if in_range is False:
if shot_id == start or (start == 0 and start_consumed is False):
in_range = True
start_consumed = True
shots.append(shot)
else:
if shot_id == end:
in_range = False
shots.append(shot)
if args.shots:
for s in args.shots:
if "P%04i" % s in shot and shot not in shots:
shots.append(shot)
elif args.range:
continue
else:
shots.append(shot)
if args.verbose:
print(" # List of shots to be screened : ")
pprint(shots)
print("%i Shots" % len(shots))
# Now the parsing has been done, and the list is ready
# Preparing the command line, default is melt, but could be rv ou djv_view
cmd = "melt "
if args.rv:
cmd = "rv -play -l "
if args.dj:
cmd = "djv_view "
# For each shot of the list, fetches the shot
# Depending on parameters provided. Default choice is using "CURRENT"
# The command ('cmd' variable) will be incremented for each shot
for s in shots:
if wip is False and compo is False:
# CURRENT
path = current + "%s.mov" % s
if os.path.exists(path):
cmd += "%s " % path
else:
print("Missing shot : %s" % s)
elif compo is True:
# COMPO IMAGE SEQUENCE
episode, seq, shot = s.split("_")
compo_path = root + "%s/%s/Compo-Render/OUT" % (seq, shot)
if os.path.exists(compo_path):
cmd += "%s " % compo_path
else:
print("Missing shot : %s" % s)
elif wip is True:
# WORK IN PROGRESS MOVIE, NOT THE CURRENT ONE
# This is more depending on our workflow, where a wip preview
# might not be in the CURRENT folder yet until publishing the
# work file (like the animation file).
episode, seq, shot = s.split("_")
wip_path = root + "%s/%s/*-Movie/%s_*.mov" % (seq, shot, s)
results = glob.glob(wip_path)
oldest_path = 0
file_path = None
for f in results:
st = os.stat(f)
if st.st_mtime > oldest_path:
oldest_path = st.st_mtime
file_path = f
if file_path:
cmd += "%s " % file_path
else:
print("Missing shot : %s" % s)
if args.verbose:
print(cmd)
# The command is now ready, and we ask the system to execute it
if args.list_only is False:
os.system(cmd)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment