class AppServerSvc(win32serviceutil.ServiceFramework): _svc_name_ = "timelog" _svc_display_name_ = "shotgun time log" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) SetConsoleCtrlHandler(lambda x: True, True) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.count = 0 self.estinmins = 0 self.isAlive = True self.envv = '' self.prlist = [] def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) self.run = False def SvcDoRun(self): servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, '')) self.sg = Shotgun('https://xxxxxxxxxxxxxxxx.shotgunstudio.com', 'timelogservice', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') self.main() def updateProject(self, projectid): servicemanager.LogWarningMsg(unicode(projectid)) filters = [["project.Project.id", "is", projectid]] fields = ["time_logs_sum", "est_in_mins"] for eventTimeLog in self.sg.find('Task', filters, fields): self.count = self.count + eventTimeLog['time_logs_sum'] if eventTimeLog['est_in_mins'] is not None: self.estinmins = self.estinmins + eventTimeLog['est_in_mins'] data = {'sg_artisttimelog': self.count / 600} asset = self.sg.update("Project", projectid, data) data = {'sg_total_bid': self.estinmins / 600} asset = self.sg.update("Project", projectid, data) def main(self): while self.isAlive: filters = [["sg_status", "is", "active"]] fields = ['id'] for f in self.sg.find('Project', filters, fields): self.prlist.append(f['id']) for prid in self.prlist: self.updateProject(prid) self.count = 0 self.estinmins = 0 if win32event.WaitForSingleObject( self.hWaitStop, 3000) == win32event.WAIT_OBJECT_0: break
class AppServerSvc(win32serviceutil.ServiceFramework): _svc_name_ = "timelog" _svc_display_name_ = "shotgun time log" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) SetConsoleCtrlHandler(lambda x: True, True) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.count = 0 self.estinmins = 0 self.isAlive = True self.envv = "" self.prlist = [] def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) self.run = False def SvcDoRun(self): servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, "") ) self.sg = Shotgun( "https://xxxxxxxxxxxxxxxx.shotgunstudio.com", "timelogservice", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) self.main() def updateProject(self, projectid): servicemanager.LogWarningMsg(unicode(projectid)) filters = [["project.Project.id", "is", projectid]] fields = ["time_logs_sum", "est_in_mins"] for eventTimeLog in self.sg.find("Task", filters, fields): self.count = self.count + eventTimeLog["time_logs_sum"] if eventTimeLog["est_in_mins"] is not None: self.estinmins = self.estinmins + eventTimeLog["est_in_mins"] data = {"sg_artisttimelog": self.count / 600} asset = self.sg.update("Project", projectid, data) data = {"sg_total_bid": self.estinmins / 600} asset = self.sg.update("Project", projectid, data) def main(self): while self.isAlive: filters = [["sg_status", "is", "active"]] fields = ["id"] for f in self.sg.find("Project", filters, fields): self.prlist.append(f["id"]) for prid in self.prlist: self.updateProject(prid) self.count = 0 self.estinmins = 0 if win32event.WaitForSingleObject(self.hWaitStop, 3000) == win32event.WAIT_OBJECT_0: break
def main(script, project): ## get shotgun script information && create the shotgun instance SERVER_PATH = "" SCRIPT_NAME = '' SCRIPT_KEY = '' sg = Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) projectList = getProjectList(sg, logging, project) ## get list of episodes to update episodeList = getEpisodeList(sg, logging, projectList['projectID']) ## for each episode in episode list ## set its path to XML && get shotList and sequenceList for i in range(0, len(episodeList)): ## get the full episode name, episodeID, && duration episodeName = episodeList[i]['code'] episodeID = episodeList[i]['id'] episodeDuration = episodeList[i]['sg_duration'] ## get the episode, xmlName, xmlFolder and path for the episode episode = episodeName.split('_') episode = episode[1] xmlName = episode.lower() + "_shotdata.xml" xmlFolder = projectList[ 'pathToProject'] + '\\05_PROD\\EPISODES\\' + episodeName + "\\99_PIPELINE\\" xmlPath = xmlFolder + xmlName ## get the sequences and shot info sequenceList = getSequenceList(sg, logging, episodeID) shotList = getShotList(sg, logging, episodeID) ## update the XML updateXML(xmlPath, episodeName, episodeDuration, sequenceList, shotList) ## update the episode to active episodeData = {'sg_status_list': 'act'} episodeUpdate = sg.update('Scene', episodeID, episodeData)
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)
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
#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}, } existing_fact = sg.find_one('CustomEntity01', [['code','is',fact_name],['sg_asset','is',{'type':'Asset','id': asset['id']}]],['id']) if existing_fact: print "asset %s has existing fact %s, updating to %s" % ( hostname, fact_name, fact_value ) sg.update('CustomEntity01', existing_fact['id'], fact_data) else: print "asset %s creating fact %s : %s" % ( hostname, fact_name, fact_value ) sg.create('CustomEntity01', fact_data, return_fields=['id'])
for a_version in versions: #pre-process all shots looking for duplicates print "</br>" if a_version['entity']['name'] in found_shots: raise MultiShotError( 'There is more than one version of shot %s in your request' % a_version['entity']['name']) else: found_shots.add(a_version['entity']['name']) for a_version in versions: # re-process all shots to set the current version field correctly entity_type = a_version['entity']['type'] # should always be 'Shot'! if entity_type == 'Shot': # we always expect a shot but OK to test shot_id = a_version['entity']['id'] linked_version = {'type': 'Version', 'id': a_version['id']} data = {CURRENT_VERSION_FIELD: linked_version} changed_asset = sg.update("Shot", shot_id, data) print 'Shot %i Has Been Updated Successfully' % shot_id print '</br>' else: success = False print('version %s is linked to something other than a shot?' % a_version_id) print '</br>' if success: #everything has gone well and the user gets a message print SUCCESS_MESSAGE_HTML except ConfigError, (errmsg): print CONFIG_ERROR_HTML
class studioShotgun(object): def __init__(self, path, name, key, project): self.SERVER_PATH = path self.SCRIPT_NAME = name self.SCRIPT_KEY = key self.project_id = project self.sg = Shotgun(self.SERVER_PATH, self.SCRIPT_NAME, self.SCRIPT_KEY) #---------------------------------------------------------------------- ## set Project id by ID def setProjectId(self, newId): self.project_id = newId #---------------------------------------------------------------------- ## set Project id by ID def setProjectName(self, name): newId = 0 projects = self.sg.find('Project', [], ['name']) for project in projects: if project['name'] == name: newId = project['id'] self.project_id = newId #---------------------------------------------------------------------- ## find asset by name def findAssetByName(self, name): fields = ['id', 'code', 'sg_asset_type', 'tasks'] filters = [[ 'project', 'is', { 'type': 'Project', 'id': self.project_id } ], ['code', 'is', name]] result = self.sg.find('Asset', filters, fields) return result #---------------------------------------------------------------------- ## find shot by name def findShotByName(self, episode, shot): fields = ['id', 'code', 'sg_asset_type', 'tasks', 'sg_sequence'] filters = [[ 'project', 'is', { 'type': 'Project', 'id': self.project_id } ], ['code', 'is', shot]] result = self.sg.find('Shot', filters, fields) for x in result: name = x['sg_sequence']['name'].split('_')[0] if name == episode: return x return [] #---------------------------------------------------------------------- ## upload thumbnail to asset def uploadThumbnail(self, asset, thumbnail): upload = 0 asset = self.findAssetByName(asset) if asset: upload = self.sg.upload_thumbnail("Asset", asset[0]['id'], thumbnail) return upload #---------------------------------------------------------------------- ## create new asset def createAsset(self, asset, assetType, template, assetFile='', description=''): ## find asset asset = self.findAssetByName(asset) if not asset: ## create asset + task template filters = [['code', 'is', template]] template = self.sg.find_one('TaskTemplate', filters) data = { 'project': { 'type': 'Project', 'id': self.project_id }, 'code': asset, 'description': description, 'sg_asset_type': assetType, 'sg_url_perforce': assetFile, 'task_template': template } asset = self.sg.create('Asset', data) return asset #---------------------------------------------------------------------- ## update file path in asset def updateAssetFilePath(self, asset, filename): asset = self.findAssetByName(asset) data = {'sg_url_perforce': filename} asset = self.sg.update("Asset", asset[0]['id'], data) return asset #---------------------------------------------------------------------- ## create new version def createVersion(self, shotId, taskId, userId, filename, comment=''): curTime = datetime.now().strftime('%Y.%m.%d_%H.%M') fname = str(filename.split('/')[-1].split('.')[0]) + '_' + curTime data = { 'project': { 'type': 'Project', 'id': self.project_id }, 'code': fname, 'description': comment, 'sg_status_list': 'rev', 'entity': { 'type': 'Shot', 'id': shotId }, 'sg_task': { 'type': 'Task', 'id': taskId }, 'user': { 'type': 'HumanUser', 'id': userId } } result = self.sg.create('Version', data) upload = self.sg.upload('Version', result['id'], filename, 'sg_uploaded_movie') return [result, upload] #---------------------------------------------------------------------- ## get user data from shotgum def getUserData(self, user): filters = [['login', 'is', user]] user = self.sg.find('HumanUser', filters) if user: return user[0] else: return [] #---------------------------------------------------------------------- ## get all user from project def getAllUsers(self): fields = ['id', 'login', 'name', 'projects', 'department'] filters = [[ 'projects', 'is', { 'type': 'Project', 'id': self.project_id } ]] users = self.sg.find('HumanUser', filters, fields) return users
class 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
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 }, } existing_fact = sg.find_one( 'CustomEntity01', [['code', 'is', fact_name], ['sg_asset', 'is', { 'type': 'Asset', 'id': asset['id'] }]], ['id']) if existing_fact: print "asset %s has existing fact %s, updating to %s" % ( hostname, fact_name, fact_value) sg.update('CustomEntity01', existing_fact['id'], fact_data) else: print "asset %s creating fact %s : %s" % (hostname, fact_name, fact_value) sg.create('CustomEntity01', fact_data, return_fields=['id'])
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': entity_id = payload['id'] # Do a lot of legwork (based on Shotgun.download_attachment()) sid = sg._get_session_token()
__author__ = 'andrew.willis' from shotgun_api3 import Shotgun sg = Shotgun("http://andrewwillish.shotgunstudio.com", "scriptTest", "8b7db88321b7c296541580d1659872d2e63527c040b37b4a2ca0eb47f9da04cb") proj = sg.find_one("Project",[['name','is','KIKO']]) idLis = [1166, 1167, 1168] for id in idLis: sg.update('Shot', id, {"sg_status_list":"wtg"})
#from dBase import * from shotgun_api3 import Shotgun import os site = 'https://chimneypot.shotgunstudio.com' scriptName = 'dBase' scriptKey = '729a76955455909c79f6d90262bb9fbe9186b92b' pName = 'kievPipelineTest' sg = Shotgun(site, scriptName, scriptKey) lst = sg.find('HumanUser', [['updated_at', 'not_in_last', 1, 'MONTH'],['sg_status_list', 'is', 'act']], ['name', 'updated_at', 'sg_status_list']) for i in lst: print "%s: %s, %s, %s"%(i['name'],i['updated_at'], i['sg_status_list'], i['id']) killEric = sg.update('HumanUser', 62, {'sg_status_list':'dis'}) def test(): print 'huy' return sg
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 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
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!!!'
for a_version in versions: #pre-process all shots looking for duplicates print "</br>" if a_version['entity']['name'] in found_shots: raise MultiShotError( 'There is more than one version of shot %s in your request' % a_version['entity']['name'] ) else: found_shots.add( a_version['entity']['name'] ) for a_version in versions: # re-process all shots to set the current version field correctly entity_type = a_version['entity']['type'] # should always be 'Shot'! if entity_type == 'Shot': # we always expect a shot but OK to test shot_id = a_version['entity']['id'] linked_version = { 'type' : 'Version' , 'id' : a_version['id'] } data = { CURRENT_VERSION_FIELD : linked_version } changed_asset = sg.update("Shot", shot_id, data) print 'Shot %i Has Been Updated Successfully' % shot_id print '</br>' else: success = False print('version %s is linked to something other than a shot?' % a_version_id) print '</br>' if success: #everything has gone well and the user gets a message print SUCCESS_MESSAGE_HTML except ConfigError, (errmsg): print CONFIG_ERROR_HTML except MultiShotError, (errmsg):
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
efilenames = {} for efile in efiles: efilenames[efile['attachment_links'][0]['name']] = efile['id'] print efilenames enames = {} for eper in epers: enames[eper['code']] = eper print enames pers = glob('pers/*.json') for per in pers: with open(per) as json_data: temp = json.load(json_data) json_data.close() data = { 'code': temp['name'], 'description': temp['desc'], 'sg_arcana': temp['arcana'], 'sg_level': (int)(temp['level']), 'sg_json': None } if temp['name'] not in enames: data['project'] = {'type': 'Project', 'id': 70} id = sg.create('CustomEntity07', data, ['id'])['id'] else: id = sg.update('CustomEntity07', enames[temp['name']]['id'], data)['id'] if temp['name'] in efilenames: sg.delete('Attachment', efilenames[temp['name']]) sg.upload('CustomEntity07', id, per, 'sg_json')
if line['est_in_mins']: # Bid print 'bid' print line['est_in_mins'] bidTask = line['est_in_mins'] newBidTask = int(bidTask * 0.8) print newBidTask # SG Update data = { 'est_in_mins': newBidTask } result = sg.update('Task', line['id'], data) if line['start_date']: # Start print 'start' print line['start_date'] # SG Update data = { 'start_date': '' } result = sg.update('Task', line['id'], data) if line['due_date']: # End print 'end' print line['due_date'] # SG Update data = { 'due_date': '' } result = sg.update('Task', line['id'], data) return if __name__ == '__main__':