class AppServerSvc(win32serviceutil.ServiceFramework): _svc_name_ = "timelog" _svc_display_name_ = "shotgun time log" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) SetConsoleCtrlHandler(lambda x: True, True) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.count = 0 self.estinmins = 0 self.isAlive = True self.envv = '' self.prlist = [] def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) self.run = False def SvcDoRun(self): servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, '')) self.sg = Shotgun('https://xxxxxxxxxxxxxxxx.shotgunstudio.com', 'timelogservice', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') self.main() def updateProject(self, projectid): servicemanager.LogWarningMsg(unicode(projectid)) filters = [["project.Project.id", "is", projectid]] fields = ["time_logs_sum", "est_in_mins"] for eventTimeLog in self.sg.find('Task', filters, fields): self.count = self.count + eventTimeLog['time_logs_sum'] if eventTimeLog['est_in_mins'] is not None: self.estinmins = self.estinmins + eventTimeLog['est_in_mins'] data = {'sg_artisttimelog': self.count / 600} asset = self.sg.update("Project", projectid, data) data = {'sg_total_bid': self.estinmins / 600} asset = self.sg.update("Project", projectid, data) def main(self): while self.isAlive: filters = [["sg_status", "is", "active"]] fields = ['id'] for f in self.sg.find('Project', filters, fields): self.prlist.append(f['id']) for prid in self.prlist: self.updateProject(prid) self.count = 0 self.estinmins = 0 if win32event.WaitForSingleObject( self.hWaitStop, 3000) == win32event.WAIT_OBJECT_0: break
class AppServerSvc(win32serviceutil.ServiceFramework): _svc_name_ = "timelog" _svc_display_name_ = "shotgun time log" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) SetConsoleCtrlHandler(lambda x: True, True) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.count = 0 self.estinmins = 0 self.isAlive = True self.envv = "" self.prlist = [] def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) self.run = False def SvcDoRun(self): servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, "") ) self.sg = Shotgun( "https://xxxxxxxxxxxxxxxx.shotgunstudio.com", "timelogservice", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) self.main() def updateProject(self, projectid): servicemanager.LogWarningMsg(unicode(projectid)) filters = [["project.Project.id", "is", projectid]] fields = ["time_logs_sum", "est_in_mins"] for eventTimeLog in self.sg.find("Task", filters, fields): self.count = self.count + eventTimeLog["time_logs_sum"] if eventTimeLog["est_in_mins"] is not None: self.estinmins = self.estinmins + eventTimeLog["est_in_mins"] data = {"sg_artisttimelog": self.count / 600} asset = self.sg.update("Project", projectid, data) data = {"sg_total_bid": self.estinmins / 600} asset = self.sg.update("Project", projectid, data) def main(self): while self.isAlive: filters = [["sg_status", "is", "active"]] fields = ["id"] for f in self.sg.find("Project", filters, fields): self.prlist.append(f["id"]) for prid in self.prlist: self.updateProject(prid) self.count = 0 self.estinmins = 0 if win32event.WaitForSingleObject(self.hWaitStop, 3000) == win32event.WAIT_OBJECT_0: break
def submitShotgunTicket(output, jobList): currentuser = str(User.currentUser().name()) title = "AtS - %s"%currentuser desc = [] desc.append(output+"\n") desc.append("JOBLIST:") for job in jobList: desc.append(str(job.key())+" - "+str(job.name())) sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) id = sg.find("HumanUser",[['login','is',currentuser]],['id']) userid = id[0] ticket_data = { 'created_by': {'type':'HumanUser','id':userid['id']}, 'title': title, 'description': "\n".join(desc), 'addressings_to':[{'type':'Group', 'id':19}, {'type':'HumanUser','id':userid['id']}], 'project': {'type':'Project', 'id':178}, 'sg_service': {'type':'CustomNonProjectEntity01', 'id':27}, } sg_ticket = sg.create('Ticket', ticket_data, ['id']) new_ticket_url = SERVER_PATH + "/detail/Ticket/" + str(sg_ticket['id']) QDesktopServices.openUrl( QUrl(new_ticket_url) )
def addSrc(): repo = '/mnt/karramba' shotFoldList = ['anim', 'comp', 'data', 'fx', 'light', 'out', 'src', 'tmp'] seqFoldList = ['anim', 'comp', 'data', 'fx', 'light', 'out', 'shots'] dataFoldList = ['cache', 'geo', 'render', 'shadowmap', 'sim', 'track', 'photonmap'] outFoldList = ['dailies', 'hires'] site = 'https://chimneypot.shotgunstudio.com' scriptName = 'addSrc' scriptKey = 'd7dac4e2c55faf486875dfb944ffc9d8e49a0c44' sg = Shotgun(site, scriptName, scriptKey) projList = sg.find('Project', [], ['name']) for i in projList: print 'id:' + str(i['id']) + ' ' + i['name'] prId = int(raw_input('Print project id:')) proj = sg.find_one('Project', [['id','is',prId]], ['name']) if not [x for x in os.listdir(repo) if x==proj['name']]: print "Project doesn't exist in repository" return s = os.sep prPath = repo + s + proj['name'] seqPath = prPath + s + 'film' + s + 'sequences' seqList = os.listdir(prPath + s + 'src') for i in seqList: sequenceFold = prPath + s + 'film' + s + 'sequences' os.makedirs(sequenceFold + s + i) for j in seqFoldList: os.makedirs(sequenceFold + s + i + s + j) for d in dataFoldList: os.makedirs(sequenceFold + s + i + s + 'data' + s + d) for o in outFoldList: os.makedirs(sequenceFold + s + i + s + 'out' + s + o) shList = os.listdir(prPath + s + 'src' + s + i) for sh in shList: shFold = sequenceFold + s + i + s + 'shots' os.makedirs(shFold + s + sh) for f in shotFoldList: os.makedirs(shFold + s + sh + s + f) for ds in dataFoldList: os.makedirs(shFold + s + sh + s + 'data' + s + ds) for ot in outFoldList: os.makedirs(shFold + s + sh + s + 'out' + s + ot) shutil.move(prPath + s + 'src' + s + i + s + sh, shFold + s + sh + s + 'src') os.system('ln -sf ' + shFold + s + sh + s + 'src ' + prPath + s + 'src' + s + i + s + sh)
def addSrc(): repo = '/mnt/karramba' shotFoldList = ['anim', 'comp', 'data', 'fx', 'light', 'out', 'src', 'tmp'] seqFoldList = ['anim', 'comp', 'data', 'fx', 'light', 'out', 'shots'] dataFoldList = [ 'cache', 'geo', 'render', 'shadowmap', 'sim', 'track', 'photonmap' ] outFoldList = ['dailies', 'hires'] site = 'https://chimneypot.shotgunstudio.com' scriptName = 'addSrc' scriptKey = 'd7dac4e2c55faf486875dfb944ffc9d8e49a0c44' sg = Shotgun(site, scriptName, scriptKey) projList = sg.find('Project', [], ['name']) for i in projList: print 'id:' + str(i['id']) + ' ' + i['name'] prId = int(raw_input('Print project id:')) proj = sg.find_one('Project', [['id', 'is', prId]], ['name']) if not [x for x in os.listdir(repo) if x == proj['name']]: print "Project doesn't exist in repository" return s = os.sep prPath = repo + s + proj['name'] seqPath = prPath + s + 'film' + s + 'sequences' seqList = os.listdir(prPath + s + 'src') for i in seqList: sequenceFold = prPath + s + 'film' + s + 'sequences' os.makedirs(sequenceFold + s + i) for j in seqFoldList: os.makedirs(sequenceFold + s + i + s + j) for d in dataFoldList: os.makedirs(sequenceFold + s + i + s + 'data' + s + d) for o in outFoldList: os.makedirs(sequenceFold + s + i + s + 'out' + s + o) shList = os.listdir(prPath + s + 'src' + s + i) for sh in shList: shFold = sequenceFold + s + i + s + 'shots' os.makedirs(shFold + s + sh) for f in shotFoldList: os.makedirs(shFold + s + sh + s + f) for ds in dataFoldList: os.makedirs(shFold + s + sh + s + 'data' + s + ds) for ot in outFoldList: os.makedirs(shFold + s + sh + s + 'out' + s + ot) shutil.move(prPath + s + 'src' + s + i + s + sh, shFold + s + sh + s + 'src') os.system('ln -sf ' + shFold + s + sh + s + 'src ' + prPath + s + 'src' + s + i + s + sh)
def getentitiesfromshotgun(name): sg = Shotgun(const.SHOTGUN_URL, const.API_NAME, const.API_KEY) sgname = name if name in const.ENTITY_MAP: sgname = const.ENTITY_MAP[name] fields = sg.schema_field_read(sgname) rawents = sg.find(sgname, [['project', 'is', { 'type': 'Project', 'id': 70 }]], list(fields.keys())) pp(rawents) clean = [] for ent in rawents: if 'image' in ent and ent['image']: directory = "data/filestorage/%s/%s/%s" % (name, ent['id'], "image") if not os.path.exists(os.path.dirname(directory)): os.makedirs(os.path.dirname(directory)) sg.download_attachment({'url': ent['image']}, directory) ent['image'] = directory for field in fields: if fields[field]['data_type']['value'] == 'url' and ent[field]: pp(ent) directory = "data/filestorage/%s/%s/%s" % (name, ent['id'], ent[field]['name']) if not isinstance(ent['id'], int): directory = "data/filestorage/%s/%s/%s" % ( name, ent['id']['value'], ent[field]['name']) if not os.path.exists(os.path.dirname(directory)): os.makedirs(os.path.dirname(directory)) sg.download_attachment(ent[field], directory) ent[field] = directory ent[field] = { "value": ent[field], "type": fields[field]['data_type']['value'] } ent.pop("created_at", None) ent.pop("created_by", None) ent.pop("updated_at", None) ent.pop("updated_by", None) ent.pop("filmstrip_image", None) ent.pop("cached_display_name", None) dic = {} dic['type'] = {'type': 'text', 'value': ent.pop('type')} for f in ent: dic[fields[f]['name']['value']] = ent[f] clean.append(dic) return clean
def _get_projects_list(): sg = Shotgun('http://yoursite.com', 'your_api', '123456') filters = [['sg_status', 'is', 'Active'], ['tank_name', 'is_not', '']] fields = ['name'] order = [{'field_name': 'name', 'direction': 'asc'}] projectsDic = sg.find('Project', filters, fields, order) newProjectsDic = [] for project in projectsDic: newProjectsDic.append(project['name'].replace(' ', '')) return newProjectsDic
class MyWidgetHolder(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) notificationList = [] # sender, receiver, date, message, noteDict ) notificationList.append( notification("Cyrilc", "john", datetime.datetime.now(), "Wait for approval ! rhooooooo lr lr bon y va oui ou non il est l'heure d'ylller j'ai faim. et de toute facon il est l'heure", "pas") ) notificationList.append( notification("Donat", "john", datetime.datetime.now(), "Peu continuer !", "pas") ) notificationList.append( notification("MikeB", "john", datetime.datetime.now(), "Oui c'est sympas", "pas") ) notificationList.append( notification("Aurelien", "john", datetime.datetime.now(), "Launch Time", "pas") ) notificationList.append( notification("Thomas", "john", datetime.datetime.now(), "Wait for appoval", "pas") ) notificationList.append( notification("James", "john", datetime.datetime.now(), "Approved", "pas") ) notificationList.append( notification("Mike", "john", datetime.datetime.now(), "Aurevoir John !", "pas") ) notificationList.append( notification("Tristan", "john", datetime.datetime.now(), "Bonjour John !", "pas") ) notificationList.append( notification("Eric", "john", datetime.datetime.now(), "Bonjour John !", "pas") ) notificationList.append( notification("Francois", "john", datetime.datetime.now(), "Bonjour John !", "pas") ) path_to_shotgunApi = getPathToShotgunApi() sys.path.append(path_to_shotgunApi) from shotgun_api3 import Shotgun self.SERVER_PATH = "https://nozon.shotgunstudio.com" self.SCRIPT_NAME = 'noteManager' self.SCRIPT_KEY = '30b93ec002ce2e22ecd6fb31fdda6063797deed1d612b4f6ca39e8030104707c' self.sg = Shotgun(self.SERVER_PATH, self.SCRIPT_NAME, self.SCRIPT_KEY) sg_spawnedNotes = self.sg.find("CustomEntity04", [ ['sg_note','is_not', None] ] , ["project"] ) for a in sg_spawnedNotes : print a self.setMinimumWidth(1000) self.setMinimumHeight(50) self.noteBarW = NotificationBar(notificationList, ["jack","popeye","james","conan le barbare"]) button = QtGui.QPushButton("pafpaf") #button.clicked.connect(self.noteBarW.addNotification) lay = QtGui.QVBoxLayout() lay.addWidget(button) lay.addWidget(self.noteBarW) lay.addWidget(QtGui.QPushButton("pafpaf")) self.setLayout(lay) lay.setSpacing(0) lay.setContentsMargins(0,0,0,0) self.show()
def submitShotgunTicket(output, jobList): currentuser = str(User.currentUser().name()) title = "AtS - %s" % currentuser desc = [] desc.append(output + "\n") desc.append("JOBLIST:") for job in jobList: desc.append(str(job.key()) + " - " + str(job.name())) sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) id = sg.find("HumanUser", [['login', 'is', currentuser]], ['id']) userid = id[0] ticket_data = { 'created_by': { 'type': 'HumanUser', 'id': userid['id'] }, 'title': title, 'description': "\n".join(desc), 'addressings_to': [{ 'type': 'Group', 'id': 19 }, { 'type': 'HumanUser', 'id': userid['id'] }], 'project': { 'type': 'Project', 'id': 178 }, 'sg_service': { 'type': 'CustomNonProjectEntity01', 'id': 27 }, } sg_ticket = sg.create('Ticket', ticket_data, ['id']) new_ticket_url = SERVER_PATH + "/detail/Ticket/" + str(sg_ticket['id']) QDesktopServices.openUrl(QUrl(new_ticket_url))
def getAllProjects(): site = 'https://chimneypot.shotgunstudio.com' scriptName = 'AssetBrowser' scriptKey = 'c35ab5f5322d4b1e8b6488bb315c03e5f38881ea' sg = Shotgun(site, scriptName, scriptKey) fields = ['id','name','type'] projects= sg.find("Project",[],fields) if len(projects) < 1: print "couldn't find any projects" #exit(0) else: print "Found "+str(len(projects))+" projects" # pprint (projects) return projects
def getShotsBySeqId(seq_id): site = 'https://chimneypot.shotgunstudio.com' scriptName = 'AssetBrowser' scriptKey = 'c35ab5f5322d4b1e8b6488bb315c03e5f38881ea' sg = Shotgun(site, scriptName, scriptKey) fields = ['id', 'type', 'code'] filters = [['sg_sequence', 'is', {'type': 'Sequence', 'id': seq_id}]] shots = sg.find("Shot", filters, fields) if len(shots) < 1: print "couldn't find any shots" #exit(0) else: None return shots
def getShotsBySeqId(seq_id): site = 'https://chimneypot.shotgunstudio.com' scriptName = 'AssetBrowser' scriptKey = 'c35ab5f5322d4b1e8b6488bb315c03e5f38881ea' sg = Shotgun(site, scriptName, scriptKey) fields = ['id','type','code'] filters = [['sg_sequence','is',{'type':'Sequence','id':seq_id}]] shots= sg.find("Shot",filters,fields) if len(shots) < 1: print "couldn't find any shots" #exit(0) else: None return shots
def getAllProjects(): site = 'https://chimneypot.shotgunstudio.com' scriptName = 'AssetBrowser' scriptKey = 'c35ab5f5322d4b1e8b6488bb315c03e5f38881ea' sg = Shotgun(site, scriptName, scriptKey) fields = ['id', 'name', 'type'] projects = sg.find("Project", [], fields) if len(projects) < 1: print "couldn't find any projects" #exit(0) else: print "Found " + str(len(projects)) + " projects" # pprint (projects) return projects
def setupLightFiles(cb010 = True, cb020 = True, cb030 = True, cb040 = True, cb050 = True, cb060 = True, optimizeEnv = True, rippleLyr = True, bgHillLyr = True, directory = 'I:/bubblebathbay/episodes', episode = 152, shots = 1): ## Initialize Shotgun API base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'audioUploader' api_key = 'bbfc5a7f42364edd915656d7a48d436dc864ae7b48caeb69423a912b930bc76a' sgsrv = Shotgun(base_url = base_url , script_name = script_name, api_key = api_key, ensure_ascii = True, connect = True) ## Query data from Shotgun data = sgsrv.find('Shot', filters = [["code", "contains", 'ep%s_sh' % episode]], fields = ['code', 'sg_cut_in', 'sg_cut_out', 'sg_tod', 'sg_ocean_type']) if data: if episode: if shots: for each in data: if each['code'].split('_')[-1].strip('sh') in shots: try: cmds.refresh(suspend = True) get_data_from_shotgun(cb010 = cb010, cb020 = cb020, cb030 = cb030, cb040 = cb040, cb050 = cb050, cb060 = cb060, optimizeEnv = optimizeEnv, rippleLyr = rippleLyr, bgHillLyr = bgHillLyr, directory = directory, **each) except: pass finally: cmds.refresh(suspend = False)
class studioShotgun(object): def __init__(self, path, name, key, project): self.SERVER_PATH = path self.SCRIPT_NAME = name self.SCRIPT_KEY = key self.project_id = project self.sg = Shotgun(self.SERVER_PATH, self.SCRIPT_NAME, self.SCRIPT_KEY) #---------------------------------------------------------------------- ## set Project id by ID def setProjectId(self, newId): self.project_id = newId #---------------------------------------------------------------------- ## set Project id by ID def setProjectName(self, name): newId = 0 projects = self.sg.find('Project', [], ['name']) for project in projects: if project['name'] == name: newId = project['id'] self.project_id = newId #---------------------------------------------------------------------- ## find asset by name def findAssetByName(self, name): fields = ['id', 'code', 'sg_asset_type', 'tasks'] filters = [['project', 'is', {'type': 'Project', 'id': self.project_id}], ['code', 'is', name]] result = self.sg.find('Asset', filters, fields) return result #---------------------------------------------------------------------- ## find shot by name def findShotByName(self, episode, shot): fields = ['id', 'code', 'sg_asset_type', 'tasks', 'sg_sequence'] filters = [['project', 'is', {'type': 'Project', 'id': self.project_id}], ['code', 'is', shot]] result = self.sg.find('Shot', filters, fields) for x in result: name = x['sg_sequence']['name'].split('_')[0] if name == episode: return x return [] #---------------------------------------------------------------------- ## upload thumbnail to asset def uploadThumbnail(self, asset, thumbnail): upload = 0 asset = self.findAssetByName(asset) if asset: upload = self.sg.upload_thumbnail("Asset", asset[0]['id'], thumbnail) return upload #---------------------------------------------------------------------- ## create new asset def createAsset(self, asset, assetType, template, assetFile='', description=''): ## find asset asset = self.findAssetByName(asset) if not asset: ## create asset + task template filters = [['code', 'is', template]] template = self.sg.find_one('TaskTemplate', filters) data = {'project': {'type': 'Project', 'id': self.project_id}, 'code': asset, 'description': description, 'sg_asset_type': assetType, 'sg_url_perforce': assetFile, 'task_template': template} asset = self.sg.create('Asset', data) return asset #---------------------------------------------------------------------- ## update file path in asset def updateAssetFilePath(self, asset, filename): asset = self.findAssetByName(asset) data = {'sg_url_perforce': filename} asset = self.sg.update("Asset", asset[0]['id'], data) return asset #---------------------------------------------------------------------- ## create new version def createVersion(self, shotId, taskId, userId, filename, comment=''): curTime = datetime.now().strftime('%Y.%m.%d_%H.%M') fname = str(filename.split('/')[-1].split('.')[0]) + '_' + curTime data = {'project': {'type': 'Project', 'id': self.project_id}, 'code': fname, 'description': comment, 'sg_status_list': 'rev', 'entity': {'type': 'Shot', 'id': shotId}, 'sg_task': {'type': 'Task', 'id': taskId}, 'user': {'type': 'HumanUser', 'id': userId}} result = self.sg.create('Version', data) upload = self.sg.upload('Version', result['id'], filename, 'sg_uploaded_movie') return [result, upload] #---------------------------------------------------------------------- ## get user data from shotgum def getUserData(self, user): filters = [['login', 'is', user]] user = self.sg.find('HumanUser', filters) if user: return user[0] else: return [] #---------------------------------------------------------------------- ## get all user from project def getAllUsers(self): fields = ['id', 'login', 'name', 'projects', 'department'] filters = [['projects', 'is', {'type': 'Project', 'id': self.project_id}]] users = self.sg.find('HumanUser', filters, fields) return users
class dMFXsubmitterDialog(QDialog, Ui_dMFXsubmitter): def __init__(self, parent=None): # set up the UI and variable here - don't forget to call updateUI at end super(dMFXsubmitterDialog, self).__init__(parent) self.acceptDrops() self.setupUi(self) # generic call to setup the Ui provided by Qt self.password = '' self.version_file_path = '' self.user = '' self.user_id = '' self.user_name = '' self.user_initials = '' self.submit_movie = False self.movie_file_path = '' self.description = '' self.login_status = False self.allOK = True self.submit_call_track = True self.version_type = 'Shot' self.created_version_id = None self.sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) self.sgu = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) self.users_with_initals = INITIALS_LIST self.user_list = [] self.lineEdit_versionFile.dragEnterEvent = types.MethodType( dragEnterEvent, self.lineEdit_versionFile) self.lineEdit_versionFile.dropEvent = types.MethodType( dropEvent, self.lineEdit_versionFile) self.lineEdit_versionFile.setAcceptDrops(True) self.lineEdit_versionFile.setDragEnabled(True) self.lineEdit_forReview.dragEnterEvent = types.MethodType( dragEnterEvent, self.lineEdit_forReview) self.lineEdit_forReview.dropEvent = types.MethodType( dropEvent, self.lineEdit_forReview) self.lineEdit_forReview.setAcceptDrops(True) self.lineEdit_forReview.setDragEnabled(True) # start things happening... get the users from sg and populate them into the drop-down self.update_user_list() self.connect(self, SIGNAL('update'), self.updateUI) self.new_value = 'this is not a new value' #self.emit(SIGNAL("update")) self.updateUI() def update_user_list(self): filters = [ ['sg_status_list', 'is', 'act'], ] fields = ['name', 'login'] users = self.sg.find('HumanUser', filters, fields) user_list = [(user['name'], user['login'], user['id']) for user in users if user['name'] != 'Template User'] user_list.sort() self.user_list = user_list self.comboBox_artistSelect.addItem('Please Select...') self.user = '******' for user in user_list: self.comboBox_artistSelect.addItem(user[0]) self.updateUI() def reset_to_go_again(self): # todo set all fields to blank, not just update the values... self.version_file_path = '' self.submit_movie = False self.movie_file_path = '' self.description = '' self.allOK = True self.created_version_id = None self.plainTextEdit_description.setPlainText('') self.lineEdit_versionFile.setText('') self.lineEdit_forReview.setText('') self.updateUI() def updateUI(self): # make sure that the UI is updated to match input self.activateWindow() # window gets keyboard focus after redraw self.allOK = True self.description = str(self.plainTextEdit_description.toPlainText()) # check user and if it needs initials, activate the text box if self.user in self.users_with_initals: self.lineEdit_initials.setEnabled(True) else: self.lineEdit_initials.setEnabled(False) # check user to see if one has been selected... set login to default if it has and there is no login set if self.user == STARTING_USER_LIST_TEXT: self.pushButton_login.setEnabled(False) else: self.pushButton_login.setEnabled(True) if not self.login_status: self.pushButton_login.setDefault(True) # check to see if logged in - if not, disable everything below login if self.login_status: self.label_password.setText("** Logged In **") self.pushButton_login.setEnabled(False) self.comboBox_artistSelect.setEnabled(False) else: self.label_password.setText("Shotgun Password") self.pushButton_login.setEnabled(True) # check the submit checkbox and enable fields if set if self.checkBox_forReview.isChecked(): self.lineEdit_forReview.setEnabled(True) self.pushButton_getForReview.setEnabled(True) self.submit_movie = True # check for movie submit check-box if self.submit_movie: self.lineEdit_forReview.setEnabled(True) self.pushButton_getForReview.setEnabled(True) else: self.lineEdit_forReview.setEnabled(False) self.pushButton_getForReview.setEnabled(False) # check for a need for initals if self.user in INITIALS_LIST: self.label_initials.setText('Add Your Initials') self.lineEdit_initials.show() else: self.label_initials.setText('') self.lineEdit_initials.hide() self.user_initials = '' self.lineEdit_initials.setText('') # check to see if the version file is a movie and, if so and the movie line is empty, fill that in if self.version_file_path and os.path.splitext( str(self.version_file_path).lower() )[1] in MOVIE_FILE_EXTENSION_LIST and not self.movie_file_path: self.movie_file_path = str(self.version_file_path) self.lineEdit_forReview.setText(self.movie_file_path) # check for conditions that allow an update to happen conditions = True # start by assuming we can go and switch if we can't if self.user in INITIALS_LIST and not self.user_initials: conditions = False if conditions and not self.login_status: conditions = False if conditions and self.version_file_path and not os.path.exists( self.version_file_path): conditions = False if conditions and self.submit_movie: if self.movie_file_path and not os.path.exists( self.movie_file_path): conditions = False if not self.movie_file_path: conditions = False #enable the submit button if appropriate if conditions: self.pushButton_submit.setEnabled(True) self.pushButton_submit.setDefault(True) else: self.pushButton_submit.setEnabled(False) # self.pushButton_login @pyqtSignature("") def on_pushButton_login_clicked(self): result = self.sgu.authenticate_human_user( self.user_name, self.lineEdit_password.text()) if result: self.login_status = True else: # user tried to log in and failed - let them know QMessageBox.about( self, "Log In Error", "Unable to login to Shotgun using your user/pass combination, please try again" ) self.updateUI() # self.pushButton_getVersionFile @pyqtSignature("") def on_pushButton_getVersionFile_clicked(self): self.version_file_path = str( QFileDialog.getOpenFileName( self, "Select the file to submit as a Version")) if self.version_file_path: self.lineEdit_versionFile.setText(self.version_file_path) self.updateUI() # self.pushButton_getForReview @pyqtSignature("") def on_pushButton_getForReview_clicked(self): self.movie_file_path = str( QFileDialog.getOpenFileNameAndFilter( self, "Select a movie file to submit for screening", filter="Movies ( *.mp4 *.mov)") [0]) # the getopenfile returns a tuple of length 2 if self.movie_file_path: self.lineEdit_forReview.setText(self.movie_file_path) self.updateUI() # self.pushButton_quit @pyqtSignature("") def on_pushButton_quit_clicked(self): QApplication.quit() # self.checkBox_forReview @pyqtSignature("bool") def on_checkBox_forReview_clicked(self): #lcheckBox_forReview boolean toggle code here self.submit_movie = self.checkBox_forReview.isChecked() self.updateUI() # self.comboBox_artistSelect @pyqtSignature("QString") def on_comboBox_artistSelect_currentIndexChanged(self): if self.user: self.user = self.comboBox_artistSelect.currentText() self.user_name = [ user[1] for user in self.user_list if user[0] == self.user ][0] self.user_id = [ user[2] for user in self.user_list if user[0] == self.user ][0] self.updateUI() # self.comboBox_version_type @pyqtSignature("QString") def on_comboBox_version_type_currentIndexChanged(self): self.version_type = str(self.comboBox_version_type.currentText()) self.updateUI() # self.lineEdit_forReview @pyqtSignature("QString") def on_lineEdit_forReview_textEdited(self): self.movie_file_path = str(self.lineEdit_forReview.text()) self.emit(SIGNAL("update")) # self.lineEdit_initials @pyqtSignature("QString") def on_lineEdit_initials_textEdited(self): self.user_initials = str(self.lineEdit_initials.text()) self.updateUI() # self.lineEdit_versionFile @pyqtSignature("QString") def on_lineEdit_versionFile_textEdited(self): self.version_file_path = str(self.lineEdit_versionFile.text()) self.updateUI() # self.lineEdit_versionFile @pyqtSignature("QString") def on_lineEdit_versionFile_textChanged(self): self.version_file_path = str(self.lineEdit_versionFile.text()) self.updateUI() # self.plainTextEdit_description @pyqtSignature("") def on_plainTextEdit_description_textEdited(self): self.updateUI() # self.pushButton_submit @pyqtSignature("") def on_pushButton_submit_clicked(self): if not self.submit_call_track: self.submit_call_track = True return else: self.submit_call_track = False sgerrmsg = "There were no matching {0}s, make sure that you have selected the right kind of entity and try again" if not self.allOK: return try: self.created_version_id = update_shotgun( self.sg, self.version_file_path, self.description, self.user_id, self.version_type, self.user_initials, self) if not self.created_version_id: # sg did not find anything! Tell the user and let them try again or quit self.allOK = False sub_dialog = dMFXsubmitterSubDialog("No Matches", "Reset", "QUIT!", sgerrmsg.format( self.version_type), boxeditable=False, parent=self) button, text, pick = sub_dialog.getValues() if sub_dialog.exec_(): sub_dialog.close() button, text, pick = sub_dialog.getValues() if button == 'No': QApplication.quit() else: return # return if they click on Retry else: return # return if they close the window mainlabel = "Success!" yeslabel = 'Go Again' nolabel = 'QUIT!' boxtext = 'Your version was successfully created' if self.allOK and self.submit_movie: if not do_submit_for_review(self.sg, self.movie_file_path, self.created_version_id): # the sym-link failed for some reason after 2 tries... mainlabel = "Partial Success..." boxtext = "Your version was created but the movie was NOT put into today's Review Folder. Please add it manually, or resubmit the Version" except Exception, e: mainlabel = "ERROR!" yeslabel = 'Reset' nolabel = 'QUIT!' boxtext = 'Something Went Horribly Wrong! -\nError: {0}\n{1}'.format( e, traceback.format_exc()) #QMessageBox.about(self, "updateUI", output_string) sub_dialog = dMFXsubmitterSubDialog(mainlabel, yeslabel, nolabel, boxtext) if sub_dialog.exec_(): sub_dialog.close() button, text, pick = sub_dialog.getValues() if button == 'No': QApplication.quit() else: self.reset_to_go_again()
class MainUI(QtGui.QWidget): def __init__(self, app): """ main UI for STATIC ENV handling I always build my UI in __init__ so suck it up.. """ QtGui.QWidget.__init__(self) self.app = app context = self.app.context self.fileBoxes = [] ## Instance the api for talking directly to shotgun. base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'audioUploader' api_key = 'bbfc5a7f42364edd915656d7a48d436dc864ae7b48caeb69423a912b930bc76a' self.sgsrv = Shotgun(base_url=base_url, script_name=script_name, api_key=api_key, ensure_ascii=True, connect=True) self.shotNum = self._getShotNum()[0] self.currentENV = self._getShotNum()[1] debug(self.app, method='MainUI', message='self.shotNum: %s' % self.shotNum, verbose=False) debug(self.app, method='MainUI', message='self.currentENV: %s' % self.currentENV, verbose=False) self.lightAlembicFolder = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_anim' % self.shotNum ## Now build the UI self.mainLayout = QtGui.QHBoxLayout(self) self.leftSideLayout = QtGui.QVBoxLayout(self) debug(self.app, method='MainUI', message='self.mainLayout built...', verbose=False) ########################## ### ENV SELECTION PULLDOWN self.envLayout = QtGui.QVBoxLayout(self) self.envPulldown = QtGui.QComboBox() getENVS = self.sgsrv.find( 'Asset', filters=[["code", "contains", 'ENV_'], ["code", "not_contains", '_ENV_'], ["code", "not_contains", 'WORLDMAP'], ["code", "not_contains", 'TSETbuild']], fields=['code']) debug(self.app, method='MainUI', message='getENVS: %s' % getENVS, verbose=False) if self.shotNum: for each in getENVS: if each['code'] == self.currentENV: self.envPulldown.addItem(each['code']) self.lightAlembicFolder = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_anim' % self.shotNum self.envPulldown.setCurrentIndex( self.envPulldown.findText(self.currentENV)) debug(self.app, method='MainUI', message='self.envPulldown setCurrentIndex...', verbose=False) else: for each in getENVS: if 'ANIM' in each['code']: self.envPulldown.addItem(each['code']) self.fetchAssetListButton = QtGui.QPushButton(Icon('refresh.png'), 'Fetch Asset List') self.fetchAssetListButton.setStyleSheet( "QPushButton {text-align : left}") self.fetchAssetListButton.released.connect(self._fetchAssetList) debug(self.app, method='MainUI', message='self.fetchAssetListButton built...', verbose=False) self.importAssetButton = QtGui.QPushButton(Icon('alembic.png'), 'Import latest Pub ABC') self.importAssetButton.setStyleSheet("QPushButton {text-align : left}") self.importAssetButton.released.connect(self._fetchMDLAlembicPublish) debug(self.app, method='MainUI', message='self.importAssetButton built...', verbose=False) self.checkMDLButton = QtGui.QPushButton(Icon('refresh.png'), 'Check For RIG Publishes') self.checkMDLButton.setStyleSheet("QPushButton {text-align : left}") self.checkMDLButton.released.connect( self._checkVersionsAgainstPublishes) debug(self.app, method='MainUI', message='self.checkMDLButton built...', verbose=False) self.checkSRFXMLButton = QtGui.QPushButton(Icon('refresh.png'), 'Check For SRF Publishes') self.checkSRFXMLButton.setStyleSheet("QPushButton {text-align : left}") self.checkSRFXMLButton.released.connect( self._checkSRFVersionsAgainstPublishes) self.lambert1Button = QtGui.QPushButton(Icon('refresh.png'), 'Check lambert1 objects') self.lambert1Button.setStyleSheet("QPushButton {text-align : left}") self.lambert1Button.released.connect(self._lambert1Object) self.checkFileInPathButton = QtGui.QPushButton( Icon('refresh.png'), 'Check Invalid FileIn Path') self.checkFileInPathButton.setStyleSheet( "QPushButton {text-align : left}") self.checkFileInPathButton.released.connect(self.checkFileInPath) self.checkNonManifoldButton = QtGui.QPushButton( Icon('refresh.png'), 'Check Non-Manifold Geometry') self.checkNonManifoldButton.setStyleSheet( "QPushButton {text-align : left}") self.checkNonManifoldButton.released.connect( self.cleanupNonManifoldGeometry) if context.step['name'] == 'Anm': self.creaseXMLButton = QtGui.QPushButton('Create crease XML') self.creaseXMLButton.released.connect(self._writeCreaseToXML) self.creaseXMLButton.setEnabled(True) if context.step['name'] == 'Light': self.fetchCreaseXMLButton = QtGui.QPushButton( 'Fetch latest published crease XML') self.fetchCreaseXMLButton.released.connect( partial(self._getCreaseFromXML, rootPrefix='ENV_DOCKS_STATICANIM_ABC_ANIM_CACHES_hrc')) self.fetchCreaseXMLButton.setEnabled(True) self.republishALL = QtGui.QPushButton('Publish ABC from ANM') self.republishALL.released.connect(self._republishAllAlembicsForENV) self.republishALL.setEnabled(True) ## Add stuff to the env layout self.envLayout.addWidget(self.envPulldown) self.envLayout.addWidget(self.fetchAssetListButton) self.envLayout.addWidget(self.importAssetButton) self.envLayout.addWidget(self.checkMDLButton) self.envLayout.addWidget(self.checkSRFXMLButton) self.envLayout.addWidget(self.lambert1Button) self.envLayout.addWidget(self.checkFileInPathButton) self.envLayout.addWidget(self.checkNonManifoldButton) self.envLayout.addWidget(self.republishALL) if context.step['name'] == 'Anm': self.envLayout.addWidget(self.creaseXMLButton) if context.step['name'] == 'Light': self.envLayout.addWidget(self.fetchCreaseXMLButton) ###################### ### ENV RELATED ASSETS self.assetLayout = QtGui.QVBoxLayout(self) ### Now do the check boxes for files.... self.scrollLayout = QtGui.QScrollArea(self) self.scrollLayout.setMinimumHeight(300) self.envAssetsGroupBox = QtGui.QGroupBox(self.scrollLayout) self.envAssetsGroupBox.setFlat(True) self.scrollLayout.setWidget(self.envAssetsGroupBox) self.scrollLayout.setWidgetResizable(True) self.envAssetsLayout = QtGui.QGridLayout(self.envAssetsGroupBox) self.assetLayout.addWidget(self.scrollLayout) self.mainLayout.addLayout(self.leftSideLayout) ## Add stuff to leftSideLayout self.leftSideLayout.addLayout(self.envLayout) self.leftSideLayout.addStretch(1) ## Add anything else to the HBox self.mainLayout.addLayout(self.assetLayout) self.resize(1000, 500) debug(self.app, method='MainUI', message='ui built successfully fetching assets now...', verbose=False) debug(self.app, method='MainUI', message='self.envPulldown.currentText(): %s' % self.envPulldown.currentText(), verbose=False) self._fetchAssetList() self.envPulldown.currentIndexChanged.connect( partial(self._getShotNumFromMenuName)) self.envPulldown.currentIndexChanged.connect( partial(self._fetchAssetList)) def _prettyPrintXML(self, elem, level=0): i = '\n' + level * ' ' if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + ' ' if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: self._prettyPrintXML(elem, level + 1) if not elem.tail or not elem.tail.strip(): elem.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i def _getCreaseFromXML(self, rootPrefix=''): scene_path = os.path.abspath(cmds.file(query=True, sn=True)) xmlPath = '%s/Anm/publish/crease_xml/ep000_Docks_Addon.xml' % '/'.join( os.path.abspath(cmds.file(query=True, sn=True)).replace( '\\', '/').split('/')[:5]) if scene_path else '' print xmlPath if os.path.isfile(xmlPath): tree = ET.parse(xmlPath) root = tree.getroot() if root.tag == 'CreaseXML': for mesh in root.getchildren(): mesh_name = mesh.attrib.get('name') mesh_name = '|'.join( [x.split(':')[-1] for x in mesh_name.split('|')]) mesh_name = '%s%s' % ( rootPrefix, mesh_name) if rootPrefix else mesh_name if cmds.objExists(mesh_name): for edge in mesh.getchildren(): vertexA = int(edge.attrib.get('vertexA')) vertexB = int(edge.attrib.get('vertexB')) creaseValue = edge.attrib.get('creaseValue') edgeID = cmds.polyListComponentConversion( '%s.vtx[%d]' % (mesh_name, vertexA), '%s.vtx[%d]' % (mesh_name, vertexB), fromVertex=1, toEdge=1, internal=1)[0].split('.')[-1] if '-inf' not in creaseValue: cmds.polyCrease('%s.%s' % (mesh_name, edgeID), value=float(creaseValue)) else: cmds.warning('%s doesn\'t exist, skipping...' % mesh_name) else: cmds.warning('Not a valid xml...') else: cmds.warning('Not a valid crease xml path...') def _writeCreaseToXML(self): scene_path = os.path.abspath( cmds.file(query=True, sn=True) ) # I:\bubblebathbay\episodes\ep106\ep106_sh030\FX\work\maya\ep106sh030.v025.ma xmlPath = '%s/publish/crease_xml/ep000_Docks_Addon.xml' % '/'.join( os.path.abspath(cmds.file(query=True, sn=True)).replace( '\\', '/').split('/')[:6]) if scene_path else '' if os.path.isdir(os.path.dirname(xmlPath)): ## Get all mesh in scene with all their edges intact i.e. |pCube1|pCubeShape1.e[0:11] (Filter out intermediate object as well as they don't get cache out) meshes = [ '%s.e[0:%s]' % (mesh, cmds.polyEvaluate(mesh, edge=True) - 1) for mesh in cmds.ls(type='mesh', long=True) if not cmds.getAttr('%s.intermediateObject' % mesh) if cmds.polyEvaluate(mesh, edge=True) ] if meshes: edge_creases = [] for mesh in meshes: mesh_name = mesh.split('.')[0] edges = cmds.polyCrease(mesh, value=True, q=True) if edges: crease_edges = [] for edge, value in enumerate(edges, start=0): if value > 0: ## 0 means no crease, more than 0 means crease... ## 2 vertices = 1 edge. Therefore, get edge's vertices id... crease_edges.append(( filter( None, cmds.polyInfo( '%s.e[%s]' % (mesh_name, edge), edgeToVertex=True)[0].split(':') [-1].replace('Hard', '').replace( '\n', '').split(' '))[0], ## Vertex A filter( None, cmds.polyInfo( '%s.e[%s]' % (mesh_name, edge), edgeToVertex=True)[0].split(':') [-1].replace('Hard', '').replace( '\n', '').split(' '))[1], ## Vertex B str( value ), ## Crease value (Reason why we put it as string is because somehow maya sometimes return value "-inf" which's going to be troublesome when applying crease to poly later... )) edge_creases.append( (mesh_name, crease_edges)) if crease_edges else None if edge_creases: ## Process root root = ET.Element('CreaseXML') for each in edge_creases: mesh = '|'.join( [x.split(':')[-1] for x in each[0].split('|')] ) ## Get rid of object names that has ":" in it as it will be stripped out during alembic cache anyways... if 'geo_hrc' in mesh: mesh = '|%s' % '|'.join( mesh.split('|')[([ i for (i, x) in enumerate(mesh.split('|'), start=0) if x == 'geo_hrc' ][0] - 1):] ) ## Get full name until root of geo_hrc meshElem = ET.SubElement(root, 'Mesh') meshElem.set('name', mesh) for child in each[1]: vertexA = child[0] vertexB = child[1] creaseValue = child[2] edgeElem = ET.SubElement(meshElem, 'Edge') edgeElem.set('vertexA', vertexA) edgeElem.set('vertexB', vertexB) edgeElem.set('creaseValue', creaseValue) ## Make directory if it doesn't exist if not os.path.exists(os.path.dirname(xmlPath)): os.makedirs(os.path.dirname(xmlPath)) ## Process XML to output nicely so it's human readable i.e. not everything in 1 line self._prettyPrintXML(root) tree = ET.ElementTree(root) ## Output .xml into directory tree.write(xmlPath, encoding='utf-8') def arraysMatch(self, a, b): ''' Utility to compare two string list ''' return True if a == b else False def cleanupNonManifoldGeometry(self, normals=True): ## Get all the mesh that has mentalraySubdivApprox connected and has non-manifold problem # subdiv_mesh = [cmds.listRelatives(mesh, parent = True, fullPath = True)[0] for mesh in cmds.ls(type = 'mesh') if cmds.listConnections(mesh, type = 'mentalraySubdivApprox') if cmds.polyInfo(mesh, nme = True) or cmds.polyInfo(nmv = True)] subdiv_mesh = [ cmds.listRelatives(mesh, parent=True, fullPath=True)[0] for mesh in cmds.ls(type='mesh') if cmds.polyInfo(mesh, nme=True) or cmds.polyInfo(nmv=True) ] subdiv_mesh = list(set(subdiv_mesh)) if subdiv_mesh: for each in subdiv_mesh: ## Make sure we do indeed have nonmanifold geometry ## nonManifold = cmds.polyInfo(each, nmv=True, nme=True) if nonManifold: proceed = cmds.confirmDialog( title='Non-Manifold Geometry!', message='Geo Name:\n%s' % each, button=['Cleanup!', 'Skip...'], defaultButton='Skip...', cancelButton='Skip...', dismissString='Skip...') if proceed == 'Cleanup!': ## Conform the geo and see if that gets rid of all the nonmanifold bits ## if normals: cmds.polyNormal('%s.f[*]' % each, normalMode=2, constructionHistory=True) edges = cmds.polyInfo(each, nme=True) if cmds.polyInfo( each, nme=True) else [] vertices = [] if edges else cmds.polyInfo(each, nmv=True) lastEdges = [] lastVertices = [] while (not self.arraysMatch(lastEdges, edges) or not self.arraysMatch(lastVertices, vertices) ) and (edges or vertices): ## Remember what was nonmanifold last time ## lastEdges = edges lastVertices = vertices ## Split any nonmanifold edges ## if edges: cmds.polySplitEdge(edges, constructionHistory=True) vertices = cmds.polyInfo(each, nmv=True) edges = [] ## Split any remaining nonmanifold vertices ## if vertices: cmds.polySplitVertex(vertices, constructionHistory=True) vertices = [] ## Now check to see if the object is still nonmanifold ## nonManifold = cmds.polyInfo(each, nmv=True, nme=True) if nonManifold: ## Chip off the faces ## nonManifoldFaces = cmds.polyListComponentConversion( nonManifold, toFace=True) cmds.polyChipOff(nonManifoldFaces, kft=0, dup=0, constructionHistory=True) ## And then check for nonmanifold bits again ## edges = cmds.polyInfo(each, nme=True) if not edges: vertices = cmds.polyInfo(each, nmv=True) ## Check to see if we failed to cleanup if edges or vertices: cmds.warning( 'Failed to cleanup non-manifold geometry of %s...' % each) def _lambert1Object(self): ## Delete sets first if cmds.objExists('lambert1_object_set'): cmds.delete('lambert1_object_set') lambert1 = cmds.ls(cmds.sets('initialShadingGroup', q=True), long=True) if lambert1: lambert1 = [ x.split('.f')[0] for x in lambert1 if cmds.objectType(x) == 'mesh' and 'CArch' not in x ] ## Create sets if bad stuffs detected if lambert1: cmds.sets(lambert1, name='lambert1_object_set') def checkFileInPath(self): ## Delete sets first if cmds.objExists('invalid_fileIn_path_set'): cmds.delete('invalid_fileIn_path_set') fileIn = cmds.ls(type='file') fileIn.extend(cmds.ls(type='mentalrayTexture')) if fileIn: badFileInPath = [ x for x in fileIn if not os.path.exists(cmds.getAttr('%s.fileTextureName' % x)) ] ## Create sets if bad stuffs detected if badFileInPath: cmds.sets(badFileInPath, name='invalid_fileIn_path_set') def _toggleCBx(self, chbx='', wtfami=''): """ Function to select on checkbox toggle @param chbx: the QCheckbox @param wtfami: WHO THE HELL KNOWS!!????!!!!!!!! @type chbox: PyQt Object :return: """ if chbx.isChecked(): cmds.select('%s_hrc' % chbx.text(), add=True) else: cmds.select('%s_hrc' % chbx.text(), d=True) def _getShotNum(self): self.workSpace = cmds.workspace(q=True, fn=True) debug(self.app, method='_getShotNum', message='self.workSpace: %s' % self.workSpace, verbose=False) envName = '' shotNum = '' if 'ep000_Docks_Addon' in self.workSpace: envName = 'ENV_DOCKS_STATICANIM' shotNum = 'ep000_Docks_Addon' else: envName = None shotNum = None return shotNum, envName def _getShotNumFromMenuName(self, index=''): self.workSpace = cmds.workspace(q=True, fn=True) envName = '' shotNum = '' if self.envPulldown.currentText() == 'ENV_DOCKS_STATICANIM': shotNum = 'ep000_Docks_Addon' else: shotNum = None return shotNum def _addVersionTag(self, assetName, versionNumber): if cmds.objExists('%s.rigVersion' % assetName): cmds.deleteAttr('%s.rigVersion' % assetName) try: cmds.addAttr(assetName, ln='rigVersion', at='long', dv=0) except: pass cmds.setAttr('%s.rigVersion' % assetName, int(versionNumber)) def _checkVersionsAgainstPublishes(self): ## Path to the assets folder pathToAssets = "I:/lsapipeline/assets" character_rootdirs = [ os.path.join(pathToAssets, dir).replace('\\', '/') for dir in os.listdir(pathToAssets) if 'Character' in dir or 'Building' in dir ] character_subdirs = [ os.path.join(rootDir, subDir).replace('\\', '/') for rootDir in character_rootdirs for subDir in os.listdir(rootDir) if 'CHAR_' in subDir or '_BLD' in subDir ] RIGVersNum = '' ## Fetch the subAssets for the ENV getData = self.sgsrv.find( 'Asset', filters=[["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) ## Now can the checkboxes and see which assets arechecked if self.fileBoxes: for eachAsset in self.fileBoxes: if eachAsset.isChecked(): for eachSGAsset in getData[0]['assets']: if eachSGAsset['name'] == eachAsset.text(): assetFolder = [ subDir for subDir in character_subdirs if os.path.basename(subDir) in eachSGAsset['name'] ][0] assetPublishFolder = '%s/RIG/publish/maya' % assetFolder if assetFolder else None if os.path.isdir(assetPublishFolder): try: getLatestPublish = max( os.listdir(assetPublishFolder)) except: getLatestPublish = [] if getLatestPublish and getLatestPublish.endswith( '.mb'): RIGVersNum = int( getLatestPublish.split('.')[-2].split( 'v')[-1]) try: getAssetVersion = cmds.getAttr( '%s_hrc.rigVersion' % eachAsset.text()) except ValueError: getAssetVersion = None if getAssetVersion: if not getAssetVersion == RIGVersNum: print '!!HIGHER VER EXISTS: %s_hrc:%s \t %s' % ( eachAsset.text(), getAssetVersion, getLatestPublish) eachAsset.setStyleSheet( "QCheckBox{background-color: red}") else: eachAsset.setStyleSheet( "QCheckBox{background-color: green}") eachAsset.setChecked(False) print 'PASSED: version match %s' % ( getLatestPublish) else: eachAsset.setStyleSheet( "QCheckBox{background-color: red}") cmds.warning( '%s IS MISSING VERSION INFORMATION! PLEASE FIX!!!' % eachAsset.text()) for eachAsset in self.fileBoxes: if eachAsset.isChecked() and eachAsset.text() == 'ALL': eachAsset.setChecked(False) eachAsset.setStyleSheet( "QCheckBox{background-color: green}") def _checkSRFVersionsAgainstPublishes(self): ## Path to the assets folder pathToAssets = "I:/lsapipeline/assets" character_rootdirs = [ os.path.join(pathToAssets, dir).replace('\\', '/') for dir in os.listdir(pathToAssets) if 'Character' in dir or 'Building' in dir ] character_subdirs = [ os.path.join(rootDir, subDir).replace('\\', '/') for rootDir in character_rootdirs for subDir in os.listdir(rootDir) if 'CHAR_' in subDir or '_BLD' in subDir ] XMLVersNum = '' ## Fetch the subAssets for the ENV getData = self.sgsrv.find( 'Asset', filters=[["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) ## Now can the checkboxes and see which assets are checked if self.fileBoxes: for eachAsset in self.fileBoxes: if eachAsset.isChecked(): #print 'Checking %s ...' % eachAsset.text() for eachSGAsset in getData[0]['assets']: if eachSGAsset['name'] == eachAsset.text(): assetFolder = [ subDir for subDir in character_subdirs if os.path.basename(subDir) in eachSGAsset['name'] ][0] assetPublishFolder = '%s/SRF/publish/xml' % assetFolder if assetFolder else None if os.path.isdir(assetPublishFolder): try: getLatestPublish = max( os.listdir(assetPublishFolder)) except: getLatestPublish = [] if getLatestPublish and getLatestPublish.endswith( '.xml'): XMLVersNum = int( getLatestPublish.split('.')[-2].split( 'v')[-1]) try: getAssetSRFVersion = cmds.getAttr( '%s_hrc.SRFversion' % eachAsset.text()) except ValueError: getAssetSRFVersion = None if getAssetSRFVersion: if not getAssetSRFVersion == XMLVersNum: print '!!HIGHER VER EXISTS: %s_hrc:%s \t %s' % ( eachAsset.text(), getAssetSRFVersion, getLatestPublish) eachAsset.setStyleSheet( "QCheckBox{background-color: red}") else: eachAsset.setStyleSheet( "QCheckBox{background-color: green}") eachAsset.setChecked(False) print 'PASSED: version match %s' % ( getLatestPublish) else: eachAsset.setStyleSheet( "QCheckBox{background-color: red}") cmds.warning( '%s IS MISSING VERSION INFORMATION! PLEASE FIX!!!' % eachAsset.text()) for eachAsset in self.fileBoxes: if eachAsset.isChecked() and eachAsset.text() == 'ALL': eachAsset.setChecked(False) eachAsset.setStyleSheet( "QCheckBox{background-color: green}") def _checkVersionNumber(self, assetName, versionNumber, attrType): """ Returns if the version number for an asset in the scene matches that of the asset in the static_folder """ foundVersion = False ## Path to the assets folder pathToAssets = "I:/lsapipeline/assets" character_rootdirs = [ os.path.join(pathToAssets, dir).replace('\\', '/') for dir in os.listdir(pathToAssets) if 'Character' in dir or 'Building' in dir ] character_subdirs = [ os.path.join(rootDir, subDir).replace('\\', '/') for rootDir in character_rootdirs for subDir in os.listdir(rootDir) if 'CHAR_' in subDir or '_BLD' in subDir ] assetFolder = [ subDir for subDir in character_subdirs if os.path.basename(subDir) in assetName ][0] assetPublishFolder = '' if attrType == 'RIG': assetPublishFolder = '%s/RIG/publish/maya' % assetFolder if assetFolder else None elif attrType == 'SRF': assetPublishFolder = '%s/SRF/publish/xml' % assetFolder if assetFolder else None if os.path.isdir(assetPublishFolder): try: getLatestPublish = max(os.listdir(assetPublishFolder)) except: getLatestPublish = [] if getLatestPublish: getlatestVersionNum = int( getLatestPublish.split('.')[-2].split('v')[-1]) if int(versionNumber) == int(getlatestVersionNum): foundVersion = True else: cmds.warning( 'There is no asset for %s found in the lighting anim alembic folder.' % assetName) return foundVersion def _fetchAssetList(self, index=''): getData = self.sgsrv.find( 'Asset', filters=[["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) debug(self.app, method='_fetchAssetList', message='getData: %s' % getData, verbose=False) if self.fileBoxes: for each in self.fileBoxes: each.setParent(None) each = None self.fileBoxes = [] ## First add the ALL checkbox self.ALL = QtGui.QCheckBox(self) self.ALL.setChecked(False) self.ALL.setText('ALL') self.ALL.toggled.connect(self._toggleAll) self.fileBoxes.append(self.ALL) self.envAssetsLayout.addWidget(self.ALL, 0, 0) self.colCount = 5 r = 1 c = 1 if getData: for eachAsset in getData[0]['assets']: self.assetCheckBox = QtGui.QCheckBox(self) self.assetCheckBox.setChecked(False) self.assetCheckBox.setText(eachAsset['name']) self.assetCheckBox.toggled.connect( partial(self._toggleCBx, self.assetCheckBox)) self.fileBoxes.append(self.assetCheckBox) if cmds.objExists('%s_hrc' % eachAsset['name']): self.assetCheckBox.setStyleSheet( "QCheckBox{background-color: #0066CC}") ## Now check the version of RIG and SRF if cmds.objExists('%s_hrc.rigVersion' % eachAsset['name']): if not self._checkVersionNumber( eachAsset['name'], cmds.getAttr( '%s_hrc.rigVersion' % eachAsset['name']), attrType='RIG'): self.assetCheckBox.setStyleSheet( "QCheckBox{background-color: red}") else: self.assetCheckBox.setStyleSheet( "QCheckBox{background-color: #990000}") cmds.warning('Asset version attr not found on %s_hrc' % eachAsset['name']) else: self.assetCheckBox.setStyleSheet( "QCheckBox{background-color: red}") if c == self.colCount: r = r + 1 c = 1 self.envAssetsLayout.addWidget(self.assetCheckBox, r, c) c = c + 1 def _toggleAll(self): """ A quick toggle for all the type checkboxes to on or off """ for each in self.fileBoxes: if each.text() == 'ALL': each.setStyleSheet("QCheckBox{background-color: grey}") if each.isChecked(): for eachAsset in self.fileBoxes: if eachAsset.text() != 'ALL': eachAsset.setChecked(True) eachAsset.setStyleSheet( "QCheckBox{background-color: grey}") else: for eachAsset in self.fileBoxes: if eachAsset.text() != 'ALL': eachAsset.setChecked(False) def _cleanupShit(self): try: cmds.delete(cmds.ls('rig_hrc')) except: pass try: cmds.delete(cmds.ls('parts_hrc')) except: pass try: cmds.delete(cmds.ls('collisionNurbsHulls')) except: pass for each in cmds.ls(type='transform'): if 'Constraint' in each: cmds.delete(each) def _fetchMDLAlembicPublish(self): """ This function will find the checked assets, and then go off and get the latest published alembic asset from the asset folder None of this is done off the database btw.. """ pathToAssets = 'I:/lsapipeline/assets' if self.shotNum: moveTo = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_anim' % self.shotNum elif self._getShotNumFromMenuName(): moveTo = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_anim' % self._getShotNumFromMenuName( ) else: cmds.warning( 'This ENV is not a valid for processing using this tool!') return -1 if os.path.isdir(moveTo): getData = self.sgsrv.find( 'Asset', filters=[["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) subAssets = [ '%s_hrc' % eachAsset['name'] for eachAsset in getData[0]['assets'] if cmds.objExists('%s_hrc' % eachAsset['name']) ] reimport_cache = True ## Prompt to continue here if subAssets: self.reply = cmds.confirmDialog( title='Remove all sub assets?', message= 'Warning you are about to remove all the sub assets!', button=['Continue...', 'Skip Import']) if self.reply == 'Continue...': ## Go through all the _hrc asset and delete the f**k off the scene ya go... [cmds.delete(subAsset) for subAsset in subAssets] elif self.reply == 'Skip Import': reimport_cache = False ## Find latest .abc alembic anim cache in ENV's published directory... if reimport_cache: try: findLatest = max(os.listdir(moveTo)) except: findLatest = [] if findLatest: ## Create base group name template according to ENV's name... if self.currentENV: groupName = '%s_ABC_ANIM_CACHES_hrc' % self.currentENV else: groupName = '%s_ABC_ANIM_CACHES_hrc' % self.envPulldown.currentText( ) ## Create the group if it doesn't exist... if not cmds.objExists(groupName): cmds.group(n=groupName, em=True) try: cmds.AbcImport('%s/%s' % (moveTo, findLatest), reparent=groupName, setToStartFrame=True) self._cleanupShit() self._fetchAssetList() except RuntimeError: cmds.warning('Failed to import cache! %s/%s' % (moveTo, findLatest)) else: cmds.warning('Nothing published for %s !' % self.shotNum) def _isRootFolderThere(self, rootFolder): """ Method used to check if root folder is valid or not eg: I:/lsapipeline/assets @param rootFolder: The path to the root folder to check for @type rootFolder: String """ if not os.path.isdir(rootFolder): print 'No such root folder found: %s' % rootFolder return -1 else: return 1 def _importSingleCache(self, folderPath, parentGrp, cacheName): """ Function to import the alembics and parent them to the right group @param folderPath: Path to the folder for the caches to import @param parentGrp: The name of the group to parent the alembics to. @type folderPath: String @type parentGrp: String """ try: findLatest = max(os.listdir(folderPath)) except: findLatest = [] if findLatest: try: cmds.AbcImport('%s/%s' % (folderPath, findLatest), reparent=parentGrp, setToStartFrame=True) except RuntimeError: cmds.warning('Failed to import cache! %s/%s' % (folderPath, findLatest)) else: cmds.warning('Nothing published for %s !' % cacheName) def _importCaches(self, folderPath, parentGrp): """ Function to import the alembics and parent them to the right group @param folderPath: Path to the folder for the caches to import @param parentGrp: The name of the group to parent the alembics to. @type folderPath: String @type parentGrp: String """ for eachCache in os.listdir(folderPath): try: cmds.AbcImport('%s/%s' % (folderPath, eachCache), reparent=parentGrp, setToStartFrame=True) except RuntimeError: cmds.warning('Failed to import cache! %s/%s' % (folderPath, eachCache)) def _republishAllAlembicsForENV(self): """ This helper will republish all the MDL alembic files from the most recently published mb files found in the assets folders for every asset associated to the ENV. getData = self.sgsrv.find('Asset', filters = [["code", "is", eachENV]], fields=['code', 'id', 'assets']) Finds the ENV name and then gets a list of Sub Assets associated with it from the assets field. This is why we want every ENV to be the parent of an asset in the system appropriately. """ ## Path to the assets folder assetWorkFolder = 'I:/lsapipeline/episodes/ep000/%s/Anm/work/maya' % self.shotNum if os.path.isdir(assetWorkFolder): getLatestScene = [ each for each in os.listdir(assetWorkFolder) if each.endswith('.ma') ] getLatestScene = max(getLatestScene) if getLatestScene: latestScene = '%s/%s' % (assetWorkFolder, getLatestScene) latestScene.replace("/", os.sep) alembicPath = latestScene.replace('Anm', 'Light').replace( 'work', 'publish').replace('.ma', '.abc').replace( 'maya', 'alembic_anim').replace('.v', '_ABC.v') ## Remove current alembic if os.path.isfile(alembicPath): os.remove(alembicPath) ## Import the file so we don't have to display anything due to the files prob being saved with textures on etc sceneName = cmds.file(sceneName=True, q=True) if not sceneName == latestScene: try: cmds.file(latestScene, o=True, f=True) except: cmds.warning('Failed to open %s...' % latestScene) cleanup.removeAllNS() ## Now export back out a new alembic with the version name that should exist in the assembly reference. roots = cmds.ls(type='transform') rootHrc = [ root for root in roots if cmds.referenceQuery(root, isNodeReferenced=True) if cmds.objExists('%s.type' % root) if str(cmds.getAttr('%s.type' % root)).startswith('anim') ] if roots else None rootName = ' -root '.join(rootHrc) if rootHrc else None if rootName: ## Change uv set map1 if the mesh has multiple uv sets for alembic cache [ cmds.polyUVSet(each, currentUVSet=True, uvSet='map1') for each in cmds.ls(type='mesh') ] ## Now scan the geo in the scene and preserve the crease information for each in cmds.ls(type='mesh', l=True): if not cmds.objExists('%s.SubDivisionMesh' % each): try: cmds.addAttr('%s' % each, ln='SubDivisionMesh', at='bool') cmds.setAttr("%s.SubDivisionMesh" % each, 1) except: pass ## Add custom attribute tag to check rig version if it doesn't exist... for root in rootHrc: rigVersion = int( os.path.basename( cmds.referenceQuery(root, filename=True)).split('.') [1].split('v')[-1]) if not cmds.objExists('%s.rigVersion' % root): cmds.addAttr(root, longName='rigVersion', attributeType='long', dv=0) cmds.setAttr('%s.rigVersion' % root, rigVersion) minTime = cmds.playbackOptions(min=True, q=True) maxTime = cmds.playbackOptions(max=True, q=True) abc_export_cmd = "-attr smoothed -attr SubDivisionMesh -attr rigVersion -ro -uvWrite -wholeFrameGeo -worldSpace -writeVisibility -fr %d %d -root %s -file %s" % ( minTime, maxTime, rootName, alembicPath) try: [cmds.currentTime(minTime) for i in range(2)] cmds.AbcExport(verbose=False, j=abc_export_cmd) # cmds.file(new = True, force = True) except: cmds.warning("Failed to export Alembic Cache!!") else: cmds.warning( 'Cannot find any proper _hrc with anim tag in this scene...' )
def launch(progressBar, logLabel, filterDataList , app, projectContext = None, sg= None ) : SERVER_PATH = "https://nozon.shotgunstudio.com" SCRIPT_NAME = 'noteManager' SCRIPT_KEY = '3fbb2a5f180457af709fcad231c96ac8a916711427af5a06c47eb1758690f6e4' if not sg : try : from shotgun_api3 import Shotgun sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) except : sg = app.engine.tank.shotgun projectId = None if projectContext : projectId = projectContext else : projectId = app.context.project today = datetime.datetime.utcnow().strftime("%Y%m%d") import os try : os.makedirs("c:/temp/EVENTLOG") except : pass if not progressBar : import glob test = outputLogFileName = "c:/temp/EVENTLOG/eventManager_"+projectId["name"]+"_"+ "*" +".html" outputLogFileName = "c:/temp/EVENTLOG/eventManager_"+projectId["name"]+"_"+ today +".html" if len(glob.glob(test)) : print "skiped" return f = open(outputLogFileName, 'w') f.write("<!DOCTYPE html><html><head><title>Page Title</title></head><body><dir>") def cout(text) : text = text.replace(" "," ") text = text.replace("\n","<br>") text = text.replace("<font color=","<font color=") f.write(str(text)+"<br>\n") eventFilter_List=[] if not filterDataList : filterEvent = event_filter() filterEvent.massTest = 60.0 eventFilter_List.append( filterEvent ) for filterData in filterDataList : eventFilter_List.append( event_filter(*filterData)) if progressBar : progressBar.setFormat("Querying database") textLineList=["<font color='#000000'>Results : </font>"] cout("Retrieving project workstation list : " + str(projectId) ) eventFilterList = ['version_up','save_file_as', 'open_file', 'file_publish', 'new_file','open_file','open_file_snapshot' ] filters = [ ["project", "is", projectId], ["event_type", "in", eventFilterList ] ] wsDictList=[] firstEventLog = None lastEventLog = None eventLogList = sg.find("EventLogEntry", filters, [ "meta" , "created_at"] ) cout("got It ! ") for eventLog in eventLogList : if eventLog["meta"].has_key("ws") : if not eventLog["meta"]["ws"] in wsDictList : wsDictList.append(eventLog["meta"]["ws"]) if not firstEventLog : firstEventLog = eventLog elif firstEventLog["id"] > eventLog["id"] : firstId = eventLog if not lastEventLog : lastEventLog = eventLog elif lastEventLog["id"] < eventLog["id"] : lastEventLog = eventLog if not firstEventLog : print "there's no event for this project " f.close() return textLineList.append(" -> " + " + ".join(wsDictList)) cout("First event " + str(firstEventLog["created_at"]) ) cout("Retrieving every event list since " + str(firstEventLog["created_at"]) ) { "filter_operator": "all", "filters": [ ["created_at", "greater_than", firstEventLog["created_at"]] , ["created_at", "smaller_than", lastEventLog["created_at"]] ] } filters = [ ["created_at", "between", [ firstEventLog["created_at"], lastEventLog["created_at"] ] ] , ["entity", 'is_not', None], ["event_type", "in", eventFilterList ] ] wsDict = {} eventLogList = sg.find("EventLogEntry", filters, [ "meta", "entity", "project", "event_type", "created_at" ] ) cout("got It ! ") for eventLog in eventLogList : thisProject = False if eventLog['project']['id'] == projectId['id'] : thisProject = True dataEvent = sg_Event( eventLog["created_at"], eventLog["entity"], eventLog["event_type"], thisProject, eventLog["id"]) # event_datetime, event_context, event_type, thisProject = True if not wsDict.has_key(eventLog["meta"]["ws"]) : wsDict[eventLog["meta"]["ws"]] = [dataEvent] else : wsDict[eventLog["meta"]["ws"]].append(dataEvent) stepProgressBar = 0 if progressBar : progressBar.setFormat("Computing events") progressBar.setValue(stepProgressBar) ev = 0 workstationDict = {} for workstation,dailyEventQueue in wsDict.iteritems(): contextList = get_contextList(dailyEventQueue) array_2D = makeArray( dailyEventQueue, contextList ) cout(" -> " + str(workstation) ) dayContext_timeTree = calculateArray(array_2D, contextList, eventFilter_List, cout) drawArray(array_2D, eventFilter_List, cout) workstationDict[workstation]=dayContext_timeTree ev+= len(array_2D) stepProgressBar+= 100/len(wsDict.keys()) if progressBar : progressBar.setValue(stepProgressBar) outputText = displayDataContext(workstationDict, cout ) outputText +="<br><br> See full log file :<br>" outputText += str(outputLogFileName) if progressBar : progressBar.setValue(100) progressBar.setFormat("Computing done") logLabel.setText(outputText.replace(" "," ")) cout("done : " + str (ev) ) f.write("</dir></body></html>") f.close() datafileName = "c:/temp/EVENTLOG/eventManager_"+projectId["name"]+"_"+ today +".pkl" displayDataContext_perDay( workstationDict, projectId["name"], datafileName )
class genericUtils: def __init__(self): self.sg = Shotgun('https://' + URL, name, API) def getFields(self, entity): '''get the fields for a type/entity as a list so we can pass it as an arg easily this is used all the time to make sure we get all the fields that we may ever need for a type/entity ''' allFields = [] fields = self.sg.schema_field_read(entity) for field in fields: allFields.append(field) return allFields def project(self, project): '''Gets the Shotgun project name and ID ''' retFields = self.getFields('Project') project = project.replace('_', ' ') return self.sg.find_one("Project", [["name", "is", project]], retFields) def sequence(self, project, sequence): '''Returns the shotgun sequence name and ID Parameters : (project, sequence) ''' retFields = self.getFields('Sequence') return self.sg.find_one( "Sequence", [["code", "is", sequence], ['project', 'is', project]], retFields) def shot(self, project, shot): '''Returns the shotgun shot name and ID Parameters : (project, shot) ''' retFields = self.getFields('Shot') return self.sg.find_one( 'Shot', [['code', 'is', shot], ['project', 'is', project]], retFields) def createProject(self, project): '''Creates a project in Shotgun given a project name Parameters : (project) ''' filters = [['code', 'is', 'a']] template = self.sg.find_one('Project', [['name', 'is', 'a']], ['layout_project', 'id']) data = {'name': project, 'layout_project': template} return self.sg.create('Project', data) def createSequence(self, project, sequence): '''Creates a sequence in shotgun given Parameters : (project, sequence) ''' data = { 'project': { "type": "Project", "id": project['id'] }, 'code': sequence } return self.sg.create('Sequence', data) def createShot(self, project, shot, seq='', taskTemplateName=''): '''Creates a sequence in shotgun given Parameters : (project, shot, seq='', taskTemplateName='Basic shot template' ''' filters = [['code', 'is', taskTemplateName]] template = self.sg.find_one('TaskTemplate', filters) data = { 'project': { "type": "Project", "id": project['id'] }, 'code': shot, 'task_template': template, 'description': '', 'self.sg_sequence': seq, 'self.sg_status_list': 'wtg' } result = self.sg.create('Shot', data) return result def notesFind(self, shotID): '''Find all notes on a shot Parameters : (shotID) Output : Note data : ['tasks', 'attachments', 'updated_at', 'replies', 'id', 'subject', 'playlist', ' addressings_to', 'created_by', 'content', 'sg_status_list', 'reply_content', 'updated_by', 'addressings_cc', 'read_by_current_user', 'user', 'note_links', 'created_at', 'sg_note_from', 'project', 'sg_note_type', 'tag_list'] ''' note = self.sg.find('Note', [['note_links', 'is', shotID]], ['subject', 'content', 'created_at'], [{ 'field_name': 'created_at', 'direction': 'desc' }]) return note def notesFindLatest(self, shotID): '''Find the latest note on a shot Parameters : (shotID) Call with notesFindLatest(shot)['content'] for the note content only Output : Note data: ['tasks', 'attachments', 'updated_at', 'replies', 'id', 'subject', 'playlist', ' addressings_to', 'created_by', 'content', 'sg_status_list', 'reply_content', 'updated_by', 'addressings_cc', 'read_by_current_user', 'user', 'note_links', 'created_at', 'sg_note_from', 'project', 'sg_note_type', 'tag_list'] ''' note = self.notesFind(shotID)[0] return note def notesCreate(self, project, shotID, subject, content): '''Create a note for a shot given Parameters : (project, shotID, subject, content) Output : noteID ''' # enter data here for a note to create data = { 'subject': subject, 'content': content, 'note_links': [shotID], 'project': project } # create the note noteID = self.sg.create('Note', data) return noteID def versionCreate(self, project, shot, verName, description, framePath, firstFrame, lastFrame, clientName=None, sourceFile=None, task=None, user=None, final=False, makeThumb=False, makeThumbShot=False): '''Create a version Parameters : (project, shotID, verName, description, framePath, firstFrame, lastFrame, clientName=None, sourceFile=None, task=None) Output : versionID ''' data = { 'project': project, 'code': verName, 'description': description, 'sg_path_to_frames': framePath, #'sg_frame_range': str(firstFrame) + '-' + str(lastFrame), 'sg_first_frame': int(firstFrame), 'sg_last_frame': int(lastFrame), 'sg_status_list': 'rev', 'entity': shot } #if user != None: #data['user'] if task != None: filters = [['content', 'is', task], ['entity', 'is', shot]] taskID = self.sg.find_one('Task', filters) data['sg_task'] = taskID #if final == True and 'send # in case we're putting a client version in here we need this code. # we are expecting a field called self.sg_client_name in the version table. # please make sure you create this in the shotgun setup # read the schema and if the client_name is not found, create it. ''' versionFields = self.sg.schema_field_read('Version') if 'sg_client_name' not in versionFields and clientName != None: newField = self.sg.schema_field_create('Version','text','Client Name') if clientName != None : data['sg_client_name'] = clientName #'user': {'type':'HumanUser', 'id':165} } # here we need to create a field for storing the source file that created this version. # if it's not there, create the field, and if it's there just update it. if 'sg_source_file' not in versionFields and sourceFile != None: newField = self.sg.schema_field_create('Version','text','Source File') if sourceFile != None: data['sg_source_file'] = sourceFile ''' versionData = self.sg.create('Version', data) # handle the thumbnail grabbing here middleFrame = (int(firstFrame) + int(lastFrame)) / 2 padding, padString = fxpipe.framePad(framePath) paddedFrame = padString % (middleFrame) if makeThumb == True: thumbData = self.sg.upload_thumbnail( 'Version', versionData['id'], framePath.replace(padding, paddedFrame)) if makeThumbShot == True: thumbData = self.sg.upload_thumbnail( 'Shot', shot['id'], framePath.replace(padding, paddedFrame)) return versionData #add a task version to the system def versionCreateTask(self, project, shot, verName, description, framePath, firstFrame, lastFrame, task, sourceFile=''): ''' DEPRECATED : USE versionCreate instead with the task='TASKNAME' Parameters : (project, shot, verName, description, framePath, firstFrame, lastFrame, task, sourceFile = '') Output : Version ID ''' filters = [['content', 'is', task], ['entity', 'is', shot]] taskID = self.sg.find_one('Task', filters) data = { 'project': project, 'code': verName, 'description': description, 'self.sg_path_to_frames': framePath, 'frame_range': str(firstFrame) + '-' + str(lastFrame), 'self.sg_first_frame': firstFrame, 'self.sg_last_frame': lastFrame, #'self.sg_uploaded_movie': '/Users/throb/Downloads/test.m4v', #'self.sg_first_frame': 1, #'self.sg_last_frame': 100, 'self.sg_status_list': 'rev', 'self.sg_task': taskID, 'entity': shot } # here we need to create a field for storing the source file that created this version. # if it's not there, create the field, and if it's there just update it. try: tmp2 = {} tmp2 = tmp['self.sg_source_file'] except: newField = self.sg.schema_field_create('Version', 'text', 'Source File') if sourceFile != '': data['self.sg_source_file'] = sourceFile return self.sg.create('Version', data) # look for specific version def versionFind(self, versionID): '''Find all versions in a shot with most recent first Parameters : (shotID) Output : Version data: ['sg_version_type', 'open_notes_count', 'code', 'playlists', 'sg_task', 'image', 'updated_at', 'sg_output', 'sg_path_to_frames', 'tasks', 'frame_range', 'id', 'description', 'sg_uploaded_movie_webm', 'open_notes', 'tank_published_file', 'task_template', 'created_by', 'sg_movie_type', 'sg_status_list', 'notes', 'sg_client_name', 'sg_uploaded_movie_mp4', 'updated_by', 'sg_send_for_final', 'user', 'sg_uploaded_movie_frame_rate', 'entity', 'step_0', 'sg_client_version', 'sg_uploaded_movie_transcoding_status', 'created_at', 'sg_qt', 'project', 'filmstrip_image', 'tag_list', 'frame_count', 'flagged'] ''' retFields = self.getFields('Version') return self.sg.find('Version', [['id', 'is', versionID]], retFields, [{ 'field_name': 'created_at', 'direction': 'desc' }])[0] # look for versions in a shot: def versionFindShot(self, shotID): '''Find all versions in a shot with most recent first Parameters : (shotID) Output : Version data: ['sg_version_type', 'open_notes_count', 'code', 'playlists', 'sg_task', 'image', 'updated_at', 'sg_output', 'sg_path_to_frames', 'tasks', 'frame_range', 'id', 'description', 'sg_uploaded_movie_webm', 'open_notes', 'tank_published_file', 'task_template', 'created_by', 'sg_movie_type', 'sg_status_list', 'notes', 'sg_client_name', 'sg_uploaded_movie_mp4', 'updated_by', 'sg_send_for_final', 'user', 'sg_uploaded_movie_frame_rate', 'entity', 'step_0', 'sg_client_version', 'sg_uploaded_movie_transcoding_status', 'created_at', 'sg_qt', 'project', 'filmstrip_image', 'tag_list', 'frame_count', 'flagged'] ''' retFields = self.getFields('Version') return self.sg.find('Version', [['entity', 'is', shotID]], retFields, [{ 'field_name': 'created_at', 'direction': 'desc' }]) def versionFindLatest(self, shotID): '''Find only the most recent version Parameters : (shotID) Output : Version data: ['sg_version_type', 'open_notes_count', 'code', 'playlists', 'sg_task', 'image', 'updated_at', 'sg_output', 'sg_path_to_frames', 'tasks', 'frame_range', 'id', 'description', 'sg_uploaded_movie_webm', 'open_notes', 'tank_published_file', 'task_template', 'created_by', 'sg_movie_type', 'sg_status_list', 'notes', 'sg_client_name', 'sg_uploaded_movie_mp4', 'updated_by', 'sg_send_for_final', 'user', 'sg_uploaded_movie_frame_rate', 'entity', 'step_0', 'sg_client_version', 'sg_uploaded_movie_transcoding_status', 'created_at', 'sg_qt', 'project', 'filmstrip_image', 'tag_list', 'frame_count', 'flagged'] ''' retFields = self.getFields('Version') return self.sg.find_one('Version', [['entity', 'is', shotID]], retFields, [{ 'field_name': 'created_at', 'direction': 'desc' }]) # search for the latest task given shotID and task info def versionFindLatestTask(self, shotID, task): retFields = self.getFields('Version') # first look for the task and get the ID filters = [['content', 'is', task], ['entity', 'is', shotID]] taskID = self.sg.find_one('Task', filters) # then look for the latest #version using the task ID. note that we need to use the [0] or else we're sending the array versus the hash versionLatest = self.sg.find_one( 'Version', [['entity', 'is', shotID], ['self.sg_task', 'is', taskID]], retFields, [{ 'field_name': 'created_at', 'direction': 'desc' }]) return versionLatest ## The following requires a field called "client_version" be added to shotgun def versionClientUpdate(self, shotID, version, clientVersionName='Client Version'): '''This takes the shotID and version (int) and updates the shot with this client version number Sometimes the client wants to see different version numbers versus the internal ones. This option allows for it. You will need to create a field. Client Version is what I have used but you can specify what you want here. Parameters: (shotID, version, clientVersionName ='Client Version') Output : Version data ''' sgFieldName = 'sg_' + clientVersionName.lower().replace(' ', '_') data = {sgFieldName: version} try: result = self.sg.update('Shot', shotID['id'], data) except: newField = self.sg.schema_field_create('Shot', 'number', clientVersionName) result = self.sg.update('Shot', shotID['id'], data) return result def uploadQT(self, entityType, item, path): '''Upload a file to shotgun in the 'self.sg_qt' field. If you do this for a shot, you will need to add this to a field the field should be called 'qt' as shotgun will add the self.sg_ to it Shotgun provides the self.sg_qt for versions automatically Parameters: (entity,item,path) uploadQT ('Version',versionData, '/my/file.mov') ''' # Make sure first letter is capitalized entity = entityType.capitalize() # upload that mother if entity.lower() == 'shot': try: result = self.sg.upload(entity, item['id'], path, 'sg_qt') except: newField = self.sg.schema_field_create('Shot', 'url', 'QT') result = self.sg.upload(entity, item['id'], path, 'sg_qt') elif entity.lower() == 'version': result = self.sg.upload(entity, item['id'], path, 'sg_uploaded_movie') return result def versionClientGet(self, shotID, clientVersion='Client Version'): '''Get latest client version number Parameters : (hotID, clientVersion='Client Version') Output : Version data ''' sgFieldName = 'sg_' + clientVersionName.lower().replace(' ', '_') try: currentVersion = shotID[sgFieldName] except: currentVersion = 0 if currentVersion == None: return 0 return currentVersion def playlistFind(self, project, playlistName): '''Search for a playlist given a project and name Parameters : (project, playlistName) Output : playlist data: ['code', 'description', 'versions', 'created_at', 'sg_cinesync_session_url', 'updated_at', 'created_by', 'project', 'filmstrip_image', 'notes', 'image', 'updated_by', 'sg_cinesync_session_key', 'sg_status', 'tag_list', 'id', 'sg_date_and_time'] ''' retFields = self.getFields('Playlist') return self.sg.find_one( 'Playlist', [['code', 'is', playlistName], ['project', 'is', project]], retFields) def playlistCreate(self, project, playlistName, playlistDescription=''): '''Create a playlist given a playlist name Parameters : (project, playlistName, playlistDescription='') Output : playlist data ''' data = { 'project': project, 'code': playlistName, 'description': playlistDescription } return self.sg.create('Playlist', data) # Add a version to a playlist def playlistAddVersion(self, project, playlistName, version): ''' Description :\n This adds a version (existing version in the system) to a playlist.\n You need to give it: (in order)\r shotgun connection class\r project (dict of the project info including name and id)\r playlist name (string of the name of the playlist)\r version (dict of the version you wish to add\n It will return with a dict of the playlist ''' my_playlist_list = self.sg.find_one( 'Playlist', [['code', 'is', playlistName], ['project', 'is', project]], ['versions']) if len(my_playlist_list): ver_list = my_playlist_list['versions'] ver_list.append({ 'type': 'Version', 'name': version['code'], 'id': version['id'] }) result = self.sg.update('Playlist', my_playlist_list['id'], {'versions': ver_list}) return result def playlistInfo(self, project, playlistName): '''Get playlist info (eg version name and description) Parameters : (project, playlistName) Output : version data ''' data = [] versionData = [] retFields = self.getFields('Version') for versionInPlaylist in self.sg.find_one( 'Playlist', [['code', 'is', playlistName], ['project', 'is', project]], ['versions'])['versions']: data.append( self.sg.find_one('Version', [['id', 'is', versionInPlaylist['id']]], retFields)) #for items in data: # versionData.append({'name':items['code'],'desc':items['description'],'first_frame':items['self.sg_first_frame}) return data def getTimeShot(self, shot): '''Given shot (as dict) return total time on shot as [0] and other times for each task on shot ''' outputData = [] retFields = ['content', 'time_logs_sum'] totalTime = 0 for curTask in shot['tasks']: taskData = self.sg.find_one('Task', [['id', 'is', curTask['id']]], fields=retFields) totalTime += taskData['time_logs_sum'] outputData.append({ 'name': taskData['content'], 'time': taskData['time_logs_sum'] }) outputData.insert(0, {'name': shot['code'], 'time': totalTime}) return outputData
# first do the studio location tank.bat studio_tank_bat = os.path.abspath(os.path.join(tank_install_root, "..", "tank.bat")) if os.path.exists(studio_tank_bat): log.info("Updating %s..." % studio_tank_bat) try: this_folder = os.path.abspath(os.path.join( os.path.dirname(__file__))) new_tank_bat = os.path.join(this_folder, "setup", "root_binaries", "tank.bat") log.debug("copying %s -> %s" % (new_tank_bat, studio_tank_bat)) shutil.copy(new_tank_bat, studio_tank_bat) os.chmod(studio_tank_bat, 0775) except Exception, e: log.error("\n\nCould not upgrade core! Please contact support! \nError: %s" % e) pcs = sg.find("PipelineConfiguration", [], ["code", "project", "windows_path", "mac_path", "linux_path"]) for pc in pcs: try: log.info("Processing Pipeline Config %s (Project %s)..." % (pc.get("code"), pc.get("project").get("name"))) local_os_path = pc.get(SG_LOCAL_STORAGE_OS_MAP[sys.platform]) if local_os_path is None: log.info("No pipeline configurations registered for this OS. Skipping...") continue if not os.path.exists(local_os_path): log.info("Pipeline Config does not exist on disk (%s) - skipping..." % local_os_path)
class DBase(object): """Wrapper for database, currently it's Shotgun""" def __init__(self): sgSite = 'https://chimneypot.shotgunstudio.com' scriptName = 'dBase' scriptKey = '729a76955455909c79f6d90262bb9fbe9186b92b' self.db = Shotgun(sgSite, scriptName, scriptKey) def getProjectsDict(self, status='Active', owner='kiev'): filters = [ ['sg_status', 'is', status], ['sg_project_owner', 'is', owner] ] fields = ['name', 'id'] projectsListRaw = self.db.find("Project", filters, fields) projectDict = {x['name']:x['id'] for x in projectsListRaw} return projectDict def getSequencesDict(self, projId): filters = [['project','is',{'type':'Project','id':projId}]] fields = ['code', 'id'] sequencesListRaw = self.db.find("Sequence", filters, fields) sequencesDict = {x['code']:x['id'] for x in sequencesListRaw} return sequencesDict def getShots(self, seqId): filters = [['sg_sequence','is',{'type':'Sequence','id':seqId}]] fields = ['code', 'id'] sequencesListRaw = self.db.find("Shot", filters, fields) sequencesDict = {x['code']:x['id'] for x in sequencesListRaw} return sequencesDict def addProject(self, projName, status='Active', owner='kiev'): data = { 'name': projName, 'sg_status': status, 'sg_project_owner': owner } newProj = self.db.create('Project', data) return newProj def addSequence(self, seqName, projId): data = { 'project': {'type': 'Project', 'id': projId}, 'code': seqName } newSeq = self.db.create('Sequence', data) return newSeq def addShot(self, shName, seqId, projId): data = { 'project': {'type': 'Project', 'id': projId}, 'sg_sequence': {'type': 'Sequence', 'id': seqId}, 'code': shName } newSh = self.db.create('Shot', data) return newSh def getProject(self, projId): filters = [['id', 'is', projId]] fields = ['name'] proj = self.db.find_one("Project", filters, fields) return proj def getSequence(self, seqId): filters = [['id', 'is', seqId]] fields = ['code', 'project', 'shots'] seq = self.db.find_one("Sequence", filters, fields) return seq def getShot(self, shId): filters = [['id', 'is', shId]] fields = ['code', 'project', 'sg_sequence', 'tasks'] sh = self.db.find_one("Shot", filters, fields) return sh
import maya.cmds as cmds import maya.mel as mel import os, sys,threading sys.path.append('//vfx-data-server/dsGlobal/globalResources/Shotgun') from shotgun_api3 import Shotgun try: server = "https://duckling.shotgunstudio.com" scriptName = "assetOpenToShotgun" scriptId = "e932e9c2864c9bcdc3f3ddf8b801cc3d565bf51f" sg = Shotgun(server, scriptName, scriptId) myPeople = sg.find("HumanUser", ["name"]) except: print "could not connect to SG Server" print "THIS IS RUNNING A USERSETUP.PY FILE" try: import vxmaya_setup import vxmaya_file import vxmaya_core except: pass mel.eval("evalDeferred dsMenu;") #mel.eval("evalDeferred overwriteProc;") if sys.platform == "win32": cmds.dirmap( en=True ) cmds.dirmap( m=('/dsPipe/', '//vfx-data-server/dsPipe/') )
contact_template = MyTemplate( '''<script type="text/javascript" src="http://download.skype.com/share/skypebuttons/js/skypeCheck.js"></script> <a href="skype:{{skype_id}}?add"><img src="http://download.skype.com/share/skypebuttons/buttons/add_green_transparent_118x23.png" style="border: none;" width="118" height="23" alt="Add me to Skype" /></a>''' ) #create a shotgun instance sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) #set up the data that we need for each user and look for non-blank skype id's fields = ['id', SKYPE_ID_FIELD, SKYPE_BUTTON_FIELD, SKYPE_ADD_CONTACT_FIELD] filters = [ [SKYPE_ID_FIELD, 'is_not', None], ] #find all the users that have skype-id's users = sg.find("HumanUser", filters, fields) #initialize an empty list to contain shotgun update requests batch_data = [] #process all users checking to see if button data is correct for the user name # (this is in case a skype user name changes) or if there is not a button for user in users: # put skype user name into template to create button html code skype_button_text = button_template.safe_substitute( skype_id=user[SKYPE_ID_FIELD]) skype_contact_text = contact_template.safe_substitute( skype_id=user[SKYPE_ID_FIELD]) if user[SKYPE_BUTTON_FIELD] <> skype_button_text: #set the skype button html into the user container
class ShotgunUtils(): ''' a light version of the shotgun utils class to connect and update shotgun task for external artist ''' def __init__(self): ''' creates the connection to the shotgun site by api ''' ''' shotgun conection ''' SERVER_PATH = "https://hcpstudio.shotgunstudio.com" SCRIPT_NAME = 'Tracker' SCRIPT_KEY = '99b5c166044037cc2d04646b1dfd58b2f44e8a146b710b425b8f561f2a21e49d' self.sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) self.userId = None self.userDic = {} self.tasks = None self.projectPath = None def getsgParameters(self, sgType, parameter=None): schema = self.sg.schema_field_read(sgType, parameter) print schema def getUserId(self, userName): filters = [['name', 'is', userName]] field = ['id', 'name', 'sg_projectpath', 'sg_keyword', 'login'] user = self.sg.find_one('HumanUser', filters, field) if user: self.userId = user['id'] self.projectPath = user['sg_projectpath'] self.userDic = user return user['id'] else: print "no {0} User found ".format(userName) return None def taskByUser(self): if not self.userId == None: filter = [[ 'task_assignees', 'is', { 'type': 'HumanUser', 'id': self.userId } ], ['sg_status_list', 'is_not', 'fin'], ['sg_status_list', 'is_not', 'apr'], ['sg_status_list', 'is_not', 'cmpt']] fields = [ 'id', 'content', 'sg_status_list', 'start_date', 'due_date', 'sg_complexity', 'sg_priority_1', 'sg_note', 'project', 'entity', 'sg_digitalmedia', 'sg_displayname' ] order = [{ 'field_name': 'due_date', 'direction': 'asc' }, { 'field_name': 'sg_priority_1', 'direction': 'asc' }, { 'field_name': 'sg_complexity', 'direction': 'desc' }] taskList = self.sg.find('Task', filter, fields, order) if taskList: self.tasks = taskList return taskList else: self.tasks = [] print "no task Asigned to: ", self.userId return taskList else: taskList = [] print "no Id found" return taskList def getTaskById(self, taskId): filter = [['id', 'is', taskId]] fields = [ 'id', 'content', 'sg_status_list', 'start_date', 'due_date', 'sg_complexity', 'sg_priority_1', 'sg_note', 'project', 'entity', 'sg_digitalmedia', 'sg_displayname' ] task = self.sg.find_one('Task', filter, fields) if task: return task else: print 'no task found' return None def updateStatusFromUser(self, taskId, status): task = self.getTaskById(taskId) if task: project = task['project'] sgStatus = status data = {'project': project, 'sg_status_list': sgStatus} self.sg.update('Task', taskId, data) return 1 else: print 'No task by this id' return None def updateProjectPath(self, projectPath): data = {'sg_projectpath': projectPath} self.sg.update('HumanUser', self.userId, data) def getNotes(self, sgTaskId): task = self.getTaskById(sgTaskId) if task: filters = [['tasks', 'is', task]] fields = ['content', 'created_at', 'user', 'addressings_to'] order = [{'field_name': 'created_at', 'direction': 'asc'}] notes = self.sg.find('Note', filters, fields, order) return notes else: print 'no Task' return None def createNote(self, taskId, content): task = self.getTaskById(taskId) if task: data = { 'project': task['project'], 'content': content, 'tasks': [task], 'user': self.userDic, 'subject': 'Note' } note = self.sg.create('Note', data) return note['id'] else: return None def uploadAttachment(self, taskId, filePath, tag): task = self.getTaskById(taskId) if task: entity = task['entity'] if entity: entityType = entity['type'] entityId = entity['id'] uploadedfile = self.sg.upload(entityType, entityId, filePath) if uploadedfile: data = {'sg_type': tag, 'sg_taskid': taskId} self.sg.update('Attachment', uploadedfile, data) return uploadedfile else: return None else: print 'no entity set' return None def downloadAttachment(self, taskId, downloadPath, parent=None): filters = [['sg_taskid', 'is', taskId], ['sg_type', 'is', 'REFERENCE']] fields = ['id', 'attachment_links', 'filename', 'created_at'] attachments = self.sg.find('Attachment', filters, fields) if attachments: progressBar = QtGui.QProgressBar(parent) progressBar.show() size = len(attachments) for x, attach in enumerate(attachments): extension = path.splitext(attach['filename']) dt = attach['created_at'].strftime("%Y_%m_%d_%H-%M-%S") name = attach['attachment_links'][0]['id'] namePadded = '{0}_{3}.{1:04d}{2}'.format( name, x, extension[-1], dt) fullPath = path.join(downloadPath, namePadded) dwFile = self.sg.download_attachment(attach, fullPath, attach['id']) progressBar.setValue(((x + 1) / size) * 100) progressBar.close() return attachments else: return None def uploadReference(self, entityType, entityId, filePath, tag, taskId): uploadedfile = self.sg.upload(entityType, entityId, filePath) if uploadedfile: data = { 'sg_type': tag, 'sg_type': 'REFERENCE', 'sg_taskid': taskId } self.sg.update('Attachment', uploadedfile, data) return uploadedfile else: return None
"sg_task_order", "Id", # 'created_at', "entity.Shot.sg_status_list", # 'content', "start_date", "due_date", "entity.Shot.sg_title", "entity.Shot.sg_title_name", # 'upstream_tasks', # 'downstream_tasks', # 'dependency_violation', # 'pinned' ] results = sg.find("Task", filters, fields) print "Due Date\tShot Code\tTitle\tTitle Name\tContent\tAssigned To" for r in results: s = str(r["due_date"]) if s == "None": print "None\t" + str(r["entity.Shot.code"]) + "\t" + str(r["entity.Shot.sg_title"]) + "\t" + str( r["entity.Shot.sg_title_name"] ) + "\t" + str(r["content"]) else: dueDate = datetime.strptime(s, "%Y-%m-%d") for u in r["task_assignees"]: print str(dueDate) + "\t" + str(r["entity.Shot.code"]) + "\t" + str(r["entity.Shot.sg_title"]) + "\t" + str( r["entity.Shot.sg_title_name"] ) + "\t" + str(r["content"]) + "\t" + str(u["name"])
class Main(QtGui.QWidget, Ui_Form, ReferenceTab, CommentWidget, Lib, TaskManager, MyTasks, WhatsNew, Asset, LogEntry, Task, AssetLoader, Moodboard_Creator, PeopleTab, RenderTab): def __init__(self): super(Main, self).__init__() self.username = os.getenv('USERNAME') self.setWindowFlags(self.windowFlags() | QtCore.Qt.CustomizeWindowHint) self.ReferenceTab = ReferenceTab self.Lib = Lib self.TaskManager = TaskManager self.RenderTab = RenderTab self.MyTasks = MyTasks self.WhatsNew = WhatsNew self.CommentWidget = CommentWidget self.Task = Task self.Asset = Asset self.AssetLoader = AssetLoader self.LogEntry = LogEntry self.Moodboard_Creator = Moodboard_Creator self.PeopleTab = PeopleTab sg_url = "http://nad.shotgunstudio.com" sg_script_name = "ThibaultGenericScript" sg_key = "e014f12acda4074561022f165e8cd1913af2ba4903324a72edbb21430abbb2dc" self.sg_project_id = 146 self.sg = Shotgun(sg_url, sg_script_name, sg_key) # Initialize the guis self.Form = self.setupUi(self) self.Form.center_window() self.setMinimumSize(1453, 923) self.setMaximumSize(1453, 923) self.db_to_load = "" self.db_path = "Z:\\Groupes-cours\\NAND999-A15-N01\\Nature\\_pipeline\\_utilities\\_database\\nature.sqlite" # Database nature if QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier: # Database Setup self.db_path = "H:\\01-NAD\\_pipeline\\_utilities\\_database\\db.sqlite" # Copie de travail # Backup database if self.db_path not in ["H:\\01-NAD\\_pipeline\\_utilities\\_database\\db.sqlite", "Z:\\Groupes-cours\\NAND999-A15-N01\\Nature\\_pipeline\\_utilities\\_database\\rendering.sqlite"]: self.backup_database() self.db = sqlite3.connect(self.db_path, check_same_thread=False, timeout=30.0) self.cursor = self.db.cursor() # Global Variables self.projectList.hide() self.i = 0 self.computer_id = socket.gethostname() self.ref_assets_instances = [] self.selected_asset = None self.utf8_codec = QtCore.QTextCodec.codecForName("utf-8") self.today = time.strftime("%d/%m/%Y", time.gmtime()) self.cur_path = os.path.dirname(os.path.realpath(__file__)) # H:\01-NAD\_pipeline\_utilities\_asset_manager self.cur_path_one_folder_up = self.cur_path.replace("\\_asset_manager", "") # H:\01-NAD\_pipeline\_utilities self.NEF_folder = self.cur_path_one_folder_up + "\\_NEF" # H:\01-NAD\_pipeline\_utilities\NEF self.screenshot_dir = self.cur_path_one_folder_up + "\\_database\\screenshots\\" self.no_img_found = self.cur_path + "\\media\\no_img_found.png" self.number_of_refreshes = 0 self.members = {"acorbin":"Alexandre", "fpasquarelli":"Francis", "costiguy": "Chloe", "cgonnord": "Christopher", "erodrigue": "Etienne", "jberger": "Jeremy", "lgregoire": "Laurence", "lclavet": "Louis-Philippe", "mbeaudoin": "Mathieu", "mroz": "Maxime", "obolduc": "Olivier", "slachapelle": "Simon", "thoudon": "Thibault", "vdelbroucq": "Valentin", "yjobin": "Yann", "yshan": "Yi"} self.sg_members = {"acorbin": "3dalcor", "fpasquarelli": "francis.pasquarelli", "costiguy": "ostiguy.chloe", "cgonnord": "christopher.gonnord", "erodrigue": "etienne.rodrigue89", "jberger": "jeremy.berger3d", "lgregoire": "lau-gregoire", "lclavet": "clavet.lp", "mbeaudoin": "beaudoinmathieu", "mroz": "maximeroz", "obolduc": "ol.bolduc", "slachapelle": "simonlachapelle", "thoudon": "houdon.thibault", "vdelbroucq": "valentin.delbroucq", "yjobin": "yannjobinphoto", "yshan": "yishan3d"} self.departments_shortname = {"Script": "spt", "Storyboard": "stb", "References": "ref", "Concepts": "cpt", "Modeling": "mod", "Texturing": "tex", "Rigging": "rig", "Animation": "anm", "Simulation": "sim", "Shading": "shd", "Camera": "cam", "Lighting": "lgt", "Layout": "lay", "DMP": "dmp", "Rendering":"rdr", "Compositing": "cmp", "Editing": "edt", "RnD": "rnd"} self.departments_longname = {"spt": "Script", "stb": "Storyboard", "ref": "References", "cam": "Camera", "cpt": "Concepts", "lgt": "Lighting", "mod": "Modeling", "tex": "Texturing", "rig": "Rigging", "anm": "Animation", "sim": "Simulation", "shd": "Shading", "lay": "Layout", "dmp": "DMP", "rdr":"Rendering", "cmp": "Compositing", "edt": "Editing", "rnd": "RnD"} refresh_icon = QtGui.QIcon(self.cur_path + "\\media\\refresh.png") self.refreshAllBtn.setIcon(refresh_icon) self.refreshAllBtn.setIconSize(QtCore.QSize(24, 24)) self.refreshAllBtn.clicked.connect(self.refresh_all) # Setup user session if it is not already setup is_setup = self.cursor.execute('''SELECT is_setup FROM preferences WHERE username=?''', (self.username,)).fetchone()[0] if is_setup == 0: self.Lib.setup_user_session(self) self.cursor.execute('''UPDATE preferences SET is_setup=1 WHERE username=?''', (self.username,)) self.db.commit() # Clear temp folder if os.path.isdir("H:/tmp"): try: shutil.rmtree("H:/tmp") except: pass try: os.makedirs("H:/tmp") except: pass # Create Favicon self.app_icon = QtGui.QIcon() self.app_icon.addFile(self.cur_path + "\\media\\favicon_cube.png", QtCore.QSize(64, 64)) self.Form.setWindowIcon(self.app_icon) # Set the StyleSheet self.themePrefComboBox.currentIndexChanged.connect(self.change_theme) self.theme = self.cursor.execute('''SELECT theme FROM preferences WHERE username=?''', (self.username,)).fetchone()[0] self.themePrefComboBox.setCurrentIndex(int(self.theme)) self.change_theme() # Admin Setup self.remove_tabs_based_on_members() # Get remaining time and set deadline Progress Bar day_start = date(2015,6,28) day_end = date(2016,4,25) day_today = datetime.now().date() months_and_days_left = relativedelta.relativedelta(day_end, day_today) total_days = abs(day_end - day_start).days remaining_days = abs(day_end - date.today()).days remaining_days_percent = (remaining_days * 100) / total_days # Converts number of remaining day to a percentage self.deadlineProgressBar.setFormat("{0} months and {1} days left ({2}%)".format(months_and_days_left.months, months_and_days_left.days, remaining_days_percent)) self.deadlineProgressBar.setMaximum(total_days) self.deadlineProgressBar.setValue(remaining_days) hue = self.fit_range(remaining_days, 0, total_days, 0, 76) self.deadlineProgressBar.setStyleSheet("QProgressBar::chunk {background-color: hsl(" + str(hue) + ", 255, 205);}") if self.username not in ["thoudon", "lclavet", "costiguy"]: self.deadlineFrame.hide() # Setup disk usage progress bar disk_usage = self.Lib.get_folder_space(self) disk_usage = int(float(disk_usage) * 1000) # Multiply disk usage by 1000. Ex: 1.819 to 1819 disk_usage = (2000 * int(disk_usage)) / 1862 # 2TO in theory = 1.862GB in reality. Remapping real disk usage to the theoric one self.diskUsageProgressBar.setFormat('{0}/2000 GB'.format(str(disk_usage))) self.diskUsageProgressBar.setRange(0, 2000) self.diskUsageProgressBar.setValue(int(disk_usage)) hue = self.fit_range(int(disk_usage), 0, 2000, 0, 76) self.diskUsageProgressBar.setStyleSheet("QProgressBar::chunk {background-color: hsl(" + str(hue) + ", 255, 205);}") # Thumbnail creation progress bar setup self.thumbnailProgressBar.setStyleSheet("QProgressBar::chunk {background-color: hsl(0, 100, 175);}") self.thumbnailProgressBar.setValue(0) self.thumbnailProgressBar.hide() # Get software paths from database and put them in preference self.photoshop_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Photoshop"''').fetchone()[0]) self.maya_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Maya"''').fetchone()[0]) self.maya_batch_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Maya Batch"''').fetchone()[0]) self.softimage_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Softimage"''').fetchone()[0]) self.softimage_batch_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Softimage Batch"''').fetchone()[0]) self.houdini_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Houdini"''').fetchone()[0]) self.houdini_batch_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Houdini Batch"''').fetchone()[0]) self.cinema4d_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Cinema 4D"''').fetchone()[0]) self.nuke_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Nuke"''').fetchone()[0]) self.zbrush_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="ZBrush"''').fetchone()[0]) if os.path.exists("C:/Program Files/Mari2.6v2/Bundle/bin/Mari2.6v2.exe"): self.mari_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Mari"''').fetchone()[0]) else: self.mari_path = "C:/Program Files/Mari2.6v5/Bundle/bin/Mari2.6v5.exe" self.blender_path = str(self.cursor.execute('''SELECT software_path FROM software_paths WHERE software_name="Blender"''').fetchone()[0]) self.cursor.execute('''UPDATE preferences SET is_online=1 WHERE username=?''', (self.username,)) self.db.commit() # Preferences setup self.prefBckGroundColorSlider.sliderMoved.connect(self.change_pref_background_color_pixmap) self.prefBckGroundColorSlider.setStyleSheet("background-color; red;") # Set systray actions self.quitAction = QtGui.QAction("Quit", self, triggered=self.terminate_program) self.quitAction.setIcon(QtGui.QIcon(self.cur_path + "/media/turn_off.png")) # Systray icon self.trayIconMenu = QtGui.QMenu(self) self.trayIconMenu.addAction(self.quitAction) self.tray_icon = QtGui.QIcon(self.cur_path + "\\media\\favicon_cube.png") self.trayIcon = QtGui.QSystemTrayIcon(self) self.trayIcon.setContextMenu(self.trayIconMenu) self.trayIcon.setIcon(self.tray_icon) self.tray_icon_log_id = "" self.tray_message = "" self.trayIcon.hide() #self.tray_icon.messageClicked.connect(self.tray_icon_message_clicked) self.trayIcon.activated.connect(self.tray_icon_clicked) # Initialize modules and connections AssetLoader.__init__(self) self.ReferenceTab.__init__(self) self.RenderTab.__init__(self) self.CommentWidget.__init__(self) self.WhatsNew.__init__(self) self.PeopleTab.__init__(self) self.WhatsNew.load_whats_new(self) self.check_last_active() #self.check_news_thread = CheckNews(self) #self.connect(self.check_news_thread, QtCore.SIGNAL("check_last_active"), self.check_last_active) #self.check_news_thread.daemon = True #self.check_news_thread.start() self.show() #self.check_shotgun_time_log() def check_shotgun_time_log(self): self.username = "******" peoples = {"acorbin":"Alexandre Corbin", "costiguy":"Chloé Ostiguy", "cgonnord":"Christopher Gonnord", "erodrigue":"Etienne Rodrigue", "fpasquarelli":"Francis Pasquarelli", "jberger":"Jérémy Berger", "lgregoire":"Laurence Grégoire", "lclavet":"Louis-Philippe Clavet", "mbeaudoin":"Mathieu Beaudoin", "mroz":"Maxime Roz", "thoudon":"Thibault Houdon", "vdelbroucq":"Valentin Delbroucq", "yjobin":"Yann Jobin", "yshan":"Yi Shan"} user = peoples[self.username] project = self.sg.find_one("Project", [["id", "is", self.sg_project_id]]) time_log = self.sg.find("TimeLog", [["date", "in_calendar_day", -1], ["project", "is", project]], ["user"]) people_logged = [log["user"]["name"] for log in time_log] people_logged = list(set(people_logged)) if user not in people_logged: time_log_window = QtGui.QDialog(self) time_log_window.setWindowTitle("Add your time log entry") layout = QtGui.QVBoxLayout(time_log_window) descriptionLabel = QtGui.QLabel(time_log_window) durationLabel = QtGui.QLabel(time_log_window) descriptionLabel.setText("Description") durationLabel.setText("Duration") self.description = QtGui.QLineEdit(time_log_window) self.duration = QtGui.QLineEdit(time_log_window) addLogEntryBtn = QtGui.QPushButton(time_log_window) addLogEntryBtn.setText("Add Time Log Entry") addLogEntryBtn.clicked.connect(self.shotgun_add_time_log) didntWorkBtn = QtGui.QPushButton(time_log_window) didntWorkBtn.setText("I didn't work on this project yesterday.") layout.addWidget(durationLabel) layout.addWidget(self.duration) layout.addWidget(descriptionLabel) layout.addWidget(self.description) layout.addWidget(addLogEntryBtn) layout.addWidget(didntWorkBtn) time_log_window.exec_() def shotgun_add_empty_time_log(self): pass def shotgun_add_time_log(self): print(self.description.text()) print(self.duration.text()) def add_tag_to_tags_manager(self): # Check if a project is selected if len(self.projectList.currentText()) == 0: Lib.message_box(text="Please select a project first.") return tag_name = unicode(self.addTagLineEdit.text()) tag_name = Lib.normalize_str(self, tag_name) if len(tag_name) == 0: Lib.message_box(text="Please enter a tag name.") return item = QtGui.QTreeWidgetItem(self.tagsTreeWidget) item.setText(0, tag_name) self.tagsTreeWidget.addTopLevelItem(item) self.addTagLineEdit.setText("") self.save_tags_list() def remove_selected_tags_from_tags_manager(self): root = self.tagsTreeWidget.invisibleRootItem() for item in self.tagsTreeWidget.selectedItems(): (item.parent() or root).removeChild(item) self.save_tags_list() def save_tags_list(self): root = self.tagsTreeWidget.invisibleRootItem() # Fetch the root item child_count = root.childCount() for item in xrange(child_count): # Get the text of the first item in the tree widget parent_text = str(root.child(item).text(0)) # Check if item already exists, if no, add it to the database, if yes, update its name and parent already_exist = self.cursor.execute('''SELECT tag_name FROM tags WHERE tag_name=?''', (parent_text,)).fetchone() if already_exist == None: self.cursor.execute('''INSERT INTO tags(project_name, tag_name, tag_parent) VALUES(?,?,?)''', (self.selected_project_name, parent_text, "",)) else: self.cursor.execute('''UPDATE tags SET tag_name=?, tag_parent=? WHERE tag_name=? AND project_name=?''', (parent_text, "", parent_text, self.selected_project_name,)) # Get all children of parent item nbr_of_children = root.child(item).childCount() for i in range(nbr_of_children): child_text = str(root.child(item).child(i).text(0)) # Check if item already exists, if no, add it to the database, if yes, update its name and parent already_exist = self.cursor.execute('''SELECT tag_name FROM tags WHERE tag_name=?''', (child_text,)).fetchone() if already_exist == None: self.cursor.execute('''INSERT INTO tags(project_name, tag_name, tag_parent) VALUES(?,?,?)''', (self.selected_project_name, child_text, parent_text,)) else: self.cursor.execute('''UPDATE tags SET tag_name=?, tag_parent=? WHERE tag_name=? AND project_name=?''', (child_text, parent_text, child_text, self.selected_project_name,)) self.db.commit() def add_assets_to_asset_list(self, assets_list): """ Add assets from assets_list to self.assetList """ self.assetList.clear() for asset in assets_list: self.assetList.addItem(asset[4]) def clear_filter(self, filter_type): """ Clear the filter edit line """ if filter_type == "seq": self.seqFilter.setText("") elif filter_type == "asset": self.assetFilter.setText("") def update_thumb(self): """ Update selected asset thumbnail """ self.Form.showMinimized() Lib.take_screenshot(self.screenshot_dir, self.selected_asset_name) pixmap = QtGui.QPixmap(self.screenshot_dir + self.selected_asset_name + ".jpg").scaled(1000, 200, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self.assetImg.setPixmap(pixmap) self.Form.showMaximized() self.Form.showNormal() def remove_tabs_based_on_members(self): if not (self.username == "thoudon" or self.username == "lclavet"): self.adminPrefFrame.hide() self.createAssetFromScratchBtn.hide() self.get_tabs_id_from_name() if self.members[self.username] == "Chloe": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Francis": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Alexandre": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Christopher": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Etienne": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Jeremy": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Laurence": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Louis-Philippe": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Mathieu": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Maxime": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Olivier": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Simon": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Thibault": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() elif self.members[self.username] == "Yann": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Yi": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Valentin": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) def get_tabs_id_from_name(self): self.tabs_list = {} for i in xrange(self.Tabs.count()): self.tabs_list[str(self.Tabs.tabText(i))] = i def change_username(self): username = str(self.usernameAdminComboBox.currentText()) self.username = username def backup_database(self): # Get creation_time of last database backup and compare it to current time database_files = Lib.get_files_from_folder(self, path="Z:\\Groupes-cours\\NAND999-A15-N01\\Nature\\_pipeline\\_utilities\\_database\\_backup") if len(database_files) > 1000: self.Lib.message_box(self, type="error", text=u"Trop de backups détectés pour la base de donnée. Veuillez avertir Thibault, merci ;)") cur_db_name = os.path.split(self.db_path)[-1].replace(".sqlite", "") database_files = [i for i in database_files if cur_db_name in os.path.split(i)[-1]] database_files = sorted(database_files) last_database_file = database_files[-1] creation_time = time.ctime(os.path.getctime(last_database_file)) creation_time = time.strptime(creation_time, "%a %b %d %H:%M:%S %Y") current_time = str(datetime.now()) current_time = time.strptime(current_time, "%Y-%m-%d %H:%M:%S.%f") time_difference = (time.mktime(current_time) - time.mktime(creation_time)) / 60 if time_difference > 180: # If last backup is older than 5 hours, do a backup fileName, fileExtension = os.path.splitext(last_database_file) last_database_file_version = int(fileName.split("_")[-1]) new_version = str(last_database_file_version + 1).zfill(4) backup_database_filename = fileName.replace(str(last_database_file_version).zfill(4), new_version) + ".sqlite" shutil.copy(self.db_path, backup_database_filename) def refresh_all(self): self.blockSignals(True) #Default refreshes self.mt_item_added = True self.item_added = True self.setup_tags() #Get current tab text current_tab_text = self.Tabs.tabText(self.Tabs.currentIndex()) if current_tab_text == "Asset Loader": self.statusLbl.setText("Status: Refreshing Asset Loader tab...") self.repaint() self.AssetLoader.load_all_assets_for_first_time(self) self.AssetLoader.load_assets_from_selected_seq_shot_dept(self) elif current_tab_text == "Task Manager": self.statusLbl.setText("Status: Refreshing Task Manager tab...") self.repaint() TaskManager.add_tasks_from_database(self) elif current_tab_text == "Tasks": self.statusLbl.setText("Status: Refreshing Tasks tab...") self.repaint() MyTasks.mt_add_tasks_from_database(self) elif current_tab_text == "Render": self.statusLbl.setText("Status: Refreshing Render tab...") self.repaint() RenderTab.add_computers_from_database(self) RenderTab.add_jobs_from_database(self) RenderTab.add_frames_from_database(self) elif current_tab_text == "People": self.statusLbl.setText("Status: Refreshing People tab...") self.repaint() self.PeopleTab.get_online_status(self) self.cursor.execute('''UPDATE preferences SET last_active=? WHERE username=?''', (datetime.now().strftime("%d/%m/%Y at %H:%M"), self.username,)) self.db.commit() elif current_tab_text == "Images Manager": self.statusLbl.setText("Status: Refreshing Images Manager tab...") self.repaint() if len(self.ref_assets_instances) > 1: self.ReferenceTab.refresh_reference_list(self) elif "What's New" in current_tab_text: self.statusLbl.setText("Status: Refreshing What's New tab...") self.repaint() self.WhatsNew.load_whats_new(self) self.statusLbl.setText("Status: Idle...") self.blockSignals(False) def change_theme(self): if self.themePrefComboBox.currentIndex() == 0: self.theme = 0 self.prefBckGroundColorSlider.setValue(114) self.Lib.apply_style(self, self) self.cursor.execute('''UPDATE preferences SET theme=? WHERE username=?''', (0, self.username,)) elif self.themePrefComboBox.currentIndex() == 1: self.theme = 1 self.prefBckGroundColorSlider.setValue(241) self.setStyleSheet("") app.setStyle(QtGui.QStyleFactory.create("cleanlooks")) self.cursor.execute('''UPDATE preferences SET theme=? WHERE username=?''', (1, self.username,)) css = QtCore.QFile(self.cur_path + "\\media\\cleanlooks.css") css.open(QtCore.QIODevice.ReadOnly) if css.isOpen(): self.Form.setStyleSheet(QtCore.QVariant(css.readAll()).toString().replace("checkbox|placeholder", self.cur_path.replace("\\", "/") + "/media/checkbox.png")) elif self.themePrefComboBox.currentIndex() == 2: self.prefBckGroundColorSlider.setValue(255) self.theme = 2 self.setStyleSheet("") app.setStyle(QtGui.QStyleFactory.create("plastique")) self.cursor.execute('''UPDATE preferences SET theme=? WHERE username=?''', (2, self.username,)) self.db.commit() def change_pref_background_color_pixmap(self): slider_value = self.prefBckGroundColorSlider.value() self.referenceThumbListWidget.setStyleSheet("background-color: rgb({0},{0},{0});".format(slider_value)) def tray_icon_message_clicked(self): if self.tray_message == "Manager is in background mode.": return clicked_log_entry = self.cursor.execute('''SELECT log_value FROM log WHERE log_id=?''', (self.tray_icon_log_id,)).fetchone()[0] clicked_log_description = self.cursor.execute('''SELECT log_entry FROM log WHERE log_id=?''', (self.tray_icon_log_id,)).fetchone()[0] if len(clicked_log_entry) == 0: return asset = self.Asset(main=self, id=clicked_log_entry, get_infos_from_id=True) if "reference" in clicked_log_description: if "video" in clicked_log_description: subprocess.Popen(["C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", asset.dependency]) else: if os.path.isfile(asset.full_path): os.system(asset.full_path) else: self.Lib.message_box(self, text="Can't find reference: it must have been deleted.") elif "comment" in clicked_log_description: self.CommentWidget(main=self, asset=asset) def tray_icon_clicked(self, reason): if reason == QtGui.QSystemTrayIcon.DoubleClick: if self.isHidden(): self.setWindowFlags(QtCore.Qt.Widget) self.show() self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) self.trayIcon.hide() else: self.hide() self.trayIcon.show() def keyPressEvent(self, event): global_pos = self.mapFromGlobal(QtGui.QCursor.pos()) widget_under_mouse = self.childAt(global_pos) key = event.key() if key == QtCore.Qt.Key_F11: if self.isFullScreen(): self.showNormal() else: self.showFullScreen() elif key == QtCore.Qt.Key_Delete: current_tab_text = self.Tabs.tabText(self.Tabs.currentIndex()) if current_tab_text == "Images Manager": ReferenceTab.remove_selected_references(self) elif key == QtCore.Qt.Key_F2: selected_reference = self.referenceThumbListWidget.selectedItems()[0] asset = selected_reference.data(QtCore.Qt.UserRole).toPyObject() ReferenceTab.rename_reference(self, asset) elif key == QtCore.Qt.Key_F1: self.show_wiki_help(widget_under_mouse) elif key == QtCore.Qt.Key_F5: self.refresh_all() def show_wiki_help(self, widget): if widget.objectName() == "publishBtn": subprocess.Popen(["C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", "file:///Z:/Groupes-cours/NAND999-A15-N01/Nature/_info/wiki/wiki.html#Modeling"]) def closeEvent(self, event): if not self.trayIcon.isVisible(): self.setWindowFlags(QtCore.Qt.Tool) self.hide() self.trayIcon.show() self.tray_message = "Manager is in background mode." self.trayIcon.showMessage('Still running...', self.tray_message, QtGui.QSystemTrayIcon.Information, 1000) self.hide() event.ignore() self.trayIcon.show() def terminate_program(self): # tasks = subprocess.check_output(['tasklist']) # if "houdin" in tasks.lower(): # self.Lib.message_box(self, type="error", text="Please close Houdini layout scenes before closing the Manager!") # return self.cursor.execute('''UPDATE preferences SET is_online=0 WHERE username=?''', (self.username,)) self.db.commit() self.Lib.switch_mari_cache(self, "perso") self.close() app.exit() # self.quit_msg = "Are you sure you want to exit the program?" # reply = QtGui.QMessageBox.question(self, 'Are you leaving :(', # quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) # # if reply == QtGui.QMessageBox.Yes: # # event.accept() # else: # event.ignore() def changeEvent(self, event): if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: self.setWindowFlags(QtCore.Qt.Tool) self.hide() self.trayIcon.show() self.tray_message = "Manager is in background mode." self.trayIcon.showMessage('Still running...', self.tray_message, QtGui.QSystemTrayIcon.Information, 1000) def check_last_active(self): for user in self.members.keys(): last_active = datetime.now().strftime("%d/%m/%Y at %H:%M") last_active_datetime = datetime.strptime(last_active, '%d/%m/%Y at %H:%M') last_active_db = self.cursor.execute('''SELECT last_active FROM preferences WHERE username=?''', (user, )).fetchone()[0] last_active_db_datetime = datetime.strptime(last_active_db, '%d/%m/%Y at %H:%M') time_difference = last_active_datetime - last_active_db_datetime if time_difference.seconds > 600: self.cursor.execute('''UPDATE preferences SET is_online=0 WHERE username=?''', (user,)) else: self.cursor.execute('''UPDATE preferences SET is_online=1 WHERE username=?''', (user,)) last_active = datetime.now().strftime("%d/%m/%Y at %H:%M") self.cursor.execute('''UPDATE preferences SET last_active=? WHERE username=?''', (last_active, self.username,)) self.db.commit()
import yaml import urllib2 from urlparse import urlparse import cookielib from shotgun_api3 import Shotgun blob = yaml.load(sys.stdin) method = sys.argv[1] config = blob['config'] payload = blob['data'] sg = Shotgun(config['shotgun_url'], config['script_name'], config['script_api_key'], 'api3_preview') if method == 'find': result = sg.find(payload['entity'], payload['filters'], payload['fields'], payload['order'], payload['filter_operator'], payload['limit'], payload['retired_only']) elif method == 'find_one': result = sg.find_one(payload['entity'], payload['filters'], payload['fields'], payload['order'], payload['filter_operator']) elif method == 'create': result = sg.create(payload['entity'], payload['data']) elif method == 'update': result = sg.update(payload['entity'], payload['id'], payload['data']) elif method == 'delete': result = sg.delete(payload['entity'], payload['id']) elif method == 'upload': result = sg.upload(payload['entity'], payload['id'], payload['path'], payload['field_name'], payload['display_name']) elif method == 'upload_thumbnail': result = sg.upload_thumbnail(payload['entity'], payload['id'], payload['path']) elif method == 'schema_field_read': result = sg.schema_field_read(payload['entity']) elif method == 'schema_field_create':
log.info("Updating %s..." % studio_tank_bat) try: this_folder = os.path.abspath( os.path.join(os.path.dirname(__file__))) new_tank_bat = os.path.join(this_folder, "setup", "root_binaries", "tank.bat") log.debug("copying %s -> %s" % (new_tank_bat, studio_tank_bat)) shutil.copy(new_tank_bat, studio_tank_bat) os.chmod(studio_tank_bat, 0775) except Exception, e: log.error( "\n\nCould not upgrade core! Please contact support! \nError: %s" % e) pcs = sg.find( "PipelineConfiguration", [], ["code", "project", "windows_path", "mac_path", "linux_path"]) for pc in pcs: try: log.info("Processing Pipeline Config %s (Project %s)..." % (pc.get("code"), pc.get("project").get("name"))) local_os_path = pc.get(SG_LOCAL_STORAGE_OS_MAP[sys.platform]) if local_os_path is None: log.info( "No pipeline configurations registered for this OS. Skipping..." ) continue
SCRIPT_USER = '******' SCRIPT_KEY = '987fd62624610c1580c070441f1ae208653541f9' sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) M = imaplib.IMAP4_SSL('imap.gmail.com', 993) M.login('*****@*****.**', 'PASSWORD') M.select("eng-support") # mailbox/tag name typ, data = M.search(None, 'ALL') for num in data[0].split(): typ, msgdata = M.fetch(num, '(RFC822)') #print 'Message %s\n%s\n' % (num, data[0][1]) msg_dict = parse.parse(msgdata[0][1]) print "message from %s" % msg_dict["from"] people = sg.find("HumanUser", [['email', 'is', msg_dict["from"]]], ['id', 'name']) if len(people) < 1: print "couldn't find user" else: # if we find a valid user, create a ticket for them user = people[0] ticket_data = { 'created_by': { 'type': 'HumanUser', 'id': user['id'] }, 'addressings_to': [{ 'type': 'Group', 'id': 5 }], 'title': msg_dict['subject'],
##shotgun try: from shotgun_api3 import Shotgun except: print "no module named Shotgun" SERVER_PATH = "http://show.macrograph.co.kr" SCRIPT_NAME = "testapi" SCRIPT_KEY = "b4332cb2077957915585fafdf27f252bdaf8a3ada1450970d0c69743253de823" sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) assetALL = sg.find('Asset', [['project.Project.name', 'is', 'dst']], ['image', 'code']) print assetALL
from shotgun_api3 import Shotgun import os SCRIPT_NAME = 'Samuel - API' SCRIPT_KEY = '2b3f3b6e442242c067501a9e17503bac1d27b6ea244a4e4b5987e26d5f6520e2' sg = Shotgun("https://objeus.shotgunstudio.com", SCRIPT_NAME, SCRIPT_KEY) echars = sg.find('Attachment', [['attachment_links', 'type_is', 'CustomEntity06']], ['attachment_links']) for echar in echars: sg.download_attachment( echar, os.path.abspath( os.path.expanduser("importdata/" + echar['attachment_links'][0]['name'] + ".json")))
# set up templates for the skype button button_template = MyTemplate('''<script type="text/javascript" src="http://download.skype.com/share/skypebuttons/js/skypeCheck.js"></script> <a href="skype:{{skype_id}}?call"><img src="http://download.skype.com/share/skypebuttons/buttons/call_blue_white_124x52.png" style="border: none;" width="124" height="52" alt="Skype Me!" />''') contact_template = MyTemplate('''<script type="text/javascript" src="http://download.skype.com/share/skypebuttons/js/skypeCheck.js"></script> <a href="skype:{{skype_id}}?add"><img src="http://download.skype.com/share/skypebuttons/buttons/add_green_transparent_118x23.png" style="border: none;" width="118" height="23" alt="Add me to Skype" /></a>''') #create a shotgun instance sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) #set up the data that we need for each user and look for non-blank skype id's fields = ['id', SKYPE_ID_FIELD , SKYPE_BUTTON_FIELD , SKYPE_ADD_CONTACT_FIELD] filters = [[SKYPE_ID_FIELD , 'is_not', None ],] #find all the users that have skype-id's users= sg.find("HumanUser",filters,fields) #initialize an empty list to contain shotgun update requests batch_data = [] #process all users checking to see if button data is correct for the user name # (this is in case a skype user name changes) or if there is not a button for user in users: # put skype user name into template to create button html code skype_button_text = button_template.safe_substitute(skype_id=user[SKYPE_ID_FIELD]) skype_contact_text = contact_template.safe_substitute(skype_id=user[SKYPE_ID_FIELD]) if user[SKYPE_BUTTON_FIELD] <> skype_button_text: #set the skype button html into the user container user[SKYPE_BUTTON_FIELD] = skype_button_text user[SKYPE_ADD_CONTACT_FIELD] = skype_contact_text
db.query("set character_set_connection=utf8;") db.query("set character_set_server=utf8;") db.query("set character_set_client=utf8;") db.query("set character_set_results=utf8;") SERVER_PATH = "http://show.macrograph.co.kr" SCRIPT_NAME = "testapi" SCRIPT_KEY = "b4332cb2077957915585fafdf27f252bdaf8a3ada1450970d0c69743253de823" sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) field = ['name','sg_status','sg_description','image','start_date','end_date'] projectsALL = sg.find('Project',[],field) for project in projectsALL: project_name = project['name'] status = project['sg_status'] description = project['sg_description'] thumbnail = project['image'] start_date = project['start_date'] end_date = project['end_date'] if thumbnail == None: thum = "noimage.jpg" else: thum = "%s_" % (datetime.today().strftime('%Y%m%d')) + str(uuid.uuid4())[:8] + ".jpg" thum_path = "/home/crystal/MG/asset/thumnail/small_thum/%s" % thum
from shotgun_api3 import Shotgun from glob import glob import json SCRIPT_NAME = 'Samuel - API' SCRIPT_KEY = '2b3f3b6e442242c067501a9e17503bac1d27b6ea244a4e4b5987e26d5f6520e2' sg = Shotgun("https://objeus.shotgunstudio.com", SCRIPT_NAME, SCRIPT_KEY) epers = sg.find('CustomEntity07', [], ['code']) efiles = sg.find('Attachment', [['attachment_links', 'type_is', 'CustomEntity07']], ['attachment_links']) efilenames = {} for efile in efiles: efilenames[efile['attachment_links'][0]['name']] = efile['id'] print efilenames enames = {} for eper in epers: enames[eper['code']] = eper print enames pers = glob('pers/*.json') for per in pers: with open(per) as json_data: temp = json.load(json_data) json_data.close() data = { 'code': temp['name'], 'description': temp['desc'], 'sg_arcana': temp['arcana'], 'sg_level': (int)(temp['level']),
progressBar.setValue(100) progressBar.setFormat("Computing done") logLabel.setText(outputText.replace(" "," ")) cout("done : " + str (ev) ) f.write("</dir></body></html>") f.close() datafileName = "c:/temp/EVENTLOG/eventManager_"+projectId["name"]+"_"+ today +".pkl" displayDataContext_perDay( workstationDict, projectId["name"], datafileName ) if __name__ == '__main__': SERVER_PATH = "https://nozon.shotgunstudio.com" SCRIPT_NAME = 'noteManager' SCRIPT_KEY = '3fbb2a5f180457af709fcad231c96ac8a916711427af5a06c47eb1758690f6e4' import sys sys.path.append("Z:/Dev/cyril/python/PACKAGES") from shotgun_api3 import Shotgun sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) projetcLit = sg.find("Project", [], ["name"]) for projectContext in projetcLit : print "\n\n###########\tPROJECT\t############\n\t\t" , projectContext["name"], projectContext["id"] launch(None, None, [] , None, projectContext, sg )
# Make the jobs directory makeDir(root) # Change directory os.chdir(root) # Start Shotgun calls fields = ['id', 'code', 'name', 'sg_status'] filters = [ ['sg_status', 'is', 'Active'], #['id', 'is_not', 4] # Add project ids to ignore ] projects = sg.find("Project",filters,fields) print projects print for p in projects: print p projectName = p['name'] makeDir(projectName) filters = [ ['project', 'is', {'type':'Project', 'id':p['id']}] ]
SCRIPT_USER = '******' SCRIPT_KEY = '987fd62624610c1580c070441f1ae208653541f9' sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) M = imaplib.IMAP4_SSL('imap.gmail.com', 993) M.login('*****@*****.**', 'PASSWORD') M.select("eng-support") # mailbox/tag name typ, data = M.search(None, 'ALL') for num in data[0].split(): typ, msgdata = M.fetch(num, '(RFC822)') #print 'Message %s\n%s\n' % (num, data[0][1]) msg_dict = parse.parse(msgdata[0][1]) print "message from %s" % msg_dict["from"] people = sg.find("HumanUser",[['email','is',msg_dict["from"]]],['id','name']) if len(people) < 1: print "couldn't find user" else: # if we find a valid user, create a ticket for them user = people[0] ticket_data = { 'created_by': {'type':'HumanUser','id':user['id']}, 'addressings_to': [{'type':'Group','id':5}], 'title': msg_dict['subject'], 'description': msg_dict['body'], 'project': {'type':'Project', 'id':178}, } sg.create('Ticket', ticket_data, return_fields=['id']) # if we made it this far the e-mail was processed, now delete it
CURRENT_VERSION_FIELD = '********' # get this from the "Configure Field" dialog in shotgun sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) fields = ['id', 'entity', 'sg_asset_type'] # version id, shot info, "version" # sg_current_version field to upate #TEST VALUES TO BE SET BY POST FROM ACTION MENU version_ids = [19, 20, 93] # replace with result from the post project_id = 64 # Replace this with the result from the post for a_version_id in version_ids: filters = [['project', 'is', { 'type': 'Project', 'id': project_id }], ['id', 'is', a_version_id]] assets = sg.find("Version", filters, fields) if len(assets) < 1: print "couldn't find any assets" exit(0) else: for an_asset in assets: entity_type = an_asset['entity'][ 'type'] # should always be 'Shot'! if entity_type == 'Shot': # we always expect a shot but OK to test shot_id = an_asset['entity']['id'] linked_version = {'type': 'Version', 'id': a_version_id} data = {CURRENT_VERSION_FIELD: linked_version} changed_asset = sg.update("Shot", shot_id, data) pprint(changed_asset) else:
class DownloadPlaylist(QWidget): def __init__(self, parent = None): QWidget.__init__(self, parent) self.setWindowTitle('Check Playlist local files...') ## Set base vars self.missingLocalFiles = [] self.missingLocalFilesDict = {} self.onlineFilesDict = {} self.tempSGFiles = [] self.badfiles = [] self.badfileBoxes = [] self.tempFileCheckBoxes = [] self.localFileCheckBoxes = [] self.playlist = [] ## Start the UI Build self.mainLayout = QVBoxLayout(self) self.allPlayLists = '' ## Instance the api for talking directly to shotgun. base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'audioUploader' api_key = 'bbfc5a7f42364edd915656d7a48d436dc864ae7b48caeb69423a912b930bc76a' self.sgsrv = Shotgun(base_url = base_url , script_name = script_name, api_key = api_key, ensure_ascii=True, connect=True) self.allPlayLists = [] ### Now find the playlists from shotgun to use. self._populatePlaylists() self.playListLayout = QHBoxLayout(self) self.playListDropDown = QComboBox(self) self.playListDropDown.setMinimumWidth(200) self.playListDropDown.setMaximumHeight(25) self.playListSearchLabel = QLabel('Search') self.playListSearchInput = QLineEdit(self) self.playListSearchInput.textChanged.connect(self._searchDropDown) self.playListLayout.addWidget(self.playListDropDown) self.playListLayout.addWidget(self.playListSearchLabel) self.playListLayout.addWidget(self.playListSearchInput) self.checkForLocal = QPushButton('Check Local Files Exist...') self.checkForLocal.clicked.connect(self._checkFiles) self.checkForLocal.setStyleSheet("QPushButton {background-color: green}") self.downloadFilesButton = QPushButton('Click to download missing files...') self.downloadFilesButton.clicked.connect(self._processDownload) self.downloadFilesButton.setStyleSheet("QPushButton {background-color: green}") self.updateList() self.mainLayout.addLayout(self.playListLayout) self.mainLayout.addWidget(self.checkForLocal) self.mainLayout.addWidget(self.downloadFilesButton) self.downloadFilesButton.hide() ### Now do the check boxes for files.... ### FILES TO LOCAL PROJECT FOLDER self.scrollLayout = QScrollArea(self) self.scrollLayout.setMinimumHeight(50) self.filesGroupBox = QGroupBox(self.scrollLayout) self.filesGroupBox.setTitle('Files to download to local drive') self.filesGroupBox.setFlat(True) self.scrollLayout.setWidget(self.filesGroupBox) self.scrollLayout.setWidgetResizable(True) self.fileLayout = QGridLayout(self.filesGroupBox) ### FILES TO LOCAL PROJECT FOLDER self.scrollLayout2 = QScrollArea(self) self.scrollLayout2.setMinimumHeight(50) self.filesGroupBox2 = QGroupBox(self.scrollLayout2) self.filesGroupBox2.setTitle('Files to download to temp folder') self.filesGroupBox2.setFlat(True) self.scrollLayout2.setWidget(self.filesGroupBox2) self.scrollLayout2.setWidgetResizable(True) self.tempFilesLayout = QGridLayout(self.filesGroupBox2) ### FILES TO LOCAL PROJECT FOLDER self.scrollLayout3 = QScrollArea(self) self.scrollLayout3.setMinimumHeight(50) self.filesGroupBox3 = QGroupBox(self.scrollLayout3) self.filesGroupBox3.setTitle('BAD FILES! Contact Co-Ord to fix.') self.filesGroupBox3.setFlat(True) self.scrollLayout3.setWidget(self.filesGroupBox3) self.scrollLayout3.setWidgetResizable(True) self.badFileCheckBoxLayout = QGridLayout(self.filesGroupBox3) self.mainLayout.addWidget(self.scrollLayout) self.mainLayout.addWidget(self.scrollLayout2) self.mainLayout.addWidget(self.scrollLayout3) def _populatePlaylists(self): self.pendingReview = self.sgsrv.find('Playlist', filters = [["sg_status", "is", 'rev']], fields=['code', 'created_at', 'versions']) self.delivered = self.sgsrv.find('Playlist', filters = [["sg_status", "is", 'dlvr']], fields=['code', 'created_at', 'versions']) if self.pendingReview: for eachPL in self.pendingReview: self.allPlayLists.append(eachPL) if self.delivered: for eachPL in self.delivered: self.allPlayLists.append(eachPL) def _clearLists(self): #os.system('echo clearing lists now...') if self.localFileCheckBoxes != []: for each in self.localFileCheckBoxes: try: each.setParent(None) sip.delete(each) each = None except RuntimeError: pass if self.tempFileCheckBoxes != []: for each in self.tempFileCheckBoxes: try: each.setParent(None) sip.delete(each) each = None except RuntimeError: pass if self.badfileBoxes != []: for each in self.badfileBoxes: try: each.setParent(None) sip.delete(each) each = None except RuntimeError: pass def _doFileCheckboxes(self): """ Process all the files found into check boxes for processing """ self._clearLists() self.badfileBoxes = [] self.tempFileCheckBoxes = [] self.localFileCheckBoxes = [] ## LOCAL DOWNLOAD ## First add the ALL checkbox self.ALL_Local = QCheckBox(self) self.ALL_Local.setChecked(False) self.ALL_Local.setText('Toggle All') self.ALL_Local.toggled.connect(self._toggleAllLocal) self.fileLayout.addWidget(self.ALL_Local, 0, 0) self.colCount = 5 r = 1 c = 1 for eachType in sorted(self.missingLocalFiles): self.fileCheckBox = QCheckBox(self) self.fileCheckBox.setChecked(True) self.fileCheckBox.setText(eachType) self.localFileCheckBoxes.append(self.fileCheckBox) if c == self.colCount: r = r + 1 c = 1 self.fileLayout.addWidget(self.fileCheckBox, r, c) c = c + 1 ## TEMP FILES ## First add the ALL checkbox self.ALL_Temp = QCheckBox(self) self.ALL_Temp.setChecked(False) self.ALL_Temp.setText('Toggle All') self.ALL_Temp.toggled.connect(self._toggleAllTemp) self.tempFilesLayout.addWidget(self.ALL_Temp, 0, 0) self.colCount = 5 r = 1 c = 1 for eachType in sorted(self.tempSGFiles): self.fileCheckBox = QCheckBox(self) self.fileCheckBox.setChecked(True) self.fileCheckBox.setText(eachType) self.tempFileCheckBoxes.append(self.fileCheckBox) if c == self.colCount: r = r + 1 c = 1 self.tempFilesLayout.addWidget(self.fileCheckBox, r, c) c = c + 1 ## BAD FILES self.colCount = 5 r = 1 c = 1 for eachType in sorted(self.badfiles): self.fileCheckBox = QLabel(self) self.fileCheckBox.setText(eachType) self.fileCheckBox.setStyleSheet("QLabel {background-color:red; text-align:center;}") self.badfileBoxes.append(self.fileCheckBox) if c == self.colCount: r = r + 1 c = 1 self.badFileCheckBoxLayout.addWidget(self.fileCheckBox, r, c) c = c + 1 self.repaint() def _toggleAllTemp(self): for eachBox in self.tempFileCheckBoxes: if self.ALL_Temp.isChecked(): eachBox.setChecked(True) else: eachBox.setChecked(False) def _toggleAllLocal(self): for eachBox in self.localFileCheckBoxes: if self.ALL_Local.isChecked(): eachBox.setChecked(True) else: eachBox.setChecked(False) def _searchDropDown(self): self.playListDropDown.clear() for eachPlayList in sorted(self.allPlayLists): if str(self.playListSearchInput.text()) in eachPlayList['code']: self.playListDropDown.addItem(eachPlayList['code']) def updateList(self): self.playListDropDown.clear() for eachPlayList in sorted(self.allPlayLists): self.playListDropDown.addItem(eachPlayList['code']) def _setPlaylist(self): """ Set the playlist from the current pulldown """ for eachPlayList in self.allPlayLists: if eachPlayList['code'] == self.playListDropDown.currentText(): print 'Fetching versions for %s now..' % eachPlayList['code'] self.playlist = eachPlayList else: pass def _getVersionInfo(self, versionData): """ Function to process the version data from shotgun If we are under darwin osx change the path to local to match our project drives so the path to local is correct for osx """ getVersInfo = self.sgsrv.find_one('Version', filters = [["id", "is", versionData['id']]], fields = ['code', 'sg_path_to_movie', 'sg_uploaded_movie']) pathToLocal = getVersInfo['sg_path_to_movie'] ## Process the osx pathToLocal if sys.platform == 'darwin': if pathToLocal: pathToLocal = pathToLocal.replace('I:', '/_projects').replace("\\", "/") getVersInfo['sg_path_to_movie'] = pathToLocal ## Now process the URL try: url = getVersInfo['sg_uploaded_movie']['url'] except TypeError: url = None return getVersInfo['code'], pathToLocal, url, getVersInfo def _checkFiles(self): self._clearLists() os.system('cls') #os.system('echo Checking Playlist: %s \n' % self.playListDropDown.currentText()) os.system('echo Looking for files on local drive....\n') self.tempSGFiles = [] self.missingLocalFiles = [] self.missingLocalFilesDict = {} self.onlineFilesDict = {} self.badfiles = [] self.getVersions = [] self.playList = [] self.missingUploadedMoveMsg = 'MISSING UPLOADED MOVIE. THIS NEEDS TO BE FIXED. PLEASE CONTACT CO-ORD ABOUT THIS!' ###################################################### ## Set the state for the UI into checking for files... self.checkForLocal.setText('Checking files...') self.checkForLocal.setStyleSheet("QPushButton {background-color: yellow}") self.downloadFilesButton.hide() self.repaint() ###################################################### ###################################################### ## Scan each path to local and then check for existing files. self._setPlaylist() self.getVersions = self.playlist['versions'] if self.getVersions: for eachVer in self.playlist['versions']: ###################################################### ## Fetch the version information from shotgun versionName, pathToLocal, url, getVersInfo = self._getVersionInfo(eachVer) print 'Checking \t%s now...' % versionName ###################################################### ## If we have a valid path to local in shotgun.... if pathToLocal and 'B:' not in pathToLocal and 'Shotgun' not in pathToLocal: print 'Path: \t\t%s' % pathToLocal ## Now check to see if the path to the file is true or not. pathExists = os.path.isfile(pathToLocal) os.system('echo EXISTS?: \t%s' % pathExists) ## If it doesn't exist mark this file for download to local path if not pathExists: ## Check if we can download this file from an uploaded movie!?! if url: os.system('echo DL: \t\t%s\n' % versionName) os.system('echo .') ## Add the file to the list for the check-boxes, and the dictionary used for download info if eachVer['name'] not in self.missingLocalFiles: self.missingLocalFiles.append(versionName)## For the check-boxes self.missingLocalFilesDict[versionName] = getVersInfo ## For the down loader else: os.system('echo %s %s' % (versionName, self.missingUploadedMoveMsg)) os.system('echo .') ## Add the file to the bad list of files as we are missing an online uploaded file to download. if eachVer['name'] not in self.badfiles: self.badfiles.append(eachVer['name']) ## If the file does exist on the local HD, check to see if we have to resume it or not. ## Check the file sizes match if they don't add to missing files.. else: if url: ## Find the online file size and compare it against the local file size on disk u = urllib2.urlopen(url) meta = u.info() onlinefileSize = int(meta.getheaders("Content-Length")[0]) localmeta = os.stat('%s' % pathToLocal) if not localmeta.st_size == onlinefileSize: os.system('echo Filesize mismatch for %s marking for download again..\n' % pathToLocal.split(os.sep)[-1]) os.system('echo Size On Disk: %.8f \tSize On SGun: %.8f' % (float(localmeta.st_size)/1000000, float(onlinefileSize)/1000000)) #print localmeta.st_size #17,892,757 bytes os.system('echo .') ## Add the file to the list for the check-boxes, and the dictionary used for download info if eachVer['name'] not in self.missingLocalFiles: self.missingLocalFiles.append(versionName)## For the check-boxes self.missingLocalFilesDict[versionName] = getVersInfo ## For the down loader else: os.system('echo %s %s' % (versionName, self.missingUploadedMoveMsg)) os.system('echo .') if eachVer['name'] not in self.badfiles: self.badfiles.append(eachVer['name']) else: ## We don't have a valid path in shotgun to a local file! if url: ## But we do have a url to an uploaded movie... os.system('echo No local path found in shotgun field for %s. File will be saved to Temp folder...' % versionName) os.system('echo .') ## Add the file to the list for the check-boxes, and the dictionary used for download info if eachVer['name'] not in self.tempSGFiles: self.tempSGFiles.append(getVersInfo['code']) ## for the check-boxes self.onlineFilesDict[getVersInfo['code']] = getVersInfo ## For the down loader else: ## OOPS this is missing both a local path and uploaded movie in shotgun :( :( :( os.system('echo %s MISSING UPLOADED MOVIE AND LOCAL PATH!!!! THIS NEEDS TO BE FIXED. PLEASE CONTACT CO-ORD ABOUT THIS!' % versionName) os.system('echo .') ## Add the file to the list of bad files. self.badfiles.append(eachVer['name']) else: print '%s has NO versions! This playlist is empty! PLEASE CONTACT CO-ORD ABOUT THIS!' % self.playlist['code'] ######################################## ## NOW CHECK THE FINAL LISTS AND SET THE UI INTO THE CORRECT STATE ## EITHER READY FOR DOWNLOAD OR START A NEW CHECK if self.missingLocalFiles or self.tempSGFiles or self.badfiles: self.downloadFilesButton.show() self.checkForLocal.setText('Check Complete...click to check again...') self.checkForLocal.setStyleSheet("QPushButton {background-color: orange}") ## Now process the check box lists... self._doFileCheckboxes() else: os.system('echo CHECKS OUT OKAY!! ALL FILES EXIST FOR THIS PLAYLIST.....\n') self.checkForLocal.setText('Check Local File Exist...') self.checkForLocal.setStyleSheet("QPushButton {background-color: green}") ## Now clear out all the checkboxes. self._clearLists() def _downloadFile(self, pathToLocal, url): """ Main download function """ fileName = pathToLocal.split(os.sep)[-1] u = urllib2.urlopen(url) meta = u.info() file_size = int(meta.getheaders("Content-Length")[0]) #os.system('cls') os.system('echo Downloading: %s \tSize: %.2f MB\n' % (fileName, float(file_size)/1000000)) f = open(pathToLocal, 'wb') file_size_dl = 0 block_sz = 8192 while True: buffer = u.read(block_sz) if not buffer: break file_size_dl += len(buffer) f.write(buffer) status = r".........%20s: %34.2f MB [%3.2f%%]" % (fileName, float(file_size_dl)/1000000, file_size_dl * 100. / file_size) status = status + chr(8)*(len(status)+1) print status, f.close() os.system('echo \n') os.system('echo Download Complete....') def _resumeDownload(self, pathToLocal, url, localSize, totalSGFileSize): """ Resume download function """ fileName = pathToLocal.split(os.sep)[-1] req = urllib2.Request(url) remainingB = totalSGFileSize - localSize ## Now set the header for the range req.headers["Range"] = "bytes=%s-%s" % (localSize, totalSGFileSize) u = urllib2.urlopen(req) #create the connection meta = u.info() file_size = int(meta.getheaders("Content-Length")[0]) #os.system('cls') os.system('echo Resuming: %s \tSize: %.2f MB \tRemaining: %.2f MB\n' % (fileName, float(totalSGFileSize)/1000000, float(remainingB)/1000000)) f = open(pathToLocal, 'ab') file_size_dl = 0 block_sz = 8192 while True: buffer = u.read(block_sz) if not buffer: break file_size_dl += len(buffer) ## Now write to the file.. f.write(buffer) ## Now print the satus status = r".........%20s: %34.2f Mb [%3.2f%%]" % (fileName, float(file_size_dl)/1000000, file_size_dl * 100. / totalSGFileSize) status = status + chr(8)*(len(status)+1) print status, f.close() os.system('echo \n') os.system('echo Download Complete....') def _preDownload(self, pathToLocal, url): """ Function to check if the file exists on the local hd if it doesn't match that of the online file """ ## First check to see if the file exists! if not os.path.isfile(pathToLocal): ## Do a full download of the file now. self._makeDirectories(pathToLocal) self._downloadFile(pathToLocal, url) else: ## The file exists, lets check to resume or skip it. u = urllib2.urlopen(url) meta = u.info() onlinefileSize = int(meta.getheaders("Content-Length")[0]) localmeta = os.stat(pathToLocal) if localmeta.st_size == onlinefileSize: os.system('echo %s already down-loaded skipping...\n' % pathToLocal) return elif localmeta.st_size > onlinefileSize: ## Delete it, it's a bad download.... print 'Removing %s ...' % pathToLocal.split(os.sep)[-1] os.remove(pathToLocal) try: self._downloadFile(pathToLocal, url) except IOError, e: os.system('echo OH NO!: %s' % e) os.system('echo Try a restart of the application and check the files again to solve this problem...') else:
import datetime import logging import logging.config import gluon.contrib.simplejson # shotgun sys.path.append('/X/tools/pythonlib') from shotgun_api3 import Shotgun SG = Shotgun(sg_server, sg_script_name, sg_script_key) session.departments = [] if not session.departments: session.departments = SG.find('Department', [['sg_status_list', 'is', 'act']], fields=['code', 'name', 'color'], order=[{'field_name':'name', 'direction':'asc'}] ) session.dept_to = [] session.dept_ny = [] for d in session.departments: if d['code'].upper().startswith('NY'): session.dept_ny.append(d['id']) else: session.dept_to.append(d['id']) PROJECT_STATUS = ['Active', 'Bidding', 'Demo/Test', 'Delivered'] if not session.projects: result = SG.find('Project', [['sg_status', 'in', PROJECT_STATUS]], fields=['code','name', 'color', 'sg_status'], order=[{'field_name':'name', 'direction':'asc'}]
#from dBase import * from shotgun_api3 import Shotgun import os site = 'https://chimneypot.shotgunstudio.com' scriptName = 'dBase' scriptKey = '729a76955455909c79f6d90262bb9fbe9186b92b' pName = 'kievPipelineTest' sg = Shotgun(site, scriptName, scriptKey) lst = sg.find('HumanUser', [['updated_at', 'not_in_last', 1, 'MONTH'],['sg_status_list', 'is', 'act']], ['name', 'updated_at', 'sg_status_list']) for i in lst: print "%s: %s, %s, %s"%(i['name'],i['updated_at'], i['sg_status_list'], i['id']) killEric = sg.update('HumanUser', 62, {'sg_status_list':'dis'}) def test(): print 'huy' return sg
form_project_id = form.getvalue('project_id') # and convert to values that can be used by Shotgun API (list and ints) version_ids = [int(x) for x in selected_ids_str.split(',') ] # list of ints from a string project_id = int(form_project_id) # integer from string success = True # keep track of errors so that true success for all requests can be reported to the user filters = [ ['project', 'is', { 'type': 'Project', 'id': project_id }], ['id', 'in'] + version_ids, ] versions = sg.find("Version", filters, fields) found_shots = set( ) # a set to hold all of the found shots so we can error if we need to... for a_version in versions: #pre-process all shots looking for duplicates print "</br>" if a_version['entity']['name'] in found_shots: raise MultiShotError( 'There is more than one version of shot %s in your request' % a_version['entity']['name']) else: found_shots.add(a_version['entity']['name']) for a_version in versions: # re-process all shots to set the current version field correctly entity_type = a_version['entity']['type'] # should always be 'Shot'! if entity_type == 'Shot': # we always expect a shot but OK to test
#sh.write(1, 10, "not filled \n# @ # ") sh.write(1, 10, "blank\nno data filled",BLANK_TASK_CELL) sh.col(0).width = 0x0ff0 sh.col(1).width = 0x0ff0 sh.col(2).width = 0x0ff0 sh.col(3).width = 0x0ff0 sh.col(4).width = 0x0ff0 sh.col(5).width = 0x0ff0 sh.col(6).width = 0x0ff0 sh.col(7).width = 0x0ff0 sh.col(8).width = 0x0ff0 sh.col(9).width = 0x0ff0 sh.col(10).width = 0x0ff0 #sh.row(0).write(col_0, 'Issue', HEADER_CELL) for cont in sg.find('HumanUser',filters , fields): maxTaskinaWeek = get_maxTask(cont['id']) # get max task for each artist for a week AtrName = sg.find_one('HumanUser',[["id","is",cont['id']]],['name'])['name'] sh.write(row, 0, AtrName,ARTIST_CELL) MaxTaskFirstPointer = row #if (AtrName == "Gyaneshwar Reddy") : rowRegister = row # save row initial value columnRegister = column # save column initial value for idx, val in enumerate(get_week(datetime.datetime.now().date() - datetime.timedelta(days=7))): #for d in get_week(datetime.datetime.now().date()): total = 0 column = column + 1 if (val.isoformat() <= datetime.date.today().strftime("%Y-%m-%d")): ret = sg.find('TimeLog',[['user','is',{"type":"HumanUser","id":cont['id']}],\ ["date","is",val.isoformat()]], ["duration","entity"])
class dMFXsubmitterDialog(QDialog, Ui_dMFXsubmitter): def __init__(self, parent = None): # set up the UI and variable here - don't forget to call updateUI at end super(dMFXsubmitterDialog,self).__init__(parent) self.acceptDrops() self.setupUi(self) # generic call to setup the Ui provided by Qt self.password = '' self.version_file_path = '' self.user = '' self.user_id = '' self.user_name = '' self.user_initials = '' self.submit_movie = False self.movie_file_path = '' self.description = '' self.login_status = False self.allOK = True self.submit_call_track = True self.version_type = 'Shot' self.created_version_id = None self.sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) self.sgu = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) self.users_with_initals = INITIALS_LIST self.user_list = [] self.lineEdit_versionFile.dragEnterEvent = types.MethodType(dragEnterEvent,self.lineEdit_versionFile) self.lineEdit_versionFile.dropEvent = types.MethodType(dropEvent,self.lineEdit_versionFile) self.lineEdit_versionFile.setAcceptDrops(True) self.lineEdit_versionFile.setDragEnabled(True) self.lineEdit_forReview.dragEnterEvent = types.MethodType(dragEnterEvent,self.lineEdit_forReview) self.lineEdit_forReview.dropEvent = types.MethodType(dropEvent,self.lineEdit_forReview) self.lineEdit_forReview.setAcceptDrops(True) self.lineEdit_forReview.setDragEnabled(True) # start things happening... get the users from sg and populate them into the drop-down self.update_user_list() self.connect(self,SIGNAL('update'),self.updateUI) self.new_value = 'this is not a new value' #self.emit(SIGNAL("update")) self.updateUI() def update_user_list(self): filters = [ ['sg_status_list', 'is', 'act' ],] fields = ['name', 'login'] users = self.sg.find('HumanUser', filters, fields) user_list = [ (user['name'],user['login'],user['id']) for user in users if user['name'] != 'Template User'] user_list.sort() self.user_list = user_list self.comboBox_artistSelect.addItem('Please Select...') self.user = '******' for user in user_list: self.comboBox_artistSelect.addItem(user[0]) self.updateUI() def reset_to_go_again(self): # todo set all fields to blank, not just update the values... self.version_file_path = '' self.submit_movie = False self.movie_file_path = '' self.description = '' self.allOK = True self.created_version_id = None self.plainTextEdit_description.setPlainText('') self.lineEdit_versionFile.setText('') self.lineEdit_forReview.setText('') self.updateUI() def updateUI(self): # make sure that the UI is updated to match input self.activateWindow() # window gets keyboard focus after redraw self.allOK = True self.description = str(self.plainTextEdit_description.toPlainText()) # check user and if it needs initials, activate the text box if self.user in self.users_with_initals: self.lineEdit_initials.setEnabled(True) else: self.lineEdit_initials.setEnabled(False) # check user to see if one has been selected... set login to default if it has and there is no login set if self.user == STARTING_USER_LIST_TEXT: self.pushButton_login.setEnabled(False) else: self.pushButton_login.setEnabled(True) if not self.login_status: self.pushButton_login.setDefault(True) # check to see if logged in - if not, disable everything below login if self.login_status: self.label_password.setText("** Logged In **") self.pushButton_login.setEnabled(False) self.comboBox_artistSelect.setEnabled(False) else: self.label_password.setText("Shotgun Password") self.pushButton_login.setEnabled(True) # check the submit checkbox and enable fields if set if self.checkBox_forReview.isChecked(): self.lineEdit_forReview.setEnabled(True) self.pushButton_getForReview.setEnabled(True) self.submit_movie=True # check for movie submit check-box if self.submit_movie: self.lineEdit_forReview.setEnabled(True) self.pushButton_getForReview.setEnabled(True) else: self.lineEdit_forReview.setEnabled(False) self.pushButton_getForReview.setEnabled(False) # check for a need for initals if self.user in INITIALS_LIST: self.label_initials.setText('Add Your Initials') self.lineEdit_initials.show() else: self.label_initials.setText('') self.lineEdit_initials.hide() self.user_initials = '' self.lineEdit_initials.setText('') # check to see if the version file is a movie and, if so and the movie line is empty, fill that in if self.version_file_path and os.path.splitext(str(self.version_file_path).lower())[1] in MOVIE_FILE_EXTENSION_LIST and not self.movie_file_path: self.movie_file_path = str(self.version_file_path) self.lineEdit_forReview.setText(self.movie_file_path) # check for conditions that allow an update to happen conditions = True # start by assuming we can go and switch if we can't if self.user in INITIALS_LIST and not self.user_initials: conditions = False if conditions and not self.login_status: conditions = False if conditions and self.version_file_path and not os.path.exists(self.version_file_path): conditions = False if conditions and self.submit_movie: if self.movie_file_path and not os.path.exists(self.movie_file_path): conditions = False if not self.movie_file_path: conditions = False #enable the submit button if appropriate if conditions: self.pushButton_submit.setEnabled(True) self.pushButton_submit.setDefault(True) else: self.pushButton_submit.setEnabled(False) # self.pushButton_login @pyqtSignature("") def on_pushButton_login_clicked(self): result = self.sgu.authenticate_human_user(self.user_name, self.lineEdit_password.text()) if result: self.login_status = True else: # user tried to log in and failed - let them know QMessageBox.about(self, "Log In Error", "Unable to login to Shotgun using your user/pass combination, please try again") self.updateUI() # self.pushButton_getVersionFile @pyqtSignature("") def on_pushButton_getVersionFile_clicked(self): self.version_file_path = str(QFileDialog.getOpenFileName(self, "Select the file to submit as a Version" )) if self.version_file_path: self.lineEdit_versionFile.setText(self.version_file_path) self.updateUI() # self.pushButton_getForReview @pyqtSignature("") def on_pushButton_getForReview_clicked(self): self.movie_file_path = str(QFileDialog.getOpenFileNameAndFilter(self, "Select a movie file to submit for screening", filter= "Movies ( *.mp4 *.mov)")[0]) # the getopenfile returns a tuple of length 2 if self.movie_file_path: self.lineEdit_forReview.setText(self.movie_file_path) self.updateUI() # self.pushButton_quit @pyqtSignature("") def on_pushButton_quit_clicked(self): QApplication.quit() # self.checkBox_forReview @pyqtSignature("bool") def on_checkBox_forReview_clicked(self): #lcheckBox_forReview boolean toggle code here self.submit_movie = self.checkBox_forReview.isChecked() self.updateUI() # self.comboBox_artistSelect @pyqtSignature("QString") def on_comboBox_artistSelect_currentIndexChanged(self): if self.user: self.user = self.comboBox_artistSelect.currentText() self.user_name = [ user[1] for user in self.user_list if user[0] == self.user][0] self.user_id = [ user[2] for user in self.user_list if user[0] == self.user][0] self.updateUI() # self.comboBox_version_type @pyqtSignature("QString") def on_comboBox_version_type_currentIndexChanged(self): self.version_type = str(self.comboBox_version_type.currentText()) self.updateUI() # self.lineEdit_forReview @pyqtSignature("QString") def on_lineEdit_forReview_textEdited(self): self.movie_file_path = str(self.lineEdit_forReview.text()) self.emit(SIGNAL("update")) # self.lineEdit_initials @pyqtSignature("QString") def on_lineEdit_initials_textEdited(self): self.user_initials = str(self.lineEdit_initials.text()) self.updateUI() # self.lineEdit_versionFile @pyqtSignature("QString") def on_lineEdit_versionFile_textEdited(self): self.version_file_path = str(self.lineEdit_versionFile.text()) self.updateUI() # self.lineEdit_versionFile @pyqtSignature("QString") def on_lineEdit_versionFile_textChanged(self): self.version_file_path = str(self.lineEdit_versionFile.text()) self.updateUI() # self.plainTextEdit_description @pyqtSignature("") def on_plainTextEdit_description_textEdited(self): self.updateUI() # self.pushButton_submit @pyqtSignature("") def on_pushButton_submit_clicked(self): if not self.submit_call_track: self.submit_call_track = True return else: self.submit_call_track = False sgerrmsg = "There were no matching {0}s, make sure that you have selected the right kind of entity and try again" if not self.allOK: return try: self.created_version_id = update_shotgun(self.sg, self.version_file_path, self.description, self.user_id, self.version_type, self.user_initials, self ) if not self.created_version_id: # sg did not find anything! Tell the user and let them try again or quit self.allOK = False sub_dialog = dMFXsubmitterSubDialog( "No Matches", "Reset", "QUIT!", sgerrmsg.format(self.version_type), boxeditable = False, parent=self ) button, text, pick = sub_dialog.getValues() if sub_dialog.exec_(): sub_dialog.close() button, text, pick = sub_dialog.getValues() if button == 'No' : QApplication.quit() else: return # return if they click on Retry else: return # return if they close the window mainlabel = "Success!" yeslabel = 'Go Again' nolabel = 'QUIT!' boxtext = 'Your version was successfully created' if self.allOK and self.submit_movie: if not do_submit_for_review(self.sg,self.movie_file_path,self.created_version_id): # the sym-link failed for some reason after 2 tries... mainlabel = "Partial Success..." boxtext = "Your version was created but the movie was NOT put into today's Review Folder. Please add it manually, or resubmit the Version" except Exception,e: mainlabel = "ERROR!" yeslabel = 'Reset' nolabel = 'QUIT!' boxtext = 'Something Went Horribly Wrong! -\nError: {0}\n{1}'.format(e,traceback.format_exc()) #QMessageBox.about(self, "updateUI", output_string) sub_dialog = dMFXsubmitterSubDialog(mainlabel,yeslabel,nolabel, boxtext ) if sub_dialog.exec_(): sub_dialog.close() button, text, pick = sub_dialog.getValues() if button == 'No' : QApplication.quit() else: self.reset_to_go_again()
form = cgi.FieldStorage() # Get data from fields selected_ids_str = form.getvalue('selected_ids') form_project_id = form.getvalue('project_id') # and convert to values that can be used by Shotgun API (list and ints) version_ids=[int(x) for x in selected_ids_str.split(',')] # list of ints from a string project_id =int(form_project_id) # integer from string success = True # keep track of errors so that true success for all requests can be reported to the user filters = [ ['project','is',{'type':'Project','id':project_id}], ['id', 'in' ] + version_ids , ] versions= sg.find("Version",filters,fields) found_shots = set() # a set to hold all of the found shots so we can error if we need to... for a_version in versions: #pre-process all shots looking for duplicates print "</br>" if a_version['entity']['name'] in found_shots: raise MultiShotError( 'There is more than one version of shot %s in your request' % a_version['entity']['name'] ) else: found_shots.add( a_version['entity']['name'] ) for a_version in versions: # re-process all shots to set the current version field correctly entity_type = a_version['entity']['type'] # should always be 'Shot'! if entity_type == 'Shot': # we always expect a shot but OK to test shot_id = a_version['entity']['id'] linked_version = { 'type' : 'Version' , 'id' : a_version['id'] }
SCRIPT_USER = "******" # your script name SCRIPT_KEY = "********" # your key here CURRENT_VERSION_FIELD = "********" # get this from the "Configure Field" dialog in shotgun sg = Shotgun(SERVER_PATH, SCRIPT_USER, SCRIPT_KEY) fields = ["id", "entity", "sg_asset_type"] # version id, shot info, "version" # sg_current_version field to upate # TEST VALUES TO BE SET BY POST FROM ACTION MENU version_ids = [19, 20, 93] # replace with result from the post project_id = 64 # Replace this with the result from the post for a_version_id in version_ids: filters = [["project", "is", {"type": "Project", "id": project_id}], ["id", "is", a_version_id]] assets = sg.find("Version", filters, fields) if len(assets) < 1: print "couldn't find any assets" exit(0) else: for an_asset in assets: entity_type = an_asset["entity"]["type"] # should always be 'Shot'! if entity_type == "Shot": # we always expect a shot but OK to test shot_id = an_asset["entity"]["id"] linked_version = {"type": "Version", "id": a_version_id} data = {CURRENT_VERSION_FIELD: linked_version} changed_asset = sg.update("Shot", shot_id, data) pprint(changed_asset) else: print ("version %s is linked to something other than a shot?" % a_version_id)
print '</br>' success = True # keep track of errors so that true success for all requests can be reported to the user # first, look to see if there is a current version in the shot # if not, then find all the versions that link to that shot and return the most recent shot_filters = [['project', 'is', { 'type': 'Project', 'id': PROJECT_ID }], [ 'id', 'in', ] + shot_ids] # #mark First get the version so that the linked shot can then be accessed. assets = sg.find("Shot", shot_filters, shot_fields) # did anything get returned? if not then error out... if len(assets) < 1: print '</br>' print "<b>Shotgun Server Did Not Return Any Shots! </b>" print '</br>' print '</br>' success = False else: # something was returned, process it! for an_asset in assets: # get the appropriate version and append it to the version list if an_asset[ CURRENT_VERSION_FIELD]: # there is a valid version in the field, append it to the list: version_ids.append(
class MainUI(QtGui.QWidget): def __init__(self, app): """ main UI for STATIC ENV handling I always build my UI in __init__ so suck it up.. """ QtGui.QWidget.__init__(self) self.app = app self.fileBoxes = [] ## Instance the api for talking directly to shotgun. base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'audioUploader' api_key = 'bbfc5a7f42364edd915656d7a48d436dc864ae7b48caeb69423a912b930bc76a' self.sgsrv = Shotgun(base_url = base_url , script_name = script_name, api_key = api_key, ensure_ascii=True, connect=True) self.shotNum = self._getShotNum()[0] self.currentENV = self._getShotNum()[1] debug(self.app, method = 'MainUI', message = 'self.shotNum: %s' % self.shotNum, verbose = False) debug(self.app, method = 'MainUI', message = 'self.currentENV: %s' % self.currentENV, verbose = False) self.lightAlembicFolder = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_static' % self.shotNum ## Now build the UI self.mainLayout = QtGui.QHBoxLayout(self) self.leftSideLayout = QtGui.QVBoxLayout(self) debug(self.app, method = 'MainUI', message = 'self.mainLayout built...', verbose = False) ########################## ### ENV SELECTION PULLDOWN self.envLayout = QtGui.QVBoxLayout(self) self.envPulldown = QtGui.QComboBox() getENVS = self.sgsrv.find('Asset', filters = [["code", "contains", 'ENV_'], ["code", "not_contains", '_ENV_'], ["code", "not_contains", 'WORLDMAP'], ["code", "not_contains", 'TSETbuild']], fields=['code']) debug(self.app, method = 'MainUI', message = 'getENVS: %s' % getENVS, verbose = False) if self.shotNum: for each in getENVS: if each['code'] == self.currentENV: self.envPulldown.addItem(each['code']) self.lightAlembicFolder = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_static' % self.shotNum self.envPulldown.setCurrentIndex(self.envPulldown.findText(self.currentENV)) debug(self.app, method = 'MainUI', message = 'self.envPulldown setCurrentIndex...', verbose = False) else: for each in getENVS: if 'STATIC' in each['code']: self.envPulldown.addItem(each['code']) self.fetchAssetListButton = QtGui.QPushButton(Icon('refresh.png'), 'Fetch Asset List') self.fetchAssetListButton.setStyleSheet("QPushButton {text-align : left}") self.fetchAssetListButton.released.connect(self._fetchAssetList) debug(self.app, method = 'MainUI', message = 'self.fetchAssetListButton built...', verbose = False) self.importAssetButton = QtGui.QPushButton(Icon('alembic.png'), 'Import latest Pub ABC for Sel') self.importAssetButton.setStyleSheet("QPushButton {text-align : left}") self.importAssetButton.released.connect(self._fetchMDLAlembicPublish) debug(self.app, method = 'MainUI', message = 'self.importAssetButton built...', verbose = False) self.checkMDLButton = QtGui.QPushButton(Icon('refresh.png'), 'Check For MDL ABC Publishes') self.checkMDLButton.setStyleSheet("QPushButton {text-align : left}") self.checkMDLButton.released.connect(self._checkVersionsAgainstPublishes) debug(self.app, method = 'MainUI', message = 'self.checkMDLButton built...', verbose = False) self.redoSetsButton = QtGui.QPushButton(Icon('plus.png'), 'ReDo Set Assignments') self.redoSetsButton.setStyleSheet("QPushButton {text-align : left}") self.redoSetsButton.released.connect(self._createSets) debug(self.app, method = 'MainUI', message = 'self.redoSetsButton built...', verbose = False) self.checkSRFXMLButton = QtGui.QPushButton(Icon('refresh.png'), 'Check For SRF Publishes') self.checkSRFXMLButton.setStyleSheet("QPushButton {text-align : left}") self.checkSRFXMLButton.released.connect(self._checkSRFVersionsAgainstPublishes) self.cleanDuplicateCoresButton = QtGui.QPushButton(Icon('AssignedFileIt.png'), 'Clean Duplicate Cores') self.cleanDuplicateCoresButton.setStyleSheet("QPushButton {text-align : left}") self.cleanDuplicateCoresButton.released.connect(self._fixTheFuckingCores) self.cleanDuplicateCoresButton.setToolTip('This is performed on every import of an static env via the multiloader.\n Exposed just in case you need to run this manually.\n This will go through a scene with multiple static ENVs in it \nand try to make sure duplicate cores are renering correctly.') self.removeCoreGrpsButton = QtGui.QPushButton(Icon('skull.png'), 'Remove old Core Grps under geo_hrc') self.removeCoreGrpsButton.setStyleSheet("QPushButton {text-align : left}") self.removeCoreGrpsButton.released.connect(self._removeCoreGrps) self.removeCoreGrpsButton.setToolTip('You can use this to clean up any old core grps under the geo_hrc grps in a scene\nafer you have done a core archive rebuild from xml...') ## THIS IS UP TO YOU TO ENABLE. IT SHOULDNT BE REQUIRED AS THE MDL PUBLISH SHOULD NOW BE EXPORTING THE CORRECT ATTRS FOR ALEMBIC self.republishALL = QtGui.QPushButton('Republish ALL MDL Alembics for %s' % self.currentENV) self.republishALL.released.connect(self._republishAllAlembicsForENV) self.republishALL.setEnabled(True) self.lambert1Button = QtGui.QPushButton(Icon('refresh.png'), 'Check lambert1 objects') self.lambert1Button.setStyleSheet("QPushButton {text-align : left}") self.lambert1Button.released.connect(self._lambert1Object) self.caNSclashCheckButton = QtGui.QPushButton(Icon('refresh.png'), 'Check Core Archive Namespace') self.caNSclashCheckButton.setStyleSheet("QPushButton {text-align : left}") self.caNSclashCheckButton.released.connect(self.coreArchiveNSclashCheck) self.checkFileInPathButton = QtGui.QPushButton(Icon('refresh.png'), 'Check Invalid FileIn Path') self.checkFileInPathButton.setStyleSheet("QPushButton {text-align : left}") self.checkFileInPathButton.released.connect(self.checkFileInPath) self.checkNonManifoldButton = QtGui.QPushButton(Icon('refresh.png'), 'Check Non-Manifold Geometry') self.checkNonManifoldButton.setStyleSheet("QPushButton {text-align : left}") self.checkNonManifoldButton.released.connect(self.cleanupNonManifoldGeometry) ## Add stuff to the env layout self.envLayout.addWidget(self.envPulldown) self.envLayout.addWidget(self.fetchAssetListButton) self.envLayout.addWidget(self.importAssetButton) self.envLayout.addWidget(self.checkMDLButton) self.envLayout.addWidget(self.checkSRFXMLButton) self.envLayout.addWidget(self.redoSetsButton) self.envLayout.addWidget(self.cleanDuplicateCoresButton) self.envLayout.addWidget(self.removeCoreGrpsButton) self.envLayout.addWidget(self.republishALL) self.envLayout.addWidget(self.lambert1Button) self.envLayout.addWidget(self.caNSclashCheckButton) self.envLayout.addWidget(self.checkFileInPathButton) self.envLayout.addWidget(self.checkNonManifoldButton) ###################### ### ENV RELATED ASSETS self.assetLayout = QtGui.QVBoxLayout(self) ### Now do the check boxes for files.... self.scrollLayout = QtGui.QScrollArea(self) self.scrollLayout.setMinimumHeight(300) self.envAssetsGroupBox = QtGui.QGroupBox(self.scrollLayout) self.envAssetsGroupBox.setFlat(True) self.scrollLayout.setWidget(self.envAssetsGroupBox) self.scrollLayout.setWidgetResizable(True) self.envAssetsLayout = QtGui.QGridLayout(self.envAssetsGroupBox) self.assetLayout.addWidget(self.scrollLayout) self.mainLayout.addLayout(self.leftSideLayout) ## Add stuff to leftSideLayout self.leftSideLayout.addLayout(self.envLayout) self.leftSideLayout.addStretch(1) ## Add anything else to the HBox self.mainLayout.addLayout(self.assetLayout) self.resize(1000, 500) debug(self.app, method = 'MainUI', message = 'ui built successfully fetching assets now...', verbose = False) debug(self.app, method = 'MainUI', message = 'self.envPulldown.currentText(): %s' % self.envPulldown.currentText(), verbose = False) self._fetchAssetList() self.envPulldown.currentIndexChanged.connect(partial(self._getShotNumFromMenuName)) self.envPulldown.currentIndexChanged.connect(partial(self._fetchAssetList)) def arraysMatch(self, a, b): ''' Utility to compare two string list ''' return True if a == b else False def cleanupNonManifoldGeometry(self, normals = True): ## Get all the mesh that has mentalraySubdivApprox connected and has non-manifold problem # subdiv_mesh = [cmds.listRelatives(mesh, parent = True, fullPath = True)[0] for mesh in cmds.ls(type = 'mesh') if cmds.listConnections(mesh, type = 'mentalraySubdivApprox') if cmds.polyInfo(mesh, nme = True) or cmds.polyInfo(nmv = True)] subdiv_mesh = [cmds.listRelatives(mesh, parent = True, fullPath = True)[0] for mesh in cmds.ls(type = 'mesh') if cmds.polyInfo(mesh, nme = True) or cmds.polyInfo(nmv = True)] subdiv_mesh = list( set( subdiv_mesh ) ) if subdiv_mesh: for each in subdiv_mesh: ## Make sure we do indeed have nonmanifold geometry ## nonManifold = cmds.polyInfo(each, nmv = True, nme = True) if nonManifold: proceed = cmds.confirmDialog(title = 'Non-Manifold Geometry!', message = 'Geo Name:\n%s' % each, button = ['Cleanup!', 'Skip...'], defaultButton = 'Skip...', cancelButton = 'Skip...', dismissString = 'Skip...') if proceed == 'Cleanup!': ## Conform the geo and see if that gets rid of all the nonmanifold bits ## if normals: cmds.polyNormal('%s.f[*]' % each, normalMode = 2, constructionHistory = True) edges = cmds.polyInfo(each, nme = True) if cmds.polyInfo(each, nme = True) else [] vertices = [] if edges else cmds.polyInfo(each, nmv = True) lastEdges = [] lastVertices = [] while ( not self.arraysMatch(lastEdges, edges) or not self.arraysMatch(lastVertices, vertices) ) and ( edges or vertices ): ## Remember what was nonmanifold last time ## lastEdges = edges lastVertices = vertices ## Split any nonmanifold edges ## if edges: cmds.polySplitEdge(edges, constructionHistory = True) vertices = cmds.polyInfo(each, nmv = True) edges = [] ## Split any remaining nonmanifold vertices ## if vertices: cmds.polySplitVertex(vertices, constructionHistory = True) vertices = [] ## Now check to see if the object is still nonmanifold ## nonManifold = cmds.polyInfo(each, nmv = True, nme = True) if nonManifold: ## Chip off the faces ## nonManifoldFaces = cmds.polyListComponentConversion(nonManifold, toFace = True) cmds.polyChipOff(nonManifoldFaces, kft = 0, dup = 0, constructionHistory = True) ## And then check for nonmanifold bits again ## edges = cmds.polyInfo(each, nme = True) if not edges: vertices = cmds.polyInfo(each, nmv = True) ## Check to see if we failed to cleanup if edges or vertices: cmds.warning('Failed to cleanup non-manifold geometry of %s...' % each) def _lambert1Object(self): ## Delete sets first if cmds.objExists('lambert1_object_set'): cmds.delete('lambert1_object_set') lambert1 = cmds.ls( cmds.sets('initialShadingGroup', q = True), long = True ) if lambert1: lambert1 = [x.split('.f')[0] for x in lambert1 if cmds.objectType(x) == 'mesh' and 'CArch' not in x] ## Create sets if bad stuffs detected if lambert1: cmds.sets(lambert1, name = 'lambert1_object_set') def coreArchiveNSclashCheck(self): coreArchive_NS = [ns for ns in cmds.namespaceInfo(listOnlyNamespaces = True) if 'CORE' in ns.split('_')[-1]] if coreArchive_NS: dup_coreArchive_NS = [ns for ns in coreArchive_NS if not ns.endswith('_CORE')] if dup_coreArchive_NS: cmds.confirmDialog(title = 'Core Archive Namespace', message = 'Core Archive namespace clashes detected, please check the namespace editor!', button = 'OK!') def checkFileInPath(self): ## Delete sets first if cmds.objExists('invalid_fileIn_path_set'): cmds.delete('invalid_fileIn_path_set') fileIn = cmds.ls(type = 'file') fileIn.extend( cmds.ls(type = 'mentalrayTexture') ) if fileIn: badFileInPath = [x for x in fileIn if not os.path.exists( cmds.getAttr('%s.fileTextureName' % x) )] ## Create sets if bad stuffs detected if badFileInPath: cmds.sets(badFileInPath, name = 'invalid_fileIn_path_set') def _removeCoreGrps(self): """ Exposing function for operator to cleanup after a rebuild """ ## Step one after import ## Clean the f*****g left over grps first if they exist ENVLIST = ['ENV_MIDDLEHARBOUR_STATIC_ABC_STATIC_CACHES_hrc', 'ENV_MIDDLEHARBOUR_EAST_STATIC_ABC_STATIC_CACHES_hrc', 'ENV_WESTHARBOUR_STATIC_ABC_STATIC_CACHES_hrc', 'ENV_THEHEADS_STATIC_ABC_STATIC_CACHES_hrc', 'ENV_BIGTOWN_STATIC_ABC_STATIC_CACHES_hrc'] getHRCS = [[eachGrp for eachGrp in cmds.listRelatives(eachENV)] for eachENV in ENVLIST if cmds.objExists(eachENV)] [[cmds.delete(eachChild) for eachChild in cmds.listRelatives(eachHrc, ad = True, f = True) if '_CORE_' in eachChild] for eachHrc in getHRCS] def _toggleCBx(self, chbx = '', wtfami = ''): """ Function to select on checkbox toggle @param chbx: the QCheckbox @param wtfami: WHO THE HELL KNOWS!!????!!!!!!!! @type chbox: PyQt Object :return: """ if chbx.isChecked(): cmds.select('%s_hrc' % chbx.text(), add = True) else: cmds.select('%s_hrc' % chbx.text(), d = True) def _getShotNum(self): self.workSpace = cmds.workspace(q = True, fn = True) debug(self.app, method = '_getShotNum', message = 'self.workSpace: %s' % self.workSpace, verbose = False) envName = '' shotNum = '' if 'ep000_sh010' in self.workSpace: envName = 'ENV_MIDDLEHARBOUR_STATIC' shotNum = 'ep000_sh010' elif 'ep000_sh020' in self.workSpace: envName = 'ENV_WESTHARBOUR_STATIC' shotNum = 'ep000_sh020' elif 'ep000_sh030' in self.workSpace: envName = 'ENV_BIGTOWN_STATIC' shotNum = 'ep000_sh030' elif 'ep000_sh040' in self.workSpace: envName = 'ENV_THEHEADS_STATIC' shotNum = 'ep000_sh040' elif 'ep000_sh050' in self.workSpace: envName = 'ENV_MIDDLEHARBOUR_EAST_STATIC' shotNum = 'ep000_sh050' else: envName = None shotNum = None return shotNum, envName def _getShotNumFromMenuName(self, index = ''): self.workSpace = cmds.workspace(q = True, fn = True) envName = '' shotNum = '' if self.envPulldown.currentText() == 'ENV_MIDDLEHARBOUR_STATIC': shotNum = 'ep000_sh010' elif self.envPulldown.currentText() == 'ENV_WESTHARBOUR_STATIC': shotNum = 'ep000_sh020' elif self.envPulldown.currentText() == 'ENV_BIGTOWN_STATIC': shotNum = 'ep000_sh030' elif self.envPulldown.currentText() == 'ENV_THEHEADS_STATIC': shotNum = 'ep000_sh040' elif self.envPulldown.currentText() == 'ENV_MIDDLEHARBOUR_EAST_STATIC': shotNum = 'ep000_sh050' else: shotNum = None return shotNum def _addVersionTag(self, assetName, versionNumber): if cmds.objExists('%s.version' % assetName): cmds.deleteAttr('%s.version' % assetName) try: cmds.addAttr(assetName, ln = 'version', at = 'long', min = 0, max = 50000, dv = 0) except: pass cmds.setAttr('%s.version' % assetName, int(versionNumber)) def _checkVersionsAgainstPublishes(self): ## Path to the assets folder pathToAssets = "I:/lsapipeline/assets" ##Hardcoded yuckiness.. MDLVersNum = '' ## Fetch the subAssets for the ENV getData = self.sgsrv.find('Asset', filters = [["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) ## Now can the checkboxes and see which assets arechecked if self.fileBoxes: for eachAsset in self.fileBoxes: if eachAsset.isChecked(): #print 'Checking %s ...' % eachAsset.text() for eachSGAsset in getData[0]['assets']: if eachSGAsset['name'] == eachAsset.text(): ## BLD if 'BLD' in eachSGAsset['name']: assetPublishFolder = "%s/Building/%s/MDL/publish/alembic" % (pathToAssets, eachSGAsset['name']) ## LND elif 'LND' in eachSGAsset['name']: assetPublishFolder = "%s/Environment/%s/MDL/publish/alembic" % (pathToAssets, eachSGAsset['name']) assetPublishFolder.replace("/", os.sep) if os.path.isdir(assetPublishFolder): try: getLatestPublish = max(os.listdir(assetPublishFolder)) except: getLatestPublish = [] if getLatestPublish and getLatestPublish.endswith('.abc'): MDLVersNum = int(getLatestPublish.split('.')[-2].split('v')[-1]) try: getAssetVersion = cmds.getAttr('%s_hrc.version' % eachAsset.text()) except ValueError: getAssetVersion = None if getAssetVersion: if not getAssetVersion == MDLVersNum: #self.envPulldown.setCurrentIndex(self.envPulldown.findText(self.currentENV)) print '!!HIGHER VER EXISTS: %s_hrc:%s \t %s' % (eachAsset.text(), getAssetVersion, getLatestPublish) eachAsset.setStyleSheet("QCheckBox{background-color: red}") else: eachAsset.setStyleSheet("QCheckBox{background-color: green}") eachAsset.setChecked(False) print 'PASSED: version match %s' % (getLatestPublish) else: eachAsset.setStyleSheet("QCheckBox{background-color: red}") cmds.warning('%s IS MISSING VERSION INFORMATION! PLEASE FIX!!!' % eachAsset.text()) for eachAsset in self.fileBoxes: if eachAsset.isChecked() and eachAsset.text() == 'ALL': eachAsset.setChecked(False) eachAsset.setStyleSheet("QCheckBox{background-color: green}") def _checkSRFVersionsAgainstPublishes(self): ## Path to the assets folder pathToAssets = "I:/lsapipeline/assets" ##Hardcoded yuckiness.. MDLVersNum = '' ## Fetch the subAssets for the ENV getData = self.sgsrv.find('Asset', filters = [["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) ## Now can the checkboxes and see which assets are checked if self.fileBoxes: for eachAsset in self.fileBoxes: if eachAsset.isChecked(): #print 'Checking %s ...' % eachAsset.text() for eachSGAsset in getData[0]['assets']: if eachSGAsset['name'] == eachAsset.text(): ## BLD if 'BLD' in eachSGAsset['name']: assetPublishFolder = "%s/Building/%s/SRF/publish/xml" % (pathToAssets, eachSGAsset['name']) ## LND elif 'LND' in eachSGAsset['name']: assetPublishFolder = "%s/Environment/%s/SRF/publish/xml" % (pathToAssets, eachSGAsset['name']) assetPublishFolder.replace("/", os.sep) if os.path.isdir(assetPublishFolder): try: getLatestPublish = max(os.listdir(assetPublishFolder)) except: getLatestPublish = [] if getLatestPublish and getLatestPublish.endswith('.xml'): XMLVersNum = int(getLatestPublish.split('.')[-2].split('v')[-1]) try: getAssetSRFVersion = cmds.getAttr('%s_hrc.SRFversion' % eachAsset.text()) except ValueError: getAssetSRFVersion = None if getAssetSRFVersion: if not getAssetSRFVersion == XMLVersNum: #self.envPulldown.setCurrentIndex(self.envPulldown.findText(self.currentENV)) print '!!HIGHER VER EXISTS: %s_hrc:%s \t %s' % (eachAsset.text(), getAssetSRFVersion, getLatestPublish) eachAsset.setStyleSheet("QCheckBox{background-color: red}") else: eachAsset.setStyleSheet("QCheckBox{background-color: green}") eachAsset.setChecked(False) print 'PASSED: version match %s' % (getLatestPublish) else: eachAsset.setStyleSheet("QCheckBox{background-color: red}") cmds.warning('%s IS MISSING VERSION INFORMATION! PLEASE FIX!!!' % eachAsset.text()) for eachAsset in self.fileBoxes: if eachAsset.isChecked() and eachAsset.text() == 'ALL': eachAsset.setChecked(False) eachAsset.setStyleSheet("QCheckBox{background-color: green}") def _checkVersionNumber(self, assetName, versionNumber): """ Returns if the version number for an asset in the scene matches that of the asset in the static_folder """ foundVersion = False assetList = [] for eachAlembic in os.listdir(self.lightAlembicFolder): if assetName.replace('_', '') in eachAlembic: assetList.append(eachAlembic) try: getlatest = max(assetList) except: getlatest = [] if getlatest: getlatestVersionNum = getlatest.split('.')[-2].split('v')[-1] if int(versionNumber) == int(getlatestVersionNum): foundVersion = True else: cmds.warning('There is no asset for %s found in the lighting static alembic folder.' % assetName) return foundVersion def _fetchAssetList(self, index = ''): getData = self.sgsrv.find('Asset', filters = [["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) debug(self.app, method = '_fetchAssetList', message = 'getData: %s' % getData, verbose = False) if self.fileBoxes: for each in self.fileBoxes: each.setParent(None) each = None self.fileBoxes = [] ## First add the ALL checkbox self.ALL = QtGui.QCheckBox(self) self.ALL.setChecked(False) self.ALL.setText('ALL') self.ALL.toggled.connect(self._toggleAll) self.fileBoxes.append(self.ALL) self.envAssetsLayout.addWidget(self.ALL, 0, 0) self.colCount = 5 r = 1 c = 1 if getData: for eachAsset in getData[0]['assets']: self.assetCheckBox = QtGui.QCheckBox(self) self.assetCheckBox.setChecked(False) self.assetCheckBox.setText(eachAsset['name']) self.assetCheckBox.toggled.connect(partial(self._toggleCBx, self.assetCheckBox)) self.fileBoxes.append(self.assetCheckBox) if cmds.objExists('%s_hrc' % eachAsset['name']): self.assetCheckBox.setStyleSheet("QCheckBox{background-color: #0066CC}") ## Now check the version if cmds.objExists('%s_hrc.version' % eachAsset['name']): self.lightAlembicFolder = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_static' % self._getShotNumFromMenuName() if not self._checkVersionNumber(eachAsset['name'], cmds.getAttr('%s_hrc.version' % eachAsset['name'])): self.assetCheckBox.setStyleSheet("QCheckBox{background-color: red}") else: self.assetCheckBox.setStyleSheet("QCheckBox{background-color: #990000}") cmds.warning('Asset version attr not found on %s_hrc' % eachAsset['name']) else: self.assetCheckBox.setStyleSheet("QCheckBox{background-color: red}") if c == self.colCount: r = r + 1 c = 1 self.envAssetsLayout.addWidget(self.assetCheckBox, r, c) c = c + 1 def _toggleAll(self): """ A quick toggle for all the type checkboxes to on or off """ for each in self.fileBoxes: if each.text() == 'ALL': each.setStyleSheet("QCheckBox{background-color: grey}") if each.isChecked(): for eachAsset in self.fileBoxes: if eachAsset.text() != 'ALL': eachAsset.setChecked(True) eachAsset.setStyleSheet("QCheckBox{background-color: grey}") else: for eachAsset in self.fileBoxes: if eachAsset.text() != 'ALL': eachAsset.setChecked(False) def _fetchMDLAlembicPublish(self): """ This function will find the checked assets, and then go off and get the latest published alembic asset from the asset folder None of this is done off the database btw.. """ pathToAssets = 'I:/lsapipeline/assets' if self.shotNum: moveTo = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_static' % self.shotNum elif self._getShotNumFromMenuName(): moveTo = 'I:/lsapipeline/episodes/ep000/%s/Light/publish/alembic_static' % self._getShotNumFromMenuName() else: cmds.warning('This ENV is not a valid for processing using this tool!') return -1 pathTo = '' toProcess = [] for eachAsset in self.fileBoxes: if eachAsset.text() != 'ALL': if eachAsset.isChecked(): toProcess.append(eachAsset.text()) if toProcess: for eachAsset in toProcess: if cmds.objExists('%s_hrc' % eachAsset): ###Prompt to continue here self.reply = cmds.confirmDialog(title = "Remove Asset? %s" % eachAsset, message = "Warning you are about to remove %s" % eachAsset, button = ['Continue...','Skip Import']) if self.reply == 'Continue...': cmds.delete('%s_hrc' % eachAsset) self._doIt(eachAsset, pathToAssets, moveTo) else: pass else: self._doIt(eachAsset, pathToAssets, moveTo) else: cmds.warning('No assets selected for importing!!') def _doIt(self, eachAsset, pathToAssets, moveTo): """ Func to process eachAsset from the _fetchMDLAlembicPublish function """ if 'BLD' in eachAsset: pathTo = "%s/Building/%s/MDL/publish/alembic" % (pathToAssets, eachAsset) ## LND elif 'LND' in eachAsset: pathTo = "%s/Environment/%s/MDL/publish/alembic" % (pathToAssets, eachAsset) if self._isRootFolderThere(rootFolder = pathTo): if os.path.isdir(pathTo): try: maxFile = max(os.listdir(pathTo)) except ValueError: maxFile = [] if maxFile: finalPath = '%s/%s' %(pathTo, maxFile) moveIT = '%s\\%s' % (moveTo.replace('/', '\\'), maxFile) if os.path.isfile(moveIT): os.remove(moveIT) print 'Copy in progress for %s' % maxFile shutil.copyfile(finalPath, '%s/%s' % (moveTo, maxFile)) else: cmds.warning('FAILED!: Nothing has been published for this asset! Talk to the modelling dept.') self._createBaseGroups() self._importSingleCache(pathTo, '%s_ABC_STATIC_CACHES_hrc' % self.currentENV, '%s_hrc' % eachAsset) for eachAssetCBx in self.fileBoxes: if eachAssetCBx.text() == eachAsset: eachAssetCBx.setChecked(False) eachAssetCBx.setStyleSheet("QCheckBox{background-color: green}") def _republishAllAlembicsForENV(self): """ This helper will republish all the MDL alembic files from the most recently published mb files found in the assets folders for every asset associated to the ENV. getData = self.sgsrv.find('Asset', filters = [["code", "is", eachENV]], fields=['code', 'id', 'assets']) Finds the ENV name and then gets a list of Sub Assets associated with it from the assets field. This is why we want every ENV to be the parent of an asset in the system appropriately. """ start = time.time() ## Empty the scene first, or BAD THINGS HAPPEN!!! cmds.file(new = True, f = True) ## Path to the assets folder pathToAssets = "I:/lsapipeline/assets" ##Hardcoded yuckiness.. ## Fetch the subAssets for the ENV getData = self.sgsrv.find('Asset', filters = [["code", "is", self.envPulldown.currentText()]], fields=['code', 'id', 'assets']) for eachAsset in getData[0]['assets']: ## BLD if 'BLD' in eachAsset['name']: assetPublishFolder = "%s/Building/%s/MDL/publish/maya" % (pathToAssets, eachAsset['name']) ## LND elif 'LND' in eachAsset['name']: assetPublishFolder = "%s/Environment/%s/MDL/publish/maya" % (pathToAssets, eachAsset['name']) assetPublishFolder.replace("/", os.sep) if os.path.isdir(assetPublishFolder): getLatestPublish = max(os.listdir(assetPublishFolder)) if getLatestPublish and getLatestPublish.endswith('.mb'): latestPublish = '%s/%s' % (assetPublishFolder, getLatestPublish) latestPublish.replace("/", os.sep) alembicPath = latestPublish.replace('.mb', '.abc').replace('maya', 'alembic').replace('.v', '_ABC.v') ## Remove current alembic if os.path.isfile(alembicPath): os.remove(alembicPath) ## Import the file so we don't have to display anything due to the files prob being saved with tesxtures on etc print '=====================' print 'Importing %s now...' % latestPublish try: cmds.file(latestPublish, i = True, f = True) except: cmds.warning('Failed to import %s...' % latestPublish) cleanup.removeAllNS() print 'Import complete' print '=====================' ## Change uv set map1 if the mesh has multiple uv sets for alembic cache [cmds.polyUVSet(each, currentUVSet = True, uvSet = 'map1') for each in cmds.ls(type = 'mesh')] ## Now scan the geo in the scene and preserve the crease information print '=====================' print 'Adding crease SubDivisionMesh attr' for each in cmds.ls(type = 'mesh', l = True): if not cmds.objExists('%s.SubDivisionMesh' % each): try: cmds.addAttr('%s' % each, ln = 'SubDivisionMesh', at = 'bool') cmds.setAttr("%s.SubDivisionMesh" % each, 1) except: pass print 'Complete..' print '=====================' ## Now export back out a new alembic with the version name that should exist in the assembly reference. rootName = '%s_hrc' % eachAsset['name'] # abc_export_cmd = "-attr smoothed -attr SubDivisionMesh -ro -uvWrite -wholeFrameGeo -worldSpace -writeVisibility -fr 1 1 -root %s -file %s" % (rootName, alembicPath) abc_export_cmd = "-attr smoothed -attr SubDivisionMesh -ro -uvWrite -wholeFrameGeo -worldSpace -writeVisibility -fr %d %d -root %s -file %s" % (1, 1, rootName, alembicPath) try: print '=====================' print 'Exporting %s to alembic cache now to %s' % (rootName, alembicPath) cmds.AbcExport(verbose = False, j = abc_export_cmd) print 'Export Complete...' print '=====================' except: print "Failed to export Alembic Cache!!" ## Now do a new scene with no save cmds.file(new = True, f = True) # print 'FINISHED FIXING ALL ALEMBIC PUBLISHES FOR ASSETS FOR ENV: %s' % eachENV print 'TIME: %s' % (time.time()-start) def _isRootFolderThere(self, rootFolder): """ Method used to check if root folder is valid or not eg: I:/lsapipeline/assets @param rootFolder: The path to the root folder to check for @type rootFolder: String """ if not os.path.isdir(rootFolder): print 'No such root folder found: %s' % rootFolder return -1 else: return 1 def findAlembicPublishes(self, envName = '', rootFolder = 'I:/lsapipeline/assets', moveTo = 'I:/lsapipeline/episodes/ep000/ep000_sh010/Light/publish/alembic_static'): """ Function to find all the LND asset published alembic MDL publishes and move them into the lighting base shot folder. Note this will grab every asset parented to the ENV asset in shotgun. If they are missing from this field they won't be pulled in correctly. Also note it was originally intended to process the entire world, so the envList is kinda old now as we're just doing the one ENV at a time. @param envName: The name of the ENV we're looking for subAssets of @param rootFolder: The path of the rootFolder for the assets to scan for @param moveTo: The path of the master shot folders alembic_static we are going to copy the files to @type envName: String @type rootFolder: String @type moveTo: String """ start = time.time() pathToAssets = "I:/lsapipeline/assets" getData = self.sgsrv.find('Asset', filters = [["code", "is", envName]], fields=['code', 'id', 'assets']) for eachAsset in getData[0]['assets']: ## BLD if 'BLD' in eachAsset['name']: pathTo = "%s/Building/%s/MDL/publish/alembic" % (rootFolder, eachAsset['name']) ## LND elif 'LND' in eachAsset['name']: pathTo = "%s/Environment/%s/MDL/publish/alembic" % (rootFolder, eachAsset['name']) if self._isRootFolderThere(rootFolder = pathTo): if os.path.isdir(pathTo): try: maxFile = max(os.listdir(pathTo)) except ValueError: maxFile = [] if maxFile: finalPath = '%s/%s' %(pathTo, maxFile) moveIT = '%s\\%s' % (moveTo.replace('/', '\\'), maxFile) if os.path.isfile(moveIT): os.remove(moveIT) print 'Copy in progress for %s' % maxFile shutil.copyfile(finalPath, '%s/%s' % (moveTo, maxFile)) self._createBaseGroups(envs[0]) self._importCaches(moveTo, '%s_ABC_STATIC_CACHES_hrc' % self.currentENV) self._createSets() def _importSingleCache(self, folderPath, parentGrp, cacheName): """ Function to import the alembics and parent them to the right group @param folderPath: Path to the folder for the caches to import @param parentGrp: The name of the group to parent the alembics to. @type folderPath: String @type parentGrp: String """ try: findLatest = max(os.listdir(folderPath)) except: findLatest = [] if findLatest: try: cmds.AbcImport('%s/%s' % (folderPath, findLatest), reparent = parentGrp, setToStartFrame = True) self._createSets() except RuntimeError: cmds.warning('Failed to import cache! %s/%s' % (folderPath, findLatest)) ## Now add the version number to the grp versionNumber = findLatest.split('.')[-2].split('v')[-1] self._addVersionTag('%s' % cacheName, versionNumber) else: cmds.warning('Nothing published for %s !' % cacheName) def _importCaches(self, folderPath, parentGrp): """ Function to import the alembics and parent them to the right group @param folderPath: Path to the folder for the caches to import @param parentGrp: The name of the group to parent the alembics to. @type folderPath: String @type parentGrp: String """ for eachCache in os.listdir(folderPath): try: cmds.AbcImport('%s/%s' % (folderPath, eachCache), reparent = parentGrp, setToStartFrame = True) except RuntimeError: cmds.warning('Failed to import cache! %s/%s' % (folderPath, eachCache)) self._createSets() def _createBaseGroups(self): """ Function to create the base grps for the caches to be parented to. @param envName: The name of the enviroment we are importing into. @type envName: String """ envName = self.currentENV if envName: grps = ['%s_ABC_STATIC_CACHES_hrc' % self.currentENV, '%s_Core_Archives_hrc' % self.currentENV] else: grps = ['%s_ABC_STATIC_CACHES_hrc' % self.envPulldown.currentText(), '%s_Core_Archives_hrc' % self.envPulldown.currentText()] for eachGrp in grps: if not cmds.objExists(eachGrp): cmds.group(n = eachGrp, em = True) def _createSets(self): """ Function used to put the alembic caches into the right sets for use witht ehlayout tool deved in house at LSky The lists were built from the base ENV scenes pre the cleanup. If new buildings are added to the sets they should be added to the lists below """ ## Now check for the sets ## Sets for MIDDLE HARBOUR if self.envPulldown.currentText() == 'ENV_MIDDLEHARBOUR_STATIC': animBuildList = ['BBB_CanoeBoatHouse_BLD', 'AI_Jetty_Dock_BLD_hrc', 'BBB_BowserBoatHouse_Dock_BLD_hrc','BBB_DockyardPier_Dock_BLD_hrc','BBB_Jetty_Dock_BLD_hrc','BBB_MainStorage_Dock_BLD_hrc','BBB_Office_Dock_BLD_hrc','BBB_TheMarina_Dock_BLD_hrc','BBB_DryDockInterior_BLD_hrc','BBB_Int_TerrysStorageshed_BLD_hrc','BBB_ZipBoatHouse_BLD_hrc', 'BBB_ZipBoathouseInterior_BLD_hrc','BBB_SydneyBoatHouse_BLD_hrc', 'BBB_SydneyBoathouseInterior_BLD_hrc'] setList = { "BBBEastPointLND" : ["BBB_Silo_BLD_hrc", "BBB_StorageShed02_BLD_hrc", "BBB_TerrysBoatHouse_BLD_hrc", "BBB_TerrysStorageShed_BLD_hrc", "BBB_DockyardPier_BLD_hrc", "BBB_EastPoint_LND_hrc"], "BBBMidPointLND" : ["BBB_Storage001_BLD_hrc", "BBB_Storage002_BLD_hrc", "BBB_StorageShed_BLD_hrc", "BBB_TheMarina_BLD_hrc", "BBB_Gen011_BLD_hrc", "BBB_Jetty_BLD_hrc", "BBB_MainStorage_BLD_hrc", "BBB_Office_BLD_hrc", "BBB_PirateShip_BLD_hrc", "BBB_MidPoint_LND_hrc", "BBB_DryDockMainBuilding_BLD_hrc", "BBB_DryDockInterior_BLD_hrc"], "BBBWestPointLND" : ["BBB_BowserBoatHouse_BLD_hrc", "BBB_Gen002_BLD_hrc", "BBB_Gen008_BLD_hrc", "BBB_Gen009_BLD_hrc", "BBB_Gen010_BLD_hrc", "BBB_Gen007_BLD_hrc", "BBB_Gen003_BLD_hrc", "BBB_Gen004_BLD_hrc", "BBB_Gen001_BLD_hrc", "BBB_Gen005_BLD_hrc", "BBB_Gen006_BLD_hrc", "BBB_WestPoint_LND_hrc", "BBB_ZipBoatHouse_BLD_hrc", "BBB_SydneyBoatHouse_BLD_hrc"], "TWRLND" : ["TWR_LND_hrc"], } ## Sets for MIDDLE HARBOUR EAST if self.envPulldown.currentText() == 'ENV_MIDDLEHARBOUR_EAST_STATIC': animBuildList = [] setList = { "AILND" : ["AI_LightHouse_BLD_hrc", "AI_LND_hrc", "AI_Jetty_BLD_hrc"], "FWBSandbarLND" : ["FWB_Rock001_LND_hrc", "FWB_Rock002_LND_hrc", "FWB_Rock003_LND_hrc", "FWB_Rock004_LND_hrc", "FWB_Rock005_LND_hrc", "FWB_Rock006_LND_hrc", "FWB_Rock007_LND_hrc", "FWB_Rock008_LND_hrc", "FWB_BeachHouse_LND_hrc", "FWB_Sandbar_LND_hrc", "FWB_Fingers_LND_hrc", ], "HCEastLND" : ["HC_ExtraBlockingRock_LND_hrc", "HC_East_LND_hrc", "HC_Island010_E_LND_hrc", "HC_Island010_F_LND_hrc", "HC_Waterfall001_LND_hrc", "HC_Bridge001_A_LND_hrc", "HC_Bridge001_B_LND_hrc", "HC_Bridge001_C_LND_hrc", "HC_Cave001_LND_hrc", "HC_Island006_A_LND_hrc", "HC_Island006_B_LND_hrc", "HC_Island007_LND_hrc", "HC_Island010_A_LND_hrc", "HC_Island010_B_LND_hrc", "HC_Island010_C_LND_hrc", "HC_Island010_D_LND_hrc"], "HCNorthLND" : ["HC_North_LND_hrc", "HC_Entrance002_LND_hrc", "HC_Island001_A_LND_hrc", "HC_Island001_B_LND_hrc", "HC_Island001_C_LND_hrc", "HC_Island001_D_LND_hrc", "HC_Island001_E_LND_hrc", "HC_Island001_F_LND_hrc", "HC_Island001_G_LND_hrc", "HC_Island001_H_LND_hrc", "HC_Island001_I_LND_hrc", "HC_Island001_J_LND_hrc", "HC_Island002_A_LND_hrc", "HC_Island002_B_LND_hrc", "HC_Island003_A_LND_hrc", "HC_Island003_B_LND_hrc", "HC_Island004_LND_hrc"], "HCSouthLND" : ["HC_South_LND_hrc"], "HCWestLND" : ["HC_Entrance001_LND_hrc", "HC_West_LND_hrc", "HC_ShipWreck_BLD_hrc", "HC_Island008_LND_hrc", "HC_Island009_LND_hrc"], } ## Sets for WEST HARBOUR elif self.envPulldown.currentText() == 'ENV_WESTHARBOUR_STATIC': animBuildList = ['BB_PP_JettyDock_01_BLD', 'BB_PP_JettyDock_02_BLD', 'DingleIsland_JettyDock_BLD', 'LittleTown_Dock001_BLD', 'LittleTown_Dock002_BLD', 'MulliganTown_JettyDock_01_BLD', 'MulliganTown_JettyDock_02_BLD', 'BB_OF_Lease_BLD'] setList = { 'AdmiralBridgeLND' : ["AdmiralBridge_LND_hrc"], 'BBOysterFarmLND' : ["BB_OysterFarm_LND_hrc", "BB_OF_Hut005_BLD_hrc", "BB_OF_Lease_BLD_hrc", "BB_OF_Hut004_BLD_hrc", "BB_OF_Hut003_BLD_hrc", "BB_OF_Hut002_BLD_hrc", "BB_OF_Hut001_BLD_hrc"], 'BBPointPeriwinkleLND' : ["BB_PointPeriwinkle_LND_hrc", "BB_PP_Jetty_BLD_hrc", "BB_PP_Huts_BLD_hrc", "BB_PP_JettyDock_01_BLD_hrc", "BB_PP_JettyDock_02_BLD_hrc"], 'DingleIslandLND' : ["DingleIsland_JettyDock_BLD_hrc", "DingleIsland_LND_hrc"], 'LittleTownLND' : ["LittleTown_EastBuilding_BLD_hrc", "LittleTown_MidBuilding_BLD_hrc", "LittleTown_MidGenBuilding_BLD_hrc", "LittleTown_WestBuilding_BLD_hrc", "LittleTown_East_LND_hrc", "LittleTown_Mid_LND_hrc", "LittleTown_West_LND_hrc"], 'MuliganTownLND' : ["MulliganTown_JettyBuilding_BLD_hrc", "MulliganTown_EastBuilding_BLD_hrc", "MulliganTown_WestBuilding_BLD_hrc", "MulliganTown_EastGenBuilding_BLD_hrc", "MulliganTown_WestGenBuilding_BLD_hrc", "MulliganTown_SateliteHouse_BLD_hrc", "MulliganTown_JettyDock_01_BLD_hrc", "MulliganTown_JettyDock_02_BLD_hrc", "MulliganTown_East_LND_hrc", "MulliganTown_West_LND_hrc"] } ## Sets for BIG TOWN elif self.envPulldown.currentText() == 'ENV_BIGTOWN_STATIC': animBuildList = ['BigPort_Shipyard_Dock_BLD'] setList = { 'BigNorthPortLND' : ["BigNorthPort_LND_hrc", "BigNorthPort_Building_BLD_hrc"], 'BigPortLND' : ["BigPort_LND_hrc", "BigPort_Shipyard_BLD_hrc"], 'BigTown01LND' : ["BigTown_01_LND_hrc", "BigTown_01_Building_BLD_hrc"], 'BigTown02LND' : ["BigTown_02_LND_hrc", "BigTown_02_Building_BLD_hrc"], 'BigTownLND' : ["BigTown_LND_hrc", "BigTown_Building_BLD_hrc"], } ## Sets for THEHEADS elif self.envPulldown.currentText() == 'ENV_THEHEADS_STATIC': animBuildList = [] setList = { 'THIrisleLND' : ['TH_IrisIsle_LND_hrc'], 'THMangoShore01LND' : ["TH_MangoShore01_LND_hrc", "TH_MangoShore02_LND_hrc"], 'THRainbowShoreLND' : ["TH_RainbowCliffs_LND_hrc", "TH_RainbowShore01_LND_hrc", "TH_RainbowShore02_LND_hrc"] } cmds.select(clear = True) for setName, itemList in setList.items(): if not cmds.objExists(setName): cmds.sets(n = setName) for eachHRC in itemList: if eachHRC not in animBuildList: try: cmds.sets(eachHRC, e = True, forceElement = setName) print 'Successfully added %s to %s' % (eachHRC, setName) except ValueError: print 'Failed to add %s' % eachHRC def _reconnectDuplicates(self, eachGeo = '', core_archive = ''): """ Stuff... """ ## Fetch the Geo Shaders ## Now reconnect getCoreConnections = cmds.listConnections('%s.message' % core_archive, plugs = True) if not cmds.objExists(core_archive): cmds.warning('_reconnectDuplicates needs a valid core_archive to work!!\n\t%s is invalid!' % core_archive) else: if '%s.miGeoShader' % eachGeo not in getCoreConnections: #print 'Reconnected %s to %s' % (eachGeo, core_archive) cmds.connectAttr('%s.message' % core_archive, '%s.miGeoShader' % eachGeo, force = True) def _fixTheFuckingCores(self): """ This is used to clean sweep the static scenes and remove the duplicate Namespaces and reconnect the bases to the duplicates """ removedNameSpaces = [] ## Remove duplicate root core namespaces getAllNameSpaces = cmds.namespaceInfo(listOnlyNamespaces = True) for eachNS in getAllNameSpaces: if eachNS.endswith('1'): print 'Removing %s' % eachNS cmds.namespace(removeNamespace = eachNS, mergeNamespaceWithRoot = True) removedNameSpaces.append(eachNS.replace('1', '').replace('_CORE', '')) ## Remove duplicate base cores for each in cmds.ls(type = 'core_archive'): if '1'in each: print 'Cleaned rootCore %s from scene...' % each cmds.delete(each) ## Now find all geo with the core name in it and proceess it for reconnection for eachCore in removedNameSpaces: #print eachCore ## Check child _hrc grps for processing getAllGeo = [eachGeo for eachGeo in cmds.ls('*%s*' % eachCore) if cmds.nodeType(eachGeo) == 'transform'] for eachGeo in getAllGeo: self._reconnectDuplicates(eachGeo, '%s_CORE_Geoshader' % eachCore) coreLib.cleanupDeadCoreArchives() def _rebuildCoresForSelected(self): """ Function to help delete all cores and rebuild for selected LND """ pass
class ShotgunUtils(): ''' this module is a collection of functions to conect the Asset manager to shogun studio website, to update, create and manages all attributes and parameters from the different entities. ''' def __init__(self): ''' creates the connection to the server and connects to database. creates list of Ids form the database collections that needs to convert to shotgun collections ''' ''' shotgun conection ''' SERVER_PATH = "https://hcpstudio.shotgunstudio.com" SCRIPT_NAME = 'sgApi' SCRIPT_KEY = '3899a8466f2cea694c2ba5341d871da845509d18d96a4feb7fb8d147de0fa819' self.sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) '''Shotgun Dictionaries for status and Piepeline Step and Entity''' self.sgStatusList = { 'CBB': 'cbb', 'CURRENT': 'crnt', 'DEPRECATED': 'dep', 'FINAL': 'fin', 'HOLD': 'hld', 'IN PROGRESS': 'ip', 'OMIT': 'omt', 'OUTDATED': 'outd', 'READY TO START': 'rdy', 'APPROVED': 'apr', 'REJECTED': 'rej', 'RETAKE': 'rtk', 'SUBMIT FOR APPROVAL': 'app', 'VARIANT': 'vari' } self.amStatusList = dict(map(reversed, self.sgStatusList.iteritems())) self.sgEntityDic = { 'ITEM': 'Asset', 'DIGITALMEDIA': 'Version', 'SHOT': 'shot', 'SEQUENCE': 'Sequence' } self.amEntityDic = dict(map(reversed, self.sgEntityDic.iteritems())) ''' DAO master conection ''' config = ConfigParser.ConfigParser() config.read("__database_config.ini") master = DaoMaster(instance=config.get('database_connection', 'instance'), db=config.get('database_connection', 'db')) session = master.getSession() storedFunctions = master.getStoredFunctions() self.ItemStatusConvert = storedFunctions.getCatalogItemStatusStoredFunctions( ) self.ShotStatusConvert = storedFunctions.getCatalogShotStatusStoredFunctions( ) self.SequenceStatusConvert = storedFunctions.getCatalogSequenceStatusStoredFunctions( ) self.DMStatusConvert = storedFunctions.getCatalogDigitalMediaStatusStoredFunctions( ) self.TaskStatusConvert = storedFunctions.getCatalogTaskStatusStoredFunctions( ) self.TaskStepConvert = storedFunctions.getCatalogTaskPipelineStepStoredFunctions( ) ''' instance entities from database ''' self.itemInstance = session.getItemDao() self.projectInstance = session.getProjectDao() self.sequenceInstance = session.getSequenceDao() self.shotInstance = session.getShotDao() self.taskInstance = session.getTaskDao() self.dmInstance = session.getDigitalMediaDao() self.userInstance = session.getUserDao() ''' Catalog instance ''' self.catalogDepartment = session.getCatalogDepartmentDao() self.catalogDMType = session.getCatalogDigitalMediaStatusDao() self.catalogDMStatus = session.getCatalogDigitalMediaStatusDao() self.catalogItemClass = session.getCatalogItemClassDao() self.catalogItemComplex = session.getCatalogItemComplexDao() self.catalogItemFormat = session.getCatalogItemFormatDao() self.catalogItemStatus = session.getCatalogItemStatusDao() self.catalogItemType = session.getCatalogItemTypeDao() self.catalogSequenceComplex = session.getCatalogSequenceComplexityDao() self.catalogSequenceStatus = session.getCatalogSequenceStatusDao() self.catalogShotComplex = session.getCatalogShotComplexityDao() self.catalogShotPriority = session.getCatalogShotPriorityDao() self.catalogShotStatus = session.getCatalogShotStatusDao() self.catalogTaskComplex = session.getCatalogTaskComplexityDao() self.catalogTaskEntity = session.getCatalogTaskEntityDao() self.catalogTaskName = session.getCatalogTaskNameDao() self.catalogTaskPipelineStep = session.getCatalogTaskPipelineStepDao() self.catalogTaskPriority = session.getCatalogTaskPriorityDao() self.catalogTaskStatus = session.getCatalogTaskStatusDao() self.ItemStatusList = self.getCatalogItemStatus() self.ItemType = self.getCatalogItemType() self.ItemClass = self.getCatalogItemCalss() self.ItemComplexity = self.getCatalogItemComplex() self.Department = self.getCatalogDepartment() self.DMStatus = self.getCatalogDMStatus() self.DMType = self.getCatalogDMType() self.SequenceComplex = self.getCatalogSequenceComplex() self.SequenceStatus = self.getCatalogSequenceStatus() self.ShotComplex = self.getCatalogShotComplex() self.ShotPriority = self.getCatalogShotPriority() self.ShotStatus = self.getCatalogShotStatus() self.TaskEntity = self.getCatalogTaskEntity() self.TaskName = self.getCatalogTaskName() self.TaskStep = self.getCatalogTaskPipelineStep() self.TaskPriority = self.getCatalogTaskPriority() self.TaskStatus = self.getCatalogTaskStatus() self.TaskComplex = self.getCatalogTaskComplex() self.sgPiepelineStepTag2IdDic = self.getSgStepsDic() self.sgPiepelineStepId2TagDic = dict( map(reversed, self.sgPiepelineStepTag2IdDic.iteritems())) def getParameterSchema(self, fieldType, fieldName=None): ''' utility function to search fields in a given entity. :param fieldType: entity to search parameters 'Project', 'Sequence', 'Shot', 'Asset', 'Version', etc. :param fieldName: name of the field to search 'id', 'name', 'coce', etc. :return: retruns a dictionary with the properties of given parameter ''' squemaDic = self.sg.schema_field_read(fieldType, fieldName) print squemaDic for field in squemaDic: print field return squemaDic def getEntities(self): ''' utility function to find all the Entities in shotgun for developing :return: renturn a list of all entities ''' squemaDic = self.sg.schema_entity_read() for entity in squemaDic: print entity return squemaDic def sgDicListFromDaoItemSubscription(self, itemSubscription): sgItemDictionaryList = [] if itemSubscription == []: return sgItemDictionaryList else: for item in itemSubscription: subscription = self.itemInstance.readOneByProperties( self.itemInstance.Properties.Id, item) if self.sg.find_one( 'Asset', [['id', 'is', subscription.getShotgunID()]]): sgDic = { 'type': 'Asset', 'id': subscription.getShotgunID() } sgItemDictionaryList.append(sgDic) else: pass return sgItemDictionaryList def sgDicListFromDaoShotSubscription(self, shotSubscription): sgShotDictionaryList = [] if shotSubscription == []: return sgShotDictionaryList else: for shot in shotSubscription: subscription = self.shotInstance.readOneByProperties( self.shotInstance.Properties.Id, shot) if self.sg.find_one( 'Shot', [['id', 'is', subscription.getShotgunID()]]): sgDic = {'type': 'Shot', 'id': subscription.getShotgunID()} sgShotDictionaryList.append(sgDic) else: pass return sgShotDictionaryList def sgDicListFromDaoSequenceSubscription(self, sequenceSubscription): sgSequenceDictionaryList = [] if sequenceSubscription == []: return sgSequenceDictionaryList else: for sequence in sequenceSubscription: subscription = self.sequenceInstance.readOneByProperties( self.sequenceInstance.Properties.Id, sequence) if self.sg.find_one( 'Sequence', [['id', 'is', subscription.getShotgunID()]]): sgDic = { 'type': 'Sequence', 'id': subscription.getShotgunID() } sgSequenceDictionaryList.append(sgDic) else: pass return sgSequenceDictionaryList def sgDicListFromDaoDMSubscription(self, dmSubscription): sgDMDictionaryList = [] if dmSubscription == []: return sgDMDictionaryList else: for dm in dmSubscription: subscription = self.dmInstance.readOneByProperties( self.dmInstance.Properties.Id, dm) if self.sg.find_one( 'Version', [['id', 'is', subscription.getShotgunID()]]): sgDic = { 'type': 'Version', 'id': subscription.getShotgunID() } sgDMDictionaryList.append(sgDic) else: pass return sgDMDictionaryList def sgDicListFromDaoUserSubscription(self, userSubscription): sgUserDictionaryList = [] if userSubscription == []: return sgUserDictionaryList else: for user in userSubscription: subscription = self.userInstance.readOneByProperties( self.userInstance.Properties.Id, user) if not subscription.getShotgunID() == 0: if self.sg.find_one( 'HumanUser', [['id', 'is', subscription.getShotgunID()]]): sgDic = { 'type': 'HumanUser', 'id': subscription.getShotgunID() } sgUserDictionaryList.append(sgDic) else: pass return sgUserDictionaryList def sgDicListFromDaoTaskSubscription(self, taskSubscription): sgUserDictionaryList = [] if taskSubscription == []: return sgUserDictionaryList else: for task in taskSubscription: subscription = self.taskInstance.readOneByProperties( self.taskInstance.Properties.Id, task) if not subscription.getShotgunID() == 0: if self.sg.find_one( 'Task', [['id', 'is', subscription.getShotgunID()]]): sgDic = { 'type': 'Task', 'id': subscription.getShotgunID() } sgUserDictionaryList.append(sgDic) else: pass return sgUserDictionaryList def amItemIdListFromSgItemSubscriptionDicList(self, sgDicList): amSubscriptionList = [] if sgDicList == []: return amSubscriptionList else: for sgDic in sgDicList: item = self.itemInstance.readOneByProperties( self.itemInstance.Properties.Id, sgDic['id']) if item: amSubscriptionList.append(item.getId()) else: pass return amSubscriptionList def amShotIdListFromSgShotSubscriptionDicList(self, sgDicList): amSubscriptionList = [] if sgDicList == []: return amSubscriptionList else: for sgDic in sgDicList: entity = self.shotInstance.readOneByProperties( self.shotInstance.Properties.Id, sgDic['id']) if entity: amSubscriptionList.append(entity.getId()) else: pass return amSubscriptionList def amSequenceIdListFromSgSequenceSubscriptionDicList(self, sgDicList): amSubscriptionList = [] if sgDicList == []: return amSubscriptionList else: for sgDic in sgDicList: entity = self.sequenceInstance.readOneByProperties( self.sequenceInstance.Properties.Id, sgDic['id']) if entity: amSubscriptionList.append(entity.getId()) else: pass return amSubscriptionList def amDMIdListFromSgDMSubscriptionDicList(self, sgDicList): amSubscriptionList = [] if sgDicList == []: return amSubscriptionList else: for sgDic in sgDicList: entity = self.dmInstance.readOneByProperties( self.dmInstance.Properties.Id, sgDic['id']) if entity: amSubscriptionList.append(entity.getId()) else: pass return amSubscriptionList def amTaskIdListFromSgTaskSubscriptionDicList(self, sgDicList): amSubscriptionList = [] if sgDicList == []: return amSubscriptionList else: for sgDic in sgDicList: entity = self.dmInstance.readOneByProperties( self.dmInstance.Properties.Id, sgDic['id']) if entity: amSubscriptionList.append(entity.getId()) else: pass return amSubscriptionList def sgIdFromItemId(self, itemId): if not itemId == 0: entity = self.itemInstance.readOneByProperties( self.itemInstance.Properties.Id, itemId) return entity.getShotgunID() else: return 0 def sgIdFromShotId(self, shotId): if not shotId == 0: entity = self.shotInstance.readOneByProperties( self.shotInstance.Properties.Id, shotId) return entity.getShotgunID() else: return 0 def sgIdFromSquenceId(self, sequenceId): if not sequenceId == 0: entity = self.sequenceInstance.readOneByProperties( self.sequenceInstance.Properties.Id, sequenceId) return entity.getShotgunID() else: return 0 def sgIdFromProjectId(self, projectId): if not projectId == 0: entity = self.projectInstance.readOneByProperties( self.projectInstance.Properties.Id, projectId) return entity.getShotgunID() else: return 0 def sgIdFromDmId(self, dmId): if not dmId == 0: entity = self.dmInstance.readOneByProperties( self.dmInstance.Properties.Id, dmId) return entity.getShotgunID() else: return 0 def sgIdFromTaskId(self, taskId): if not taskId == 0: entity = self.taskInstance.readOneByProperties( self.taskInstance.Properties.Id, taskId) return entity.getShotgunID() else: return 0 def getCatalogDepartment(self): listFromCatalog = [] catalogAll = self.catalogDepartment.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogDMStatus(self): listFromCatalog = [] catalogAll = self.catalogDMStatus.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogDMType(self): listFromCatalog = [] catalogAll = self.catalogDMType.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogItemCalss(self): listFromCatalog = [] catalogAll = self.catalogItemClass.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogItemComplex(self): listFromCatalog = [] catalogAll = self.catalogItemComplex.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def itemStatus2Dao(self, status): return self.ItemStatusConvert.getIdFromTag(status) def shotStatus2Dao(self, status): return self.ShotStatusConvert.getIdFromTag(status) def sequenceStatus2Dao(self, status): return self.SequenceStatusConvert.getIdFromTag(status) def dmStatus2Dao(self, status): return self.SequenceStatusConvert.getIdFromTag(status) def taskStatus2Dao(self, status): return self.TaskStatusConvert.getIdFromTag(status) def getCatalogItemStatus(self): listFromCatalog = [] catalogAll = self.catalogItemStatus.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogItemType(self): listFromCatalog = [] catalogAll = self.catalogItemType.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogSequenceComplex(self): listFromCatalog = [] catalogAll = self.catalogSequenceComplex.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogSequenceStatus(self): listFromCatalog = [] catalogAll = self.catalogSequenceStatus.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogShotComplex(self): listFromCatalog = [] catalogAll = self.catalogShotComplex.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogShotPriority(self): listFromCatalog = [] catalogAll = self.catalogShotPriority.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogShotStatus(self): listFromCatalog = [] catalogAll = self.catalogShotStatus.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogTaskComplex(self): listFromCatalog = [] catalogAll = self.catalogTaskComplex.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogTaskEntity(self): listFromCatalog = [] catalogAll = self.catalogTaskEntity.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogTaskName(self): listFromCatalog = [] catalogAll = self.catalogTaskName.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogTaskPipelineStep(self): listFromCatalog = [] catalogAll = self.catalogTaskPipelineStep.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogTaskPriority(self): listFromCatalog = [] catalogAll = self.catalogTaskPriority.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getCatalogTaskStatus(self): listFromCatalog = [] catalogAll = self.catalogTaskStatus.readAll() for catalog in catalogAll: listFromCatalog.append(catalog.getTag()) return listFromCatalog def getSgStepsDic(self): sgFields = ['id', 'code'] dictionaryList = self.sg.find('Step', [], sgFields) stepDic = {} for dictionary in dictionaryList: stepDic.update({dictionary['code']: dictionary['id']}) return stepDic def daoitem2sgDic(self, itemId): entity = self.itemInstance.readOneByProperties( self.itemInstance.Properties.Id, itemId) sgDic = {} if entity: if not entity.getShotgunID() == 0: sgDic = {'type': 'Asset', 'id': entity.getShotgunID()} return sgDic else: return None else: return None def daoShot2sgDic(self, itemId): entity = self.shotInstance.readOneByProperties( self.shotInstance.Properties.Id, itemId) sgDic = {} if entity: if not entity.getShotgunID() == 0: sgDic = {'type': 'Shot', 'id': entity.getShotgunID()} return sgDic else: return None else: return None def daoSequence2sgDic(self, itemId): entity = self.sequenceInstance.readOneByProperties( self.sequenceInstance.Properties.Id, itemId) sgDic = {} if entity: if not entity.getShotgunID() == 0: sgDic = {'type': 'Sequence', 'id': entity.getShotgunID()} return sgDic else: return None else: return None def daoDM2sgDic(self, itemId): entity = self.dmInstance.readOneByProperties( self.dmInstance.Properties.Id, itemId) sgDic = {} if entity: if not entity.getShotgunID() == 0: sgDic = {'type': 'Version', 'id': entity.getShotgunID()} return sgDic else: return None else: return None def daoHumanUser2sgDic(self, itemId): entity = self.userInstance.readOneByProperties( self.userInstance.Properties.Id, itemId) sgDic = {} if entity: if not entity.getShotgunID() == 0: sgDic = {'type': 'Asset', 'id': entity.getShotgunID()} return sgDic else: return None else: return None def daoTask2sgDic(self, itemId): entity = self.taskInstance.readOneByProperties( self.taskInstance.Properties.Id, itemId) sgDic = {} if entity: if not entity.getShotgunID() == 0: sgDic = {'type': 'Task', 'id': entity.getShotgunID()} return sgDic else: return None else: return None
class genericUtils: def __init__(self): self.sg = Shotgun('https://' + URL,name,API) def getFields (self, entity): '''get the fields for a type/entity as a list so we can pass it as an arg easily this is used all the time to make sure we get all the fields that we may ever need for a type/entity ''' allFields = [] fields = self.sg.schema_field_read(entity) for field in fields: allFields.append(field) return allFields def project (self, project): '''Gets the Shotgun project name and ID ''' retFields = self.getFields('Project') project = project.replace('_', ' ') return self.sg.find_one("Project", [["name", "is", project]], retFields ) def sequence (self, project, sequence): '''Returns the shotgun sequence name and ID Parameters : (project, sequence) ''' retFields = self.getFields('Sequence') return self.sg.find_one("Sequence", [["code", "is", sequence],['project','is',project]], retFields) def shot (self, project, shot): '''Returns the shotgun shot name and ID Parameters : (project, shot) ''' retFields = self.getFields('Shot') return self.sg.find_one('Shot',[['code','is',shot],['project','is',project]],retFields) def createProject (self, project): '''Creates a project in Shotgun given a project name Parameters : (project) ''' filters = [['code','is','a']] template = self.sg.find_one('Project',[['name','is','a']],['layout_project','id']) data = {'name':project, 'layout_project': template } return self.sg.create('Project',data) def createSequence (self, project, sequence): '''Creates a sequence in shotgun given Parameters : (project, sequence) ''' data = {'project': {"type":"Project","id": project['id']}, 'code': sequence} return self.sg.create('Sequence', data) def createShot (self, project, shot, seq='', taskTemplateName=''): '''Creates a sequence in shotgun given Parameters : (project, shot, seq='', taskTemplateName='Basic shot template' ''' filters = [['code','is',taskTemplateName ]] template = self.sg.find_one('TaskTemplate',filters) data = { 'project': {"type":"Project","id": project['id']}, 'code': shot, 'task_template' : template, 'description': '', 'self.sg_sequence': seq, 'self.sg_status_list': 'wtg' } result = self.sg.create('Shot', data) return result def notesFind (self, shotID): '''Find all notes on a shot Parameters : (shotID) Output : Note data : ['tasks', 'attachments', 'updated_at', 'replies', 'id', 'subject', 'playlist', ' addressings_to', 'created_by', 'content', 'sg_status_list', 'reply_content', 'updated_by', 'addressings_cc', 'read_by_current_user', 'user', 'note_links', 'created_at', 'sg_note_from', 'project', 'sg_note_type', 'tag_list'] ''' note = self.sg.find('Note',[['note_links','is', shotID]],['subject','content', 'created_at'],[{'field_name':'created_at','direction':'desc'}]) return note def notesFindLatest (self, shotID): '''Find the latest note on a shot Parameters : (shotID) Call with notesFindLatest(shot)['content'] for the note content only Output : Note data: ['tasks', 'attachments', 'updated_at', 'replies', 'id', 'subject', 'playlist', ' addressings_to', 'created_by', 'content', 'sg_status_list', 'reply_content', 'updated_by', 'addressings_cc', 'read_by_current_user', 'user', 'note_links', 'created_at', 'sg_note_from', 'project', 'sg_note_type', 'tag_list'] ''' note = self.notesFind(shotID)[0] return note def notesCreate(self, project, shotID, subject, content): '''Create a note for a shot given Parameters : (project, shotID, subject, content) Output : noteID ''' # enter data here for a note to create data = {'subject':subject,'content':content,'note_links':[shotID],'project':project} # create the note noteID = self.sg.create('Note',data) return noteID def versionCreate(self, project, shot, verName, description, framePath, firstFrame, lastFrame, clientName=None, sourceFile=None, task=None, user=None, final=False, makeThumb=False, makeThumbShot=False): '''Create a version Parameters : (project, shotID, verName, description, framePath, firstFrame, lastFrame, clientName=None, sourceFile=None, task=None) Output : versionID ''' data = {'project': project, 'code': verName, 'description': description, 'sg_path_to_frames': framePath, #'sg_frame_range': str(firstFrame) + '-' + str(lastFrame), 'sg_first_frame' : int(firstFrame), 'sg_last_frame' : int(lastFrame), 'sg_status_list': 'rev', 'entity': shot} #if user != None: #data['user'] if task != None: filters = [['content','is',task],['entity','is',shot]] taskID = self.sg.find_one('Task',filters) data['sg_task']=taskID #if final == True and 'send # in case we're putting a client version in here we need this code. # we are expecting a field called self.sg_client_name in the version table. # please make sure you create this in the shotgun setup # read the schema and if the client_name is not found, create it. ''' versionFields = self.sg.schema_field_read('Version') if 'sg_client_name' not in versionFields and clientName != None: newField = self.sg.schema_field_create('Version','text','Client Name') if clientName != None : data['sg_client_name'] = clientName #'user': {'type':'HumanUser', 'id':165} } # here we need to create a field for storing the source file that created this version. # if it's not there, create the field, and if it's there just update it. if 'sg_source_file' not in versionFields and sourceFile != None: newField = self.sg.schema_field_create('Version','text','Source File') if sourceFile != None: data['sg_source_file'] = sourceFile ''' versionData = self.sg.create('Version',data) # handle the thumbnail grabbing here middleFrame = (int(firstFrame) + int(lastFrame)) / 2 padding, padString = fxpipe.framePad(framePath) paddedFrame = padString % (middleFrame) if makeThumb == True: thumbData = self.sg.upload_thumbnail('Version', versionData['id'], framePath.replace(padding,paddedFrame)) if makeThumbShot == True: thumbData = self.sg.upload_thumbnail('Shot', shot['id'], framePath.replace(padding,paddedFrame)) return versionData #add a task version to the system def versionCreateTask(self, project, shot, verName, description, framePath, firstFrame, lastFrame, task, sourceFile = ''): ''' DEPRECATED : USE versionCreate instead with the task='TASKNAME' Parameters : (project, shot, verName, description, framePath, firstFrame, lastFrame, task, sourceFile = '') Output : Version ID ''' filters = [['content','is',task],['entity','is',shot]] taskID = self.sg.find_one('Task',filters) data = {'project': project, 'code': verName, 'description': description, 'self.sg_path_to_frames': framePath, 'frame_range': str(firstFrame) + '-' + str(lastFrame), 'self.sg_first_frame' : firstFrame, 'self.sg_last_frame' : lastFrame, #'self.sg_uploaded_movie': '/Users/throb/Downloads/test.m4v', #'self.sg_first_frame': 1, #'self.sg_last_frame': 100, 'self.sg_status_list': 'rev', 'self.sg_task': taskID, 'entity': shot} # here we need to create a field for storing the source file that created this version. # if it's not there, create the field, and if it's there just update it. try: tmp2 = {} tmp2 = tmp['self.sg_source_file'] except: newField = self.sg.schema_field_create('Version','text','Source File') if sourceFile != '': data['self.sg_source_file'] = sourceFile return self.sg.create('Version',data) # look for specific version def versionFind(self, versionID): '''Find all versions in a shot with most recent first Parameters : (shotID) Output : Version data: ['sg_version_type', 'open_notes_count', 'code', 'playlists', 'sg_task', 'image', 'updated_at', 'sg_output', 'sg_path_to_frames', 'tasks', 'frame_range', 'id', 'description', 'sg_uploaded_movie_webm', 'open_notes', 'tank_published_file', 'task_template', 'created_by', 'sg_movie_type', 'sg_status_list', 'notes', 'sg_client_name', 'sg_uploaded_movie_mp4', 'updated_by', 'sg_send_for_final', 'user', 'sg_uploaded_movie_frame_rate', 'entity', 'step_0', 'sg_client_version', 'sg_uploaded_movie_transcoding_status', 'created_at', 'sg_qt', 'project', 'filmstrip_image', 'tag_list', 'frame_count', 'flagged'] ''' retFields = self.getFields('Version') return self.sg.find('Version',[['id','is',versionID]],retFields,[{'field_name':'created_at','direction':'desc'}])[0] # look for versions in a shot: def versionFindShot(self, shotID): '''Find all versions in a shot with most recent first Parameters : (shotID) Output : Version data: ['sg_version_type', 'open_notes_count', 'code', 'playlists', 'sg_task', 'image', 'updated_at', 'sg_output', 'sg_path_to_frames', 'tasks', 'frame_range', 'id', 'description', 'sg_uploaded_movie_webm', 'open_notes', 'tank_published_file', 'task_template', 'created_by', 'sg_movie_type', 'sg_status_list', 'notes', 'sg_client_name', 'sg_uploaded_movie_mp4', 'updated_by', 'sg_send_for_final', 'user', 'sg_uploaded_movie_frame_rate', 'entity', 'step_0', 'sg_client_version', 'sg_uploaded_movie_transcoding_status', 'created_at', 'sg_qt', 'project', 'filmstrip_image', 'tag_list', 'frame_count', 'flagged'] ''' retFields = self.getFields('Version') return self.sg.find('Version',[['entity','is',shotID]],retFields,[{'field_name':'created_at','direction':'desc'}]) def versionFindLatest(self, shotID): '''Find only the most recent version Parameters : (shotID) Output : Version data: ['sg_version_type', 'open_notes_count', 'code', 'playlists', 'sg_task', 'image', 'updated_at', 'sg_output', 'sg_path_to_frames', 'tasks', 'frame_range', 'id', 'description', 'sg_uploaded_movie_webm', 'open_notes', 'tank_published_file', 'task_template', 'created_by', 'sg_movie_type', 'sg_status_list', 'notes', 'sg_client_name', 'sg_uploaded_movie_mp4', 'updated_by', 'sg_send_for_final', 'user', 'sg_uploaded_movie_frame_rate', 'entity', 'step_0', 'sg_client_version', 'sg_uploaded_movie_transcoding_status', 'created_at', 'sg_qt', 'project', 'filmstrip_image', 'tag_list', 'frame_count', 'flagged'] ''' retFields = self.getFields('Version') return self.sg.find_one('Version',[['entity','is',shotID]],retFields,[{'field_name':'created_at','direction':'desc'}]) # search for the latest task given shotID and task info def versionFindLatestTask(self, shotID, task): retFields = self.getFields('Version') # first look for the task and get the ID filters = [['content','is',task],['entity','is',shotID]] taskID = self.sg.find_one('Task',filters) # then look for the latest #version using the task ID. note that we need to use the [0] or else we're sending the array versus the hash versionLatest = self.sg.find_one('Version',[['entity','is',shotID],['self.sg_task','is',taskID]],retFields,[{'field_name':'created_at','direction':'desc'}]) return versionLatest ## The following requires a field called "client_version" be added to shotgun def versionClientUpdate (self, shotID, version, clientVersionName ='Client Version'): '''This takes the shotID and version (int) and updates the shot with this client version number Sometimes the client wants to see different version numbers versus the internal ones. This option allows for it. You will need to create a field. Client Version is what I have used but you can specify what you want here. Parameters: (shotID, version, clientVersionName ='Client Version') Output : Version data ''' sgFieldName = 'sg_' + clientVersionName.lower().replace(' ','_') data = { sgFieldName: version} try: result = self.sg.update('Shot', shotID['id'], data) except: newField = self.sg.schema_field_create('Shot', 'number', clientVersionName) result = self.sg.update('Shot', shotID['id'], data) return result def uploadQT (self, entityType, item, path): '''Upload a file to shotgun in the 'self.sg_qt' field. If you do this for a shot, you will need to add this to a field the field should be called 'qt' as shotgun will add the self.sg_ to it Shotgun provides the self.sg_qt for versions automatically Parameters: (entity,item,path) uploadQT ('Version',versionData, '/my/file.mov') ''' # Make sure first letter is capitalized entity = entityType.capitalize() # upload that mother if entity.lower() == 'shot': try: result = self.sg.upload (entity, item['id'], path,'sg_qt') except: newField = self.sg.schema_field_create('Shot', 'url', 'QT') result = self.sg.upload (entity, item['id'], path,'sg_qt') elif entity.lower() == 'version': result = self.sg.upload (entity, item['id'], path,'sg_uploaded_movie') return result def versionClientGet (self, shotID, clientVersion='Client Version'): '''Get latest client version number Parameters : (hotID, clientVersion='Client Version') Output : Version data ''' sgFieldName = 'sg_' + clientVersionName.lower().replace(' ','_') try : currentVersion = shotID[sgFieldName] except : currentVersion = 0 if currentVersion == None: return 0 return currentVersion def playlistFind (self, project, playlistName): '''Search for a playlist given a project and name Parameters : (project, playlistName) Output : playlist data: ['code', 'description', 'versions', 'created_at', 'sg_cinesync_session_url', 'updated_at', 'created_by', 'project', 'filmstrip_image', 'notes', 'image', 'updated_by', 'sg_cinesync_session_key', 'sg_status', 'tag_list', 'id', 'sg_date_and_time'] ''' retFields = self.getFields('Playlist') return self.sg.find_one('Playlist',[['code','is',playlistName],['project','is',project]],retFields) def playlistCreate (self, project, playlistName, playlistDescription=''): '''Create a playlist given a playlist name Parameters : (project, playlistName, playlistDescription='') Output : playlist data ''' data = {'project':project,'code':playlistName, 'description':playlistDescription} return self.sg.create('Playlist',data) # Add a version to a playlist def playlistAddVersion (self, project, playlistName, version): ''' Description :\n This adds a version (existing version in the system) to a playlist.\n You need to give it: (in order)\r shotgun connection class\r project (dict of the project info including name and id)\r playlist name (string of the name of the playlist)\r version (dict of the version you wish to add\n It will return with a dict of the playlist ''' my_playlist_list = self.sg.find_one('Playlist',[['code','is',playlistName],['project','is',project]],['versions']); if len(my_playlist_list): ver_list = my_playlist_list['versions']; ver_list.append({'type':'Version','name':version['code'],'id':version['id']}) result = self.sg.update('Playlist', my_playlist_list['id'], {'versions' : ver_list}) return result def playlistInfo (self, project, playlistName): '''Get playlist info (eg version name and description) Parameters : (project, playlistName) Output : version data ''' data = [] versionData = [] retFields = self.getFields('Version') for versionInPlaylist in self.sg.find_one('Playlist',[['code','is',playlistName],['project','is',project]],['versions'])['versions']: data.append (self.sg.find_one('Version',[['id','is',versionInPlaylist['id']]],retFields)) #for items in data: # versionData.append({'name':items['code'],'desc':items['description'],'first_frame':items['self.sg_first_frame}) return data def getTimeShot(self, shot): '''Given shot (as dict) return total time on shot as [0] and other times for each task on shot ''' outputData = [] retFields = ['content','time_logs_sum'] totalTime = 0 for curTask in shot['tasks']: taskData = self.sg.find_one('Task',[['id','is',curTask['id']]],fields=retFields) totalTime += taskData['time_logs_sum'] outputData.append({'name':taskData['content'],'time':taskData['time_logs_sum']}) outputData.insert(0,{'name':shot['code'],'time':totalTime}) return outputData
try: print '<h3>Processing request to create playlist from current version of these shots...</h3>' print '</br>' print '</br>' success = True # keep track of errors so that true success for all requests can be reported to the user shot_filters = [ ['project','is',{'type':'Project','id':PROJECT_ID}], ['id', 'in', ] + shot_ids ] # #mark First get the version so that the linked shot can then be accessed. assets= sg.find("Shot", shot_filters, shot_fields) # did anything get returned? if not then error out... if len(assets) < 1: print '</br>' print "<b>Shotgun Server Did Not Return Any Shots! </b>" print '</br>' print '</br>' success = False else: # something was returned, process it! for an_asset in assets: # get the appropriate version and append it to the version list # first, look to see if there is a current version in the shot data
document.add_heading(fileName, 0) # Writing it out document.add_paragraph(unicode(feed, 'utf-8')) try : document.save('I:\dev_JC\_Python\Data_Pull\WD\\' + fileName + '.docx') except IOError: document.save('I:\dev_JC\_Python\Data_Pull\WD\\' + "Bad_Name" + '.docx') # Pulls a shotgun Thread based on the id formatting ={} filters = [ ['id', 'is', 123]] ##This is the controller, place whatever project ID you need docs for project = sg.find_one('Project', filters, fields=['id']) filters = [ ['project', 'is', {'type':'Project', 'id':project['id']}], ] #result = sg.find('Asset', filters, fields=['sg_rpm_number', 'notes', 'id', 'sg_rpm_number']) result = sg.find('Asset', filters, fields=['sg_rpm_number', 'cached_display_name','notes', 'id', 'sg_rpm_number']) print result for i in result: thread = "" dict = i['notes'] excludeRPM = [] excludeID = [] # Filter out array elements that are not threads in list/bad job numbers if not dict: continue if i['sg_rpm_number'] in excludeRPM: continue
class Main(QtGui.QWidget, Ui_Form, ReferenceTab, CommentWidget, Lib, TaskManager, MyTasks, WhatsNew, Asset, LogEntry, Task, AssetLoader, Moodboard_Creator, PeopleTab, RenderTab): def __init__(self): super(Main, self).__init__() self.username = os.getenv('USERNAME') self.setWindowFlags(self.windowFlags() | QtCore.Qt.CustomizeWindowHint) self.ReferenceTab = ReferenceTab self.Lib = Lib self.TaskManager = TaskManager self.RenderTab = RenderTab self.MyTasks = MyTasks self.WhatsNew = WhatsNew self.CommentWidget = CommentWidget self.Task = Task self.Asset = Asset self.AssetLoader = AssetLoader self.LogEntry = LogEntry self.Moodboard_Creator = Moodboard_Creator self.PeopleTab = PeopleTab sg_url = "http://nad.shotgunstudio.com" sg_script_name = "ThibaultGenericScript" sg_key = "e014f12acda4074561022f165e8cd1913af2ba4903324a72edbb21430abbb2dc" self.sg_project_id = 146 self.sg = Shotgun(sg_url, sg_script_name, sg_key) # Initialize the guis self.Form = self.setupUi(self) self.Form.center_window() self.setMinimumSize(1453, 923) self.setMaximumSize(1453, 923) self.db_to_load = "" self.db_path = "Z:\\Groupes-cours\\NAND999-A15-N01\\Nature\\_pipeline\\_utilities\\_database\\nature.sqlite" # Database nature if QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier: # Database Setup self.db_path = "H:\\01-NAD\\_pipeline\\_utilities\\_database\\db.sqlite" # Copie de travail # Backup database if self.db_path not in [ "H:\\01-NAD\\_pipeline\\_utilities\\_database\\db.sqlite", "Z:\\Groupes-cours\\NAND999-A15-N01\\Nature\\_pipeline\\_utilities\\_database\\rendering.sqlite" ]: self.backup_database() self.db = sqlite3.connect(self.db_path, check_same_thread=False, timeout=30.0) self.cursor = self.db.cursor() # Global Variables self.projectList.hide() self.i = 0 self.computer_id = socket.gethostname() self.ref_assets_instances = [] self.selected_asset = None self.utf8_codec = QtCore.QTextCodec.codecForName("utf-8") self.today = time.strftime("%d/%m/%Y", time.gmtime()) self.cur_path = os.path.dirname(os.path.realpath( __file__)) # H:\01-NAD\_pipeline\_utilities\_asset_manager self.cur_path_one_folder_up = self.cur_path.replace( "\\_asset_manager", "") # H:\01-NAD\_pipeline\_utilities self.NEF_folder = self.cur_path_one_folder_up + "\\_NEF" # H:\01-NAD\_pipeline\_utilities\NEF self.screenshot_dir = self.cur_path_one_folder_up + "\\_database\\screenshots\\" self.no_img_found = self.cur_path + "\\media\\no_img_found.png" self.number_of_refreshes = 0 self.members = { "acorbin": "Alexandre", "fpasquarelli": "Francis", "costiguy": "Chloe", "cgonnord": "Christopher", "erodrigue": "Etienne", "jberger": "Jeremy", "lgregoire": "Laurence", "lclavet": "Louis-Philippe", "mbeaudoin": "Mathieu", "mroz": "Maxime", "obolduc": "Olivier", "slachapelle": "Simon", "thoudon": "Thibault", "vdelbroucq": "Valentin", "yjobin": "Yann", "yshan": "Yi" } self.sg_members = { "acorbin": "3dalcor", "fpasquarelli": "francis.pasquarelli", "costiguy": "ostiguy.chloe", "cgonnord": "christopher.gonnord", "erodrigue": "etienne.rodrigue89", "jberger": "jeremy.berger3d", "lgregoire": "lau-gregoire", "lclavet": "clavet.lp", "mbeaudoin": "beaudoinmathieu", "mroz": "maximeroz", "obolduc": "ol.bolduc", "slachapelle": "simonlachapelle", "thoudon": "houdon.thibault", "vdelbroucq": "valentin.delbroucq", "yjobin": "yannjobinphoto", "yshan": "yishan3d" } self.departments_shortname = { "Script": "spt", "Storyboard": "stb", "References": "ref", "Concepts": "cpt", "Modeling": "mod", "Texturing": "tex", "Rigging": "rig", "Animation": "anm", "Simulation": "sim", "Shading": "shd", "Camera": "cam", "Lighting": "lgt", "Layout": "lay", "DMP": "dmp", "Rendering": "rdr", "Compositing": "cmp", "Editing": "edt", "RnD": "rnd" } self.departments_longname = { "spt": "Script", "stb": "Storyboard", "ref": "References", "cam": "Camera", "cpt": "Concepts", "lgt": "Lighting", "mod": "Modeling", "tex": "Texturing", "rig": "Rigging", "anm": "Animation", "sim": "Simulation", "shd": "Shading", "lay": "Layout", "dmp": "DMP", "rdr": "Rendering", "cmp": "Compositing", "edt": "Editing", "rnd": "RnD" } refresh_icon = QtGui.QIcon(self.cur_path + "\\media\\refresh.png") self.refreshAllBtn.setIcon(refresh_icon) self.refreshAllBtn.setIconSize(QtCore.QSize(24, 24)) self.refreshAllBtn.clicked.connect(self.refresh_all) # Setup user session if it is not already setup is_setup = self.cursor.execute( '''SELECT is_setup FROM preferences WHERE username=?''', (self.username, )).fetchone()[0] if is_setup == 0: self.Lib.setup_user_session(self) self.cursor.execute( '''UPDATE preferences SET is_setup=1 WHERE username=?''', (self.username, )) self.db.commit() # Clear temp folder if os.path.isdir("H:/tmp"): try: shutil.rmtree("H:/tmp") except: pass try: os.makedirs("H:/tmp") except: pass # Create Favicon self.app_icon = QtGui.QIcon() self.app_icon.addFile(self.cur_path + "\\media\\favicon_cube.png", QtCore.QSize(64, 64)) self.Form.setWindowIcon(self.app_icon) # Set the StyleSheet self.themePrefComboBox.currentIndexChanged.connect(self.change_theme) self.theme = self.cursor.execute( '''SELECT theme FROM preferences WHERE username=?''', (self.username, )).fetchone()[0] self.themePrefComboBox.setCurrentIndex(int(self.theme)) self.change_theme() # Admin Setup self.remove_tabs_based_on_members() # Get remaining time and set deadline Progress Bar day_start = date(2015, 6, 28) day_end = date(2016, 4, 25) day_today = datetime.now().date() months_and_days_left = relativedelta.relativedelta(day_end, day_today) total_days = abs(day_end - day_start).days remaining_days = abs(day_end - date.today()).days remaining_days_percent = ( remaining_days * 100 ) / total_days # Converts number of remaining day to a percentage self.deadlineProgressBar.setFormat( "{0} months and {1} days left ({2}%)".format( months_and_days_left.months, months_and_days_left.days, remaining_days_percent)) self.deadlineProgressBar.setMaximum(total_days) self.deadlineProgressBar.setValue(remaining_days) hue = self.fit_range(remaining_days, 0, total_days, 0, 76) self.deadlineProgressBar.setStyleSheet( "QProgressBar::chunk {background-color: hsl(" + str(hue) + ", 255, 205);}") if self.username not in ["thoudon", "lclavet", "costiguy"]: self.deadlineFrame.hide() # Setup disk usage progress bar disk_usage = self.Lib.get_folder_space(self) disk_usage = int( float(disk_usage) * 1000) # Multiply disk usage by 1000. Ex: 1.819 to 1819 disk_usage = ( 2000 * int(disk_usage) ) / 1862 # 2TO in theory = 1.862GB in reality. Remapping real disk usage to the theoric one self.diskUsageProgressBar.setFormat('{0}/2000 GB'.format( str(disk_usage))) self.diskUsageProgressBar.setRange(0, 2000) self.diskUsageProgressBar.setValue(int(disk_usage)) hue = self.fit_range(int(disk_usage), 0, 2000, 0, 76) self.diskUsageProgressBar.setStyleSheet( "QProgressBar::chunk {background-color: hsl(" + str(hue) + ", 255, 205);}") # Thumbnail creation progress bar setup self.thumbnailProgressBar.setStyleSheet( "QProgressBar::chunk {background-color: hsl(0, 100, 175);}") self.thumbnailProgressBar.setValue(0) self.thumbnailProgressBar.hide() # Get software paths from database and put them in preference self.photoshop_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Photoshop"''' ).fetchone()[0]) self.maya_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Maya"''' ).fetchone()[0]) self.maya_batch_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Maya Batch"''' ).fetchone()[0]) self.softimage_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Softimage"''' ).fetchone()[0]) self.softimage_batch_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Softimage Batch"''' ).fetchone()[0]) self.houdini_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Houdini"''' ).fetchone()[0]) self.houdini_batch_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Houdini Batch"''' ).fetchone()[0]) self.cinema4d_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Cinema 4D"''' ).fetchone()[0]) self.nuke_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Nuke"''' ).fetchone()[0]) self.zbrush_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="ZBrush"''' ).fetchone()[0]) if os.path.exists( "C:/Program Files/Mari2.6v2/Bundle/bin/Mari2.6v2.exe"): self.mari_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Mari"''' ).fetchone()[0]) else: self.mari_path = "C:/Program Files/Mari2.6v5/Bundle/bin/Mari2.6v5.exe" self.blender_path = str( self.cursor.execute( '''SELECT software_path FROM software_paths WHERE software_name="Blender"''' ).fetchone()[0]) self.cursor.execute( '''UPDATE preferences SET is_online=1 WHERE username=?''', (self.username, )) self.db.commit() # Preferences setup self.prefBckGroundColorSlider.sliderMoved.connect( self.change_pref_background_color_pixmap) self.prefBckGroundColorSlider.setStyleSheet("background-color; red;") # Set systray actions self.quitAction = QtGui.QAction("Quit", self, triggered=self.terminate_program) self.quitAction.setIcon( QtGui.QIcon(self.cur_path + "/media/turn_off.png")) # Systray icon self.trayIconMenu = QtGui.QMenu(self) self.trayIconMenu.addAction(self.quitAction) self.tray_icon = QtGui.QIcon(self.cur_path + "\\media\\favicon_cube.png") self.trayIcon = QtGui.QSystemTrayIcon(self) self.trayIcon.setContextMenu(self.trayIconMenu) self.trayIcon.setIcon(self.tray_icon) self.tray_icon_log_id = "" self.tray_message = "" self.trayIcon.hide() #self.tray_icon.messageClicked.connect(self.tray_icon_message_clicked) self.trayIcon.activated.connect(self.tray_icon_clicked) # Initialize modules and connections AssetLoader.__init__(self) self.ReferenceTab.__init__(self) self.RenderTab.__init__(self) self.CommentWidget.__init__(self) self.WhatsNew.__init__(self) self.PeopleTab.__init__(self) self.WhatsNew.load_whats_new(self) self.check_last_active() #self.check_news_thread = CheckNews(self) #self.connect(self.check_news_thread, QtCore.SIGNAL("check_last_active"), self.check_last_active) #self.check_news_thread.daemon = True #self.check_news_thread.start() self.show() #self.check_shotgun_time_log() def check_shotgun_time_log(self): self.username = "******" peoples = { "acorbin": "Alexandre Corbin", "costiguy": "Chloé Ostiguy", "cgonnord": "Christopher Gonnord", "erodrigue": "Etienne Rodrigue", "fpasquarelli": "Francis Pasquarelli", "jberger": "Jérémy Berger", "lgregoire": "Laurence Grégoire", "lclavet": "Louis-Philippe Clavet", "mbeaudoin": "Mathieu Beaudoin", "mroz": "Maxime Roz", "thoudon": "Thibault Houdon", "vdelbroucq": "Valentin Delbroucq", "yjobin": "Yann Jobin", "yshan": "Yi Shan" } user = peoples[self.username] project = self.sg.find_one("Project", [["id", "is", self.sg_project_id]]) time_log = self.sg.find( "TimeLog", [["date", "in_calendar_day", -1], ["project", "is", project]], ["user"]) people_logged = [log["user"]["name"] for log in time_log] people_logged = list(set(people_logged)) if user not in people_logged: time_log_window = QtGui.QDialog(self) time_log_window.setWindowTitle("Add your time log entry") layout = QtGui.QVBoxLayout(time_log_window) descriptionLabel = QtGui.QLabel(time_log_window) durationLabel = QtGui.QLabel(time_log_window) descriptionLabel.setText("Description") durationLabel.setText("Duration") self.description = QtGui.QLineEdit(time_log_window) self.duration = QtGui.QLineEdit(time_log_window) addLogEntryBtn = QtGui.QPushButton(time_log_window) addLogEntryBtn.setText("Add Time Log Entry") addLogEntryBtn.clicked.connect(self.shotgun_add_time_log) didntWorkBtn = QtGui.QPushButton(time_log_window) didntWorkBtn.setText("I didn't work on this project yesterday.") layout.addWidget(durationLabel) layout.addWidget(self.duration) layout.addWidget(descriptionLabel) layout.addWidget(self.description) layout.addWidget(addLogEntryBtn) layout.addWidget(didntWorkBtn) time_log_window.exec_() def shotgun_add_empty_time_log(self): pass def shotgun_add_time_log(self): print(self.description.text()) print(self.duration.text()) def add_tag_to_tags_manager(self): # Check if a project is selected if len(self.projectList.currentText()) == 0: Lib.message_box(text="Please select a project first.") return tag_name = unicode(self.addTagLineEdit.text()) tag_name = Lib.normalize_str(self, tag_name) if len(tag_name) == 0: Lib.message_box(text="Please enter a tag name.") return item = QtGui.QTreeWidgetItem(self.tagsTreeWidget) item.setText(0, tag_name) self.tagsTreeWidget.addTopLevelItem(item) self.addTagLineEdit.setText("") self.save_tags_list() def remove_selected_tags_from_tags_manager(self): root = self.tagsTreeWidget.invisibleRootItem() for item in self.tagsTreeWidget.selectedItems(): (item.parent() or root).removeChild(item) self.save_tags_list() def save_tags_list(self): root = self.tagsTreeWidget.invisibleRootItem() # Fetch the root item child_count = root.childCount() for item in xrange(child_count): # Get the text of the first item in the tree widget parent_text = str(root.child(item).text(0)) # Check if item already exists, if no, add it to the database, if yes, update its name and parent already_exist = self.cursor.execute( '''SELECT tag_name FROM tags WHERE tag_name=?''', (parent_text, )).fetchone() if already_exist == None: self.cursor.execute( '''INSERT INTO tags(project_name, tag_name, tag_parent) VALUES(?,?,?)''', ( self.selected_project_name, parent_text, "", )) else: self.cursor.execute( '''UPDATE tags SET tag_name=?, tag_parent=? WHERE tag_name=? AND project_name=?''', ( parent_text, "", parent_text, self.selected_project_name, )) # Get all children of parent item nbr_of_children = root.child(item).childCount() for i in range(nbr_of_children): child_text = str(root.child(item).child(i).text(0)) # Check if item already exists, if no, add it to the database, if yes, update its name and parent already_exist = self.cursor.execute( '''SELECT tag_name FROM tags WHERE tag_name=?''', (child_text, )).fetchone() if already_exist == None: self.cursor.execute( '''INSERT INTO tags(project_name, tag_name, tag_parent) VALUES(?,?,?)''', ( self.selected_project_name, child_text, parent_text, )) else: self.cursor.execute( '''UPDATE tags SET tag_name=?, tag_parent=? WHERE tag_name=? AND project_name=?''', ( child_text, parent_text, child_text, self.selected_project_name, )) self.db.commit() def add_assets_to_asset_list(self, assets_list): """ Add assets from assets_list to self.assetList """ self.assetList.clear() for asset in assets_list: self.assetList.addItem(asset[4]) def clear_filter(self, filter_type): """ Clear the filter edit line """ if filter_type == "seq": self.seqFilter.setText("") elif filter_type == "asset": self.assetFilter.setText("") def update_thumb(self): """ Update selected asset thumbnail """ self.Form.showMinimized() Lib.take_screenshot(self.screenshot_dir, self.selected_asset_name) pixmap = QtGui.QPixmap(self.screenshot_dir + self.selected_asset_name + ".jpg").scaled(1000, 200, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self.assetImg.setPixmap(pixmap) self.Form.showMaximized() self.Form.showNormal() def remove_tabs_based_on_members(self): if not (self.username == "thoudon" or self.username == "lclavet"): self.adminPrefFrame.hide() self.createAssetFromScratchBtn.hide() self.get_tabs_id_from_name() if self.members[self.username] == "Chloe": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Francis": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Alexandre": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Christopher": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Etienne": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Jeremy": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Laurence": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Louis-Philippe": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Mathieu": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Maxime": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) elif self.members[self.username] == "Olivier": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Simon": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Thibault": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() elif self.members[self.username] == "Yann": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Yi": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) elif self.members[self.username] == "Valentin": self.Tabs.removeTab(self.tabs_list["Tasks"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Task Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Tags Manager"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Misc"]) self.get_tabs_id_from_name() self.Tabs.removeTab(self.tabs_list["Render"]) def get_tabs_id_from_name(self): self.tabs_list = {} for i in xrange(self.Tabs.count()): self.tabs_list[str(self.Tabs.tabText(i))] = i def change_username(self): username = str(self.usernameAdminComboBox.currentText()) self.username = username def backup_database(self): # Get creation_time of last database backup and compare it to current time database_files = Lib.get_files_from_folder( self, path= "Z:\\Groupes-cours\\NAND999-A15-N01\\Nature\\_pipeline\\_utilities\\_database\\_backup" ) if len(database_files) > 1000: self.Lib.message_box( self, type="error", text= u"Trop de backups détectés pour la base de donnée. Veuillez avertir Thibault, merci ;)" ) cur_db_name = os.path.split(self.db_path)[-1].replace(".sqlite", "") database_files = [ i for i in database_files if cur_db_name in os.path.split(i)[-1] ] database_files = sorted(database_files) last_database_file = database_files[-1] creation_time = time.ctime(os.path.getctime(last_database_file)) creation_time = time.strptime(creation_time, "%a %b %d %H:%M:%S %Y") current_time = str(datetime.now()) current_time = time.strptime(current_time, "%Y-%m-%d %H:%M:%S.%f") time_difference = (time.mktime(current_time) - time.mktime(creation_time)) / 60 if time_difference > 180: # If last backup is older than 5 hours, do a backup fileName, fileExtension = os.path.splitext(last_database_file) last_database_file_version = int(fileName.split("_")[-1]) new_version = str(last_database_file_version + 1).zfill(4) backup_database_filename = fileName.replace( str(last_database_file_version).zfill(4), new_version) + ".sqlite" shutil.copy(self.db_path, backup_database_filename) def refresh_all(self): self.blockSignals(True) #Default refreshes self.mt_item_added = True self.item_added = True self.setup_tags() #Get current tab text current_tab_text = self.Tabs.tabText(self.Tabs.currentIndex()) if current_tab_text == "Asset Loader": self.statusLbl.setText("Status: Refreshing Asset Loader tab...") self.repaint() self.AssetLoader.load_all_assets_for_first_time(self) self.AssetLoader.load_assets_from_selected_seq_shot_dept(self) elif current_tab_text == "Task Manager": self.statusLbl.setText("Status: Refreshing Task Manager tab...") self.repaint() TaskManager.add_tasks_from_database(self) elif current_tab_text == "Tasks": self.statusLbl.setText("Status: Refreshing Tasks tab...") self.repaint() MyTasks.mt_add_tasks_from_database(self) elif current_tab_text == "Render": self.statusLbl.setText("Status: Refreshing Render tab...") self.repaint() RenderTab.add_computers_from_database(self) RenderTab.add_jobs_from_database(self) RenderTab.add_frames_from_database(self) elif current_tab_text == "People": self.statusLbl.setText("Status: Refreshing People tab...") self.repaint() self.PeopleTab.get_online_status(self) self.cursor.execute( '''UPDATE preferences SET last_active=? WHERE username=?''', ( datetime.now().strftime("%d/%m/%Y at %H:%M"), self.username, )) self.db.commit() elif current_tab_text == "Images Manager": self.statusLbl.setText("Status: Refreshing Images Manager tab...") self.repaint() if len(self.ref_assets_instances) > 1: self.ReferenceTab.refresh_reference_list(self) elif "What's New" in current_tab_text: self.statusLbl.setText("Status: Refreshing What's New tab...") self.repaint() self.WhatsNew.load_whats_new(self) self.statusLbl.setText("Status: Idle...") self.blockSignals(False) def change_theme(self): if self.themePrefComboBox.currentIndex() == 0: self.theme = 0 self.prefBckGroundColorSlider.setValue(114) self.Lib.apply_style(self, self) self.cursor.execute( '''UPDATE preferences SET theme=? WHERE username=?''', ( 0, self.username, )) elif self.themePrefComboBox.currentIndex() == 1: self.theme = 1 self.prefBckGroundColorSlider.setValue(241) self.setStyleSheet("") app.setStyle(QtGui.QStyleFactory.create("cleanlooks")) self.cursor.execute( '''UPDATE preferences SET theme=? WHERE username=?''', ( 1, self.username, )) css = QtCore.QFile(self.cur_path + "\\media\\cleanlooks.css") css.open(QtCore.QIODevice.ReadOnly) if css.isOpen(): self.Form.setStyleSheet( QtCore.QVariant(css.readAll()).toString().replace( "checkbox|placeholder", self.cur_path.replace("\\", "/") + "/media/checkbox.png")) elif self.themePrefComboBox.currentIndex() == 2: self.prefBckGroundColorSlider.setValue(255) self.theme = 2 self.setStyleSheet("") app.setStyle(QtGui.QStyleFactory.create("plastique")) self.cursor.execute( '''UPDATE preferences SET theme=? WHERE username=?''', ( 2, self.username, )) self.db.commit() def change_pref_background_color_pixmap(self): slider_value = self.prefBckGroundColorSlider.value() self.referenceThumbListWidget.setStyleSheet( "background-color: rgb({0},{0},{0});".format(slider_value)) def tray_icon_message_clicked(self): if self.tray_message == "Manager is in background mode.": return clicked_log_entry = self.cursor.execute( '''SELECT log_value FROM log WHERE log_id=?''', (self.tray_icon_log_id, )).fetchone()[0] clicked_log_description = self.cursor.execute( '''SELECT log_entry FROM log WHERE log_id=?''', (self.tray_icon_log_id, )).fetchone()[0] if len(clicked_log_entry) == 0: return asset = self.Asset(main=self, id=clicked_log_entry, get_infos_from_id=True) if "reference" in clicked_log_description: if "video" in clicked_log_description: subprocess.Popen([ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", asset.dependency ]) else: if os.path.isfile(asset.full_path): os.system(asset.full_path) else: self.Lib.message_box( self, text="Can't find reference: it must have been deleted." ) elif "comment" in clicked_log_description: self.CommentWidget(main=self, asset=asset) def tray_icon_clicked(self, reason): if reason == QtGui.QSystemTrayIcon.DoubleClick: if self.isHidden(): self.setWindowFlags(QtCore.Qt.Widget) self.show() self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) self.trayIcon.hide() else: self.hide() self.trayIcon.show() def keyPressEvent(self, event): global_pos = self.mapFromGlobal(QtGui.QCursor.pos()) widget_under_mouse = self.childAt(global_pos) key = event.key() if key == QtCore.Qt.Key_F11: if self.isFullScreen(): self.showNormal() else: self.showFullScreen() elif key == QtCore.Qt.Key_Delete: current_tab_text = self.Tabs.tabText(self.Tabs.currentIndex()) if current_tab_text == "Images Manager": ReferenceTab.remove_selected_references(self) elif key == QtCore.Qt.Key_F2: selected_reference = self.referenceThumbListWidget.selectedItems( )[0] asset = selected_reference.data(QtCore.Qt.UserRole).toPyObject() ReferenceTab.rename_reference(self, asset) elif key == QtCore.Qt.Key_F1: self.show_wiki_help(widget_under_mouse) elif key == QtCore.Qt.Key_F5: self.refresh_all() def show_wiki_help(self, widget): if widget.objectName() == "publishBtn": subprocess.Popen([ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", "file:///Z:/Groupes-cours/NAND999-A15-N01/Nature/_info/wiki/wiki.html#Modeling" ]) def closeEvent(self, event): if not self.trayIcon.isVisible(): self.setWindowFlags(QtCore.Qt.Tool) self.hide() self.trayIcon.show() self.tray_message = "Manager is in background mode." self.trayIcon.showMessage('Still running...', self.tray_message, QtGui.QSystemTrayIcon.Information, 1000) self.hide() event.ignore() self.trayIcon.show() def terminate_program(self): # tasks = subprocess.check_output(['tasklist']) # if "houdin" in tasks.lower(): # self.Lib.message_box(self, type="error", text="Please close Houdini layout scenes before closing the Manager!") # return self.cursor.execute( '''UPDATE preferences SET is_online=0 WHERE username=?''', (self.username, )) self.db.commit() self.Lib.switch_mari_cache(self, "perso") self.close() app.exit() # self.quit_msg = "Are you sure you want to exit the program?" # reply = QtGui.QMessageBox.question(self, 'Are you leaving :(', # quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) # # if reply == QtGui.QMessageBox.Yes: # # event.accept() # else: # event.ignore() def changeEvent(self, event): if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: self.setWindowFlags(QtCore.Qt.Tool) self.hide() self.trayIcon.show() self.tray_message = "Manager is in background mode." self.trayIcon.showMessage('Still running...', self.tray_message, QtGui.QSystemTrayIcon.Information, 1000) def check_last_active(self): for user in self.members.keys(): last_active = datetime.now().strftime("%d/%m/%Y at %H:%M") last_active_datetime = datetime.strptime(last_active, '%d/%m/%Y at %H:%M') last_active_db = self.cursor.execute( '''SELECT last_active FROM preferences WHERE username=?''', (user, )).fetchone()[0] last_active_db_datetime = datetime.strptime( last_active_db, '%d/%m/%Y at %H:%M') time_difference = last_active_datetime - last_active_db_datetime if time_difference.seconds > 600: self.cursor.execute( '''UPDATE preferences SET is_online=0 WHERE username=?''', (user, )) else: self.cursor.execute( '''UPDATE preferences SET is_online=1 WHERE username=?''', (user, )) last_active = datetime.now().strftime("%d/%m/%Y at %H:%M") self.cursor.execute( '''UPDATE preferences SET last_active=? WHERE username=?''', ( last_active, self.username, )) self.db.commit()
import logging import logging.config import gluon.contrib.simplejson # shotgun sys.path.append('/X/tools/pythonlib') from shotgun_api3 import Shotgun SG = Shotgun(sg_server, sg_script_name, sg_script_key) session.departments = [] if not session.departments: session.departments = SG.find('Department', [['sg_status_list', 'is', 'act']], fields=['code', 'name', 'color'], order=[{ 'field_name': 'name', 'direction': 'asc' }]) session.dept_to = [] session.dept_ny = [] for d in session.departments: if d['code'].upper().startswith('NY'): session.dept_ny.append(d['id']) else: session.dept_to.append(d['id']) PROJECT_STATUS = ['Active', 'Bidding', 'Demo/Test', 'Delivered'] if not session.projects: result = SG.find('Project', [['sg_status', 'in', PROJECT_STATUS]],