Hook: Create Shot Folders and batchgroups + save plates

Author: Stefan
Version: 01b
Version: 2020 and up?

Script link

Automate the creation of a VFX Shots folders structure:
– Create a VFX library like VFX_ABC
– Create a folder per shot, like ABC_0010
– Create subfolders as needed, based on a given set (plates, renders, elements …)
– Creates a BatchGroup per shot and save it in the proper folder.
– Include a Write File node per BatchGroup.
– Save previously selected clips (plates) to their respective ‘plates’ folder.

You can assign a shortcut to launch it.
Open the app and set things up:
– Select clips from a reel (optionnal)
– Set the openclip path: pattern-ed path for the Write file to write to (renders, .clip, setups)
– set the amount of shots to create, increments, subfolders to include, Schematic and shelf reels to include, start frame, duration.
– The Duration box should be removed, since it can be the default (100) anyway.
– Hit ‘Create’ and enjoy.

Hope you find it useful!
Comments and feedback are more than welcome and appreciated.

Sorry, the pasted code is tripping on something and replacing some characters with >>>> …
Please ignore and browse through for quick view, otherwise simply down the script from the above link.

</pre>
# -*- coding: utf-8 -*-

'''
Stefan Gaillot
xenjee@gmail.com
2019/05/04
sg_breakout_lib_and_clips.py
'''

from PySide2 import QtCore, QtWidgets
import json
import os
import flame

print ""
print "CUA BREAKOUT - WITH CLIPS"

global MainClass, QtWidgets
global openclip_path_json

# To save the json config file per project
prj = flame.project.current_project

# To save the json config file per project
openclip_path_json = '/opt/Autodesk/project/' + prj.project_name + '/cfg/openclip_path_json.json'

# print "openclip_path_json: ", openclip_path_json

