View difference between Paste ID: Nm5ygKfk and mj3bK3bs
SHOW: | | - or go back to the newest paste.
1
'''
2
FCP XML to Nuke
3
v1.1 - Made support for Premiere FCPXML format more robust. Premiere FCP XML stores all sequences in the project, whereas
4
Final Cut Pro's XML format stores only a single sequence. I added a box that lets you choose what sequence 
5
of the Premiere XML file to process, and it should work more reliably now.
6
v1.0 - Initial release.
7
8
This script takes a Final Cut XML file with a single flattened video track, and builds Nuke scripts for each clip in the timeline.
9
It is intended as a simple way to automate workflows between FCP/Premiere and Nuke.
10
It creates a Nuke script with global first and last frame set, a frameRange node with the proper framerange, and a Write node
11
set to the output path.
12
There is an option for creating subdirectories for every Nuke script created. Handles are also an option.
13
It can parse reel number and clip number from Red and Alexa footage, or can use the clip filename as the base naming for the output files.
14
15
This script was somewhat inspired by compflows.blogspot.com, but has been written from scratch and is a bit more flexible (although it only goes from XML->NukeScripts and not back at the moment).
16
This has only been tested on OSX, but in theory should be cross-platform compatible. Comments and suggestions are welcome!
17
18
19
# The menu.py example entry below adds this script in a folder called "Scripts" in your toolbar.
20
import fcpxml_to_nuke
21
nuke.toolbar('Nodes').addMenu('Scripts').addCommand('FCP XML to Nuke', 'fcpxml_to_nuke.process_xml()')
22
'''
23
24
import nuke, os
25
from xml.dom.minidom import parse
26
27
def process_xml():
28
	'''
29
	Imports an FCP XML file, locates each clip in the timeline on Track 1, 
30
	and for each clip, builds a nuke script for that file and puts it in the output directory specified
31
32
	New Features that would be nice to have: 
33
	Customized naming patterns based on reel/clip number.
34
	Handle FCP XML from Premiere or FCP / FCPX ( Are there differences in the XML structure for these? )
35
	Choose additional output naming and directory formatting patterns
36
	'''
37
38
	# Build the Nuke Panel where locations and stuff is specified.
39
	p = nuke.Panel("FCP XML Import")
40-
	xml_file = '/Users/fx4/Desktop/fcpxml/test_fcp_to_xml.xml' #FCP XML Import
40+
	xml_file = '/Volumes/heka/Programming/nuke-scripts/fcpxml_to_nuke/fcpxml_test 960 0.xml' #FCP XML Import
41-
	output_dir = '/Users/fx4/Desktop/fcpxml/output' #Directory to Output Nuke Scripts
41+
	output_dir = '/Volumes/heka/Programming/nuke-scripts/fcpxml_to_nuke/output' #Directory to Output Nuke Scripts
42
	subdirectories = 'Create subdirectories for each script?'
43-
	render_dir = '/Users/fx4/Desktop/fcpxml/output' #Render Directory for All Write Nodes
43+
	render_dir = '/Volumes/heka/Programming/nuke-scripts/fcpxml_to_nuke/output' #Render Directory for All Write Nodes
44
	handle_length = "0 5 10 15 20 30 35 40"
45
	clip_name_format = "Bypass RED Alexa"
46
47
	p.addFilenameSearch("FCP XML File", xml_file)
48
	p.addBooleanCheckBox("Create subdirectories for each script", subdirectories)
49
	p.addFilenameSearch("Output Directory", output_dir)
50
	p.addFilenameSearch("Render Directory", render_dir)
51
	p.addEnumerationPulldown("Handle Length", handle_length)
52
	p.addEnumerationPulldown("Clip Name Format", clip_name_format)
53
	p.setWidth(600)
54
	if not p.show():
55
		return
56
57
	# Assign vars from Nuke Panel user-entered data 
58
	xml_file 	= p.value("FCP XML File")
59
	output_dir	= p.value("Output Directory")
60
	subdirectories = p.value("Create subdirectories for each script")
61
	render_dir 	= p.value("Render Directory")
62
	handle_length = int( p.value("Handle Length") )
63
	clip_name_format = p.value("Clip Name Format")
64
65
	# Create paths for render directory if it does not exist
66
	if not os.path.isdir(render_dir):
67
		os.mkdir(render_dir)
68
	if not os.path.isdir(output_dir):
69
		os.mkdir(output_dir)
