def main(notebookName): #Get your developer token here: https://www.evernote.com/api/DeveloperToken.action and put it here dev_token = 'yourEvernoteDevKey' #Put your Shotgun script details here sg = Shotgun('https://yourSite.shotgunstudio.com','evernote-shotgun','yourScriptKey') #Put the Shotgun HumanUser ID here for the person you want to appear as the Note's author in Shotgun sgUserId = 45 sgUser = sg.find_one("HumanUser",[['id', 'is', sgUserId]]) #Establish a connection to Evernote and store note and user data client = EvernoteClient(token=dev_token, sandbox=False) userStore = client.get_user_store() user = userStore.getUser() noteStore = client.get_note_store() #Check if the supplied notebook exists, and if it does, send to processNotebook() print('\nFinding notebook') notebooks = noteStore.listNotebooks() notebookNames = [notebook.name for notebook in notebooks] if notebookName not in notebookNames: print('\nSorry, there are no notebooks in your account named {0}'.format(notebookName)) else: for notebook in notebooks: if notebook.name == notebookName: print('\nProcessing notebook - BEGIN') processNotebook(noteStore, notebook, sg, sgUser) print('\nProcessing notebook - DONE\n') else: continue
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 _moveFilesToPublish(self): base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'playBlastPublisher' api_key = '718daf67bfd2c7e974f24e7cbd55b86bb101c4e5618e6d5468bc4145840e4558' sgsrv = Shotgun(base_url = base_url , script_name = script_name, api_key = api_key, ensure_ascii=True, connect=True) selectedShots = [item.text(0) for item in self.treeWidgetItems if item.checkState(0)] if selectedShots: for each in selectedShots: episode = each.split('sh')[0] shotName = '%s_sh%s' % (each.split('sh')[0], each.split('sh')[1].split('Lay')[0]) self.publishPath = self.publishingPath(episode, shotName) for root, dirs, files in os.walk(self.shFldPath): for fl in sorted(files): if fl.endswith('.mov') and fl == '%s.mov' % each: srcPath = os.path.join(root,fl) self.playblastName = fl while os.path.exists(os.path.join(self.publishPath, fl)): allFiles= os.listdir(self.publishPath) publishFiles = [] if allFiles: for allFile in allFiles: if allFile.endswith('.mov'): publishFiles.append(allFile) versionNumber = int(sorted(publishFiles)[-1].split('.v')[1].split('.mov')[0]) versionNumber += 1 if versionNumber < 10: publishFileName = '%sLayout.v%03d.mov' % (shotName.replace('_', ''), versionNumber) self.publishPath = os.path.join(self.publishPath, publishFileName) self.playblastName = os.path.basename(self.publishPath) else: publishFileName = '%sLayout.v%02d.mov' % (shotName.replace('_', ''), versionNumber) self.publishPath = os.path.join(self.publishPath, publishFileName) self.playblastName = os.path.basename(self.publishPath) shutil.copy2(srcPath, self.publishPath) publishMovPath = os.path.join(self.publishingPath(episode, shotName), self.playblastName) getShotTasks = sgsrv.find_one('Shot', filters = [["code", "is", shotName]], fields=['id', 'tasks']) for key, values in getShotTasks.iteritems(): if key == 'tasks': for value in values: if value['name'] == 'Layout': self.taskId = value['id'] if self.publishPath.endswith('review'): self.publishPath = os.path.join(self.publishPath,fl) self.playblastName = fl data = { 'project': {'type':'Project','id': 66}, 'code': self.playblastName, 'description': 'Layout playblast published', 'sg_path_to_movie': publishMovPath, 'sg_status_list': 'rev', 'entity': {'type':'Shot', 'id':getShotTasks['id']}, 'sg_task': {'type':'Task', 'id':self.taskId}, 'user': {'type':'HumanUser', 'id':92} } result = sgsrv.create('Version', data) result2 = sgsrv.upload("Version", result['id'], publishMovPath, "sg_uploaded_movie") print "Done"
def are_credentials_expired(self): """ Checks if the credentials for the user are expired. This check is done solely on the Shotgun side. If SSO is being used, we do not attempt to contact the IdP to validate the session. :returns: True if the credentials are expired, False otherwise. """ print('creation expired') logger.debug( "Connecting to shotgun to determine if credentials have expired..." ) sg = Shotgun(self.get_host(), session_token=self.get_session_token(), http_proxy=self.get_http_proxy()) try: sg.find_one("HumanUser", []) return False except ProtocolError as e: # One potential source of the error is that our SAML claims have # expired. We check if we were given a 302 and the # saml_login_request URL. # But if we get there, it means our session_token is still valid # as far as Shotgun is concerned. if (e.errcode == httplib.FOUND and "location" in e.headers and e.headers["location"].endswith( "/saml/saml_login_request")): # If we get here, the session_token is still valid. logger.debug( "The SAML claims have expired. But the session_token is still valid" ) return False else: logger.error( "Unexpected exception while validating credentials: %s" % e) return True except AuthenticationFault: return True
def get_app_store_credentials(connection): """ Return the validated script for this site to connect to the app store """ (script, key) = __get_app_store_key(connection) # get the proxy string from the connection proxy = get_proxy_from_connection(connection) # connect to the app store try: sg_app_store = Shotgun(constants.SGTK_APP_STORE, script, key, http_proxy=proxy) # pull down the full script information app_store_script = sg_app_store.find_one( "ApiUser", [["firstname", "is", script]], fields=["type", "firstname", "id", "salted_password"]) except Exception: return None return app_store_script
def get_app_store_credentials(connection, proxy): """ Return the validated script for this site to connect to the app store """ (script, key) = __get_app_store_key(connection) # connect to the app store try: sg_app_store = Shotgun(constants.SGTK_APP_STORE, script, key, http_proxy=proxy, connect=False) # pull down the full script information app_store_script = sg_app_store.find_one( "ApiUser", [["firstname", "is", script]], fields=["type", "firstname", "id", "salted_password"]) except AuthenticationFault: raise InvalidAppStoreCredentialsError( "The Toolkit App Store credentials found in Shotgun are invalid.") return app_store_script
def main(notebookName): #Get your developer token here: https://www.evernote.com/api/DeveloperToken.action and put it here dev_token = 'yourEvernoteDevKey' #Put your Shotgun script details here sg = Shotgun('https://yourSite.shotgunstudio.com', 'evernote-shotgun', 'yourScriptKey') #Put the Shotgun HumanUser ID here for the person you want to appear as the Note's author in Shotgun sgUserId = 45 sgUser = sg.find_one("HumanUser", [['id', 'is', sgUserId]]) #Establish a connection to Evernote and store note and user data client = EvernoteClient(token=dev_token, sandbox=False) userStore = client.get_user_store() user = userStore.getUser() noteStore = client.get_note_store() #Check if the supplied notebook exists, and if it does, send to processNotebook() print('\nFinding notebook') notebooks = noteStore.listNotebooks() notebookNames = [notebook.name for notebook in notebooks] if notebookName not in notebookNames: print('\nSorry, there are no notebooks in your account named {0}'. format(notebookName)) else: for notebook in notebooks: if notebook.name == notebookName: print('\nProcessing notebook - BEGIN') processNotebook(noteStore, notebook, sg, sgUser) print('\nProcessing notebook - DONE\n') else: continue
def _moveFilesToPublish(self): base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'playBlastPublisher' api_key = '718daf67bfd2c7e974f24e7cbd55b86bb101c4e5618e6d5468bc4145840e4558' sgsrv = Shotgun(base_url=base_url, script_name=script_name, api_key=api_key, ensure_ascii=True, connect=True) selectedShots = [ item.text(0) for item in self.treeWidgetItems if item.checkState(0) ] if selectedShots: for each in selectedShots: episode = each.split('sh')[0] shotName = '%s_sh%s' % (each.split('sh')[0], each.split('sh')[1].split('Lay')[0]) self.publishPath = self.publishingPath(episode, shotName) for root, dirs, files in os.walk(self.shFldPath): for fl in sorted(files): ext = os.path.splitext(fl)[-1] if (fl.endswith('.mov') and (fl == '%s.mov' % each)) or (fl.endswith('.MOV') and (fl == "%s.MOV" % each)): srcPath = os.path.join(root, fl) # print srcPath, ext self.playblastName = fl while os.path.exists( os.path.join(self.publishPath, fl)): allFiles = os.listdir(self.publishPath) publishFiles = [] if allFiles: for allFile in allFiles: if allFile.endswith(ext): print allFile publishFiles.append(allFile) versionNumber = int( sorted(publishFiles)[-1].split('.v') [1].split(ext)[0]) versionNumber += 1 if versionNumber < 10: publishFileName = '%sLayout.v%03d%s' % ( shotName.replace( '_', ''), versionNumber, ext) self.publishPath = os.path.join( self.publishPath, publishFileName) self.playblastName = os.path.basename( self.publishPath) else: publishFileName = '%sLayout.v%02d%s' % ( shotName.replace( '_', ''), versionNumber, ext) self.publishPath = os.path.join( self.publishPath, publishFileName) self.playblastName = os.path.basename( self.publishPath) shutil.copy2(srcPath, self.publishPath) publishMovPath = os.path.join( self.publishingPath(episode, shotName), self.playblastName) getShotTasks = sgsrv.find_one( 'Shot', filters=[["code", "is", shotName]], fields=['id', 'tasks']) for key, values in getShotTasks.iteritems(): if key == 'tasks': for value in values: if value['name'] == 'Layout': self.taskId = value['id'] if self.publishPath.endswith('review'): self.publishPath = os.path.join( self.publishPath, fl) self.playblastName = fl data = { 'project': { 'type': 'Project', 'id': 66 }, 'code': self.playblastName, 'description': 'Layout playblast published', 'sg_path_to_movie': publishMovPath, 'sg_status_list': 'rev', 'entity': { 'type': 'Shot', 'id': getShotTasks['id'] }, 'sg_task': { 'type': 'Task', 'id': self.taskId }, 'user': { 'type': 'HumanUser', 'id': 92 } } result = sgsrv.create('Version', data) result2 = sgsrv.upload("Version", result['id'], publishMovPath, "sg_uploaded_movie") print "Done"
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
__author__ = 'andrew.willis' from shotgun_api3 import Shotgun sg = Shotgun("http://andrewwillish.shotgunstudio.com", "scriptTest", "8b7db88321b7c296541580d1659872d2e63527c040b37b4a2ca0eb47f9da04cb") proj = sg.find_one("Project",[['name','is','KIKO']]) print sg.create("shot",{'code':'SEQ01','project':proj}) #sg.update('Shot',shot['id'],{"sg_status_list":"ip"}) #sg.delete("Shot", 1160)
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
from shotgun_api3 import Shotgun from shotgun_api3 import __version__ as VERSION from pprint import pprint from faker import Faker fake = Faker() import sys import os import json SERVER_PATH = 'https://bwillenbring1.shotgunstudio.com' sg = Shotgun(SERVER_PATH, login='******', password='******') user = {'type':'HumanUser','id':42} proj = {'type':'Project','id':69} page_id = sg.find_one('Page',[['page_type','is','project_overview'],['project','is', proj]])['id'] # Set the user's home page to the Cypress Test Projects shots page data = {'custom_home_page':{'type':'Page','id':page_id}} success = sg.update('HumanUser', user['id'], data=data) pprint (success['custom_home_page']['id'] == page_id)
from docx import Document from shotgun_api3 import Shotgun # Setting up API for Shotgun SERVER_PATH = "" SCRIPT_NAME = '' SCRIPT_KEY = '' sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) # Tools used to Query the project name to their ID proj = sg.find_one("Project", [["name", "is", "Walt Denny"]]) print proj query = sg.schema_read()['Asset'].keys() print query print sg.schema_read()['Asset'].get('sg_rpm_number') # Function to format the text that gets read by Note_Thread_Read def formatted(x): x.pop("type", None) x.pop("id", None) Name = x.get('created_by', {}).get('name') Name2 = x.get('user', {}).get('name') global thread if 'content' in x: if Name == None: thread += "\n" thread += str(Name2) + ":" thread += "\n" else: thread += "\n" thread += str(Name) + ":"
shutil.copy(tmp_icon, icon_path) i['image'] = icon_path print '- Download thumbnail : ' + icon_path return entitys # def sg_get_shot(): asset_entitys = sg_get_asset(project_name) filters = [['project.Project.name', 'is', project_name], ['code', 'is', shot_name]] shot_entity = sg.find_one('Shot', filters, fields=[]) def sg_set_assets_to_shot(asset_entitys, shot_entity): shot_id = shot_entity['id'] data = {'assets': asset_entitys} return sg.update('Shot', shot_id, data) print sg_set_assets_to_shot(asset_entitys, shot_entity) # # first SG Lists # sg_asset_lists() # # respond with listWidgetItem selected
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()
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
stdout=subprocess.PIPE).communicate()[0] for line in raw_facts.split("\n"): try: line.index("=>") except: continue #print "facter: %s" % line (key, value) = line.split("=>") #print "fkey: %s fvalue: %s" % ( key, value ) ret[key.strip()] = value.strip() return ret hostname = gethostname().split('.', 1)[0] asset = sg.find_one("Asset", [['code', 'is', hostname]], ['id']) if not asset: print "couldn't find asset" else: # if we find a valid asset, sync the facts for it fact_data = get_fact_data() for fact_name, fact_value in fact_data.items(): if not fact_name in facts_to_sync: continue fact_data = { 'code': fact_name, 'sg_asset': { 'type': 'Asset', 'id': asset['id'] },
def dropSG( mimeType, text ): ''' Parse the received url for the ID, connect to shotgun and retrieve info for the particular ID. args: text - url of a shotgun version ''' # DO SOME MORE CHECKING IF WE CARE ABOUT THIS PARTICULAR URL. # THIS PARTICULAR SCRIPT ONLY CARES ABOUT VERSIONS if not mimeType == 'text/plain' or not (text.startswith( 'http' ) and 'shotgunstudio' in text): return False def idCheck( url, sgType ): foundID = re.match( '.+%s/(\d+)' % sgType, url ) foundIDinEmail = re.match( '.+entity_id=(\d+).+entity_type=%s' % sgType, url ) foundIDinURL = re.match( r'.+#%s_(\d+)_' % sgType, url ) if not foundID and not foundIDinEmail and not foundIDinURL: return try: if foundID: return int( foundID.group(1) ) elif foundIDinEmail: return int( foundIDinEmail.group(1) ) elif foundIDinURL: return int( foundIDinURL.group(1) ) except ValueError: return SERVER_PATH = 'https://duckling.shotgunstudio.com' # use your shotgun server name (i.e. "https://studioName.shotgunstudio.com") SCRIPT_NAME = 'assetOpenToShotgun' # use the name of the shotgun api script that will do the query (needs to be set up in Shotgun's admin area) SCRIPT_KEY = 'e932e9c2864c9bcdc3f3ddf8b801cc3d565bf51f' # use the script key as generated by Shotgun when the above script was created in Shotgun's admin area #-------------------------------- VERSION if 'Version' in text: sgID = idCheck( text, 'Version' ) print 'retrieving shotgun version %s' % sgID #DO THE SHOTGUN THING CONNECT = Shotgun( SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY ) # QUERY SHOTGUN FOR THE FOUND ID columns = ['sg_path_to_frames', 'sg_first_frame', 'sg_last_frame'] filters = [ [ 'id', 'is', sgID] ] v = CONNECT.find_one( 'Version', filters, columns ) #DO THE NUKE THING nuke.createNode( 'Read', 'file %(sg_path_to_frames)s first %(sg_first_frame)s last %(sg_last_frame)s origfirst %(sg_first_frame)s origlast %(sg_last_frame)s' % v ) return True #-------------------------------- PLAYLIST elif 'Playlist' in text: sgID = idCheck( text, 'Playlist' ) print 'retrieving shotgun playlist %s' % sgID #DO THE SHOTGUN THING CONNECT = Shotgun( SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY ) versions = getPlaylistVersionsByID( CONNECT, sgID ) #DO THE NUKE THING for v in versions: nuke.createNode( 'Read', 'file %(sg_path_to_frames)s first %(sg_first_frame)s last %(sg_last_frame)s origfirst %(sg_first_frame)s origlast %(sg_last_frame)s' % v ) return True #-------------------------------- SHOT elif 'Shot' in text: sgID = idCheck( text, 'Shot' ) print 'retrieving shotgun shot %s' % sgID #DO THE SHOTGUN THING CONNECT = Shotgun( SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY ) versions = getVersions( CONNECT, {'type':'Shot', 'id':int(sgID)}, ignore=['omt'] ) # GET SHOT DESCRIPTION columns = ['description'] filters = [ [ 'id', 'is', sgID] ] shot = CONNECT.find_one( 'Shot', filters, columns ) desc = shot['description'] #DO THE NUKE THING for v in versions: nuke.createNode( 'Read', 'file %(sg_path_to_frames)s first %(sg_first_frame)s last %(sg_last_frame)s origfirst %(sg_first_frame)s origlast %(sg_last_frame)s label %(sg_version_type)s' % v ) if desc: nuke.createNode( 'StickyNote', 'label "%s"' % desc ) return True else: return False
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': result = sg.schema_field_create(payload['entity'], payload['type'], payload['name'], payload['attrs']) elif method == '_url_for_attachment_id':
iw ) + ":height=" + str( fbh ) + ":t=max,drawtext=fontfile='" + wmfont + "': text=\'" + dstr + " | " + pn + " | SEQ=" + qn + " | SHOT=" + sn + " | " + imgn + " | " + "f %{eif\\:n+1\\:d}\': [email protected]: fontsize=" + ffs + ": x=10: y=(main_h-text_h)-10\" -pix_fmt yuv420p -vcodec h264 -g 30 -b:v 2000k -vprofile high -bf 0 -y \"" + rvid + "\"" #print '\n' print "fcmd = %s" % fcmd fret = subprocess.call(fcmd, shell=True) fret = 1 if fret == 0: # shotgun... # override username for offsite testing: #un = "cpb" filters = [ ['name', 'is', pn], ] p = sg.find_one('Project', filters) if p != None: pid = p['id'] #print "local login user is %s" % un filters = [ ['name', 'is', un], ] u = sg.find_one('HumanUser', filters) if u != None: uid = u['id'] #print "user = %s, sg_humanuser = %s, sg_uid = %s" % (un, u, uid) filters = [[ 'project', 'is', { 'type': 'Project', 'id': pid }
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
class PublishMayaAudio(QWidget): def __init__(self, defaultSource = 'I:/lsapipeline/audios/', parent = None): QWidget.__init__(self, parent) self.setWindowTitle('Audio Publishing Tool') self.parent = parent ## Connect to shotgun from shotgun_api3 import Shotgun ## 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) ## Get the user name self.user = getpass.getuser() ## Define the variable for the source folder and destination folder (local and remote as it were) self.sourceFolder = defaultSource or '' self.fileBoxes = {} ## Build the UI self.mainLayout = QVBoxLayout(self) self.epNumLayout = QHBoxLayout() self.epNumLabel = QLabel('EpNum:') self.epNumber = QLineEdit('', self) self.epNumber.setStyleSheet('QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.epNumber.textChanged.connect(self.epTextChange) self.epNumber.setText('ep') self.epNumLayout.addWidget(self.epNumLabel) self.epNumLayout.addWidget(self.epNumber) ## Set the layout for the source text input and browse button self.pathLayout = QHBoxLayout(self) self.sourceLabel = QLabel('Set Src Path:') ## Define the widgets for this layout self.sourceInput = QLineEdit(self) if self.sourceFolder: self.sourceInput.setText(self.sourceFolder) self.sourceInput.textChanged.connect(partial(self.doFileCheckboxes)) self.browseButton = QPushButton('Browse') self.browseButton.released.connect(partial(self._browseDialog, dest = False)) ## Add the widgets to the layout self.pathLayout.addWidget(self.sourceLabel) self.pathLayout.addWidget(self.sourceInput) self.pathLayout.addWidget(self.browseButton) self.optionsLayout = QHBoxLayout(self) self.makeSGEntries = QCheckBox(self) self.makeSGEntries.setChecked(True) self.makeSGEntries.setText('Make SGun Entries?') self.goButton = QPushButton('Publish Audio Files') self.goButton.setStyleSheet('QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.clicked.connect(self._doit) self.optionsLayout.addWidget(self.makeSGEntries) self.optionsLayout.addWidget(self.goButton) self.split = HR.Widget_hr() self.mainLayout.addWidget(self.split) self.mainLayout.addLayout(self.epNumLayout) self.mainLayout.addLayout(self.pathLayout) self.mainLayout.addLayout(self.optionsLayout) ### Now do the check boxes for files.... self.scrollLayout = QScrollArea(self) self.scrollLayout.setMinimumHeight(300) self.filesGroupBox = QGroupBox(self.scrollLayout) self.filesGroupBox.setFlat(True) self.scrollLayout.setWidget(self.filesGroupBox) self.scrollLayout.setWidgetResizable(True) self.fileLayout = QGridLayout(self.filesGroupBox) self.mainLayout.addWidget(self.scrollLayout) def epTextChange(self): if len(self.epNumber.text()) > 5: self.epNumber.setStyleSheet('QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setStyleSheet('QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) elif self.epNumber.text() != 'ep' and len(self.epNumber.text()) == 5: self.epNumber.setStyleSheet('QLineEdit {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setStyleSheet('QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setText('Publish Audio Files') self.goButton.setEnabled(True) else: self.epNumber.setStyleSheet('QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setStyleSheet('QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) def _toggleAll(self): """ A quick toggle for all the type checkboxes to on or off """ for eachType in self.fileBoxes: if eachType.text() == 'ALL': if eachType.isChecked(): for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(True) else: for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(False) def doFileCheckboxes(self, myPath = ''): """ Process all the folders/files found into check boxes for processing """ ## try to get the epNumber from a file epNum = os.listdir(self.sourceInput.text())[0].split('_')[0] if epNum: self.epNumber.setText(epNum) if self.fileBoxes != {}: for key, var in self.fileBoxes.items(): key.setParent(None) sip.delete(key) key = None self.repaint() self.files = [] self.fileBoxes = {} ## First add the ALL checkbox self.ALL = QCheckBox(self) self.ALL.setChecked(False) self.ALL.setText('ALL') self.ALL.toggled.connect(self._toggleAll) self.fileBoxes[self.ALL] = None self.fileLayout.addWidget(self.ALL, 0, 0) self.colCount = 10 r = 1 c = 1 ## Now process the folder and add the folders found as check boxes. try: ## Scan the entire folder structure for audio files to publish if self.isRootFolderThere(rootFolder = self.sourceFolder): print '%s found processing now...' % self.sourceFolder for dirname, dirnames, filenames in os.walk(self.sourceFolder): if dirname.endswith('\\wav'): print 'Scanning %s now..' % dirname print 'Files: %s' % os.listdir(dirname) getMaxFile = max(os.listdir(dirname)) if getMaxFile: ## we have a folder with files in it... if getMaxFile.endswith(".wav"): pathToWav = os.path.join(dirname, getMaxFile) self.fileCheckBox = QCheckBox(self) self.fileCheckBox.setChecked(False) self.fileCheckBox.setText(getMaxFile) self.fileBoxes[self.fileCheckBox] = pathToWav.replace('\\', '/') if c == self.colCount: r = r + 1 c = 1 self.fileLayout.addWidget(self.fileCheckBox, r, c) c = c + 1 print 'Adding %s to layout now..' % pathToWav else: print '%s is emtpy...' % dirname else: self.files = ['No root folder found...'] except: self.files = ['No wav files found...'] def _browseDialog(self, dest = False): """ This opens up a QFileDialog hard set to browse into the assets folder by default. @param dest: To set if you are setting the destination input or the source input @type dest: Boolean """ if sys.platform == 'win32': print 'OPENING WIN BROWSE DIALOG NOW...' myPath = QFileDialog(self, 'rootDir', self.sourceFolder).getExistingDirectory().replace('\\', '/') else: print 'OPENING %s BROWSE DIALOG NOW...' % sys.platform myPath = QFileDialog(self, 'rootDir', self.sourceFolder).getExistingDirectory().replace('\\', '/') ## try to get the epNumber from a file epNum = os.listdir(myPath)[0].split('_')[0] if epNum: self.epNumber.setText(epNum) self.sourceFolder = str(myPath) os.system('echo epNum: %s' % self.epNumber) os.system('echo sourceFolder: %s' % self.sourceFolder) os.system('echo final myPath: %s' % myPath) self.sourceInput.setText(myPath) #self.doFileCheckboxes(myPath) def _versionUp(self, path): return int(max(os.listdir(path)).split('.v')[-1].split('.wav')[0]) + 1 def _writeMaFile(self, fileName, pathToWav, wavName, publishPath): ## Check the folder exists, if not make one now. if not os.path.isdir(os.path.dirname(self.publishPath)): os.makedirs(os.path.dirname(self.publishPath)) self.header = [ r'//Maya ASCII 2013ff10 scene', r'//Name: %s' % fileName, r'//Last modified: Tue, Jun 17, 2014 10:41:32 AM', r'//Codeset: 1252', r'requires maya "2013ff10";', r'requires "Mayatomr" "2013.0 - 3.10.1.11 ";', r'currentUnit -l centimeter -a degree -t film;', r'fileInfo "application" "maya";', r'fileInfo "product" "Maya 2013";', r'fileInfo "version" "2013 x64";', r'fileInfo "cutIdentifier" "201301140020-856945";', r'fileInfo "osv" "Microsoft Windows 7 Ultimate Edition, 64-bit Windows 7 Service Pack 1 (Build 7601)\n";', ] self.audioNode = [ '\n%s' % r'createNode audio -n "%s";' % wavName.replace('.', '_'), '\t%s' % r'setAttr ".ef" 1000;', '\t%s' % r'setAttr ".se" 1000;', '\t%s' % r'setAttr ".f" -type "string" "%s";' % pathToWav, ] self.footer = [ '\n%s' % r'// End of %s.ma' % fileName] ## Now write the ma file ## Fail if the version already exists pathToTextFile = publishPath if not os.path.isfile(pathToTextFile): outfile = open(pathToTextFile, "w") for eachLine in self.header: outfile.write('%s\n' % eachLine) for eachLine in self.audioNode: outfile.write('%s\n' % eachLine) for eachLine in self.footer: outfile.write('%s\n' % eachLine) outfile.close() else: ## Remove it because we are republishing the same version again. os.remove(pathToTextFile) ## Note we can just delete this file already and move on if needed. outfile = open(pathToTextFile, "w") for eachLine in self.header: outfile.write('%s\n' % eachLine) for eachLine in self.audioNode: outfile.write('%s\n' % eachLine) for eachLine in self.footer: outfile.write('%s\n' % eachLine) outfile.close() def _createPublish(self, publishPath, fileName, pathToWav, wavName, version_number, localPath, localPathMac, wavSGName, ctx): self.pathToWav = pathToWav self.publishPath = publishPath self.localPath = localPath self.localPathMac = localPathMac self.fileName = fileName self.wavName = wavName self.wavSGName = wavSGName self.version_number = version_number data = { "code" : self.wavSGName, "description" : None, "name" : self.wavSGName, "project" : ctx.project, "entity" : {'id': self.exists['id'], 'name': self.wavSGName, 'type': 'CustomEntity03'}, "version_number": self.version_number, 'path_cache' : self.publishPath.replace('/', '\\'), 'published_file_type' : {'type' : 'PublishedFileType', 'id': 1}, 'updated_by' : { 'type' : 'HumanUser', 'id' : 53 }, 'path' : { 'content_type': None, 'link_type': 'local', 'url': 'file:///%s' % self.publishPath.replace('/', '\\'), "local_path": self.publishPath.replace('/', '\\'), 'local_path_linux': '', 'local_path_mac': '%s' % self.localPathMac, 'local_path_windows': '%s' % self.publishPath.replace('/', '\\'), 'local_storage': {'id': 1, 'name': 'primary', 'type': 'LocalStorage'}, 'name': self.fileName, } } self.sgsrv.create('PublishedFile', data) print 'Publish file created for %s' % self.wavSGName def _publishAudio(self): """ Function to add the publish a maya audio file both making a maya file with an audio node and publishing this to shotgun as a version """ for key, var in self.fileBoxes.items(): if var: if key.isChecked(): ## Work out what we need for the creation of the ma file ## and the publish for shotgun self.pathToWav = var if sys.platform == 'win32': self.publishPath = var.replace('/publish/wav', '/publish/maya').replace('.wav', '.ma').replace('/', '\\') self.localPath = self.publishPath.split('I:')[-1] self.localPathMac = self.publishPath.replace('I:', '/_projects') self.fileName = str(key.text()).replace('.wav', '.ma') self.wavName = str(key.text()) self.wavSGName = str(key.text().replace('_AUD', '').split('.')[0]) self.version_number = int(str(key.text()).split('.')[-2].split('v')[-1]) ## Now register the publish with Shotgun ## First find the audio on shotgun for processing. self.exists = self.sgsrv.find_one('CustomEntity03', filters = [["code", "is", self.wavSGName]], fields=['code', 'tasks', 'id']) if not self.exists: print '%s has no shotgun entry! You should make sure this has been processed correctly before proceeding!!' % self.wavName else: ## now publish tk = sgtk.sgtk_from_path("I:/lsapipeline/") ctx = tk.context_from_path(self.publishPath) ## For existing check ## CHECK FOR EXISTING PUBLISH WITH THE SAME VERSION NUMBER!!!! findExisting = self.sgsrv.find_one('PublishedFile', filters = [["code", "is", self.wavSGName]], fields=['code', 'id', 'version_number', 'created_at', 'entity']) if findExisting: if findExisting['version_number'] == self.version_number: print 'A PUBLISHED FILE FOR THIS VERSION ALREADY EXISTS SKIPPING! VERSION UP OR DELETE EXISTING SHOTGUN PUBLISH ENTRIES IF YOU NEED TO YOU SHOULDNT BUT YOU MIGHT!' ## WRITE THE MA ## Now write the ma file we are going to publish with the audio node created. ## Note this will delete and re-make any ma files with the same name in the folder if they exist self._writeMaFile(self.fileName, self.pathToWav, self.wavName, self.publishPath) else:## This is a new version number ## WRITE THE MA ## Now write the ma file we are going to publish with the audio node created. ## Note this will delete and re-make any ma files with the same name in the folder if they exist self._writeMaFile(self.fileName, self.pathToWav, self.wavName, self.publishPath) self._createPublish(publishPath = self.publishPath, fileName = self.fileName, pathToWav = self.pathToWav, wavName = self.wavName, version_number = self.version_number, localPath = self.localPath, localPathMac = self.localPathMac, wavSGName = self.wavSGName, ctx = ctx) else:## nothing already exists so build a fresh publish ## WRITE THE MA ## Now write the ma file we are going to publish with the audio node created. ## Note this will delete and re-make any ma files with the same name in the folder if they exist self._writeMaFile(self.fileName, self.pathToWav, self.wavName, self.publishPath) self._createPublish(publishPath = self.publishPath, fileName = self.fileName, pathToWav = self.pathToWav, wavName = self.wavName, version_number = self.version_number, localPath = self.localPath, localPathMac = self.localPathMac, wavSGName = self.wavSGName, ctx = ctx) print 'Complete' self.goButton.setText('COMPLETE.. click to run again') self.goButton.setStyleSheet('QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.repaint() def _checkTypes(self): anythingChecked = False if self.fileBoxes: for each in self.fileBoxes: if each.isChecked(): anythingChecked = True return anythingChecked def _setINPROG(self): self.goButton.setText('IN PROGRESS...') self.goButton.setStyleSheet('QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.repaint() return True def _doit(self): if self._setINPROG(): if not self._checkTypes(): self.goButton.setText('OOPS..') self.goButton.setStyleSheet('QPushButton {background-color: darkred; border: 2px solid 1 ; border-radius: 6px;}') self.reply = QMessageBox.question(self, 'Nope!', "Nothing to transfer. Try selecting something and try again", QMessageBox.Ok) else: self._publishAudio() def isRootFolderThere(self, rootFolder): """ Method used to check if root folder is valid or not """ if not os.path.isdir(rootFolder): print 'No such root folder found.' return -1 else: return 1
sg = Shotgun(url, script_name, key) filename = "Z:/Groupes-cours/NAND999-A15-N01/Nature/assets/mod/.thumb/banc_02_full.jpg" result = sg.upload("Version",1048,filename,"sg_uploaded_movie") my_local_file = { 'attachment_links': [{'type':'Version','id':1048}], 'project': {'type':'Project','id':146} } asset = sg.find_one("Asset", [["code","is","afficheOeuvre"]], ["code"]) sg_user = sg.find_one('HumanUser', [['login', 'is', "houdon.thibault"]]) data = { 'project': {'type':'Project','id':project_id}, 'note_links': [asset], 'user': sg_user, 'content':'Test', 'subject':"Thibault's Note on afficheOeuvre" } sg.create("Note", data) #version = sg.create("Version", data)
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
# filename = 'file:///Users/mmontagnino/Desktop/python-api-master/fullcalendar-2.8.0/demos/' + 'Calendar.html' id = "d54c59d248f978ad103976c2b47875b06df5dc56c71afa774901d7791d9d9870" name = "Test_Calendar" srvr = "https://participant.shotgunstudio.com" sg = Shotgun(srvr, name, id) colors = { "Helen Ly": "red", "Rafiah Sessoms": "blue", "Nathaniel Bryan": "green", "Nick Kubinski": "purple", "Marian Montagnino": "cyan", } proj = sg.find_one("Project", [["name", "is", "Asset Pipeline"]]) print proj filters = [["project", "is", proj], ["sg_status_list", "is", "wtg"]] fields = [ "entity.Shot.sg_sequence.Sequence.code", "entity.Shot.sg_air_date", "entity.Shot.code", "content", "task_assignees", "sg_task_order", "Id", # 'created_at', "entity.Shot.sg_status_list", # 'content', "start_date",
def get_fact_data(): ret = {} raw_facts = subprocess.Popen(["facter"], stdout=subprocess.PIPE).communicate()[0] for line in raw_facts.split("\n"): try: line.index("=>") except: continue #print "facter: %s" % line (key, value) = line.split("=>") #print "fkey: %s fvalue: %s" % ( key, value ) ret[key.strip()] = value.strip() return ret hostname = gethostname().split('.', 1)[0] asset = sg.find_one("Asset",[['code','is',hostname]],['id']) if not asset: print "couldn't find asset" else: # if we find a valid asset, sync the facts for it fact_data = get_fact_data() for fact_name,fact_value in fact_data.items(): if not fact_name in facts_to_sync: continue fact_data = { 'code': fact_name, 'sg_asset': {'type':'Asset', 'id':asset['id']}, 'description': fact_value, 'project': {'type':'Project', 'id':178}, }
ID = raw_input("Type the id of the %s:\n" % typeToUpload) while validRequest == False: #Number Validation while validId == False: try: ID = int(ID) validId = True except: print "Invalid input, the id must be a Number" ID = raw_input("Type the CORRECT id of the Asset:\n") #Shotgun Validation shoot = {'id': ID, 'type': typeToUpload} filters = [['entity', 'is', shoot]] fields = ['code'] versions = sg.find_one(typeToUpload, [["id", "is", ID]], ["id", "code", "sg_status_list"]) if versions == None: print "The ID doesnt exist in Shotgun" ID = raw_input("Type the CORRECT id of the Asset:\n") validId = False else: print "%s name: %s" % (typeToUpload, versions['code']) try: versions = sg.find("Version", filters, fields) except Exception as e: print e if len(versions) > 0: print "The %s have this versions already:\n" % typeToUpload for version in versions: print " -%s" % version["code"]
from shotgun_api3 import Shotgun if True: sg = connect() else: sg = Shotgun('http://127.0.0.1:8020', 'name', 'key') print sg.server_info proj = sg.create('Project', {'name': 'Mock Project Test'}) seq = sg.create('Sequence', {'code': 'AA', 'project': proj}) shot = sg.create('Shot', {'code': 'AA_001', 'sg_sequence': seq}) print proj print seq print shot # # print sg.find('Project', [('id', 'is_not', 0)], ['name'], order=[ # {'field_name': 'id', 'direction': 'asc'}, # ]) print sg._call_rpc('count', None) exit() print sg.create('Project', {'name': 'Test Project'}) print sg.count() print sg.find_one('Project', [], order=[ {'field_name': 'id', 'direction': 'asc'}, ], fields=['task_assignees'])
class StoryboardFileManagement(QWidget): def __init__(self, defaultSource='', parent=None): QWidget.__init__(self, parent) self.setWindowTitle('StoryBoard File Processing') self.parent = parent ## Connect to shotgun from shotgun_api3 import Shotgun ## Instance the api for talking directly to shotgun. base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'audioUploader' api_key = 'bbfc5a7f42364edd915656d7a48d436dc864ae7b48caeb69423a912b930bc76a' print 'Connecting to shotgun....' self.sgsrv = Shotgun(base_url=base_url, script_name=script_name, api_key=api_key, ensure_ascii=True, connect=True) ## Get the user name self.user = getpass.getuser() ## Define the variable for the source folder and destination folder (local and remote as it were) self.sourceFolder = defaultSource or '' self.fileBoxes = [] ## Build the UI self.mainLayout = QVBoxLayout(self) self.epNumLayout = QHBoxLayout() self.epNumLabel = QLabel('EpNum:') self.epNumber = QLineEdit('', self) self.epNumber.setStyleSheet( 'QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.epNumber.textChanged.connect(self.epTextChange) self.epNumber.setText('ep') self.epNumLayout.addWidget(self.epNumLabel) self.epNumLayout.addWidget(self.epNumber) ## Set the layout for the source text input and browse button self.pathLayout = QHBoxLayout(self) self.sourceLabel = QLabel('Set Src Path:') ## Define the widgets for this layout self.sourceInput = QLineEdit(self) self.sourceInput.textChanged.connect(self.doFileCheckboxes) self.browseButton = QPushButton('Browse') self.browseButton.released.connect( partial(self._browseDialog, dest=False)) ## Add the widgets to the layout self.pathLayout.addWidget(self.sourceLabel) self.pathLayout.addWidget(self.sourceInput) self.pathLayout.addWidget(self.browseButton) self.optionsLayout = QHBoxLayout(self) self.makeSGEntries = QCheckBox(self) self.makeSGEntries.setChecked(True) self.makeSGEntries.setText('Make SGun Entries?') self.goButton = QPushButton( 'Transfer SBrd Files To Episode Version Folders') self.goButton.setStyleSheet( 'QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.clicked.connect(self._doit) self.optionsLayout.addWidget(self.makeSGEntries) self.optionsLayout.addWidget(self.goButton) self.split = HR.Widget_hr() self.mainLayout.addWidget(self.split) self.mainLayout.addLayout(self.epNumLayout) self.mainLayout.addLayout(self.pathLayout) self.mainLayout.addLayout(self.optionsLayout) ### Now do the check boxes for files.... self.scrollLayout = QScrollArea(self) self.scrollLayout.setMinimumHeight(300) self.filesGroupBox = QGroupBox(self.scrollLayout) self.filesGroupBox.setFlat(True) self.scrollLayout.setWidget(self.filesGroupBox) self.scrollLayout.setWidgetResizable(True) self.fileLayout = QGridLayout(self.filesGroupBox) self.mainLayout.addWidget(self.scrollLayout) def epTextChange(self): if len(self.epNumber.text()) > 5: self.epNumber.setStyleSheet( 'QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setStyleSheet( 'QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) elif self.epNumber.text() != 'ep' and len(self.epNumber.text()) == 5: self.epNumber.setStyleSheet( 'QLineEdit {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setStyleSheet( 'QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setText( 'Transfer SBrd Files To Episode Version Folders') self.goButton.setEnabled(True) else: self.epNumber.setStyleSheet( 'QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setStyleSheet( 'QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) def _toggleAll(self): """ A quick toggle for all the type checkboxes to on or off """ for eachType in self.fileBoxes: if eachType.text() == 'ALL': if eachType.isChecked(): for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(True) else: for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(False) def doFileCheckboxes(self, myPath=''): """ Process all the folders/files found into checkboxes for processing """ ## try to get the epNumber from a file epNum = str(os.listdir(self.sourceInput.text())[0].split('_')[0]) if epNum == '.DS' or epNum == '.DS_Store': getFiles = os.listdir(self.sourceInput.text()) for each in getFiles: if ".mov" in each: epNum = each.split('_')[0] #print 'I AM A BAD NAUGHTY VARIABLE!: %s' % epNum if epNum: self.epNumber.setText(epNum) if self.fileBoxes != []: for each in self.fileBoxes: each.setParent(None) sip.delete(each) each = None self.files = [] self.fileBoxes = [] ## First add the ALL checkbox self.ALL = QCheckBox(self) self.ALL.setChecked(False) self.ALL.setText('ALL') self.ALL.toggled.connect(self._toggleAll) self.fileBoxes.append(self.ALL) self.fileLayout.addWidget(self.ALL, 0, 0) ## Now process the folder and add the folders found as checkboxes. try: if myPath: if sys.platform == 'win32': self.sourceFolder = myPath.replace('/', '\\') else: self.sourceFolder = myPath else: self.sourceFolder = str(self.sourceInput.text()) for eachFile in os.listdir(self.sourceFolder): if eachFile.endswith('.mov'): self.files.append(eachFile) except: self.files = ['No mov files found...'] self.colCount = 10 r = 1 c = 1 for eachType in sorted(self.files): self.fileCheckBox = QCheckBox(self) self.fileCheckBox.setChecked(False) self.fileCheckBox.setText(eachType) self.fileBoxes.append(self.fileCheckBox) if c == self.colCount: r = r + 1 c = 1 self.fileLayout.addWidget(self.fileCheckBox, r, c) c = c + 1 def _browseDialog(self, dest=False): """ This opens up a QFileDialog hard set to browse into the assets folder by default. @param dest: To set if you are setting the destination input or the source input @type dest: Boolean """ try: if sys.platform == 'win32': myPath = QFileDialog( self, 'rootDir', 'O:/EPISODE DELIVERY').getExistingDirectory().replace( '\\', '/') else: myPath = QFileDialog( self, 'rootDir', '/Volumes/LemonSky/OUT TO LEMONSKY/EPISODE DELIVERY' ).getExistingDirectory().replace('\\', '/') except: myPath = QFileDialog(self, 'rootDir', '').getExistingDirectory().replace('\\', '/') ## try to get the epNumber from a file epNum = os.listdir(myPath)[0].split('_')[0] if epNum: self.epNumber.setText(epNum) self.sourceInput.setText(myPath) self.sourceFolder = str(myPath) self.doFileCheckboxes(myPath) def _versionUp(self, path): return int(max(os.listdir(path)).split('.v')[-1].split('.mov')[0]) + 1 def addStoryboardVersionToShotgun(self, path, epName, shotName, verNum, fullVersPublishName): """ Function to add the audio asset to shotgun correctly for tasks etc and the pipeline to see it """ #self.shotNum = each.text().split('.mov')[0] #self.addStoryboardVersionToShotgun(str(self.shotReviewDir), str(self.epName), self.shotNum, self.vNum, self.shotReviewFileName) ## Now start processing stuff.. self.epName = epName.lower() self.shotName = shotName.lower() self.boardName = fullVersPublishName.lower() self.taskName = 'StoryBoard' self.sg_version = verNum self.pathToMovie = '%s%s' % (path, self.boardName) ## First find it the task exists self.getShotTasks = self.sgsrv.find_one( 'Shot', filters=[["code", "is", self.shotName]], fields=['id', 'tasks']) ## Now check and see if the task we need is there... self.tasks = [] self.taskList = [] if self.getShotTasks: for eachTaskDict in self.getShotTasks['tasks']: self.tasks.append(eachTaskDict['name']) self.taskList.append(eachTaskDict) if self.taskName not in self.tasks: ## Create new task for the shot self.myNewTask = self.sgsrv.create( 'Task', { 'project': { 'type': 'Project', 'id': 66 }, 'step': { 'type': 'Step', 'id': 72, 'name': 'StoryBoard' }, 'content': 'StoryBoard', 'sg_status_list': 'apr', 'template_task': { 'type': 'Task', 'id': 31333 } }) self.taskId = int(self.myNewTask['id']) ## Returns {'project': {'type': 'Project', 'id': 66, 'name': 'bubblebathbay'}, 'step': {'type': 'Step', 'id': 72, 'name': 'StoryBoard'}, 'type': 'Task', 'id': 32335} ## Add this dict to the list of dict for updating the shot task list with. self.taskList.append({ 'type': 'Task', 'id': self.myNewTask['id'], 'name': 'StoryBoard' }) ## Now update the shots task list. self.sgsrv.update( 'Shot', self.getShotTasks['id'], { 'project': { 'type': 'Project', 'id': 66 }, 'tasks': self.taskList }) print 'Successfully updated shot %s with task %s' % ( self.shotName, self.taskId) ## Now create a version for this print 'Adding version %s to %s now' % (self.boardName, self.shotName) data = { 'project': { 'type': 'Project', 'id': 66 }, 'code': self.boardName, 'description': 'I am not a fluffy bunny!', 'sg_path_to_movie': self.pathToMovie, 'sg_status_list': 'rev', 'entity': { 'type': 'Shot', 'id': self.getShotTasks['id'] }, 'sg_task': { 'type': 'Task', 'id': self.taskId }, 'sg_status_list': 'vwd', 'user': { 'type': 'HumanUser', 'id': 53 } } result = self.sgsrv.create('Version', data) ## Now upload to shotgun print 'Uploading version %s to %s now' % (self.boardName, self.shotName) result2 = self.sgsrv.upload("Version", result['id'], self.pathToMovie, "sg_uploaded_movie") self._turnOffCheckBox('%s.mov' % self.shotName) else: ## Get the story board task id for eachTask in self.taskList: if eachTask['name'] == 'StoryBoard': self.taskId = eachTask['id'] ## Now create a version for this print 'Adding version %s to %s now' % (self.boardName, self.shotName) data = { 'project': { 'type': 'Project', 'id': 66 }, 'code': self.boardName, 'description': 'I am not a fluffy bunny!', 'sg_path_to_movie': self.pathToMovie, 'sg_status_list': 'rev', 'entity': { 'type': 'Shot', 'id': self.getShotTasks['id'] }, 'sg_task': { 'type': 'Task', 'id': self.taskId }, 'sg_status_list': 'vwd', 'user': { 'type': 'HumanUser', 'id': 53 } } result = self.sgsrv.create('Version', data) ## Now upload to shotgun print 'Uploading version %s to %s now' % (self.boardName, self.shotName) result2 = self.sgsrv.upload("Version", result['id'], self.pathToMovie, "sg_uploaded_movie") self._turnOffCheckBox('%s.mov' % self.shotName) else: print 'NO TASKS EXIST FOR %s skipping...' % self.shotName self._turnOffCheckBox('%s.mov' % self.shotName) def _turnOffCheckBox(self, shotName): """ Func for turning off the uploaded movies as we progress through them so if we error out we have a way to see what has been processed already """ for each in self.fileBoxes: if str(each.text()) == shotName: each.setChecked(False) self.repaint() def _checkTypes(self): anythingChecked = False if self.fileBoxes: for each in self.fileBoxes: if each.isChecked(): anythingChecked = True return anythingChecked def _setINPROG(self): self.goButton.setText('IN PROGRESS...') self.goButton.setStyleSheet( 'QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.repaint() return True def _doit(self): if self._setINPROG(): if not self._checkTypes(): self.goButton.setText('OOPS..') self.goButton.setStyleSheet( 'QPushButton {background-color: darkred; border: 2px solid 1 ; border-radius: 6px;}' ) self.reply = QMessageBox.question( self, 'Nope!', "Nothing to transfer. Try selecting something and try again", QMessageBox.Ok) else: self.processStoryBoardFolder() def processStoryBoardFolder(self): """ Function to copy over all the audio files from a single output folder into the correct locations for the bubblebathbay IDrive audios folders @param epNum: The episode name @param pathToFolder: The path to the folder full of wav files you want to copy over. @type pathToFolder: String @type epNum: String NOTE: this tool has been written around the following audio output naming convention from TOONBOOM ep106_sh001.wav ep106_sh002.wav ep106_sh002_A.wav """ if self.epNumber.text() != 'ep': for each in self.fileBoxes: if each.isChecked() and each.text() != 'ALL': ## We will always start with a base version number of 0 as the audio files from Toonboom ## Do NOT have any versioning...Therefore iteration folders from toonboom can be correctly versioned into ## the publish wav folders without freaking out.... self.vNum = '000' self.epName = str(self.epNumber.text()).lower() self.shotNum = str(each.text()).split('.mov')[0].lower() if sys.platform == 'win32': self.shotReviewDir = 'I:/lsapipeline/episodes/%s/%s/SBoard/publish/review/' % ( self.epName, self.shotNum) else: self.shotReviewDir = '/Volumes/lsapipeline/episodes/%s/%s/SBoard/publish/review/' % ( self.epName, self.shotNum) self.shotReviewFileName = '%s_BOARD.v%s.mov' % ( self.shotNum, self.vNum) self.finalPath = '%s%s' % (self.shotReviewDir, self.shotReviewFileName) ## Check for folder, if it doesn't exist make it if not os.path.isdir(self.shotReviewDir): os.makedirs(self.shotReviewDir) ## Now check for existing file, if so version it up just in case so we don't even delete. if os.path.isfile(self.finalPath): newVersNum = self._versionUp(self.shotReviewDir) if newVersNum <= 10: self.vNum = '00%s' % newVersNum elif newVersNum <= 100: self.vNum = '0%s' % newVersNum else: self.vNum = '%s' % newVersNum ## Now update the name and path vars as final. self.shotReviewFileName = '%s_BOARD.v%s.mov' % ( self.shotNum, self.vNum) self.finalPath = '%s%s' % (self.shotReviewDir, self.shotReviewFileName) ## Now get the original path for the audio file we are copying. originalPath = '%s\\%s' % (self.sourceFolder, each.text()) ## Now perform the copy. shutil.copyfile(originalPath, self.finalPath) #p = subprocess.Popen(cmd, cwd=None, shell=True, bufsize=4096) # Wait until process terminates #while p.poll() is None: # time.sleep(0.5) print 'Copied file: %s to \t%s' % (each.text(), self.finalPath) if self.makeSGEntries.isChecked(): print 'Adding StoryBoard item to shotgun... %s: ' % self.shotReviewFileName self.addStoryboardVersionToShotgun( str(self.shotReviewDir), str(self.epName), str(self.shotNum), str(self.vNum), str(self.shotReviewFileName)) print 'Finished processing files' self.goButton.setText('COMPLETED... click to do over...') self.goButton.setStyleSheet( 'QPushButton {background-color: yellow; border: 2px solid 1 ; border-radius: 6px;}' ) else: self.goButton.setText('Invalid Ep Number... click to do over...') self.goButton.setStyleSheet( 'QPushButton {background-color: blue; border: 2px solid 1 ; border-radius: 6px;}' ) print 'You must set a valid episode number!!!'
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:
sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) project = 'TBD' dir = "//home/crystal/Desktop/project_test/" + project.lower() assetALL = sg.find('Asset', [['project.Project.name', 'is', project]], ['image', 'code']) for asset in assetALL: asset_name = asset['code'] asset_thum = asset['image'] lookdevALL = sg.find_one('Version', [['project.Project.name', 'is', project], ['entity.Asset.code', 'is', asset_name], ['sg_task.Task.step.Step.id', 'is', 18]], ['image', 'sg_path_to_movie']) lookdev_mov = lookdevALL['sg_path_to_movie'] print lookdev_mov # lookdev_mov = str(lookdev_mov).replace("\\", "/") # print lookdev_mov # thum = "%s_" % (datetime.today().strftime('%Y%m%d')) + str(uuid.uuid4())[:8] + ".jpg" # thum_path = "/home/crystal/MG/asset/thumnail/small_thum/%s" % thum # # cate_arr = os.listdir(dir) # for cate in cate_arr: # dir_cate = dir + "/" + cate # asset_arr = os.listdir(dir_cate) # # for asset2 in asset_arr:
p.product_rmk, p.prod_cls_n FROM item i JOIN product p ON i.product_id = p.product_id WHERE product_n not like 'Unknown %' ORDER BY item_sc DESC ''') row = cur.fetchone() while row: if not row['item_sc']: row = cur.fetchone() continue asset_data = transform_asset(row) existing_asset = sg.find_one('Asset', [['code', 'is', asset_data['code']]]) if existing_asset: print "asset %s exists" % (asset_data['code']) sg.update('Asset', existing_asset['id'], asset_data) else: print "asset %s creating" % (asset_data['code']) try: sg.create('Asset', asset_data, return_fields=['id']) pass except Exception: pprint.pprint(row) pprint.pprint(asset_data) row = cur.fetchone() conn.close()
class StoryboardFileManagement(QWidget): def __init__(self, defaultSource = '', parent = None): QWidget.__init__(self, parent) self.setWindowTitle('StoryBoard File Processing') self.parent = parent ## Connect to shotgun from shotgun_api3 import Shotgun ## Instance the api for talking directly to shotgun. base_url = "http://bubblebathbay.shotgunstudio.com" script_name = 'audioUploader' api_key = 'bbfc5a7f42364edd915656d7a48d436dc864ae7b48caeb69423a912b930bc76a' print 'Connecting to shotgun....' self.sgsrv = Shotgun(base_url = base_url , script_name = script_name, api_key = api_key, ensure_ascii=True, connect=True) ## Get the user name self.user = getpass.getuser() ## Define the variable for the source folder and destination folder (local and remote as it were) self.sourceFolder = defaultSource or '' self.fileBoxes = [] ## Build the UI self.mainLayout = QVBoxLayout(self) self.epNumLayout = QHBoxLayout() self.epNumLabel = QLabel('EpNum:') self.epNumber = QLineEdit('', self) self.epNumber.setStyleSheet('QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.epNumber.textChanged.connect(self.epTextChange) self.epNumber.setText('ep') self.epNumLayout.addWidget(self.epNumLabel) self.epNumLayout.addWidget(self.epNumber) ## Set the layout for the source text input and browse button self.pathLayout = QHBoxLayout(self) self.sourceLabel = QLabel('Set Src Path:') ## Define the widgets for this layout self.sourceInput = QLineEdit(self) self.sourceInput.textChanged.connect(self.doFileCheckboxes) self.browseButton = QPushButton('Browse') self.browseButton.released.connect(partial(self._browseDialog, dest = False)) ## Add the widgets to the layout self.pathLayout.addWidget(self.sourceLabel) self.pathLayout.addWidget(self.sourceInput) self.pathLayout.addWidget(self.browseButton) self.optionsLayout = QHBoxLayout(self) self.makeSGEntries = QCheckBox(self) self.makeSGEntries.setChecked(True) self.makeSGEntries.setText('Make SGun Entries?') self.goButton = QPushButton('Transfer SBrd Files To Episode Version Folders') self.goButton.setStyleSheet('QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.clicked.connect(self._doit) self.optionsLayout.addWidget(self.makeSGEntries) self.optionsLayout.addWidget(self.goButton) self.split = HR.Widget_hr() self.mainLayout.addWidget(self.split) self.mainLayout.addLayout(self.epNumLayout) self.mainLayout.addLayout(self.pathLayout) self.mainLayout.addLayout(self.optionsLayout) ### Now do the check boxes for files.... self.scrollLayout = QScrollArea(self) self.scrollLayout.setMinimumHeight(300) self.filesGroupBox = QGroupBox(self.scrollLayout) self.filesGroupBox.setFlat(True) self.scrollLayout.setWidget(self.filesGroupBox) self.scrollLayout.setWidgetResizable(True) self.fileLayout = QGridLayout(self.filesGroupBox) self.mainLayout.addWidget(self.scrollLayout) def epTextChange(self): if len(self.epNumber.text()) > 5: self.epNumber.setStyleSheet('QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setStyleSheet('QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) elif self.epNumber.text() != 'ep' and len(self.epNumber.text()) == 5: self.epNumber.setStyleSheet('QLineEdit {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setStyleSheet('QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setText('Transfer SBrd Files To Episode Version Folders') self.goButton.setEnabled(True) else: self.epNumber.setStyleSheet('QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setStyleSheet('QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) def _toggleAll(self): """ A quick toggle for all the type checkboxes to on or off """ for eachType in self.fileBoxes: if eachType.text() == 'ALL': if eachType.isChecked(): for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(True) else: for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(False) def doFileCheckboxes(self, myPath = ''): """ Process all the folders/files found into checkboxes for processing """ ## try to get the epNumber from a file epNum = str(os.listdir(self.sourceInput.text())[0].split('_')[0]) if epNum == '.DS' or epNum == '.DS_Store': getFiles = os.listdir(self.sourceInput.text()) for each in getFiles: if ".mov" in each: epNum = each.split('_')[0] #print 'I AM A BAD NAUGHTY VARIABLE!: %s' % epNum if epNum: self.epNumber.setText(epNum) if self.fileBoxes != []: for each in self.fileBoxes: each.setParent(None) sip.delete(each) each = None self.files = [] self.fileBoxes = [] ## First add the ALL checkbox self.ALL = QCheckBox(self) self.ALL.setChecked(False) self.ALL.setText('ALL') self.ALL.toggled.connect(self._toggleAll) self.fileBoxes.append(self.ALL) self.fileLayout.addWidget(self.ALL, 0, 0) ## Now process the folder and add the folders found as checkboxes. try: if myPath: if sys.platform == 'win32': self.sourceFolder = myPath.replace('/', '\\') else: self.sourceFolder = myPath else: self.sourceFolder = str(self.sourceInput.text()) for eachFile in os.listdir(self.sourceFolder): if eachFile.endswith('.mov'): self.files.append(eachFile) except: self.files = ['No mov files found...'] self.colCount = 10 r = 1 c = 1 for eachType in sorted(self.files): self.fileCheckBox = QCheckBox(self) self.fileCheckBox.setChecked(False) self.fileCheckBox.setText(eachType) self.fileBoxes.append(self.fileCheckBox) if c == self.colCount: r = r + 1 c = 1 self.fileLayout.addWidget(self.fileCheckBox, r, c) c = c + 1 def _browseDialog(self, dest = False): """ This opens up a QFileDialog hard set to browse into the assets folder by default. @param dest: To set if you are setting the destination input or the source input @type dest: Boolean """ try: if sys.platform == 'win32': myPath = QFileDialog(self, 'rootDir', 'O:/EPISODE DELIVERY').getExistingDirectory().replace('\\', '/') else: myPath = QFileDialog(self, 'rootDir', '/Volumes/LemonSky/OUT TO LEMONSKY/EPISODE DELIVERY').getExistingDirectory().replace('\\', '/') except : myPath = QFileDialog(self, 'rootDir', '').getExistingDirectory().replace('\\', '/') ## try to get the epNumber from a file epNum = os.listdir(myPath)[0].split('_')[0] if epNum: self.epNumber.setText(epNum) self.sourceInput.setText(myPath) self.sourceFolder = str(myPath) self.doFileCheckboxes(myPath) def _versionUp(self, path): return int(max(os.listdir(path)).split('.v')[-1].split('.mov')[0]) + 1 def addStoryboardVersionToShotgun(self, path, epName, shotName, verNum, fullVersPublishName): """ Function to add the audio asset to shotgun correctly for tasks etc and the pipeline to see it """ #self.shotNum = each.text().split('.mov')[0] #self.addStoryboardVersionToShotgun(str(self.shotReviewDir), str(self.epName), self.shotNum, self.vNum, self.shotReviewFileName) ## Now start processing stuff.. self.epName = epName.lower() self.shotName = shotName.lower() self.boardName = fullVersPublishName.lower() self.taskName = 'StoryBoard' self.sg_version = verNum self.pathToMovie = '%s%s' % (path, self.boardName) ## First find it the task exists self.getShotTasks = self.sgsrv.find_one('Shot', filters = [["code", "is", self.shotName]], fields=['id', 'tasks']) ## Now check and see if the task we need is there... self.tasks = [] self.taskList = [] if self.getShotTasks: for eachTaskDict in self.getShotTasks['tasks']: self.tasks.append(eachTaskDict['name']) self.taskList.append(eachTaskDict) if self.taskName not in self.tasks: ## Create new task for the shot self.myNewTask = self.sgsrv.create( 'Task', { 'project': { 'type': 'Project', 'id': 66 }, 'step': { 'type': 'Step', 'id': 72, 'name': 'StoryBoard' }, 'content': 'StoryBoard', 'sg_status_list': 'apr', 'template_task': { 'type': 'Task', 'id': 31333 } } ) self.taskId = int(self.myNewTask['id']) ## Returns {'project': {'type': 'Project', 'id': 66, 'name': 'bubblebathbay'}, 'step': {'type': 'Step', 'id': 72, 'name': 'StoryBoard'}, 'type': 'Task', 'id': 32335} ## Add this dict to the list of dict for updating the shot task list with. self.taskList.append({'type': 'Task', 'id': self.myNewTask['id'], 'name': 'StoryBoard'}) ## Now update the shots task list. self.sgsrv.update( 'Shot', self.getShotTasks['id'], { 'project': { 'type':'Project', 'id':66 }, 'tasks': self.taskList } ) print 'Successfully updated shot %s with task %s' % (self.shotName, self.taskId) ## Now create a version for this print 'Adding version %s to %s now' % (self.boardName, self.shotName) data = { 'project': {'type':'Project','id': 66}, 'code': self.boardName, 'description': 'I am not a fluffy bunny!', 'sg_path_to_movie': self.pathToMovie, 'sg_status_list': 'rev', 'entity': {'type':'Shot', 'id':self.getShotTasks['id']}, 'sg_task': {'type':'Task', 'id':self.taskId}, 'sg_status_list': 'vwd', 'user': {'type':'HumanUser', 'id':53} } result = self.sgsrv.create('Version', data) ## Now upload to shotgun print 'Uploading version %s to %s now' % (self.boardName, self.shotName) result2 = self.sgsrv.upload("Version", result['id'], self.pathToMovie, "sg_uploaded_movie") self._turnOffCheckBox('%s.mov' % self.shotName) else: ## Get the story board task id for eachTask in self.taskList: if eachTask['name'] == 'StoryBoard': self.taskId = eachTask['id'] ## Now create a version for this print 'Adding version %s to %s now' % (self.boardName, self.shotName) data = { 'project': {'type':'Project','id': 66}, 'code': self.boardName, 'description': 'I am not a fluffy bunny!', 'sg_path_to_movie': self.pathToMovie, 'sg_status_list': 'rev', 'entity': {'type':'Shot', 'id':self.getShotTasks['id']}, 'sg_task': {'type':'Task', 'id':self.taskId}, 'sg_status_list': 'vwd', 'user': {'type':'HumanUser', 'id': 53} } result = self.sgsrv.create('Version', data) ## Now upload to shotgun print 'Uploading version %s to %s now' % (self.boardName, self.shotName) result2 = self.sgsrv.upload("Version", result['id'], self.pathToMovie, "sg_uploaded_movie") self._turnOffCheckBox('%s.mov' % self.shotName) else: print 'NO TASKS EXIST FOR %s skipping...' % self.shotName self._turnOffCheckBox('%s.mov' % self.shotName) def _turnOffCheckBox(self, shotName): """ Func for turning off the uploaded movies as we progress through them so if we error out we have a way to see what has been processed already """ for each in self.fileBoxes: if str(each.text()) == shotName: each.setChecked(False) self.repaint() def _checkTypes(self): anythingChecked = False if self.fileBoxes: for each in self.fileBoxes: if each.isChecked(): anythingChecked = True return anythingChecked def _setINPROG(self): self.goButton.setText('IN PROGRESS...') self.goButton.setStyleSheet('QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}') self.repaint() return True def _doit(self): if self._setINPROG(): if not self._checkTypes(): self.goButton.setText('OOPS..') self.goButton.setStyleSheet('QPushButton {background-color: darkred; border: 2px solid 1 ; border-radius: 6px;}') self.reply = QMessageBox.question(self, 'Nope!', "Nothing to transfer. Try selecting something and try again", QMessageBox.Ok) else: self.processStoryBoardFolder() def processStoryBoardFolder(self): """ Function to copy over all the audio files from a single output folder into the correct locations for the bubblebathbay IDrive audios folders @param epNum: The episode name @param pathToFolder: The path to the folder full of wav files you want to copy over. @type pathToFolder: String @type epNum: String NOTE: this tool has been written around the following audio output naming convention from TOONBOOM ep106_sh001.wav ep106_sh002.wav ep106_sh002_A.wav """ if self.epNumber.text() != 'ep': for each in self.fileBoxes: if each.isChecked() and each.text() != 'ALL': ## We will always start with a base version number of 0 as the audio files from Toonboom ## Do NOT have any versioning...Therefore iteration folders from toonboom can be correctly versioned into ## the publish wav folders without freaking out.... self.vNum = '000' self.epName = str(self.epNumber.text()).lower() self.shotNum = str(each.text()).split('.mov')[0].lower() if sys.platform == 'win32': self.shotReviewDir = 'I:/lsapipeline/episodes/%s/%s/SBoard/publish/review/' % ( self.epName, self.shotNum) else: self.shotReviewDir = '/Volumes/lsapipeline/episodes/%s/%s/SBoard/publish/review/' % ( self.epName, self.shotNum) self.shotReviewFileName = '%s_BOARD.v%s.mov' % (self.shotNum, self.vNum) self.finalPath = '%s%s' % (self.shotReviewDir, self.shotReviewFileName) ## Check for folder, if it doesn't exist make it if not os.path.isdir(self.shotReviewDir): os.makedirs(self.shotReviewDir) ## Now check for existing file, if so version it up just in case so we don't even delete. if os.path.isfile(self.finalPath): newVersNum = self._versionUp(self.shotReviewDir) if newVersNum <= 10: self.vNum = '00%s' %newVersNum elif newVersNum <= 100: self.vNum = '0%s' %newVersNum else: self.vNum = '%s' %newVersNum ## Now update the name and path vars as final. self.shotReviewFileName = '%s_BOARD.v%s.mov' % (self.shotNum, self.vNum) self.finalPath = '%s%s' % (self.shotReviewDir, self.shotReviewFileName) ## Now get the original path for the audio file we are copying. originalPath = '%s\\%s' % (self.sourceFolder, each.text()) ## Now perform the copy. shutil.copyfile(originalPath, self.finalPath) #p = subprocess.Popen(cmd, cwd=None, shell=True, bufsize=4096) # Wait until process terminates #while p.poll() is None: # time.sleep(0.5) print 'Copied file: %s to \t%s' % (each.text(), self.finalPath) if self.makeSGEntries.isChecked(): print 'Adding StoryBoard item to shotgun... %s: ' % self.shotReviewFileName self.addStoryboardVersionToShotgun(str(self.shotReviewDir), str(self.epName), str(self.shotNum), str(self.vNum), str(self.shotReviewFileName)) print 'Finished processing files' self.goButton.setText('COMPLETED... click to do over...') self.goButton.setStyleSheet('QPushButton {background-color: yellow; border: 2px solid 1 ; border-radius: 6px;}') else: self.goButton.setText('Invalid Ep Number... click to do over...') self.goButton.setStyleSheet('QPushButton {background-color: blue; border: 2px solid 1 ; border-radius: 6px;}') print 'You must set a valid episode number!!!'
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
p.product_rmk, p.prod_cls_n FROM item i JOIN product p ON i.product_id = p.product_id WHERE product_n not like 'Unknown %' ORDER BY item_sc DESC ''') row = cur.fetchone() while row: if not row['item_sc']: row = cur.fetchone() continue asset_data = transform_asset( row ) existing_asset = sg.find_one('Asset', [['code','is',asset_data['code']]]) if existing_asset: print "asset %s exists" % ( asset_data['code'] ) sg.update('Asset', existing_asset['id'], asset_data) else: print "asset %s creating" % ( asset_data['code'] ) try: sg.create('Asset', asset_data, return_fields=['id']) pass except Exception: pprint.pprint(row) pprint.pprint(asset_data) row = cur.fetchone() conn.close()
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 PublishMayaAudio(QWidget): def __init__(self, defaultSource='I:/lsapipeline/audios/', parent=None): QWidget.__init__(self, parent) self.setWindowTitle('Audio Publishing Tool') self.parent = parent ## Connect to shotgun from shotgun_api3 import Shotgun ## 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) ## Get the user name self.user = getpass.getuser() ## Define the variable for the source folder and destination folder (local and remote as it were) self.sourceFolder = defaultSource or '' self.fileBoxes = {} ## Build the UI self.mainLayout = QVBoxLayout(self) self.epNumLayout = QHBoxLayout() self.epNumLabel = QLabel('EpNum:') self.epNumber = QLineEdit('', self) self.epNumber.setStyleSheet( 'QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.epNumber.textChanged.connect(self.epTextChange) self.epNumber.setText('ep') self.epNumLayout.addWidget(self.epNumLabel) self.epNumLayout.addWidget(self.epNumber) ## Set the layout for the source text input and browse button self.pathLayout = QHBoxLayout(self) self.sourceLabel = QLabel('Set Src Path:') ## Define the widgets for this layout self.sourceInput = QLineEdit(self) if self.sourceFolder: self.sourceInput.setText(self.sourceFolder) self.sourceInput.textChanged.connect(partial(self.doFileCheckboxes)) self.browseButton = QPushButton('Browse') self.browseButton.released.connect( partial(self._browseDialog, dest=False)) ## Add the widgets to the layout self.pathLayout.addWidget(self.sourceLabel) self.pathLayout.addWidget(self.sourceInput) self.pathLayout.addWidget(self.browseButton) self.optionsLayout = QHBoxLayout(self) self.makeSGEntries = QCheckBox(self) self.makeSGEntries.setChecked(True) self.makeSGEntries.setText('Make SGun Entries?') self.goButton = QPushButton('Publish Audio Files') self.goButton.setStyleSheet( 'QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.clicked.connect(self._doit) self.optionsLayout.addWidget(self.makeSGEntries) self.optionsLayout.addWidget(self.goButton) self.split = HR.Widget_hr() self.mainLayout.addWidget(self.split) self.mainLayout.addLayout(self.epNumLayout) self.mainLayout.addLayout(self.pathLayout) self.mainLayout.addLayout(self.optionsLayout) ### Now do the check boxes for files.... self.scrollLayout = QScrollArea(self) self.scrollLayout.setMinimumHeight(300) self.filesGroupBox = QGroupBox(self.scrollLayout) self.filesGroupBox.setFlat(True) self.scrollLayout.setWidget(self.filesGroupBox) self.scrollLayout.setWidgetResizable(True) self.fileLayout = QGridLayout(self.filesGroupBox) self.mainLayout.addWidget(self.scrollLayout) def epTextChange(self): if len(self.epNumber.text()) > 5: self.epNumber.setStyleSheet( 'QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setStyleSheet( 'QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) elif self.epNumber.text() != 'ep' and len(self.epNumber.text()) == 5: self.epNumber.setStyleSheet( 'QLineEdit {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setStyleSheet( 'QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setText('Publish Audio Files') self.goButton.setEnabled(True) else: self.epNumber.setStyleSheet( 'QLineEdit {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setStyleSheet( 'QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.goButton.setText('BAD EP NUMBER') self.goButton.setEnabled(False) def _toggleAll(self): """ A quick toggle for all the type checkboxes to on or off """ for eachType in self.fileBoxes: if eachType.text() == 'ALL': if eachType.isChecked(): for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(True) else: for eachSubType in self.fileBoxes: if eachSubType.text() != 'ALL': eachSubType.setChecked(False) def doFileCheckboxes(self, myPath=''): """ Process all the folders/files found into check boxes for processing """ ## try to get the epNumber from a file epNum = os.listdir(self.sourceInput.text())[0].split('_')[0] if epNum: self.epNumber.setText(epNum) if self.fileBoxes != {}: for key, var in self.fileBoxes.items(): key.setParent(None) sip.delete(key) key = None self.repaint() self.files = [] self.fileBoxes = {} ## First add the ALL checkbox self.ALL = QCheckBox(self) self.ALL.setChecked(False) self.ALL.setText('ALL') self.ALL.toggled.connect(self._toggleAll) self.fileBoxes[self.ALL] = None self.fileLayout.addWidget(self.ALL, 0, 0) self.colCount = 10 r = 1 c = 1 ## Now process the folder and add the folders found as check boxes. try: ## Scan the entire folder structure for audio files to publish if self.isRootFolderThere(rootFolder=self.sourceFolder): print '%s found processing now...' % self.sourceFolder for dirname, dirnames, filenames in os.walk(self.sourceFolder): if dirname.endswith('\\wav'): print 'Scanning %s now..' % dirname print 'Files: %s' % os.listdir(dirname) getMaxFile = max(os.listdir(dirname)) if getMaxFile: ## we have a folder with files in it... if getMaxFile.endswith(".wav"): pathToWav = os.path.join(dirname, getMaxFile) self.fileCheckBox = QCheckBox(self) self.fileCheckBox.setChecked(False) self.fileCheckBox.setText(getMaxFile) self.fileBoxes[ self.fileCheckBox] = pathToWav.replace( '\\', '/') if c == self.colCount: r = r + 1 c = 1 self.fileLayout.addWidget( self.fileCheckBox, r, c) c = c + 1 print 'Adding %s to layout now..' % pathToWav else: print '%s is emtpy...' % dirname else: self.files = ['No root folder found...'] except: self.files = ['No wav files found...'] def _browseDialog(self, dest=False): """ This opens up a QFileDialog hard set to browse into the assets folder by default. @param dest: To set if you are setting the destination input or the source input @type dest: Boolean """ if sys.platform == 'win32': print 'OPENING WIN BROWSE DIALOG NOW...' myPath = QFileDialog( self, 'rootDir', self.sourceFolder).getExistingDirectory().replace('\\', '/') else: print 'OPENING %s BROWSE DIALOG NOW...' % sys.platform myPath = QFileDialog( self, 'rootDir', self.sourceFolder).getExistingDirectory().replace('\\', '/') ## try to get the epNumber from a file epNum = os.listdir(myPath)[0].split('_')[0] if epNum: self.epNumber.setText(epNum) self.sourceFolder = str(myPath) os.system('echo epNum: %s' % self.epNumber) os.system('echo sourceFolder: %s' % self.sourceFolder) os.system('echo final myPath: %s' % myPath) self.sourceInput.setText(myPath) #self.doFileCheckboxes(myPath) def _versionUp(self, path): return int(max(os.listdir(path)).split('.v')[-1].split('.wav')[0]) + 1 def _writeMaFile(self, fileName, pathToWav, wavName, publishPath): ## Check the folder exists, if not make one now. if not os.path.isdir(os.path.dirname(self.publishPath)): os.makedirs(os.path.dirname(self.publishPath)) self.header = [ r'//Maya ASCII 2013ff10 scene', r'//Name: %s' % fileName, r'//Last modified: Tue, Jun 17, 2014 10:41:32 AM', r'//Codeset: 1252', r'requires maya "2013ff10";', r'requires "Mayatomr" "2013.0 - 3.10.1.11 ";', r'currentUnit -l centimeter -a degree -t film;', r'fileInfo "application" "maya";', r'fileInfo "product" "Maya 2013";', r'fileInfo "version" "2013 x64";', r'fileInfo "cutIdentifier" "201301140020-856945";', r'fileInfo "osv" "Microsoft Windows 7 Ultimate Edition, 64-bit Windows 7 Service Pack 1 (Build 7601)\n";', ] self.audioNode = [ '\n%s' % r'createNode audio -n "%s";' % wavName.replace('.', '_'), '\t%s' % r'setAttr ".ef" 1000;', '\t%s' % r'setAttr ".se" 1000;', '\t%s' % r'setAttr ".f" -type "string" "%s";' % pathToWav, ] self.footer = ['\n%s' % r'// End of %s.ma' % fileName] ## Now write the ma file ## Fail if the version already exists pathToTextFile = publishPath if not os.path.isfile(pathToTextFile): outfile = open(pathToTextFile, "w") for eachLine in self.header: outfile.write('%s\n' % eachLine) for eachLine in self.audioNode: outfile.write('%s\n' % eachLine) for eachLine in self.footer: outfile.write('%s\n' % eachLine) outfile.close() else: ## Remove it because we are republishing the same version again. os.remove(pathToTextFile) ## Note we can just delete this file already and move on if needed. outfile = open(pathToTextFile, "w") for eachLine in self.header: outfile.write('%s\n' % eachLine) for eachLine in self.audioNode: outfile.write('%s\n' % eachLine) for eachLine in self.footer: outfile.write('%s\n' % eachLine) outfile.close() def _createPublish(self, publishPath, fileName, pathToWav, wavName, version_number, localPath, localPathMac, wavSGName, ctx): self.pathToWav = pathToWav self.publishPath = publishPath self.localPath = localPath self.localPathMac = localPathMac self.fileName = fileName self.wavName = wavName self.wavSGName = wavSGName self.version_number = version_number data = { "code": self.wavSGName, "description": None, "name": self.wavSGName, "project": ctx.project, "entity": { 'id': self.exists['id'], 'name': self.wavSGName, 'type': 'CustomEntity03' }, "version_number": self.version_number, 'path_cache': self.publishPath.replace('/', '\\'), 'published_file_type': { 'type': 'PublishedFileType', 'id': 1 }, 'updated_by': { 'type': 'HumanUser', 'id': 53 }, 'path': { 'content_type': None, 'link_type': 'local', 'url': 'file:///%s' % self.publishPath.replace('/', '\\'), "local_path": self.publishPath.replace('/', '\\'), 'local_path_linux': '', 'local_path_mac': '%s' % self.localPathMac, 'local_path_windows': '%s' % self.publishPath.replace('/', '\\'), 'local_storage': { 'id': 1, 'name': 'primary', 'type': 'LocalStorage' }, 'name': self.fileName, } } self.sgsrv.create('PublishedFile', data) print 'Publish file created for %s' % self.wavSGName def _publishAudio(self): """ Function to add the publish a maya audio file both making a maya file with an audio node and publishing this to shotgun as a version """ for key, var in self.fileBoxes.items(): if var: if key.isChecked(): ## Work out what we need for the creation of the ma file ## and the publish for shotgun self.pathToWav = var if sys.platform == 'win32': self.publishPath = var.replace( '/publish/wav', '/publish/maya').replace('.wav', '.ma').replace('/', '\\') self.localPath = self.publishPath.split('I:')[-1] self.localPathMac = self.publishPath.replace( 'I:', '/_projects') self.fileName = str(key.text()).replace('.wav', '.ma') self.wavName = str(key.text()) self.wavSGName = str(key.text().replace('_AUD', '').split('.')[0]) self.version_number = int( str(key.text()).split('.')[-2].split('v')[-1]) ## Now register the publish with Shotgun ## First find the audio on shotgun for processing. self.exists = self.sgsrv.find_one( 'CustomEntity03', filters=[["code", "is", self.wavSGName]], fields=['code', 'tasks', 'id']) if not self.exists: print '%s has no shotgun entry! You should make sure this has been processed correctly before proceeding!!' % self.wavName else: ## now publish tk = sgtk.sgtk_from_path("I:/lsapipeline/") ctx = tk.context_from_path(self.publishPath) ## For existing check ## CHECK FOR EXISTING PUBLISH WITH THE SAME VERSION NUMBER!!!! findExisting = self.sgsrv.find_one( 'PublishedFile', filters=[["code", "is", self.wavSGName]], fields=[ 'code', 'id', 'version_number', 'created_at', 'entity' ]) if findExisting: if findExisting[ 'version_number'] == self.version_number: print 'A PUBLISHED FILE FOR THIS VERSION ALREADY EXISTS SKIPPING! VERSION UP OR DELETE EXISTING SHOTGUN PUBLISH ENTRIES IF YOU NEED TO YOU SHOULDNT BUT YOU MIGHT!' ## WRITE THE MA ## Now write the ma file we are going to publish with the audio node created. ## Note this will delete and re-make any ma files with the same name in the folder if they exist self._writeMaFile(self.fileName, self.pathToWav, self.wavName, self.publishPath) else: ## This is a new version number ## WRITE THE MA ## Now write the ma file we are going to publish with the audio node created. ## Note this will delete and re-make any ma files with the same name in the folder if they exist self._writeMaFile(self.fileName, self.pathToWav, self.wavName, self.publishPath) self._createPublish( publishPath=self.publishPath, fileName=self.fileName, pathToWav=self.pathToWav, wavName=self.wavName, version_number=self.version_number, localPath=self.localPath, localPathMac=self.localPathMac, wavSGName=self.wavSGName, ctx=ctx) else: ## nothing already exists so build a fresh publish ## WRITE THE MA ## Now write the ma file we are going to publish with the audio node created. ## Note this will delete and re-make any ma files with the same name in the folder if they exist self._writeMaFile(self.fileName, self.pathToWav, self.wavName, self.publishPath) self._createPublish( publishPath=self.publishPath, fileName=self.fileName, pathToWav=self.pathToWav, wavName=self.wavName, version_number=self.version_number, localPath=self.localPath, localPathMac=self.localPathMac, wavSGName=self.wavSGName, ctx=ctx) print 'Complete' self.goButton.setText('COMPLETE.. click to run again') self.goButton.setStyleSheet( 'QPushButton {background-color: green; border: 2px solid 1 ; border-radius: 6px;}' ) self.repaint() def _checkTypes(self): anythingChecked = False if self.fileBoxes: for each in self.fileBoxes: if each.isChecked(): anythingChecked = True return anythingChecked def _setINPROG(self): self.goButton.setText('IN PROGRESS...') self.goButton.setStyleSheet( 'QPushButton {background-color: red; border: 2px solid 1 ; border-radius: 6px;}' ) self.repaint() return True def _doit(self): if self._setINPROG(): if not self._checkTypes(): self.goButton.setText('OOPS..') self.goButton.setStyleSheet( 'QPushButton {background-color: darkred; border: 2px solid 1 ; border-radius: 6px;}' ) self.reply = QMessageBox.question( self, 'Nope!', "Nothing to transfer. Try selecting something and try again", QMessageBox.Ok) else: self._publishAudio() def isRootFolderThere(self, rootFolder): """ Method used to check if root folder is valid or not """ if not os.path.isdir(rootFolder): print 'No such root folder found.' return -1 else: return 1
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
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"]) if (ret != []): switchForTask = 1
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()
else: sg = Shotgun('http://127.0.0.1:8020', 'name', 'key') print sg.server_info proj = sg.create('Project', {'name': 'Mock Project Test'}) seq = sg.create('Sequence', {'code': 'AA', 'project': proj}) shot = sg.create('Shot', {'code': 'AA_001', 'sg_sequence': seq}) print proj print seq print shot # # print sg.find('Project', [('id', 'is_not', 0)], ['name'], order=[ # {'field_name': 'id', 'direction': 'asc'}, # ]) print sg._call_rpc('count', None) exit() print sg.create('Project', {'name': 'Test Project'}) print sg.count() print sg.find_one('Project', [], order=[ { 'field_name': 'id', 'direction': 'asc' }, ], fields=['task_assignees'])