class Ui_Widget(object):
def setupUi(self, Widget):
Widget.setObjectName("Widget")
Widget.setEnabled(True)
Widget.resize(545, 589)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(Widget.sizePolicy().hasHeightForWidth())
Widget.setSizePolicy(sizePolicy)
Widget.setMinimumSize(QtCore.QSize(450, 400))
self.verticalLayout_8 = QtWidgets.QVBoxLayout(Widget)
self.verticalLayout_8.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.verticalLayout_8.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_8.setObjectName("verticalLayout_8")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setContentsMargins(11, 11, 11, 11)
self.verticalLayout.setSpacing(6)
self.verticalLayout.setObjectName("verticalLayout")
self.HLayout_main = QtWidgets.QHBoxLayout()
self.HLayout_main.setContentsMargins(11, 11, 11, 11)
self.HLayout_main.setSpacing(6)
self.HLayout_main.setObjectName("HLayout_main")
self.GB_folders = QtWidgets.QGroupBox(Widget)
self.GB_folders.setObjectName("GB_folders")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.GB_folders)
self.verticalLayout_2.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_2.setSpacing(6)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.groupBox_3 = QtWidgets.QGroupBox(self.GB_folders)
self.groupBox_3.setTitle("")
self.groupBox_3.setObjectName("groupBox_3")
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_3)
self.verticalLayout_4.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_4.setSpacing(6)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout.setSpacing(6)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_basename = QtWidgets.QLabel(self.groupBox_3)
self.label_basename.setMinimumSize(QtCore.QSize(0, 25))
self.label_basename.setObjectName("label_basename")
self.horizontalLayout.addWidget(self.label_basename)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.lineEdit_sequence_name = QtWidgets.QLineEdit(self.groupBox_3)
self.lineEdit_sequence_name.setMinimumSize(QtCore.QSize(0, 25))
self.lineEdit_sequence_name.setObjectName("lineEdit_sequence_name")
self.horizontalLayout.addWidget(self.lineEdit_sequence_name)
self.verticalLayout_4.addLayout(self.horizontalLayout)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_3.setSpacing(6)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.label_shot_amount = QtWidgets.QLabel(self.groupBox_3)
self.label_shot_amount.setMinimumSize(QtCore.QSize(0, 25))
self.label_shot_amount.setObjectName("label_shot_amount")
self.horizontalLayout_3.addWidget(self.label_shot_amount)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem1)
self.SB_shots_amount = QtWidgets.QSpinBox(self.groupBox_3)
self.SB_shots_amount.setMinimumSize(QtCore.QSize(0, 25))
self.SB_shots_amount.setMaximum(1000)
self.SB_shots_amount.setObjectName("SB_shots_amount")
self.horizontalLayout_3.addWidget(self.SB_shots_amount)
self.verticalLayout_4.addLayout(self.horizontalLayout_3)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_4.setSpacing(6)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_start_at = QtWidgets.QLabel(self.groupBox_3)
self.label_start_at.setMinimumSize(QtCore.QSize(0, 25))
self.label_start_at.setObjectName("label_start_at")
self.horizontalLayout_4.addWidget(self.label_start_at)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_4.addItem(spacerItem2)
self.SB_start_at = QtWidgets.QSpinBox(self.groupBox_3)
self.SB_start_at.setMinimumSize(QtCore.QSize(0, 25))
self.SB_start_at.setMaximum(1000)
self.SB_start_at.setObjectName("SB_start_at")
self.horizontalLayout_4.addWidget(self.SB_start_at)
self.verticalLayout_4.addLayout(self.horizontalLayout_4)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_5.setSpacing(6)
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.label_increments = QtWidgets.QLabel(self.groupBox_3)
self.label_increments.setMinimumSize(QtCore.QSize(0, 25))
self.label_increments.setObjectName("label_increments")
self.horizontalLayout_5.addWidget(self.label_increments)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_5.addItem(spacerItem3)
self.SB_increments = QtWidgets.QSpinBox(self.groupBox_3)
self.SB_increments.setMinimumSize(QtCore.QSize(0, 25))
self.SB_increments.setMaximum(1000)
self.SB_increments.setObjectName("SB_increments")
self.horizontalLayout_5.addWidget(self.SB_increments)
self.verticalLayout_4.addLayout(self.horizontalLayout_5)
self.verticalLayout_2.addWidget(self.groupBox_3)
self.groupBox_4 = QtWidgets.QGroupBox(self.GB_folders)
self.groupBox_4.setTitle("")
self.groupBox_4.setObjectName("groupBox_4")
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_4)
self.verticalLayout_6.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_6.setSpacing(6)
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.CB_fldr_plates = QtWidgets.QCheckBox(self.groupBox_4)
self.CB_fldr_plates.setObjectName("CB_fldr_plates")
self.verticalLayout_6.addWidget(self.CB_fldr_plates)
self.CB_fldr_refs = QtWidgets.QCheckBox(self.groupBox_4)
self.CB_fldr_refs.setObjectName("CB_fldr_refs")
self.verticalLayout_6.addWidget(self.CB_fldr_refs)
self.CB_fldr_elements = QtWidgets.QCheckBox(self.groupBox_4)
self.CB_fldr_elements.setObjectName("CB_fldr_elements")
self.verticalLayout_6.addWidget(self.CB_fldr_elements)
self.CB_fldr_mattes = QtWidgets.QCheckBox(self.groupBox_4)
self.CB_fldr_mattes.setObjectName("CB_fldr_mattes")
self.verticalLayout_6.addWidget(self.CB_fldr_mattes)
self.CB_fldr_batch = QtWidgets.QCheckBox(self.groupBox_4)
self.CB_fldr_batch.setObjectName("CB_fldr_batch")
self.verticalLayout_6.addWidget(self.CB_fldr_batch)
self.CB_fldr_result = QtWidgets.QCheckBox(self.groupBox_4)
self.CB_fldr_result.setObjectName("CB_fldr_result")
self.verticalLayout_6.addWidget(self.CB_fldr_result)
self.verticalLayout_2.addWidget(self.groupBox_4)
self.HLayout_main.addWidget(self.GB_folders)
self.GB_batchgroup = QtWidgets.QGroupBox(Widget)
self.GB_batchgroup.setObjectName("GB_batchgroup")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.GB_batchgroup)
self.verticalLayout_3.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_3.setSpacing(6)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.groupBox_5 = QtWidgets.QGroupBox(self.GB_batchgroup)
self.groupBox_5.setTitle("")
self.groupBox_5.setObjectName("groupBox_5")
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.groupBox_5)
self.verticalLayout_5.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_5.setSpacing(6)
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.horizontalLayout_7.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_7.setSpacing(6)
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.label_startframe = QtWidgets.QLabel(self.groupBox_5)
self.label_startframe.setMinimumSize(QtCore.QSize(0, 25))
self.label_startframe.setObjectName("label_startframe")
self.horizontalLayout_7.addWidget(self.label_startframe)
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_7.addItem(spacerItem4)
self.SB_start_frame = QtWidgets.QSpinBox(self.groupBox_5)
self.SB_start_frame.setMinimumSize(QtCore.QSize(0, 25))
self.SB_start_frame.setMaximum(1001)
self.SB_start_frame.setObjectName("SB_start_frame")
self.horizontalLayout_7.addWidget(self.SB_start_frame)
self.verticalLayout_5.addLayout(self.horizontalLayout_7)
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
self.horizontalLayout_8.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_8.setSpacing(6)
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.label_duration = QtWidgets.QLabel(self.groupBox_5)
self.label_duration.setMinimumSize(QtCore.QSize(0, 25))
self.label_duration.setObjectName("label_duration")
self.horizontalLayout_8.addWidget(self.label_duration)
spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_8.addItem(spacerItem5)
self.SB_duration = QtWidgets.QSpinBox(self.groupBox_5)
self.SB_duration.setMinimumSize(QtCore.QSize(0, 25))
self.SB_duration.setMaximum(1000)
self.SB_duration.setObjectName("SB_duration")
self.horizontalLayout_8.addWidget(self.SB_duration)
self.verticalLayout_5.addLayout(self.horizontalLayout_8)
self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
self.horizontalLayout_9.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_9.setSpacing(6)
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
self.label_task = QtWidgets.QLabel(self.groupBox_5)
self.label_task.setMinimumSize(QtCore.QSize(0, 25))
self.label_task.setObjectName("label_task")
self.horizontalLayout_9.addWidget(self.label_task)
spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_9.addItem(spacerItem6)
self.lineEdit_task = QtWidgets.QLineEdit(self.groupBox_5)
self.lineEdit_task.setMinimumSize(QtCore.QSize(0, 25))
self.lineEdit_task.setObjectName("lineEdit_task")
self.horizontalLayout_9.addWidget(self.lineEdit_task)
self.verticalLayout_5.addLayout(self.horizontalLayout_9)
self.verticalLayout_3.addWidget(self.groupBox_5)
self.groupBox_6 = QtWidgets.QGroupBox(self.GB_batchgroup)
self.groupBox_6.setTitle("")
self.groupBox_6.setObjectName("groupBox_6")
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_6)
self.verticalLayout_7.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_7.setSpacing(6)
self.verticalLayout_7.setObjectName("verticalLayout_7")
self.CB_batch_plates = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_plates.setObjectName("CB_batch_plates")
self.verticalLayout_7.addWidget(self.CB_batch_plates)
self.CB_batch_elements = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_elements.setObjectName("CB_batch_elements")
self.verticalLayout_7.addWidget(self.CB_batch_elements)
self.CB_batch_mattes = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_mattes.setObjectName("CB_batch_mattes")
self.verticalLayout_7.addWidget(self.CB_batch_mattes)
self.CB_batch_cg = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_cg.setObjectName("CB_batch_cg")
self.verticalLayout_7.addWidget(self.CB_batch_cg)
self.CB_batch_prerender = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_prerender.setObjectName("CB_batch_prerender")
self.verticalLayout_7.addWidget(self.CB_batch_prerender)
self.CB_batch_result = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_result.setObjectName("CB_batch_result")
self.verticalLayout_7.addWidget(self.CB_batch_result)
self.CB_batch_shelf = QtWidgets.QCheckBox(self.groupBox_6)
self.CB_batch_shelf.setObjectName("CB_batch_shelf")
self.verticalLayout_7.addWidget(self.CB_batch_shelf)
self.verticalLayout_3.addWidget(self.groupBox_6)
self.HLayout_main.addWidget(self.GB_batchgroup)
self.verticalLayout.addLayout(self.HLayout_main)
self.GB_writefile = QtWidgets.QGroupBox(Widget)
self.GB_writefile.setTitle("")
self.GB_writefile.setObjectName("GB_writefile")
self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.GB_writefile)
self.verticalLayout_9.setContentsMargins(11, 11, 11, 11)
self.verticalLayout_9.setSpacing(6)
self.verticalLayout_9.setObjectName("verticalLayout_9")
# trying
self.horizontalLayout_20 = QtWidgets.QHBoxLayout()
self.horizontalLayout_20.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_20.setSpacing(6)
self.horizontalLayout_20.setObjectName("horizontalLayout_20")
#
self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
self.horizontalLayout_14.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_14.setSpacing(6)
self.horizontalLayout_14.setObjectName("horizontalLayout_14")
# trying
self.CB_batchgroup = QtWidgets.QCheckBox(self.GB_writefile)
self.CB_batchgroup.setObjectName("CB_batchgroup")
self.horizontalLayout_20.addWidget(self.CB_batchgroup)
#
self.label_openclip_mainpath = QtWidgets.QLabel(self.GB_writefile)
self.label_openclip_mainpath.setObjectName("label_openclip_mainpath")
self.horizontalLayout_14.addWidget(self.label_openclip_mainpath)
# WRITE FILE LINE EDIT #
self.lineEdit_openclip_mainpath = QtWidgets.QLineEdit(self.GB_writefile)
self.lineEdit_openclip_mainpath.setMinimumSize(QtCore.QSize(0, 25))
self.lineEdit_openclip_mainpath.setObjectName("lineEdit_openclip_mainpath")
self.horizontalLayout_14.addWidget(self.lineEdit_openclip_mainpath)
self.btn_openclip_path = QtWidgets.QPushButton(self.GB_writefile)
self.btn_openclip_path.setMinimumSize(QtCore.QSize(0, 25))
self.btn_openclip_path.setObjectName("btn_openclip_path")
# NEED TO SAVE IN A JSON FILE - When the 'Create' button is pressed
self.horizontalLayout_14.addWidget(self.btn_openclip_path)
# trying
self.verticalLayout_9.addLayout(self.horizontalLayout_20)
#
self.verticalLayout_9.addLayout(self.horizontalLayout_14)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_2.setSpacing(6)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_file_type = QtWidgets.QLabel(self.GB_writefile)
self.label_file_type.setObjectName("label_file_type")
self.horizontalLayout_2.addWidget(self.label_file_type)
spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem7)
self.CB_file_type = QtWidgets.QComboBox(self.GB_writefile)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.CB_file_type.sizePolicy().hasHeightForWidth())
self.CB_file_type.setSizePolicy(sizePolicy)
self.CB_file_type.setMinimumSize(QtCore.QSize(0, 25))
self.CB_file_type.setObjectName("CB_file_type")
self.horizontalLayout_2.addWidget(self.CB_file_type)
self.verticalLayout_9.addLayout(self.horizontalLayout_2)
spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_9.addItem(spacerItem8)
self.verticalLayout.addWidget(self.GB_writefile)
self.verticalLayout_8.addLayout(self.verticalLayout)
spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_8.addItem(spacerItem9)
self.BB_apply_cancel = QtWidgets.QDialogButtonBox(Widget)
self.BB_apply_cancel.setStandardButtons(QtWidgets.QDialogButtonBox.Close | QtWidgets.QDialogButtonBox.Ok)
self.BB_apply_cancel.setCenterButtons(True)
self.BB_apply_cancel.setObjectName("BB_apply_cancel")
self.verticalLayout_8.addWidget(self.BB_apply_cancel)
self.retranslateUi(Widget)
QtCore.QMetaObject.connectSlotsByName(Widget)

