def getSearchResults(self, nodes): # PERFORM SEARCH AND UPDATE INFO KNOB nodeMatches, knobMatches = self.search(self.searchStr.value(), nodes) nodes = [n.name() for n in nodeMatches] infoStr1 = '%s node(s) found:\n\t%s' % (len(nodes), ', '.join(nodes)) infoStr2 = '' for k in knobMatches: newStr = nukescripts.replaceHashes(self.__doReplace(k)) # CHECK IF PATH IS VALID FOR CURRENT FRAME curFrame = int( nuke.Root()['frame'].value() ) # there is a bug which prevents nuke.frame() to work properly inside of python panels (6.3v5) try: curPath = newStr % curFrame except: curPath = newStr exists = { True: ' VALID PATH AT FRAME %s' % curFrame, False: ' !!! PATH IS INVALID AT CURRENT FRAME (%s)!!!' % curFrame }[os.path.exists(curPath)] # BUILD INFO STRING infoStr2 += '%s.%s:\n\tbefore\t%s\n\tafter\t%s %s\n' % ( k.node().name(), k.name(), k.value(), newStr, exists) self.info.setValue('\n'.join([infoStr1, infoStr2])) return knobMatches
def actualFilename(node): """ Given a node that reads a file, returns a tuple where: [0] The parent/containing folder of the file [1] The file's name you see in nuke's panel [2] A real name for the file """ (dirPath, basename) = os.path.split(nuke.filename(node)) def getFirstFrameOfSequence(): first_frame = node["first"].value() if node.Class() == "Write" and (node["first"].value() == node["last"].value()): # For Write nodes without a render range set, assume the # first frame is the comp's first frame. first_frame = nuke.root().firstFrame() return first_frame if re.search("#+", basename): # NOTE: On Read nodes, for some fucky reason, if a node's file name # is file.%05d.jpg -- nuke.filename(node) gives you file.#####.jpg instead. # c = '%0' + str(len(re.findall('#',basename))) + 'd' # filename = re.sub('#+',c,basename) % getFirstFrameOfSequence() basename = nukescripts.replaceHashes(basename) if re.search(r"%\d+d", basename): # Sequence files filename = basename % getFirstFrameOfSequence() else: # Standalone/single non-sequence files filename = basename return dirPath, basename, filename
def sendToAvconv(codec = 'dnxhd'): # Configuration renderSlug = False vcodec = { 'x264' : 'libx264 -pre baseline', 'dnxhd' : 'dnxhd -b 36M', } extension = '.mov' # set some variables fps = nuke.root().knob('fps').value() firstFrame = nuke.root().knob('first_frame').value() ss = 0 if renderSlug == True else secondsToStr(firstFrame/fps) # grabs the write node's file value and makes sure the path uses printf style filenames imgSeqPath = nukescripts.replaceHashes(nuke.filename(nuke.thisNode())) # generate mov path base, ext = os.path.splitext(os.path.basename(imgSeqPath)) movPath = os.path.dirname(os.path.dirname(imgSeqPath)) + '/' + re.sub('\.?%0\d+d$', '', base) + extension # make shell command enc = 'avconv -y -r %s -i \'%s\' -s \'hd1080\' -an -ss %s -vcodec %s -threads 0 \'%s\'' % (fps, imgSeqPath, ss, vcodec[codec], movPath) #print enc subprocess.Popen(shlex.split(enc), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def generateReadFromWrite(): writeSelected = 0 firstFrame = int(nuke.root().knob('first_frame').value()) lastFrame = int(nuke.root().knob('last_frame').value()) for i in nuke.selectedNodes(): if i.Class() == 'Write': writeSelected = writeSelected + 1 fileName = i.knob('file').value() newRead = nuke.createNode('Read') newRead.knob('file').setValue(fileName) cleanPath = nukescripts.replaceHashes(fileName) padRE = re.compile('%0(\d+)d') padMatch = padRE.search(cleanPath) if padMatch: padSize = int(padMatch.group(1)) frameList = sorted(glob.iglob(padRE.sub('[0-9]' * padSize, cleanPath))) first = os.path.splitext(frameList[0])[0][-padSize:] last = os.path.splitext(frameList[-1])[0][-padSize:] newRead['file'].fromUserText('%s %s-%s' % (cleanPath, first, last)) if len(nuke.selectedNodes()) == 0: nuke.message('select a Write node') writeSelected = writeSelected + 1 if writeSelected == 0: nuke.message('No Write nodes present in the current selection')
def djvViewThis(selectedNodes): args = '' for n in selectedNodes: name = n.knob('file').value() if "%0" in name: name = nukescripts.replaceHashes(name) % n.knob('first').value() colorspace = n.knob('colorspace').value() if 'default (' in colorspace: colorspace = colorspace[9:-1] args += '"%s" -ocio_image "%s" ' % (name, colorspace) args += '-speed "%s"' % (str(int(nuke.root().knob('fps').value()))) args += ' -frame "%s"' % (str(nuke.frame())) openDjvView(args)
def getSearchResults( self, nodes ): # PERFORM SEARCH AND UPDATE INFO KNOB nodeMatches, knobMatches = self.search( self.searchStr.value(), nodes ) nodes = [n.name() for n in nodeMatches] infoStr1 = '%s node(s) found:\n\t%s' % ( len(nodes), ', '.join( nodes ) ) infoStr2 = '' for k in knobMatches: newStr = nukescripts.replaceHashes( self.__doReplace( k ) ) # CHECK IF PATH IS VALID FOR CURRENT FRAME curFrame = int( nuke.Root()['frame'].value() ) # there is a bug which prevents nuke.frame() to work properly inside of python panels (6.3v5) try: curPath = newStr % curFrame except: curPath = newStr exists = {True:' VALID PATH AT FRAME %s' % curFrame, False:' !!! PATH IS INVALID AT CURRENT FRAME (%s)!!!' % curFrame}[os.path.exists( curPath )] # BUILD INFO STRING infoStr2 += '%s.%s:\n\tbefore\t%s\n\tafter\t%s %s\n' % ( k.node().name(), k.name(), k.value(), newStr, exists ) self.info.setValue( '\n'.join( [infoStr1, infoStr2] ) ) return knobMatches
def checkForErrors(): ''' check existense of all images of all read nodes and all other nodes on error ''' errors = [] nuke.errors_nodes = [] nuke.errors_lenErrors = 0 for node in nuke.allNodes(): #special case read nodes - check all images of sequences if node.Class() == "Read": for frame in range(int(node["first"].getValue()), int(node["last"].getValue()) + 1): try: f = nukescripts.replaceHashes( node['file'].value()) % (frame) except: f = "" if not os.path.isfile(f): errors.append(f) if f not in nuke.errors_missingFrames: nuke.errors_missingFrames.append(f) if node not in nuke.errors_nodes: nuke.errors_nodes.append(node) #all other nodes else: if node.hasError() == True: errors.append(node.name()) if node not in nuke.errors_nodes: nuke.errors_nodes.append(node) if len(errors) > 0: nuke.errors_lenErrors = len(errors) else: nuke.message("No errors found in script.")
def outputmov(src,out): #global log try: readNode = nuke.createNode('Read') writeNode = nuke.createNode('Write') readNode.knob('file').setValue(src) filePath = nukescripts.replaceHashes(readNode.knob('file').getValue()).replace('%d', '%01d') padRe = re.compile('%0(\d+)d') padMatch = padRe.search(filePath) padSize = int(padMatch.group(1)) if padMatch: frameList = sorted(glob.iglob(padRe.sub('[0-9]' * padSize, filePath))) if frameList: missing = 0 firstVal = os.path.splitext(frameList[0])[0][-padSize:] lastVal = os.path.splitext(frameList[-1])[0][-padSize:] readNode.knob('first').setValue(int(firstVal)) readNode.knob('last').setValue(int(lastVal)) readNode.knob('origfirst').setValue(int(firstVal)) readNode.knob('origlast').setValue(int(lastVal)) else: missing = 1 errFlg = 1 readNode.knob('colorspace').setValue("rec709") #readNode.knob("reload").execute() writeNode.knob('file_type').setValue("mov") writeNode.knob('file').setValue(out) writeNode.knob('colorspace').setValue("rec709") writeNode.knob('meta_codec').setValue("png") writeNode.knob('mov64_fps').setValue(25) nuke.execute('Write1', int(firstVal),int(lastVal)) nuke.delete(writeNode) nuke.delete(readNode) except: print 'Error' nuke.delete(writeNode) nuke.delete(readNode)
def checkForErrors(): ''' check existense of all images of all read nodes and all other nodes on error ''' errors=[] nuke.errors_nodes=[] nuke.errors_lenErrors=0 for node in nuke.allNodes(): #special case read nodes - check all images of sequences if node.Class() == "Read": for frame in range(int(node["first"].getValue()), int(node["last"].getValue())+1): try: f = nukescripts.replaceHashes(node['file'].value() ) % (frame) except: f = "" if not os.path.isfile(f): errors.append(f) if f not in nuke.errors_missingFrames: nuke.errors_missingFrames.append(f) if node not in nuke.errors_nodes: nuke.errors_nodes.append(node) #all other nodes else: if node.hasError() == True: errors.append(node.name()) if node not in nuke.errors_nodes: nuke.errors_nodes.append(node) if len(errors)>0: nuke.errors_lenErrors=len(errors) else: nuke.message("No errors found in script.")
def deleteFiles(): #gather a list of all selected read nodes and filter out non-read nodes all = nuke.selectedNodes() for node in all: if not node.Class() == 'Read': all.remove(node) files = [] #get a list of files to be deleted for n in all: #get file path while repalcing the hashes with %0#d path = nukescripts.replaceHashes(nuke.filename(n)) padd = re.search(r'%.*d', path) framerange = range(n['first'].value(), n['last'].value() + 1) for index in framerange: if padd: fra = (padd.group(0)) % index name = str(re.sub(r'%.*d', str(fra), path)) elif not padd: name = path if name not in files: files.append(name) #list of node names about to be deleted nodesToDelete = [] for na in all: nodesToDelete.append(na['name'].value()) #Confirm files deletion if nodesToDelete: if nuke.ask('About to delete files from: ' + '\n' + str(nodesToDelete) + '\n' + "Confirm?"): for e in files: try: os.remove(e) except: pass else: pass
def knobChanged(self, knob): #update if knob.name() == "update": #reset for btn in nuke.errors_footageBtn: self.removeKnob(btn) nuke.errors_footageBtn = [] errors = [] nuke.errors_nodes = [] nuke.errors_missingFrames = [] with nuke.root(): all = nuke.allNodes() for n in all: if n.Class() != "Read": if n.hasError(): errors.append(n.name()) if n not in nuke.errors_nodes: nuke.errors_nodes.append(n) else: for frame in range(int(n["first"].getValue()), int(n["last"].getValue()) + 1): try: f = nukescripts.replaceHashes( n['file'].value()) % (frame) except: f = "" if not os.path.isfile(f): errors.append(f) if f not in nuke.errors_missingFrames: nuke.errors_missingFrames.append(f) if n not in nuke.errors_nodes: nuke.errors_nodes.append(n) for errorNode in nuke.errors_nodes: self.en = nuke.PyScript_Knob(errorNode.name(), errorNode.name()) self.addKnob(self.en) nuke.errors_footageBtn.append(self.en) nuke.errors_lenErrors = len(errors) if nuke.errors_lenErrors == 0: col = "green" else: col = "red" countErrors = '<span style="color:{col}">{countErr}</span>'.format( col=col, countErr=nuke.errors_lenErrors) self.errorCount.setValue(countErrors) #write if knob.name() == "write": if self.outputPath.getValue() != "": try: script = os.path.basename(nuke.root().name()) output = os.path.dirname(self.outputPath.getValue( )) + "/errorReport_%s" % script.replace(".nk", ".txt") errorOutput = open(output, 'w') date = time.strftime("%d-%m-%Y %H:%M:%S", time.gmtime()) header = "error report \nscript name: {scriptname}\nscript path: {scriptPath}\ndate: {date}\nnumber of errors: {countErrors}\n------------------------------".format( scriptname=script, scriptPath=nuke.root().name(), date=date, countErrors=nuke.errors_lenErrors) errorOutput.write(header) #all read nodes errorOutput.write("\nread nodes\n\n") for n in nuke.errors_nodes: if n.Class() == "Read": errorOutput.write("read node: %s\n" % n.name()) #all missing frames errorOutput.write("\n----------\nmissing frames\n\n") for f in nuke.errors_missingFrames: errorOutput.write("missing frame: %s\n" % f) #all other nodes errorOutput.write("\n----------\nother nodes\n\n") for n in nuke.errors_nodes: if n.Class() != "Read": errorOutput.write("node: %s\n" % n.name()) nuke.message( "successfully written error report to:\n\n%s" % output) except: nuke.message( "some error occured. The report could not be written.") else: nuke.message( "Please enter a output path for the error report.") #all other error nodes else: allNodes = nuke.allNodes() pKnob = knob.name() for n in allNodes: if n.name() == pKnob: nuke.zoom(1, [n.xpos(), n.ypos()]) nukescripts.clear_selection_recursive() n.setSelected(True)
for required_attr in ["inputPath", "inputResolution", "outputPath", "outputResolution", "frameStart", "frameEnd"]: if getattr(options, required_attr) is None: parser.error("No --%s specified." % required_attr) input_path = options.inputPath mode = options.mode nuke_node_path = options.nukeNodePath input_resolution = options.inputResolution output_resolution = options.outputResolution output_path = options.outputPath first = options.frameStart last = options.frameEnd onlyDump = options.onlyDump # use Nuke-style instead of hashes input_path = nukescripts.replaceHashes(input_path) input_path = os.path.abspath(input_path) if nuke_node_path: # read undistort node nuke.scriptReadFile(nuke_node_path) tde_node = nuke.root().nodes()[0] # read the input read_plate = nuke.nodes.Read(name="plate_in") read_plate["file"].fromUserText(input_path) read_plate["first"].setValue(first) read_plate["last"].setValue(last) read_plate["colorspace"].setValue("Cineon") last_node = read_plate
import os import nuke import nukescripts import subprocess mocha_path = "//ldn-fs1/projects/__pipeline/software/windows/mocha/bin/mocha Pro V5/bin/mochapro.exe" try: n = nuke.selectedNode() first_frame = n["first"].getValue() path = n["file"].getValue() path = nukescripts.replaceHashes(path) % n.firstFrame() print path cmd = "<Q>" + mocha_path + "<Q> <Q>" + path + "<Q>" cmd = cmd.replace("<Q>", '"') print cmd subprocess.Popen([mocha_path, path]) except: nuke.message("Something went wrong :( ") pass
def ftrackPublishKnobChanged(forceRefresh=False, g=None): g = g or nuke.thisNode() if 'ftable' in g.knobs(): header = getHeaderKnob(g) nodeAssetType = '' if nuke.thisKnob().name() in ['inputChange', 'fscript' ] or forceRefresh == True: thisNodeName = g['name'].value() g = nuke.toNode(HelpFunctions.safeString(thisNodeName)) # Add new labels cmdString = '' assetType = None availableAssetTypes = [''] inputMissmatch = None tableWidget = g['ftable'].getObject().tableWidget tableWidget.setRowCount(0) components = [] for inputNode in range(g.inputs()): inNode = g.input(inputNode) if inNode: if inNode.Class() in ['Read', 'Write']: nodeAssetType = 'img' elif inNode.Class() in ['WriteGeo']: nodeAssetType = 'geo' else: nodeAssetType = '' if not assetType: assetType = nodeAssetType if assetType != nodeAssetType: inputMissmatch = True if nodeAssetType == 'img': fileComp = str(inNode['file'].value()) proxyComp = str(inNode['proxy'].value()) nameComp = str(inNode['name'].value()).strip() if inNode.Class() == 'Read': first = str(inNode['first'].value()) last = str(inNode['last'].value()) if first == '0.0' and last == '0.0': first = str( int(nuke.root().knob( "first_frame").value())) last = str( int(nuke.root().knob( "last_frame").value())) availableAssetTypes = ['img', 'render'] elif inNode.Class() == 'Write': # use the timeline to define the amount of frames first = str( int(nuke.root().knob("first_frame").value())) last = str( int(nuke.root().knob("last_frame").value())) # then in case check if the limit are set if inNode['use_limit'].value(): first = str(inNode['first'].value()) last = str(inNode['last'].value()) # always check how many frames are actually available frames = inNode['file'].value() try: # Try to collect the sequence prefix, padding # and extension. If this fails with a ValueError # we are probably handling a non-sequence file. # If so rely on the first_frame and last_frame # of the root node. prefix, padding, extension = frames.split('.') except ValueError: FnAssetAPI.logging.debug( 'Could not determine prefix, padding ' 'and extension from "".'.format(frames)) availableAssetTypes = ['render'] else: root = os.path.dirname(prefix) files = glob.glob('{0}/*.{1}'.format( root, extension)) collections = clique.assemble(files) for collection in collections[0]: if prefix in collection.head: indexes = list(collection.indexes) first = str(indexes[0]) last = str(indexes[-1]) break availableAssetTypes = ['img'] try: compNameComp = inNode['fcompname'].value() except: compNameComp = '' if compNameComp == '': compNameComp = nameComp components.append( (fileComp, compNameComp, first, last, nameComp)) if proxyComp != '': components.append( (proxyComp, compNameComp + '_proxy', first, last, nameComp)) elif nodeAssetType == 'geo': fileComp = str(inNode['file'].value()) nameComp = str(inNode['name'].value()).strip() first = str(inNode['first'].value()) last = str(inNode['last'].value()) if first == '0.0' and last == '0.0': first = str( int(nuke.root().knob("first_frame").value())) last = str( int(nuke.root().knob("last_frame").value())) try: compNameComp = inNode['fcompname'].value() except: compNameComp = '' if compNameComp == '': compNameComp = nameComp components.append( (fileComp, compNameComp, first, last, nameComp)) availableAssetTypes = ['geo', 'cam'] rowCount = len(components) tableWidget.setRowCount(rowCount) if len(components) == 0: g.knob('pknob').setEnabled(False) else: g.knob('pknob').setEnabled(True) l = [x[1] for x in components] wodup = list(set(l)) if len(l) != len(wodup): g.knob('pknob').setEnabled(False) header.setMessage('Components can not have the same name', 'warning') rowCntr = 0 for comp in components: cb = QtWidgets.QCheckBox('') cb.setChecked(True) tableWidget.setCellWidget(rowCntr, 0, cb) componentItem = QtWidgets.QTableWidgetItem() componentItem.setText(comp[0]) componentItem.setToolTip(comp[0]) tableWidget.setItem(rowCntr, 1, componentItem) componentItem = QtWidgets.QTableWidgetItem() componentItem.setText(comp[1]) componentItem.setToolTip(comp[1]) tableWidget.setItem(rowCntr, 2, componentItem) try: fileCurrentFrame = nukescripts.replaceHashes( comp[0]) % int(float(comp[2])) except: print 'File is not sequence' fileCurrentFrame = comp[0] if os.path.isfile(fileCurrentFrame): fileExist = 'T' else: fileExist = 'F' componentItem = QtWidgets.QTableWidgetItem() if fileExist == 'T': componentItem.setBackground(QtGui.QColor(20, 161, 74)) else: componentItem.setBackground(QtGui.QColor(227, 99, 22)) componentItem.setToolTip(fileExist) tableWidget.setItem(rowCntr, 4, componentItem) componentItem = QtWidgets.QTableWidgetItem() componentItem.setText(comp[2]) componentItem.setToolTip(comp[2]) tableWidget.setItem(rowCntr, 5, componentItem) componentItem = QtWidgets.QTableWidgetItem() componentItem.setText(comp[3]) componentItem.setToolTip(comp[3]) tableWidget.setItem(rowCntr, 6, componentItem) componentItem = QtWidgets.QTableWidgetItem() componentItem.setText(comp[4]) componentItem.setToolTip(comp[4]) tableWidget.setItem(rowCntr, 3, componentItem) rowCntr += 1 g['ftrackassettype'].setValues(availableAssetTypes) if inputMissmatch: tableWidget.setRowCount(0) g['ftrackassettype'].setValues(['Missmatch inputs']) if cmdString == '': cmdString = 'No inputs connected' assetEnums = ['New'] if nodeAssetType != '': # assets = connector.Connector.objectById(os.environ['FTRACK_SHOTID']).getAssets(assetTypes=[g['ftrackassettype'].value()]) pubto = g.knob('fpubto').getObject().targetTask assets = connector.Connector.objectById(pubto).getAssets( assetTypes=[g['ftrackassettype'].value()]) assets = sorted(assets, key=lambda entry: entry.getName().lower()) assetEnums = assetEnums + [ HelpFunctions.safeString(x.getName()) for x in assets ] FnAssetAPI.logging.info(assetEnums) g['fassetnameexisting'].setValues(assetEnums) g = nuke.toNode(HelpFunctions.safeString(thisNodeName)) g.begin() # Add more inputs if full realInputCount = 0 for inputNode in range(g.inputs()): if g.input(inputNode): realInputCount += 1 if realInputCount == g.maxInputs(): inputNode = nuke.createNode("Input", inpanel=False) g.end() elif nuke.thisKnob().name() == 'ftrackassettype': nodeAssetType = g['ftrackassettype'].value() #print nodeAssetType assetEnums = ['New'] if nodeAssetType != '' and nodeAssetType != 'Missmatch inputs': # assets = connector.Connector.objectById(os.environ['FTRACK_SHOTID']).getAssets(assetTypes=[nodeAssetType]) pubto = g.knob('fpubto').getObject().targetTask assets = connector.Connector.objectById(pubto).getAssets( assetTypes=[nodeAssetType]) assetEnums = assetEnums + [ HelpFunctions.safeString(x.getName()) for x in assets ] g['fassetnameexisting'].setValues(assetEnums)
def ffmpeg_knobChanged(): n = nuke.thisNode() k = nuke.thisKnob() watch_list = [ 'inFile', 'outFile', 'prefix', 'fileName', 'suffix', 'env', 'envPath', 'fileType', 'codec', 'colorspace', 'fps', 'crf', 'audio', 'startFrame', 'endFrame', 'limit', 'outPreview' ] input = n['inFile'] output = n['outFile'] prefix = n['prefix'] filename = n['fileName'] suffix = n['suffix'] customFFmpeg = n['env'] ffmpegPath = n['envPath'] outputPreview = n['outPreview'] cmdPreview = n['cmdPreview'] fileType = n['fileType'] codec = ['libx264', 'libx265'] colorspace = ['gamma22', 'linear'] limit = n['limit'] # Custom ffmpeg path if k.name() == 'env': if customFFmpeg.value(): ffmpegPath.setVisible(True) else: ffmpegPath.setFlag(0x40000) # disable knobs if limit frane range is not checked if k.name() == 'limit': if not limit.value(): for knob in ['startFrame', 'endFrame']: n[knob].setFlag(0x80) else: for knob in ['startFrame', 'endFrame']: n[knob].clearFlag(0x80) # set first and last frame n['startFrame'].setValue(n.input(0)['first'].value()) n['endFrame'].setValue(n.input(0)['last'].value()) #Set values when input gets connected if n.input(0) and os.path.isfile(n.input(0)['file'].evaluate()): if not input.value(): input.setValue(nukescripts.replaceHashes(nuke.filename( n.input(0)))) if not output.value(): output.setValue( os.path.dirname(nukescripts.replaceHashes(input.value())) + '/') if not filename.value(): filename.setValue( re.sub( r'.%.*d.exr', "", os.path.basename(nukescripts.replaceHashes( input.value())))) #set output preview outputPreview.setValue(''.join( (output.value() + prefix.value(), filename.value(), suffix.value(), '.', fileType.value()))) #Set command preview if k.name() in watch_list: # watch changes and adjust output # Check if use custom ffmpeg path and start compiling command if customFFmpeg.value() and os.path.isfile(ffmpegPath.value()): ffmpegPath = ffmpegPath.value() else: ffmpegPath = 'ffmpeg' if n['audio'].value(): audioPath = '"%s"' % os.path.abspath(n['audio'].evaluate()) else: audioPath = None inputPath = '"%s"' % os.path.abspath(input.value()) outputPath = '"%s"' % os.path.abspath(outputPreview.value()) startFrame = int(n['startFrame'].value()) endFrame = int(n['endFrame'].value()) framerange = endFrame - startFrame + 1 args = '%s%s -apply_trc %s -framerate %s -start_number %s -i %s -c:v %s%s -crf %s -pix_fmt yuv420p %s' % ( ffmpegPath, '' if not n['audio'].value() is None else (' -i %s' % audioPath), colorspace[int( n['colorspace'].getValue())], str(n['fps'].value()), str(startFrame), inputPath, codec[int(n['codec'].getValue())], '' if not n['limit'].value() else ' -frames:v %s' % str(framerange), str(int(n['crf'].value())), outputPath) cmdPreview.setValue(args)
def _collect(localPath): n = nuke.allNodes() seqPads = ['%01d', '%02d', '%03d', '%04d', '%05d', '%06d', '%07d', '%08d', '%d', '%1d'] # Get script name scriptName = os.path.basename(nuke.Root().name()) # Save script to archive path newScriptPath = localPath + scriptName nuke.scriptSaveAs(newScriptPath) # Build lists of nodes (also remove duplicate Read nodes) if nuke.allNodes("Read"): readNodes = _dupReadDestroy(False) readPaths = [nukescripts.replaceHashes(node['file'].value()) for node in readNodes] else: readNodes = None readGeoNodes = nuke.allNodes("ReadGeo2") + nuke.allNodes("ReadGeo") readGeoPaths = [nukescripts.replaceHashes(node['file'].value()) for node in readGeoNodes] fbxNodes = [node for node in nuke.allNodes("Axis2") + nuke.allNodes("Camera2") if node['read_from_file'].value()] # Check to make sure there is something to archive if not readNodes and not readGeoNodes and not fbxNodes: return False # Create log file and write header info to it fOut = open(localPath + 'Archive Log.txt', 'w') fOut.write('Comp archived %s at %s\n\n\n' % (strftime("%m/%d/%Y"), strftime("%H:%M:%S"))) fOut.write('Comp Name: %s\n\n' % scriptName) fOut.write('Files archived to:\n\t%s\n\n\n' % localPath) # Archive Read nodes (if applicable) if readNodes: fOut.write('Read nodes and associated source files:\n') # Create footage directory os.makedirs(localPath + "Footage") footagePath = localPath + "Footage/" for node in readNodes: # Get Read node's footage path currentPath = node['file'].value() seqName = os.path.basename(currentPath) seqTuple = os.path.splitext(seqName) # Build local path to assign to Read node localReadFolder = footagePath + node.name() os.mkdir(localReadFolder) # Check for a sequence and copy if applicable if seqTuple[0].endswith(tuple(seqPads)): curFrame = node.firstFrame() while curFrame <= node.lastFrame(): fileName = seqName % (curFrame, ) shutil.copy2('%s/%s' % (os.path.dirname(currentPath), fileName), localReadFolder) curFrame += 1 # Copy single file else: shutil.copy2(currentPath, localReadFolder) # Re-link Read node to local footage node['file'].setValue('%s/%s' % (localReadFolder, seqName)) # Output Read node info to log file fOut.write('\t%s: %s\n' % (node.name(), seqName)) # Archive Geometry nodes (if applicable) if readGeoNodes: fOut.write('\nReadGeo nodes and associated geometry files:\n') # Create geometry directory os.makedirs(localPath + "Geometry") geoPath = localPath + "Geometry/" for node in readGeoNodes: # Get Geo node's file path currentPath = node['file'].value() seqName = os.path.basename(currentPath) seqTuple = os.path.splitext(seqName) # Build local path to assign to Geo node localGeoFolder = geoPath + node.name() os.mkdir(localGeoFolder) # Check for a geo sequence and copy if applicable # A little different than Read node since ReadGeo nodes have no explicit frame range if seqTuple[0].endswith(tuple(seqPads)): if seqTuple[0].endswith(('%d', '%1d')): padLength = 1 if seqTuple[0].endswith('%d'): baseName = seqTuple[0][:-2] else: baseName = seqTuple[0][:-3] else: padLength = seqPads.index(seqTuple[0][-4:]) + 1 baseName = seqTuple[0][:-4] extMatch = [i for i in os.listdir(os.path.dirname(currentPath)) if os.path.splitext(i)[1] == seqTuple[1]] fnPattern = baseName for i in range(0,padLength): fnPattern += '[0-9]' fnPattern += seqTuple[1] for f in extMatch: if fnmatch(f, fnPattern): shutil.copy2('%s/%s' % (os.path.dirname(currentPath), f), localGeoFolder) # Copy single file else: shutil.copy2(currentPath, localGeoFolder) # Re-link Geo node to local footage node['file'].setValue('%s/%s' % (localGeoFolder, seqName)) # Output Geo node info to log file fOut.write('\t%s: %s\n' % (node.name(), seqName)) # Archive FBX-dependent nodes (if applicable) if fbxNodes: fOut.write('\nFBX-dependent nodes and associated FBX files:\n') # Create FBX directory os.makedirs(localPath + "FBX") fbxPath = localPath + "FBX/" for node in fbxNodes: # Get FBX node's file path currentPath = node['file'].value() fileName = os.path.basename(currentPath) # Build local path to assign to FBX node localFBXFolder = fbxPath + node.name() os.mkdir(localFBXFolder) # Copy FBX file to local path shutil.copy2(currentPath, localFBXFolder) # Re-link FBX node to local footage node['file'].setValue('%s/%s' % (localFBXFolder, fileName)) # Output FBX node info to log file fOut.write('\t%s: %s\n' % (node.name(), fileName)) # Write total number of copied files to log file fOut.write('\n\n%d files total' % (sum((len(f) for _, _, f in os.walk(localPath)))-2, )) fOut.close() # Save script and return successfully nuke.scriptSave() return True
def knobChanged( self, knob ): #update if knob.name()=="update": #reset for btn in nuke.errors_footageBtn: self.removeKnob(btn) nuke.errors_footageBtn=[] errors=[] nuke.errors_nodes=[] nuke.errors_missingFrames=[] with nuke.root(): all = nuke.allNodes() for n in all: if n.Class()!="Read": if n.hasError(): errors.append(n.name()) if n not in nuke.errors_nodes: nuke.errors_nodes.append(n) else: for frame in range(int(n["first"].getValue()), int(n["last"].getValue())+1): try: f = nukescripts.replaceHashes(n['file'].value() ) % (frame) except: f = "" if not os.path.isfile(f): errors.append(f) if f not in nuke.errors_missingFrames: nuke.errors_missingFrames.append(f) if n not in nuke.errors_nodes: nuke.errors_nodes.append(n) for errorNode in nuke.errors_nodes: self.en = nuke.PyScript_Knob(errorNode.name(), errorNode.name()) self.addKnob(self.en) nuke.errors_footageBtn.append(self.en) nuke.errors_lenErrors=len(errors) if nuke.errors_lenErrors==0: col="green" else: col="red" countErrors = '<span style="color:{col}">{countErr}</span>'.format(col=col, countErr=nuke.errors_lenErrors) self.errorCount.setValue(countErrors) #write if knob.name()=="write": if self.outputPath.getValue()!="": try: script = os.path.basename(nuke.root().name()) output= os.path.dirname(self.outputPath.getValue()) + "/errorReport_%s" % script.replace(".nk",".txt") errorOutput = open(output,'w') date = time.strftime("%d-%m-%Y %H:%M:%S", time.gmtime()) header="error report \nscript name: {scriptname}\nscript path: {scriptPath}\ndate: {date}\nnumber of errors: {countErrors}\n------------------------------".format(scriptname=script, scriptPath=nuke.root().name(), date=date, countErrors=nuke.errors_lenErrors) errorOutput.write(header) #all read nodes errorOutput.write("\nread nodes\n\n") for n in nuke.errors_nodes: if n.Class()=="Read": errorOutput.write("read node: %s\n" % n.name()) #all missing frames errorOutput.write("\n----------\nmissing frames\n\n") for f in nuke.errors_missingFrames: errorOutput.write("missing frame: %s\n" % f) #all other nodes errorOutput.write("\n----------\nother nodes\n\n") for n in nuke.errors_nodes: if n.Class()!="Read": errorOutput.write("node: %s\n" % n.name()) nuke.message("successfully written error report to:\n\n%s" % output) except: nuke.message("some error occured. The report could not be written.") else: nuke.message("Please enter a output path for the error report.") #all other error nodes else: allNodes=nuke.allNodes() pKnob=knob.name() for n in allNodes: if n.name() == pKnob: nuke.zoom( 1, [ n.xpos(), n.ypos() ]) nukescripts.clear_selection_recursive() n.setSelected(True)