70
71
72
	############################
73
	# Begin Parsing XML File
74
	############################
75
	dom = parse( xml_file )
76
77
	# Prompt user to choose which sequence to process, because Premiere's XML export includes all sequences.
78
	# Much of this complexity is to handle sequences with spaces in their names, because the nuke.panel
79
	# addEnumerationPulldown is space-demarcated. The logic below handles spaces in sequence names and allows the user 
80
	# to choose which sequence to process, and stores the sequence to process as a variable to access
81
82
	sequences = []
83
	i = 0
84
	# Makes a list of all sequence names
85
	for seq in dom.getElementsByTagName('sequence'):
86
		seqname = seq.getElementsByTagName('name')[0].firstChild.data
87
		sequences.append( [seqname] )
88
		# If a sequence name has space characters, replace them with underscores for the Nuke enumeration pulldown panel
89
		if seqname.find(' ') != -1:
90
			sequences[i].append( seqname.replace(' ', '_') )
91
		i += 1
92
	print "Sequences are: ", sequences
93
	# ??? Do all of the below messy work to prepare for deciding between multiple sequences, including dealing with spaces in sequence names
94
	# but only if there is more than one sequence in the XML file. If not, we'll just set the 'row' var to 0, and roll with that.
95
	if len(sequences) > 1:
96
		# Makes a " " demarcated string with all sequence names for the nuke enumeration pulldown panel
97
		seq_enum = ''
98
		i = 0
99
		for seq in sequences:
100
			if len(sequences[i]) == 1:
101
				seq_enum += sequences[i][0] + ' '
102
			else:
103
				seq_enum += sequences[i][1] + ' '
104
			i += 1
105
106
		# Create a Nuke panel for the user to choose which sequence to process
107
		seq_panel = nuke.Panel("Choose Sequence To Process")
108
		seq_panel.addEnumerationPulldown("Choose Sequence", seq_enum)
109
		seq_panel.setWidth(400)
110
		if not seq_panel.show():
111
			return
112
		chosen_sequence = seq_panel.value("Choose Sequence")
113
114
		# Gets the index of the chosen sequence in the list of sequences, stores the sequence XML object as a variable
115
		for row, i in enumerate(sequences):
116
				try:
117
					column = i.index( chosen_sequence )
118
				except ValueError:
119
					continue
120
				break
121
	else:
122
		row = 0
123
	chosen_seqobj = dom.getElementsByTagName('sequence')[row]
124
	print "Chosen sequence is: ", chosen_seqobj.getElementsByTagName('name')[0].firstChild.data
125
126
	seq_res_x = int( chosen_seqobj.getElementsByTagName('format')[0].getElementsByTagName('width')[0].firstChild.data )
127
	seq_res_y = int( chosen_seqobj.getElementsByTagName('format')[0].getElementsByTagName('height')[0].firstChild.data )
128
	print "Sequence resolution is ", seq_res_x,"x",seq_res_y
129
130
	# Set optional effect parameters to False
131
	timeremap_value = False
132
	scale_value = False
133
	x_move = False
134
	y_move = False
135
	rotation_value = False
136
137
	seq_clip_number = 1
138
	track = chosen_seqobj.getElementsByTagName('track')[0]
139
	for clip in track.getElementsByTagName('clipitem'):
140
		masterclipid 	= clip.getElementsByTagName('masterclipid')[0].firstChild.data
141
		clip_name 		= clip.getElementsByTagName("name")[0].firstChild.data
142
		in_point 		= int( clip.getElementsByTagName('in')[0].firstChild.data )
143
		out_point 		= int( clip.getElementsByTagName('out')[0].firstChild.data )
144
		clip_duration 	= int( clip.getElementsByTagName("duration")[0].firstChild.data )
145
		
146
		# Fetch the pathurl of the clip by cycling through all <pathurl> nodes and comparing the filename of the clip to the clip_name
147
		# This is necessary because in Premiere XMLs, the pathurl for a clip is not always stored in the clipitem node, but rather in a seperate node in the master-clip
148
		
149
		#??? Instead: Check for pathurl node in current clip node. If it doesn't exist, cycle through all 
150
		# clipitem nodes to find another that matches the name node with the current clip_name.
151
		# If it finds a matching named clipitem, search for a pathurl in that node.
152
		try:
153
			file_path = clip.getElementsByTagName('pathurl')[0].firstChild.data.split("file://localhost")[1].replace("%20", " ")