def retranslateUi(self, Widget):
_translate = QtCore.QCoreApplication.translate
Widget.setWindowTitle(_translate("Widget", "Breakout - include clips"))
self.GB_folders.setTitle(_translate("Widget", "Folders"))
self.label_basename.setText(_translate("Widget", "Seq Name"))
self.label_shot_amount.setText(_translate("Widget", "Amount of shots"))
self.label_start_at.setText(_translate("Widget", "Start at"))
self.label_increments.setText(_translate("Widget", "Increments"))
self.CB_fldr_plates.setText(_translate("Widget", "Plates"))
self.CB_fldr_refs.setText(_translate("Widget", "Refs"))
self.CB_fldr_elements.setText(_translate("Widget", "Elements"))
self.CB_fldr_mattes.setText(_translate("Widget", "Mattes"))
self.CB_fldr_batch.setText(_translate("Widget", "Batch"))
self.CB_fldr_result.setText(_translate("Widget", "Result"))
self.GB_batchgroup.setTitle(_translate("Widget", "Batch Group"))
self.label_startframe.setText(_translate("Widget", "Start Frame"))
self.label_duration.setText(_translate("Widget", "Duration"))
self.label_task.setText(_translate("Widget", "Task"))
self.CB_batch_plates.setText(_translate("Widget", "Plates"))
self.CB_batch_elements.setText(_translate("Widget", "Elements"))
self.CB_batch_mattes.setText(_translate("Widget", "Mattes"))
self.CB_batch_cg.setText(_translate("Widget", "CG"))
self.CB_batch_prerender.setText(_translate("Widget", "Pre_Renders"))
self.CB_batch_result.setText(_translate("Widget", "Result"))
self.CB_batch_shelf.setText(_translate("Widget", "Shelf reel"))
self.label_openclip_mainpath.setText(_translate("Widget", "Openclips Path"))
self.btn_openclip_path.setText(_translate("Widget", "Browse"))
self.label_file_type.setText(_translate("Widget", "File type"))
# trying
self.CB_batchgroup.setText(_translate("Widget", "Create Batchgroups"))
#

