def process(self, context): files = [os.path.join(root, name) for root, dirs, files in os.walk(os.getcwd()) for name in files if name.endswith('.png')] for seq in pyseq.get_sequences(files): name = seq.head() # stripping the last character if its a symbol # for cleaner names if name[-1] in '{}()[].,:;+-_*/&|<>=~$': name = name[:-1] instance = context.create_instance(name=name) instance.set_data('family', value='png') path = os.path.join(os.path.dirname(seq.path()), seq.format(fmt='%h%p%t %R')) instance.set_data('path', value=path) path = os.path.join(seq.dirname, seq.format('%h%p%t %R')) components = {name: {'path': path}} instance.set_data('ftrackComponents', value=components) instance.set_data('ftrackAssetType', value='img') ftrack_data = context.data('ftrackData') asset_name = ftrack_data['Task']['name'] instance.set_data('ftrackAssetName', value=asset_name)
def test_get_sequences_is_working_properly_1(self): """testing if get_sequences is working properly """ seqs = get_sequences('./files/') expected_results = [ '012_vb_110_v001.1-10.png', '012_vb_110_v002.1-10.png', 'a.1-14.tga', 'alpha.txt', 'bnc01_TinkSO_tx_0_ty_0.101-105.tif', 'bnc01_TinkSO_tx_0_ty_1.101-105.tif', 'bnc01_TinkSO_tx_1_ty_0.101-105.tif', 'bnc01_TinkSO_tx_1_ty_1.101-105.tif', 'file.1-2.tif', 'file.info.03.rgb', 'file01_40-43.rgb', 'file02_44-47.rgb', 'file1-4.03.rgb', 'fileA.1-3.jpg', 'fileA.1-3.png', 'file_02.tif', 'z1_001_v1.1-4.png', 'z1_002_v1.1-4.png', 'z1_002_v2.1-4.png', ] for seq, expected_result in zip(seqs, expected_results): self.assertEqual( expected_result, str(seq) )
def test_get_sequences_is_working_properly_2(self): """testing if get_sequences is working properly """ seqs = get_sequences(['fileA.1.rgb', 'fileA.2.rgb', 'fileB.1.rgb']) expected_results = ['fileA.1-2.rgb', 'fileB.1.rgb'] for seq, expected_result in zip(seqs, expected_results): self.assertEqual(expected_result, str(seq))
def test_get_sequences_is_working_properly_1(self): """testing if get_sequences is working properly """ seqs = get_sequences('./files/') expected_results = [ '012_vb_110_v001.1-10.png', '012_vb_110_v002.1-10.png', 'a.1-14.tga', 'alpha.txt', 'bnc01_TinkSO_tx_0_ty_0.101-105.tif', 'bnc01_TinkSO_tx_0_ty_1.101-105.tif', 'bnc01_TinkSO_tx_1_ty_0.101-105.tif', 'bnc01_TinkSO_tx_1_ty_1.101-105.tif', 'file.1-2.tif', 'file.info.03.rgb', 'file01_40-43.rgb', 'file02_44-47.rgb', 'file1-4.03.rgb', 'fileA.1-3.jpg', 'fileA.1-3.png', 'file_02.tif', 'z1_001_v1.1-4.png', 'z1_002_v1.1-4.png', 'z1_002_v2.1-4.png', ] for seq, expected_result in zip(seqs, expected_results): self.assertEqual(expected_result, str(seq))
def get_seq_name_from_filePath(filePath, lib="ffmpeg"): dir_path = os.path.dirname(filePath) framePadding = get_seq_padding_count_from_filePath(filePath) if not framePadding: print ">>> Invalid Sequence Padding...!! Please use as image.%04d.tga or image.####.tga" return False import pyseq all_seqs = pyseq.get_sequences(dir_path) basename = os.path.basename(filePath).split("#")[0] basename = basename.split("%")[0] for seq in all_seqs: stringFormat = seq.format('%h') if not str(basename) == str(stringFormat): continue if seq.missing(): print ">>> Total Frame Range found : ", seq.format('%r') print ">>> Missing Frames found : ", seq.missing() continue if lib == "ffmpeg": seq_renders = "{0}{1}{2}".format(seq.format('%h'), seq.format('%p'), seq.format('%t')) if lib == "djv": seq_renders = set_seq_padding(seq.format('%h'), seq.format('%r'), framePadding, seq.format('%t')) return "/".join([dir_path, seq_renders]) print ">>> No image sequence found as mentioned...!!!" return False
def process(self, context): files = [ os.path.join(root, name) for root, dirs, files in os.walk(os.getcwd()) for name in files if name.endswith('.png') ] for seq in pyseq.get_sequences(files): name = seq.head() # stripping the last character if its a symbol # for cleaner names if name[-1] in '{}()[].,:;+-_*/&|<>=~$': name = name[:-1] instance = context.create_instance(name=name) instance.set_data('family', value='png') path = os.path.join(os.path.dirname(seq.path()), seq.format(fmt='%h%p%t %R')) instance.set_data('path', value=path) path = os.path.join(seq.dirname, seq.format('%h%p%t %R')) components = {name: {'path': path}} instance.set_data('ftrackComponents', value=components) instance.set_data('ftrackAssetType', value='img') ftrack_data = context.data('ftrackData') asset_name = ftrack_data['Task']['name'] instance.set_data('ftrackAssetName', value=asset_name)
def get_seq_object(self, path, basename): '''Check the directory for sequences and returns a sequence object''' dir_contents = pyseq.get_sequences(os.listdir(path)) for content in dir_contents: if content.contains(basename): return content else: return pyseq.Sequence([basename])
def check_seq(self, node): path = self._compute_output_path(node) node_color = hou.Color((0, 0.8, 0)) return_str = None if '$F4' in path: path = path.replace('$F4', '*') sequences = pyseq.get_sequences(path) if len(sequences) == 1: seq = sequences[0] if seq: if seq.missing(): return_str = '[%s-%s], missing %s' % (seq.format('%s'), seq.format('%e'), seq.format('%M')) else: return_str = seq.format('%R') node_color = hou.Color((0.8, 0, 0)) else: return_str = 'Invalid Sequence Object!' else: return_str = 'No or multiple sequences detected!' elif path.split('.')[-1] == 'abc': if os.path.exists(path): abcRange = abc.alembicTimeRange(path) if abcRange: return_str = '[%s-%s] - ABC Archive' % (int( abcRange[0] * hou.fps()), int(abcRange[1] * hou.fps())) else: return_str = 'Single Abc' node_color = hou.Color((0.8, 0, 0)) else: return_str = 'No Cache!' else: if os.path.exists(path): return_str = 'Single Frame' node_color = hou.Color((0.8, 0, 0)) else: return_str = 'No Cache!' # update shotgun files node as well for file_node in node.dependents(include_children=False): if file_node.type().name() == 'sgtk_file' and file_node.parm( 'mode').evalAsString() == 'out' and file_node.parm( 'rop').evalAsString() == node.path( ) and file_node.parm('overver').evalAsInt() == 0: file_node.parm('seqlabel').set(return_str) node.setColor(node_color) node.parm('seqlabel').set(return_str)
def check_seq(self, node): # sync with rop node if node.parm('mode').evalAsString( ) == 'out' and node.parm('overver').evalAsInt() != 1: rop_node_path = node.parm('rop').evalAsString() rop_node = hou.node(rop_node_path) if rop_node and rop_node.type().name() == 'sgtk_geometry': rop_node.hm().app().handler.check_seq(rop_node) else: node.parm('seqlabel').set('Invalid Out node!') else: path = node.parm('filepath').evalAsString() if node.parm('mode').evalAsString() == 'file' or node.parm( 'overver').evalAsInt(): path = node.parm('filepath').unexpandedString() returnStr = None if '$F' in path: path = path.replace('$F4', '*') path = path.replace('$F', '*') sequences = pyseq.get_sequences(path) if len(sequences) == 1: seq = sequences[0] if seq: if seq.missing(): returnStr = '[%s-%s], missing %s' % (seq.format( '%s'), seq.format('%e'), seq.format('%M')) else: returnStr = seq.format('%R') else: returnStr = 'Invalid Sequence Object!' else: returnStr = 'No or multiple sequences detected!' elif path.split('.')[-1] == 'abc': if os.path.exists(path): abcRange = abc.alembicTimeRange(path) if abcRange: returnStr = '[%s-%s] - ABC Archive' % (int( abcRange[0] * hou.fps()), int(abcRange[1] * hou.fps())) else: returnStr = 'Single Abc' else: returnStr = 'No Cache!' else: if os.path.exists(path): returnStr = 'Single Frame' else: returnStr = 'No Cache!' node.parm('seqlabel').set(returnStr)
def detect_sequences( pad): # geeft een pad aan en ontvang alle sequences uit dat pad. folder = pyseq.get_sequences( pad) # dit is een pad waar meerdere sequences in bestaan #pp = pprint.PrettyPrinter(indent=4) #pp.pprint(folder) #print(str(pad) + " bevat volgende aantal file sequenses: " + str(len(folder))) # aantal folder in folder #print_lijstnamen(folder) #print("type folder is:" + str(type(folder))) return folder
def add_source(self, path): if os.path.isfile(path): _file = self._get_allowed_files([path]) if not _file: return [] return [ Source(os.path.dirname(path), pyseq.get_sequences(_file[0])[0]) ] elif os.path.isdir(path): result = [] for root, _, files in os.walk(path): allowed_files = self._get_allowed_files(files) sequences = pyseq.get_sequences(allowed_files) sources = [] for sequence in sequences: sources.append(Source(root, sequence)) result.extend(sources) return result return []
def test_get_sequences_is_working_properly_3(self): """testing if get_sequences is working properly """ seqs = get_sequences('./tests/files/bnc*') expected_results = [ 'bnc01_TinkSO_tx_0_ty_0.%04d.tif 101-105', 'bnc01_TinkSO_tx_0_ty_1.%04d.tif 101-105', 'bnc01_TinkSO_tx_1_ty_0.%04d.tif 101-105', 'bnc01_TinkSO_tx_1_ty_1.%04d.tif 101-105', ] for seq, expected_result in zip(seqs, expected_results): self.assertEqual(expected_result, seq.format('%h%p%t %r'))
def test_get_sequences_is_working_properly_2(self): """testing if get_sequences is working properly """ seqs = get_sequences(['fileA.1.rgb', 'fileA.2.rgb', 'fileB.1.rgb']) expected_results = [ 'fileA.1-2.rgb', 'fileB.1.rgb' ] for seq, expected_result in zip(seqs, expected_results): self.assertEqual( expected_result, str(seq) )
def _set_range(self): sequences = pyseq.get_sequences(self._path.replace('$F4', '*')) cache_range = 'Invalid Sequence Object!' if sequences: self._sequence = sequences[0] if self._sequence.missing(): cache_range = '[%s-%s], missing %s' % ( self._sequence.format('%s'), self._sequence.format('%e'), self._sequence.format('%m')) else: cache_range = self._sequence.format('%R') self.setText(self._column_names.index_name('range'), cache_range)
def test_get_sequences_is_working_properly_3(self): """testing if get_sequences is working properly """ seqs = get_sequences('./tests/files/bnc*') expected_results = [ 'bnc01_TinkSO_tx_0_ty_0.%04d.tif 101-105', 'bnc01_TinkSO_tx_0_ty_1.%04d.tif 101-105', 'bnc01_TinkSO_tx_1_ty_0.%04d.tif 101-105', 'bnc01_TinkSO_tx_1_ty_1.%04d.tif 101-105', ] for seq, expected_result in zip(seqs, expected_results): self.assertEqual( expected_result, seq.format('%h%p%t %r') )
def main(): """ Command-line interface. """ usage = """ lss [path] [-f format] [-d] Formatting options: You can format the output of lss using the --format option and passing in a format string. Default format string is "%s" Supported directives: %%s sequence start %%e sequence end %%l sequence length %%f list of found files %%m list of missing files %%p padding, e.g. %%06d %%r absolute range, start-end %%R expanded range, start-end [missing] %%h string preceding sequence number %%t string after the sequence number Format directives support padding, for example: "%%04l". """ % pyseq.global_format parser = optparse.OptionParser(usage=usage, version="%prog " + pyseq.__version__) parser.add_option("-f", "--format", dest="format", default=pyseq.global_format, help="format the output string") parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="set logging level to debug (or $PYSEQ_LOG_LEVEL)") (options, args) = parser.parse_args() if options.debug: pyseq.log.setLevel(logging.DEBUG) if len(args) == 0: args = os.listdir(os.getcwd()) elif len(args) == 1 and os.path.isdir(args[0]): args = os.listdir(args[0]) for seq in pyseq.get_sequences(args): print seq.format(options.format) return 0
def check_seq(self, node): path = node.parm('filepath').evalAsString() if node.parm('mode').evalAsString() == 'file' or node.parm( 'overver').evalAsInt(): path = node.parm('filepath').unexpandedString() returnStr = None if '$F' in path: path = path.replace('$F4', '*') path = path.replace('$F', '*') sequences = pyseq.get_sequences(path) if len(sequences) == 1: seq = sequences[0] if seq: if seq.missing(): returnStr = '[%s-%s], missing %s' % (seq.format('%s'), seq.format('%e'), seq.format('%m')) else: returnStr = seq.format('%R') else: returnStr = 'Invalid Sequence Object!' else: returnStr = 'No or multiple sequences detected!' elif path.split('.')[-1] == 'abc': if os.path.exists(path): abcRange = abc.alembicTimeRange(path) if abcRange: returnStr = '[%s-%s] - ABC Archive' % (int( abcRange[0] * hou.fps()), int(abcRange[1] * hou.fps())) else: returnStr = 'Single Abc' else: returnStr = 'No Cache!' else: if os.path.exists(path): returnStr = 'Single Frame' else: returnStr = 'No Cache!' node.parm('seqlabel').set(returnStr)
def _set_range(self): sequences = pyseq.get_sequences(self._path.replace('$F4', '*')) cache_range = 'Invalid Sequence Object!' if sequences: self._sequence = sequences[0] if self._sequence.missing(): cache_range = '[%s-%s], missing %s' % ( self._sequence.format('%s'), self._sequence.format('%e'), self._sequence.format('%m')) else: cache_range = self._sequence.format('%R') self._fields['data']['first_frame'] = self._sequence.start() self._fields['data']['last_frame'] = self._sequence.end() self._fields['data']['range'] = cache_range self.setText(self._column_names.index_name('range'), cache_range)
def dropEvent(self, e): if e.mimeData().hasFormat('text/uri-list'): for url in e.mimeData().urls(): # for every folder dropped seq_path = url.path() # get the path if path.isdir(seq_path): # if it's a path seqs = pyseq.get_sequences(seq_path) # get the sequence # TODO: Implement check for missing files from sequence for s in seqs: paddedName = s.format('%h%p%t') sequenceName = s.format('%h') cmd = 'ffmpeg -i {} -pix_fmt yuv420p {}.mov'.format(seq_path + paddedName, seq_path + sequenceName) thread = pexpect.spawn(cmd) print("started {}".format(cmd)) cpl = thread.compile_pattern_list([ pexpect.EOF, 'frame= \s*\d+', '(.+)', ]) while True: i = thread.expect_list(cpl, timeout=None) if i == 0: # EOF print("the sub process exited") break elif i == 1: frame_number_bytes = thread.match.group(0) fn_str = frame_number_bytes.decode("utf-8") formatted_fn = fn_str.rsplit('= ', 1)[1] percentage = (int(formatted_fn.lstrip()) / int(s.length())) * 100 print("frame: {} of {} -- {}%".format(formatted_fn, s.length(), int(percentage))) self.progress.setValue(percentage) qApp.processEvents() thread.close() self.progress.setValue(0) else: super(Example, self).dragMoveEvent(e)
def get_seq_padding_count_from_filePath(filePath): import pyseq all_seqs = pyseq.get_sequences(os.path.dirname(filePath)) basename = os.path.basename(filePath).split("#")[0] basename = basename.split("%")[0] for seq in all_seqs: stringFormat = seq.format('%h') if not str(basename) == str(stringFormat): continue if seq.missing(): print ">>> Total Frame Range found : ", seq.format('%r') print ">>> Missing Frames found : ", seq.missing() continue if not re.search("%\d+d", seq.format('%p')): return False framePad = re.search("%\d+d", seq.format('%p')).group(0) return int(re.search("\d+", framePad).group(0))
def _formatImageSeq(self, filePath): """ Checks the path if it belongs to a sequence and formats it ready to be passes to FFMPEG :param filePath: a single member of a sequence :return: (String) Formatted path, (int) Starting frame """ sourceDir, sourceFile = os.path.split(filePath) seqList = pyseq.get_sequences(sourceDir) theSeq = self._findItem(sourceFile, seqList) if not theSeq: msg = "Cannot get the sequence list." raise Exception(msg) formattedName = "{0}{1}{2}".format(theSeq.head(), theSeq._get_padding(), theSeq.tail()) formattedPath = os.path.normpath(os.path.join(sourceDir, formattedName)) return formattedPath, theSeq.start()
def process(self, instance): seq = pyseq.get_sequences(os.path.dirname(instance.data('path')))[0] msg = 'Image sequence is missing: %s' % seq.missing() assert not seq.missing(), msg
import os import pyseq reload(pyseq) # # def _findItem(itemPath, seqlist): # for x in seqlist: # if x.contains(itemPath): # return x testDir = os.path.normpath( "E:\\testingArea\\defaultsTest_defaultsTest_defaultsTest_190627\\Playblasts\\Houdini\\Model\\testMin\\v001" ) # testSel = "shot01_beauty_v002_.0037.exr" seqList = pyseq.get_sequences(testDir) print seqList # theSeq = _findItem(testSel, seqList) # if not theSeq: # msg = "Cannot get the sequence list." # print msg # else: # print "found" # print theSeq.head() # print theSeq._get_padding() # # print "StartFrame", theSeq.start() # startFrame = theSeq.start() # startFrameAsStr = str(startFrame).format((theSeq._get_padding())) # print "HERD", startFrameAsStr # # print "{0}{1}{2}".format(theSeq.head(), theSeq._get_padding(), theSeq.tail())
def get_invalid(cls, instance): import pyseq start_frame = instance.data.get("frameStart", 0) end_frame = instance.data.get("frameEnd", 0) required = range(int(start_frame), int(end_frame) + 1) invalid = list() resources = instance.data.get("resources", []) for resource in resources: if not is_cache_resource(resource): continue node = resource['node'] all_files = resource['files'][:] all_lookup = set(all_files) # The first file is usually the .xml description file. xml = all_files.pop(0) assert xml.endswith(".xml") if VERBOSE: cls.log.info("Checking: {0}".format(all_files)) # Ensure all files exist (including ticks) # The remainder file paths should be the .mcx or .mcc files valdidate_files(all_files) # Maya particle caches support substeps by saving out additional # files that end with a Tick60.mcx, Tick120.mcx, etc. suffix. # To avoid `pyseq` getting confused we filter those out and then # for each file (except the last frame) check that at least all # ticks exist. tick_files, ticks = filter_ticks(all_files) if tick_files: files = [f for f in all_files if f not in tick_files] else: files = all_files sequences = pyseq.get_sequences(files) if len(sequences) != 1: invalid.append(node) cls.log.warning("More than one sequence found? " "{0} {1}".format(node, files)) cls.log.warning("Found caches: {0}".format(sequences)) continue sequence = sequences[0] cls.log.debug("Found sequence: {0}".format(sequence)) start = sequence.start() end = sequence.end() if start > start_frame or end < end_frame: invalid.append(node) cls.log.warning("Sequence does not have enough " "frames: {0}-{1} (requires: {2}-{3})" "".format(start, end, start_frame, end_frame)) continue # Ensure all frames are present missing = set(sequence.missing()) if missing: required_missing = [x for x in required if x in missing] if required_missing: invalid.append(node) cls.log.warning("Sequence is missing required frames: " "{0}".format(required_missing)) continue # Ensure all tick files (substep) exist for the files in the folder # for the frames required by the time range. if ticks: ticks = list(sorted(ticks)) cls.log.info("Found ticks: {0} " "(substeps: {1})".format(ticks, len(ticks))) # Check all frames except the last since we don't # require subframes after our time range. tick_check_frames = set(required[:-1]) # Check all frames for item in sequence: frame = item.frame if not frame: invalid.append(node) cls.log.error("Path is not a frame in sequence: " "{0}".format(item)) continue # Not required for our time range if frame not in tick_check_frames: continue path = item.path for num in ticks: base, ext = os.path.splitext(path) tick_file = base + "Tick{0}".format(num) + ext if tick_file not in all_lookup: invalid.append(node) cls.log.warning("Tick file found that is not " "in cache query filenames: " "{0}".format(tick_file)) return invalid
#!/usr/bin/env python3 #-*- coding: utf-8 -*- """ Usage: seqls.py {folder} """ import os import re import sys sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from pyseq import Item, Sequence, diff, uncompress, get_sequences from pyseq import SequenceError import pyseq pyseq.default_format = '%h%r%t' if len(sys.argv) < 2: print('Not enough arguments.', __doc__) sys.exit() folder = sys.argv[1] seqs = pyseq.get_sequences(folder) for s in seqs: print(s.format('%h%p%t %R %4l'))
def setup_node(self, node): default_name = self._app.get_setting('default_node_name') node.setName(default_name, unique_name=True) try: self._app.log_metric("Create", log_version=True) except: # ingore any errors. ex: metrics logging not supported pass #Set initial expressions for transforms node.parm('tx').setExpression("detail('./OUT_cam_attrib/', 't', 0)", language=hou.exprLanguage.Hscript) node.parm('ty').setExpression("detail('./OUT_cam_attrib/', 't', 1)", language=hou.exprLanguage.Hscript) node.parm('tz').setExpression("detail('./OUT_cam_attrib/', 't', 2)", language=hou.exprLanguage.Hscript) node.parm('rx').setExpression("detail('./OUT_cam_attrib/', 'r', 0)", language=hou.exprLanguage.Hscript) node.parm('ry').setExpression("detail('./OUT_cam_attrib/', 'r', 1)", language=hou.exprLanguage.Hscript) node.parm('rz').setExpression("detail('./OUT_cam_attrib/', 'r', 2)", language=hou.exprLanguage.Hscript) node.parm('tx').hide(True) node.parm('ty').hide(True) node.parm('tz').hide(True) node.parm('rx').hide(True) node.parm('ry').hide(True) node.parm('rz').hide(True) # get plate from shotgun filters = [[ 'project.Project.name', 'is', self._app.context.project['name'] ], ['entity', 'is', self._app.context.entity], ['name', 'is', 'undistort-jpeg']] order = [{"field_name": "version_number", "direction": "desc"}] result = self._app.shotgun.find_one('PublishedFile', filters, ['path', 'name'], order) # if undistort-jpeg does not exist check for plate if not result: self._app.log_info( 'Did not find undistorted plate, looking for plate!') filters = [[ 'project.Project.name', 'is', self._app.context.project['name'] ], ['entity', 'is', self._app.context.entity], ['name', 'is', 'plate-jpeg']] order = [{"field_name": "version_number", "direction": "desc"}] result = self._app.shotgun.find_one('PublishedFile', filters, ['path', 'name'], order) if result: # set plate path plate_path = result['path']['local_path'].replace( os.sep, '/').replace('%04d', '$F4') node.parm('vm_background').set(plate_path) # set resolution plate_path = plate_path.replace('$F4', '*') sequences = pyseq.get_sequences(plate_path) if sequences: first_image_path = sequences[0][0].path img = Image.open(first_image_path) node.parm('baseresx').set(img.size[0]) node.parm('baseresy').set(img.size[1])