154
155
		except:
156
			print 'Failed to get pathurl in current clipitem. Searching other clipitems for matching name.'
157
			for pathurl_clip in dom.getElementsByTagName('clipitem'):
158
				if pathurl_clip.getElementsByTagName('name')[0].firstChild.data == clip_name:
159
					try:
160
						file_path = pathurl_clip.getElementsByTagName('pathurl')[0].firstChild.data.split("file://localhost")[1].replace("%20", " ")
161
						break
162
					except:
163
						continue
164
		print clip_name, in_point, out_point, clip_duration, file_path
165
166
		# Get resolution of this clip in the clipitem node, 
167
		# Else, look for a masterclip with the same name and try to get the resolution from there, Else: fail?
168
		try:
169
			clip_width = int( clip.getElementsByTagName('width')[0].firstChild.data )
170
			clip_height = int( clip.getElementsByTagName('height')[0].firstChild.data )
171
			print "Clip resolution is: ", clip_width, "x", clip_height
172
		except:	
173
			for masterclip in dom.getElementsByTagName('clipitem'):
174
				if masterclip.getElementsByTagName('name')[0].firstChild.data == clip_name:
175
					#!!! This is triggered if a clip is used more than once in the sequence.
176
					try:
177
						#print "found master clip: ", masterclip.getElementsByTagName('name')[0].firstChild.data, " and "
178
						clip_width = int( masterclip.getElementsByTagName('width')[0].firstChild.data )
179
						clip_height = int( masterclip.getElementsByTagName('height')[0].firstChild.data )
180
						break
181
					except:
182
						continue
183
		# Get all effects applied to this clip
184
		for effect in clip.getElementsByTagName('effect'):
185
			effect_name = effect.childNodes[1].firstChild.data
186
			if effect_name == 'Time Remap':
187
				# Loop through all parameters of the effect
188
				for param in effect.getElementsByTagName('parameter'):
189
					param_id = param.childNodes[1].firstChild.data
190
					if param_id == 'speed':
191
						timeremap_value = float( param.getElementsByTagName('value')[0].firstChild.data )
192
						print effect_name, param_id, timeremap_value
193
194
			if effect_name == 'Basic Motion':
195
				for param in effect.getElementsByTagName('parameter'):
196
					param_id = param.childNodes[1].firstChild.data
197
					if param_id == 'scale':
198
						scale_value = float( param.getElementsByTagName('value')[0].firstChild.data )
199
						print effect_name, param_id, scale_value
200
					if param_id == 'rotation':
201
						rotation_value = float( param.getElementsByTagName('value')[0].firstChild.data )
202
						print effect_name, param_id, rotation_value
203
					if param_id == 'center':
204
						x_move = float( param.getElementsByTagName('value')[0].childNodes[1].firstChild.data )
205
						y_move = float( param.getElementsByTagName('value')[0].childNodes[3].firstChild.data )
206
						print effect_name, param_id, x_move, y_move
207
						'''
208-
						So.... 
208+
						So.... Figuring out how Premiere handles position values:
209
						Prem 0-0 clip is centered upper left: value = .5,.5
210-
						prem 1920-1080, clip is centered lower right: value = -.5,-.5
210+
						prem 1920-1080, clip is centered lower right: value = .5 .5??
211-
						prem: 1060-640, value: 0.052083 0.092593
211+
						prem 1060-640, value: 0.052083 0.092593
212-
						prem: 960-1080, value: 0.0 0.5
212+
						prem center bottom: 960-1080, value: 0.0 0.5
213-
						prem: 
213+
						prem center top: 960 0, value: 0.0 -0.5
214
						prem UR 1919 0, value: 0.499479 -0.5
215
						
216
						location 	x, y
217
						center 		0, 0
218
						UL			-0.5, -0.5
219
						UR 			0.5, -0.5
220
						LR 			0.5, 0.5
221
						LL 			0, 0.5
222
						y-up is negative
223
						x-right is positive
224
						The range from edge to edge of sequence space is 1. 
225
						-.5 is left, .5 is right. 
226
						-.5 is up, .5 is down.
227
						.125, 0 would be 1200x540 = (seq_res_x * x_move) = how many pixels to move from center) = 1920*.125 + 1920/2 = 1200
228
						for x: seq_res_x * x_move
229
						for y: seq_res_y * -y_move
230
						'''
231
		
232
		# Gets the shot name, which is the formatted clip_name with clip# and reel#, with the sequence clipnumber.