self.show()

# --------------------
#
# MainClass
#
# --------------------

class MainClass(QtWidgets.QWidget, Ui_Widget):
'''

Set up the user interface from widget.ui (created in Qt designer) converted to widget_UI.py
terminal command line to convert: pyuic5 widget.ui -o widget_UI.py
Then change 'from PyQt5 import ...' to 'from PySide2 import ...' in the widget_UI.py file.
'''

def __init__(self, selection):
super(MainClass, self).__init__()
self.selection = selection

self.setupUi(self)

global flame

# ---------- VARIABLES ----------
self.shots_folders_list = []
self.shots_subfolders_list = []
self.schematic_reels_list = []
self.shelf_reels_list = []
self.shot_name_only = ''
self.shot_name_plus = ''
self.seq_name = ''
self.lib_name = ''
self.vfx_lib = ''
self.list_of_filetypes = ['DPX 10bits', 'OpenEXR 16fp']

# ---------- PRE CONFIGURATION - and place holders ----------
# comment out or un-comment for default 'preset' configuration
self.lineEdit_sequence_name.setText("ABC")
self.SB_shots_amount.setValue(1)
self.SB_start_at.setValue(10)
self.SB_increments.setValue(10)
self.CB_fldr_plates.setChecked(True)
# self.CB_fldr_refs.setChecked(True)
# self.CB_fldr_elements.setChecked(True)
# self.CB_fldr_mattes.setChecked(True)
# self.CB_fldr_batch.setChecked(True)
# self.CB_fldr_result.setChecked(True)
self.SB_start_frame.setValue(1)
self.SB_duration.setValue(100)
self.lineEdit_task.setText("taskname")
self.CB_batch_plates.setChecked(True)
# self.CB_batch_elements.setChecked(True)
# self.CB_batch_mattes.setChecked(True)
# self.CB_batch_cg.setChecked(True)
self.CB_batch_prerender.setChecked(True)
self.CB_batch_result.setChecked(True)
self.CB_batch_shelf.setChecked(True)
self.CB_batchgroup.setChecked(True)
# Read from a json config file - When the window is created, set the open clip root path from it.
with open(openclip_path_json, 'r') as my_file:
for i in my_file.readlines():
print "&gt;&gt;&gt;&gt; read from json file: ", i
self.lineEdit_openclip_mainpath.setText(i.replace('"', ''))
my_file.close()

# ---------- Connections and other STUFF ----------

self.BB_apply_cancel.button(QtWidgets.QDialogButtonBox.Ok).setText("Create")
self.BB_apply_cancel.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.click_create)
self.BB_apply_cancel.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.close_window)
self.BB_apply_cancel.button(QtWidgets.QDialogButtonBox.Ok).setShortcut("Return")
self.connect(self.btn_openclip_path, QtCore.SIGNAL('clicked()'), self.openclip_chose_path)
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.CB_file_type.addItems(self.list_of_filetypes)

# --------------------
# MAIN LOGIC
# --------------------

def click_create(self):
print "-" * 60
self.get_folders_infos()
self.create_subfolders_list()
self.create_vfx_lib()
self.create_schematic_reels_list()
self.create_shelf_reels_list()
self.create_batchGroup()
self.create_server_sequence_folders()
self.close_window()

# NEED TO SAVE TO THE JSON FILE - When the 'Create' button is pressed
with open(openclip_path_json, 'w') as openclip_path_to_json:
openclip_path_to_json.write(json.dumps(self.lineEdit_openclip_mainpath.text()))

# --------------------
# FOLDERS &amp; SUBFOLDERS
# --------------------

def get_folders_infos(self):
shots_amount = int(self.SB_shots_amount.value())
start_at = int(self.SB_start_at.value())
increments = int(self.SB_increments.value())
self.seq_name = self.lineEdit_sequence_name.text()
task_name = str(self.lineEdit_task.text())
# stop_before = shots_amount * increments + start_at
stop_before = start_at + (increments * shots_amount)

for x in range(start_at, stop_before, increments):
folder_name = (self.seq_name + '_' + '%04d' % x)
print "&gt;&gt;&gt;&gt; folder to create: ", folder_name
self.shots_folders_list.append(folder_name)

print "-" * 30

def create_subfolders_list(self):
if self.CB_fldr_plates.isChecked():
print "&gt;&gt;&gt;&gt; CB_fldr_plates ... is Checked ... adding to list"
self.shots_subfolders_list.append("Plates")