233
		# uses camera type (Red, Alexa, etc), and the clip_name string (the filename of the clip used in FCP) 
234
		# Also takes the seq_clip_number for returning the correct shot_name (the name that will be used to name the nuke script)
235
		if clip_name_format == 'RED':
236
			# This works for Red footage of format: A###_C###_RANDOMDATA
237
			reel_number = clip_name.split('_')[0][1:]
238
			clip_number = clip_name.split('_')[1][1:]
239
240
		if clip_name_format == 'Alexa':
241
			# Alexa footage is A###C###_######_R####
242
			reel_number = int(clip_name.split('C')[0][1:])
243
			clip_number = int( clip_name.split('C')[1].split('_')[0] )
244
245
		if clip_name_format == 'Bypass':
246
			shot_name = "%02d0_%s" %(seq_clip_number, os.path.splitext(clip_name)[0])
247
		else:
248
			# shot_name is the string that defines the name that the nuke script is saved to. seq_clip_number+0_A{reelnumber}_C{clipnumber}
249
			shot_name = "%02d0_A%sC%s" %(seq_clip_number, reel_number, clip_number)
250
251
252
		############################
253
		# Build Nuke Script
254-
			first_frame = round(first_frame/(100/timeremap_value))
254+
255-
			last_frame = round(last_frame/(100/timeremap_value))
255+
256
		# if the subdirectories checkbox is checked, set the output_shotdir to be a subdirectory named with the shot_name
257
		if subdirectories:
258
			output_shotdir = output_dir
259
			output_shotdir = os.path.join(output_dir, shot_name)
260
		else:
261
			output_shotdir = output_dir
262
		# If the output_shotdir does not exist, create it (auto-creates subdirectories)
263
		if not os.path.isdir(output_shotdir):
264
				os.mkdir(output_shotdir)
265
266
		
267
		###########################
268
		# Compute values to plug into the Nuke Script
269-
		nuke_script.write('''Read {{\n inputs 0\n file \"{0}\"\n first 0\n last {1}\n frame_mode offset\n frame 1\n origlast {1}\n origset true\n name Read1\n selected true\n xpos -425\n ypos -40\n}}\n'''.format(file_path,clip_duration))
269+
270
		# Compute Handles and set first_frame and last_frame
271
		first_frame = in_point - handle_length
272
		last_frame = out_point-1 + handle_length
273
274
		if timeremap_value:
275
			timeremap_value 	= timeremap_value/100
276
			new_clip_duration 	= last_frame - first_frame
277
			clip_duration 		= clip_duration * timeremap_value
278
			first_frame 		= first_frame * timeremap_value
279
			last_frame 			= first_frame + new_clip_duration
280
			
281
			'''
282
			you have the duration of the original clip, and the in and out points of the retimed clip 
283
			originalIn = newIn * retime
284
			originalOut = newOut * retime
285
			new duration = lastFrame - first_frame
286
			'''
287
288
289
		# Set Format 
290
		if seq_res_x == 1920 and seq_res_y == 1080:
291
			fcp_xml_resolution = 'HD'
292
		else:
293
			fcp_xml_resolution = 'from_xml'
294
295
296
		#!!! This creates a nuke script by appending text to the .nk file instead of using nuke.nodeCopy(), which is slow and messy, and so that root node settings can be added.
297
		# The strings that are written are triple-quoted. newlines are created with '\n'. {} chars in the string have to be doubled so as not to throw a KeyError
298
		nuke_file = os.path.join(output_shotdir, "%s_v001.nk"%(shot_name))