if self.CB_fldr_refs.isChecked():
print "&gt;&gt;&gt;&gt; CB_fldr_refs ... is Checked ... adding to list"
self.shots_subfolders_list.append("Refs")

if self.CB_fldr_elements.isChecked():
print "&gt;&gt;&gt;&gt; CB_fldr_elements ... is Checked ... adding to list"
self.shots_subfolders_list.append("Elements")

if self.CB_fldr_mattes.isChecked():
print "&gt;&gt;&gt;&gt; CB_fldr_mattes ... is Checked ... adding to list"
self.shots_subfolders_list.append("Mattes")

if self.CB_fldr_batch.isChecked():
print "&gt;&gt;&gt;&gt; CB_fldr_batch ... is Checked ... adding to list"
self.shots_subfolders_list.append("Batch")

if self.CB_fldr_result.isChecked():
print "&gt;&gt;&gt;&gt; CB_fldr_result ... is Checked ... adding to list"
self.shots_subfolders_list.append("Result")

print "-" * 30

# --------------------
# FLAME STUFF - create VFX lib and folders
# Then save each clip in its corresponding 'Plates' folder.
# --------------------

def create_vfx_lib(self):
import flame

print "&gt;&gt;&gt;&gt; shots_folders_list: ", self.shots_folders_list
print "&gt;&gt;&gt;&gt; shots_subfolders_list: ", self.shots_subfolders_list

desk = flame.project.current_project.current_workspace.desktop
ws = flame.project.current_project.current_workspace

# Set the VFX library name:
self.lib_name = "VFX_" + self.seq_name
# Create the library ans store it to a variable (self.vfx_lib)
self.vfx_lib = ws.create_library(str(self.lib_name))

# Create folders and subfolders.
for fldr in self.shots_folders_list:
shot_folder = self.vfx_lib.create_folder(str(fldr))
for subfldr in self.shots_subfolders_list:
sub_folder = shot_folder.create_folder(subfldr)

# SAVE CLIPS IN FOLDERS
for clip in self.selection:
print "clip.name: ", str(clip.name).replace("'", "")
clip_name = '_'.join(str(clip.name).replace("'", "").split('_')[0:2])
print "clip_name: ", clip_name
if fldr == '_'.join(str(clip_name).split('_')[0:2]):
if str(subfldr) == "Plates":
desk.destination = sub_folder
clip.save()

# --------------------
# FLAME STUFF - create batchgroups with writeFile nodes (openclip)
# --------------------

def create_schematic_reels_list(self):
print "-" * 30
if self.CB_batch_plates.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_plates ... is Checked ... adding to list"
self.schematic_reels_list.append("Plates")

if self.CB_batch_elements.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_elements ... is Checked ... adding to list"
self.schematic_reels_list.append("Elements")

if self.CB_batch_mattes.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_mattes ... is Checked ... adding to list"
self.schematic_reels_list.append("Mattes")

if self.CB_batch_cg.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_cg ... is Checked ... adding to list"
self.schematic_reels_list.append("CG")

if self.CB_batch_prerender.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_prerender ... is Checked ... adding to list"
self.schematic_reels_list.append("Pre_Renders")

if self.CB_batch_result.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_result ... is Checked ... adding to list"
self.schematic_reels_list.append("Result")

def create_shelf_reels_list(self):
print "-" * 30
if self.CB_batch_shelf.isChecked():
print "&gt;&gt;&gt;&gt; CB_batch_shelf ... is Checked ... adding to list"
self.shelf_reels_list.append("batch_renders")

def openclip_chose_path(self):
self.lineEdit_openclip_mainpath.setText(QtWidgets.QFileDialog.getExistingDirectory(
self, "Browser", "/var/temp", QtWidgets.QFileDialog.ShowDirsOnly))

def create_batchGroup(self):
import flame
desk = flame.project.current_project.current_workspace.desktop
# my_libs = flame.project.current_project.current_workspace.libraries

print "-" * 60
batch_start_frame = int(self.SB_start_frame.value())
batch_duration = int(self.SB_duration.value())
task_name = str(self.lineEdit_task.text())

for shotname in self.shots_folders_list:
print "&gt;&gt;&gt;&gt; shotname: ", shotname
self.shot_name_only = shotname
self.shot_name_plus = shotname + "_" + task_name

batchGroup = flame.batch.create_batch_group(str(self.shot_name_plus), start_frame=batch_start_frame,
duration=batch_duration, reels=self.schematic_reels_list,
shelf_reels=self.shelf_reels_list)

self.create_write_file()

subfldr_list = []
for fldr in self.vfx_lib.folders:
if fldr.name == str(shotname):
for subfldr in fldr.folders:
subfldr_list.append(subfldr.name)
if subfldr.name == 'Batch':
desk.destination = subfldr
print "subfldr_list: ", subfldr_list
if str('Batch') not in subfldr_list:
desk.destination = fldr

batchGroup.save()
flame.delete(batchGroup)

desk.destination = self.vfx_lib

def create_write_file(self):
import flame
write_file = flame.batch.create_node("Write File")
write_file.name = "&lt;batch name&gt;"
# write_file.shot_name = "ABC_0000"
write_file.shot_name = str(self.shot_name_only)
clip_path = self.lineEdit_openclip_mainpath.text() + '/'
self.clip_result_path = clip_path + self.lineEdit_sequence_name.text()
write_file.media_path = str(self.clip_result_path)
write_file.media_path_pattern = "&lt;shot name&gt;/renders/&lt;name&gt;_&lt;version name&gt;/&lt;name&gt;_&lt;version name&gt;"
write_file.create_clip_path = "&lt;shot name&gt;/&lt;name&gt;"
write_file.include_setup = True
write_file.include_setup_path = "&lt;shot name&gt;/setups/&lt;name&gt;_&lt;version name&gt;"
write_file.version_mode = "Follow Iteration"
write_file.version_name = "&lt;version&gt;"
write_file.version_padding = 3
write_file.frame_padding = 4

if self.CB_file_type.currentText() == 'DPX 10bits':
write_file.file_type = "Dpx"
write_file.bit_depth = 10

if self.CB_file_type.currentText() == 'OpenEXR 16fp':
write_file.file_type = "OpenEXR"
write_file.bit_depth = 16

# PICKUP HERE ##########################################
def create_server_sequence_folders(self):
print "&gt;&gt;&gt;&gt;&gt;&gt; self.clip_result_path,: ", self.clip_result_path
seq_folder = os.path.dirname(self.clip_result_path) + "/" + self.seq_name
print "seq_folder: ", seq_folder
if not os.path.exists(seq_folder):
print "creating sequence folder_name"
os.makedirs(seq_folder)

# ################################# Close Window
def close_window(self):
print "&gt;&gt;&gt;&gt; close_window"
self.close()

# --------------------
# FLAME MENU ENTRY
# --------------------

def start_process(selection):
import flame
import os
import json

# create a dummy string (does it need to be a list?) to create and feed a .json config file if there was none.
# the following path should be changed to use a pattern including the project name (auto detected)
default_openclip_path = "/var/temp/OPENCLIP"

if not os.path.isfile(openclip_path_json):
print "-" * 30 + "FILE NOT FOUND, CREATING FILE" + "-" * 30

with open(openclip_path_json, "w+") as myfilepy:
myfilepy.write(json.dumps(default_openclip_path))
myfilepy.close()

form = MainClass(selection)
form.show()
return form

def get_media_panel_custom_ui_actions():
"""
Return custom UI actions to execute on media panel objects.
"""

return [
{
"name": "Breakout",
"actions": [
{
"name": "Create VFX Lib and Save Plates",
# "execute": start_process,
"execute": start_process,
}
]
}
]

# end of script
<pre>