299-
'''.format( x_move, y_move, -rotation_value, scale_value/100, seq_res_x/2, seq_res_y/2 ) )
299+
300
		# Create Root node
301
		nuke_script.write('''Root {{\n inputs 0\n name {0}\n project_directory \"\[python \{{nuke.script_directory()\}}]\"\n first_frame {1}\n last_frame {2}\n format \"{3} {4} 0 0 {3} {4} 1 {5}\"\n proxy_type scale\n}}\n'''.format(nuke_file, first_frame, last_frame, seq_res_x, seq_res_y, fcp_xml_resolution))
302
		# Create Read node
303
		nuke_script.write('''Read {{\n inputs 0\n file \"{0}\"\n first 0\n last {1}\n frame_mode offset\n frame 1\n origlast {1}\n origset true\n name Read1\n selected true\n xpos -425\n ypos -40\n}}\n'''.format(file_path, clip_duration))
304
		# Create TimeRemap if there is retiming on the clip
305
		if timeremap_value:
306
			nuke_script.write('''Group {{
307
 name RetimeFromFrame
308
 selected true
309
 addUserKnob {{20 Retime t "Retime From Frame Parameters"}}
310
 addUserKnob {{41 StartFrame l "SourceStart Frame" t "The source frame from which retiming starts. For example, if you have a clip that you are using a range from frames 200-300 in, and you want to retime that clip to be 50\% speed, you would set this to be 200. \\n\\nThis gizmo references the root.first_frame value to determine the \\\"in-point\\\" of the clip." T RetimeControls.StartFrame}}
311
 addUserKnob {{41 PlaybackSpeed l "Playback Speed" t "Retime speed as a fraction of one. That is, 0.5 = 50\% speed, 2 = 200\% speed." T RetimeControls.PlaybackSpeed}}
312
}}
313
 Input {{
314
  inputs 0
315
  name Input1
316
  xpos 0
317
 }}
318
 TimeOffset {{
319
  time_offset {{{{-RetimeControls.StartFrame/RetimeScreen.timingSpeed}}}}
320
  name Retime_TimeOffset
321
  tile_color 0xff0000ff
322
  xpos 0
323
  ypos 132
324
 }}
325
 OFXuk.co.thefoundry.time.oflow_v100 {{
326
  method Motion
327
  timing Speed
328
  timingFrame 1
329
  timingSpeed {{{{RetimeControls.PlaybackSpeed}}}}
330
  filtering Normal
331
  warpMode Normal
332
  correctLuminance false
333
  automaticShutterTime false
334
  shutterTime 0
335
  shutterSamples 1
336
  vectorDetail 0.2
337
  smoothness 0.5
338
  blockSize 6
339
  Tolerances 0
340
  weightRed 0.3
341
  weightGreen 0.6
342
  weightBlue 0.1
343
  showVectors false
344
  cacheBreaker false
345
  name RetimeScreen
346
  tile_color 0xff0000ff
347
  selected true
348
  xpos 0
349
  ypos 156
350
 }}
351
 TimeOffset {{
352
  time_offset {{{{root.first_frame}}}}
353
  name GlobalStart_Offset
354
  tile_color 0xff0000ff
355
  xpos 0
356
  ypos 180
357
 }}
358
 Output {{
359
  name Output1
360
  xpos 0
361
  ypos 393
362
 }}
363
 NoOp {{
364
  inputs 0
365
  name RetimeControls
366
  xpos -174
367
  ypos 126
368
  addUserKnob {{20 User}}
369
  addUserKnob {{7 PlaybackSpeed l "Playback Speed" R 0 100}}
370-
end_group\n'''.format( timeremap_value/100, first_frame ))
370+
371
  addUserKnob {{3 StartFrame l "Start Frame" t "Offset video start frame"}}
372
  StartFrame {1}
373
 }}
374
end_group\n'''.format( timeremap_value, first_frame ))
375
		
376
		# Create FrameRange node 
377
		nuke_script.write('''FrameRange {{\n first_frame {0}\n last_frame {1}\n name FrameRange1\n label "\\[knob first_frame]-\\[knob last_frame]"\n selected true\n}}\n'''.format(first_frame, last_frame))
378
		
379
		# Create a Transform node with pans and scales, if they exist
380
		if 	scale_value or x_move or y_move or rotation_value:
381
			if not scale_value:
382
				scale_value = 1
383
			if not x_move:
384
				x_move = 0
385
			if not y_move:
386
				y_move = 0
387
			if not rotation_value:
388
				rotation_value = 0
389
			# Create a reformat node if there are pans or scales
390
			nuke_script.write('''Reformat {{
391
 resize none
392
 black_outside true
393
 name Reformat1
394
 selected true
395
}}
396
'''.format())
397
			nuke_script.write( '''Transform {{
398
 translate {{{0} {1}}}
399
 rotate {2}
400
 scale {3}
401
 center {{{4} {5}}}
402
 name Transform1
403
 selected true
404
 }}
405
'''.format( (seq_res_x * x_move), (seq_res_y * -y_move), -rotation_value, scale_value/100, seq_res_x/2, seq_res_y/2 ) )
406
407
		# Create Write node
408
		nuke_script.write('''Write {{\n file \"{0}\"\n file_type mov\n codec apch\n fps 23.976\n checkHashOnRead false\n name Write1\n selected true\n}}\n'''.format('{0}_v001.mov'.format(os.path.join(render_dir, shot_name)) ) )
409
		# Create Viewer node
410
		nuke_script.write('''Viewer {\n name Viewer1\n selected true\n}\n''')
411
		# Create Backdrop node
412
		nuke_script.write('''BackdropNode {{\n inputs 0\n name BackdropNode1\n tile_color 0x26434dff\n label \"<img src=\\\"Read.png\\\"> Read Plate <br/><font size=1> {0} <br/> {1}-{2}<br/>{3} frame handles\"\n note_font_size 30\n selected true\n xpos -500\n ypos -150\n bdwidth 234\n bdheight 254\n}}\n'''.format(shot_name, in_point, out_point, handle_length))
413
414
415
416
417
		seq_clip_number += 1
418
		# Reset option effect parameters to false for next clip iteration
419
		timeremap_value = False
420
		scale_value = False
421
		x_move = False
422
		y_move = False
423
		rotation_value = False
424
		### End of for loop which processes each clip in timeline.
425
426
427
	nuke.message('All clips processed successfully!')
428
	return
429
430
431
432
'''
433
		### ??? ALTERNATIVE METHOD FOR CREATING THE SCRIPT FILES
434
		### This approach uses the script that import_xml is executed from as a base for creating nodes, and then using nuke.nodeCopy() to 'paste' the data into each script file.
435
		### The approach I ended up using instead just uses python to format .nk scripts as text, inputting the variables where relevant. It is much faster and more efficient.
436
		for node in nuke.allNodes():
437
			node.setSelected(True)
438
		nuke.nodeDelete()
439
440
		# Create Read node
441
		read = nuke.createNode("Read")
442
		read.knob("file").setValue(file_path)
443
		read.knob("frame_mode").setValue('offset')
444
		read.knob("frame").setValue('1')
445
		read.knob("first").setValue(0)
446
		read.knob("last").setValue(clip_duration)
447
448
		# Create a NoOp node to hold shot info
449
		#!!! This is not needed
450
		#shotInfo = nuke.createNode('NoOp')
451
		#shotInfo.knob('name').setValue(shot_name+"_info")
452
		#shotInfo.addKnob( nuke.String_Knob("The original name of the clip", "clip_name", clip_name) )
453
		#shotInfo.addKnob( nuke.String_Knob("Base name of the nuke script", "shot_name", shot_name) )
454
455
		# Create FrameRange node
456
		frame_range = nuke.createNode("FrameRange")
457
		frame_range.knob('label').setValue('[knob first_frame]-[knob last_frame]')
458
		frame_range.knob('first_frame').setValue( in_point - handle_length ) 
459
		frame_range.knob('last_frame').setValue( out_point-1 + handle_length )
460
		
461
		# Create Write node
462
		write = nuke.createNode("Write")
463
		write.knob('file').setValue('{0}{1}_v001.mov'.format(render_dir, shot_name))
464
		#write.knob("file_type").setValue("mov")
465
		#write.knob("mov.codec").setValue("apch")
466
		#write.knob("mov.fps").setValue("23.976")
467
468
		# Create Viewer Node
469
		nuke.createNode('Viewer')
470
471
		# Informational Backdrop Node
472
		bd_node = nuke.createNode("BackdropNode")
473
		bd_node.knob("tile_color").setValue(0x26434dff)
474
		bd_node.knob("note_font_size").setValue(30)
475
		bd_node.knob("bdwidth").setValue(234)
476
		bd_node.knob("bdheight").setValue(254)
477
		bd_node.knob("label").setValue('<img src=\"Read.png\"> Read Plate <br/><font size=1> %s <br/> %s-%s'%(shot_name,int(in_point),int(out_point)))
478
479
		# Set root script values
480
		#nuke.toNode('root').knob('project_directory').setValue('[python {nuke.script_directory()}]')
481
		#nuke.toNode('root').knob('first_frame').setValue( in_point-handle_length)
482
		#nuke.toNode('root').knob('first_frame').setValue( (out_point-1) + handle_length)
483
		#nuke.toNode('root').knob('format').setValue('HD')
484
485
		# Select all created nodes and copy them into a new script
486
		for node in nuke.allNodes():
487
			node.setSelected(True)
488
		nuke.nodeCopy(nuke_file)
489
		'''