12 Replies to “Hook: Create Shot Folders and batchgroups + save plates”

  1. Salut Steph,

    Le lien pour télécharger le .py de Hook: Create Shot Folders Structure n’est pas dispo sur la page. Est-ce normal ?

    As-tu envisager de faire un script d’install à la façon de PyFlame, afin que tes scripts se retrouvent bien ranger dans un menu ?
    Y-t-il moyen que tu collabores avec PyFlame pour qu’il y ajoute tes scripts ?

    Concernant ton script Create Shot Folders, j’aimerai pouvoir l’utiliser afin de ranger dans des Desktop tous les “Create Batch Group” créés à partir du bouton dans le module “Conform”.

    Je m’explique :
    Dans notre workflow, nous faisons nos confos et créons à partir du module “Confort” tous les Batch automatiquement avec la fonction “Create Batch Group”, dans l’idéal, j’aimerai qu’au lieu de créer les Batch Group seulement, ces derniers soient ranger chacun dans un desktop différent, car dans notre façon de travailler, chaque effet à son Desktop. Crois-tu que cela soit possible directement dans le module “Confort” sans passer par “Create Batch Group”, ou alors avec une fonction qui permette de ranger automatiquement chaque Batch Group dans une arborescence préalablement définie par un script?

    J’espère que ça roule pour toi, Gros Bisous et merci

    Sebquismoke

    1. Salut Seb,

      Merci pour l’info, c’est corrigé, lien vers le script et code aussi dans la page.
      Faute de temps et pour quelques autres raisons je ne pense pas faire un script d’install. Je vais réfléchir a poster quelque chose qui expliquerait comment modifier des scripts pour qu’ils apparaissent de la manière convenant a chacun.
      Pour ton workflow, je ne suis pas sur que le shot creator soit une bonne base, meme si tu peux utiliser des parties pour tel ou tel truc.
      Le problème depuis une timeline est qu’il n’est pas encore possible de sauver un segment vers quelque part dans le media panel (comme un desktop). Je n’ai pas encore regardé s’il était possible d’utiliser la fonction flame “Create Batch Group” avec python, et de hacker un peu, aucune idée 🙂
      Je vais y réfléchir un peu plus …

      Tout va bien ici, pareil pour toi !
      La bises amigo !
      Stef

      1. Salut Stef,
        Merci pour m’avoir répondu rapidement et pour la modif.
        J’ai touché deux mots à Michael Vaglienty (de PyFlame) pour cette histoire d’installation de scripts extérieurs via son script “PyFlame installer” et apparemment il y réfléchi de son côté.
        Pour ce qui est de ma demande sur ton script Create Shot Folders Structure, il n’est pas question de prendre un segment d’une timeline, mais plutôt de prendre les batch créés à partir de la partie “Conform” à l’aide de la touche “Create Batch Group” qui se retrouvent dans la library et de les déplacer ou copier chacun dans un Desktop différent.
        Merci Stef, La Grosse BiZ
        Seb

    1. ca devrait marcher maintenant.
      Ah ok je comprends. Tu peux piocher dans la partie batchgroups mais il n’y a pas grand chose dans ce script qui concerne ce que tu décris.
      Je n’ai pas trop de temps en ce moment, mais si tu veux m’envoyer un screengrab de ton genre de library je peux y réfléchir.
      Sinon pioche ce que tu peux et je pourrais peut-etre d’aider pour la suite.
      La bise

    1. Yo!
      j’ai bricolé un peu et ca a l’air de marcher. Testé sur mac Flame 2020.1

      # Stefan Gaillot
      # xenjee@gmail.com
      # 2019/09/21
      # sg_batchgroups_to_lib.py
      
      # Idea and help request from Sebquismoke:
      # Starting with Batchgroups previously created with the "create batchgroup' function in the Timeline.
      # Assuming all Batchgroups are saved in a single Library, select the library and run the script:
      # Create a new Library for destination
      # Create a Desktop per Batchgroup and save each Desktop in the newly created Library.
      
      
      def scope_library(selection):
          import flame
          for item in selection:
              if isinstance(item, (flame.PyLibrary)):
                  return True
          return False
      
      
      def create_shots_lib():
          import flame
          ws = flame.project.current_project.current_workspace
          desk = flame.project.current_project.current_workspace.desktop
          shots_lib = ws.create_library("VFX_SHOTS")
          desk.destination = shots_lib
          return shots_lib
      
      
      def organize_batchgroups(Selection):
          print ""
          print "execute script: ", "sg_batchgroups_to_lib.py"
      
          import flame
          selected_lib = Selection[0]
          print selected_lib.name
          print type(selected_lib)
      
          desk = flame.project.current_project.current_workspace.desktop
          for batchgroup in selected_lib.batch_groups:
              # print "batchgroup.name: ", batchgroup.name
              batchgroup.open_as_batch_group()
              desk.name = str(batchgroup.name)
              for bg in desk.batch_groups:
                  if str(bg.name) != str(batchgroup.name):
                      # print "not shot name: ", bg.name
                      flame.delete(bg)
              desk.save()
      
      
      def clear_current_desk():
          import flame
          desk = flame.project.current_project.current_workspace.desktop
          for batchgroup in desk.batch_groups:
              flame.delete(batchgroup)
          desk.name = "New_Desktop"
          desk.batch_groups[0].name = "New_Batch"
      
      
      def order_of_operations(Selection):
          create_shots_lib()
          organize_batchgroups(Selection)
          clear_current_desk()
      
      
      def get_media_panel_custom_ui_actions():
          return [
              {
                  "name": "SEB",
                  "actions": [
                      {
                          "name": "Organize Batchgroups",
                          "isVisible": scope_library,
                          "execute": order_of_operations,
                      }
                  ]
              }
          ]
      
      
      

Leave a Reply