def launch(self, event): if "values" in event["data"]: # Do something with the values or return a new form. values = event["data"]["values"] success = True msg = "Asset deleted." # deleting all assets if values["asset"] == "all": entity = None try: entity = ftrack.Project( event["data"]["selection"][0]["entityId"]) except: entity = ftrack.Task( event["data"]["selection"][0]["entityId"]) for asset in entity.getAssets(): asset.delete() return {"success": success, "message": "All assets deleted."} asset = ftrack.Asset(values["asset"]) asset.delete() return {"success": success, "message": msg} data = [] entity = None try: entity = ftrack.Project(event["data"]["selection"][0]["entityId"]) except: entity = ftrack.Task(event["data"]["selection"][0]["entityId"]) for asset in entity.getAssets(): if asset.getName(): name = "{0} ({1})".format(asset.getName(), asset.getType().getName()) data.append({"label": name, "value": asset.getId()}) else: data.append({"label": "None", "value": asset.getId()}) if len(data) > 1: data.append({"label": "All", "value": "all"}) return { "items": [{ "label": "Asset", "type": "enumerator", "name": "asset", "data": data }] }
def getVersionsInSelection(self, selection): '''Return list of versions in *selection*.''' versions = [] for item in selection: self.logger.info( 'Looking for versions on entity ({0}, {1})'.format( item['entityId'], item['entityType'])) if item['entityType'] == 'assetversion': versions.append(ftrack.AssetVersion(item['entityId'])) continue entity = None if item['entityType'] == 'show': entity = ftrack.Project(item['entityId']) elif item['entityType'] == 'task': entity = ftrack.Task(item['entityId']) if not entity: continue assets = entity.getAssets(includeChildren=True) self.logger.info('Found {0} assets on entity'.format(len(assets))) for asset in assets: assetVersions = asset.getVersions() self.logger.info('Found {0} versions on asset {1}'.format( len(assetVersions), asset.getId())) versions.extend(assetVersions) self.logger.info('Found {0} versions in selection'.format( len(versions))) return versions
def get_path(self, instance): ftrack_data = instance.context.data('ftrackData') parent_name = None try: parent_name = ftrack_data['Shot']['name'] except: parent_name = ftrack_data['Asset_Build']['name'].replace(' ', '_') project = ftrack.Project(id=ftrack_data['Project']['id']) root = project.getRoot() file_name = os.path.basename(instance.context.data('currentFile')) file_name = os.path.splitext(file_name)[0] task_name = ftrack_data['Task']['name'].replace(' ', '_').lower() version_number = instance.context.data('version') version_name = 'v%s' % (str(version_number).zfill(3)) filename = '.'.join([parent_name, task_name, version_name, '%04d']) path = [root, 'renders', 'img_sequences'] task = ftrack.Task(ftrack_data['Task']['id']) for p in reversed(task.getParents()[:-1]): path.append(p.getName()) path.append(task_name) path.append(version_name) path.append(str(instance)) path.append(filename) return os.path.join(*path).replace('\\', '/')
def process(self, instance, context): seq = instance[0] seq_format = seq.format() seq_framerate = seq.framerate() project = ftrack.Project(context.data('ftrackData')['Project']['id']) project_width = int(project.get('resolution_width')) project_height = int(project.get('resolution_height')) check = True if project.get('fps') != seq.framerate(): msg = 'Framerate "%s" ' % seq.framerate() msg += 'was expected to be "%s"' % project.get('fps') self.log.error(msg) check = False if seq_format.width() != project_width: msg = 'Width "%s" ' % seq_format.width() msg += 'was expected to be "%s"' % project_width self.log.error(msg) check = False if seq_format.height() != project_height: msg = 'Height "%s" ' % seq_format.height() msg += 'was expected to be "%s"' % project_height self.log.error(msg) check = False assert check, 'Sequence "%s" settings are not correct.' % seq.name()
def launch(self, event): selection = event['data'].get('selection', []) entityType = selection[0]['entityType'] if 'values' in event['data']: values = event['data']['values'] if 'number_of_tasks' in values and int(values['number_of_tasks']) >= 0: form = self.getForm(int(values['number_of_tasks'])) return form else: structure = self.generate_structure(values) project = ftrack.Project(selection[0]['entityId']) projectFolder = self.getProjectFolder(project) self.create(project, structure, projectFolder, projectFolder, values['create_template']) return { 'success': True, 'message': 'Action completed successfully' } return { 'items': [{ 'label': 'Number of tasks', 'type': 'number', 'name': 'number_of_tasks', 'value': 2 }] }
def createNotes(self, selection, text, category): entityCount = len(selection) logging.info('Creating notes on {0} entities'.format(entityCount)) job = ftrack.createJob( 'Creating notes ({0} of {1})'.format(1, entityCount), 'running' ) try: for index, item in enumerate(selection, start=1): entityType = item['entityType'] entityId = item['entityId'] entity = None if index != 1: job.setDescription('Creating notes ({0} of {1})'.format(index, entityCount)) if entityType == 'show': entity = ftrack.Project(entityId) elif entityType == 'task': entity = ftrack.Task(entityId) elif entityType == 'assetversion': entity = ftrack.AssetVersion(entityId) if not entity: logging.warning( u'Entity ({0}, {1}) not a valid type, skipping..' .format(entityId, entityType) ) entity.createNote(text, category) except Exception: job.setStatus('failed') logging.info('Note creation completed.') job.setStatus('done')
def _onEntityBrowseButtonClicked(self): '''Handle entity browse button clicked.''' # Ensure browser points to parent of currently selected entity. if self._entity is not None: location = [] try: parents = self._entity.getParents() except AttributeError: pass else: for parent in parents: location.append(parent.getId()) location.reverse() self.entityBrowser.setLocation(location) # Launch browser. if self.entityBrowser.exec_(): selected = self.entityBrowser.selected() if selected: # Translate new api entity to instance of ftrack.Task # TODO: this should not be necessary once connect has been # updated to use the new api. if selected[0].entity_type == 'Project': entity = ftrack.Project(selected[0]['id']) else: entity = ftrack.Task(selected[0]['id']) self.setEntity(entity) else: self.setEntity(None)
def launch(self, event): '''Callback method for custom action.''' selection = event['data'].get('selection', []) ####################################################################### job = ftrack.createJob(description="Creating Folders", status="running") try: ftrack.EVENT_HUB.publishReply(event, data={ 'success': True, 'message': 'Folder Creation Job Started!' }) for entity in selection: if entity['entityType'] == 'task': entity = ftrack.Task(entity['entityId']) else: entity = ftrack.Project(entity['entityId']) self.createFoldersFromEntity(entity) # inform the user that the job is done job.setStatus('done') except: job.setStatus('failed') raise ####################################################################### return {'success': True, 'message': 'Created Folders Successfully!'}
def getFolders(self, entityType, entityId): if entityType == 'show': project = ftrack.Project(entityId) rootFolder = self.getProjectFolder(project) shotsFolder = os.path.join(rootFolder, 'shots') parent = project else: task = ftrack.Task(entityId) project = ftrack.Project(task.get('showid')) rootFolder = self.getProjectFolder(project) projectFolder = os.path.join(rootFolder, 'shots') shotsFolder = self.getParentFolders(task, projectFolder) shotsFolder = os.path.join(shotsFolder, task.getName()) if entityType == 'Shot': shotsFolder = os.path.join(shotsFolder, 'scene') parent = task return parent, shotsFolder
def get_path(self, instance): path = [] filename = [] # get ftrack data ftrack_data = instance.context.data('ftrackData') project = ftrack.Project(id=ftrack_data['Project']['id']) path.append(ftrack_data['Project']['root']) try: ep_name = ftrack_data['Episode']['name'].replace(' ', '_').lower() path.append('episodes') path.append(ep_name) except: self.log.info('No episodes found.') try: seq_name = ftrack_data['Sequence']['name'].replace(' ', '_').lower() if 'Episode' not in ftrack_data: path.append('sequences') path.append(seq_name) except: self.log.info('No sequences found.') try: shot_name = ftrack_data['Shot']['name'].replace(' ', '_').lower() path.append(shot_name) filename.append(shot_name) except: self.log.info('No shot found.') task_name = ftrack_data['Task']['name'].replace(' ', '_').lower() path.append(task_name) filename.append(task_name) # get version data version = 1 if instance.context.has_data('version'): version = instance.context.data('version') version_string = 'v%s' % str(version).zfill(3) filename.append(version_string) # extension ext = os.path.splitext(instance.context.data('currentFile'))[1] self.log.info(instance.context.data('currentFile')) try: filename.append(ext.split('.')[1]) except: filename.append('hrox') path.append('.'.join(filename)) return os.path.join(*path).replace('\\', '/')
def getShotPlatesFolder(shot): project = ftrack.Project(id=shot.get('showid')) projectFolder = getProjectFolder(project) sequenceName = shot.getParent().getName() shotName = shot.getName() imgFolder = os.path.join(projectFolder, 'shots', sequenceName, shotName, 'img') platesFolder = os.path.join(imgFolder, 'plates') if not os.path.exists(platesFolder): platesFolder = os.path.join(platesFolder, 'proxy') return platesFolder
def launch(self, event): '''Callback method for action.''' selection = event['data'].get('selection', []) self.logger.info(u'Launching action with selection \ {0}'.format(selection)) # Prepare lists to keep track of failures and successes fails = [] hits = set([]) for item in selection: # Filter between 'tasks' and projects if item['entityType'] == 'task': entity = ftrack.Task(item['entityId']) else: entity = ftrack.Project(item['entityId']) # Get paths base on the entity. # This function needs to be chagned to fit your path logic paths = self.get_paths(entity) # For each path, check if it exists on the disk and try opening it for path in paths: if os.path.isdir(path): self.logger.info('Opening: ' + path) # open the folder if sys.platform == 'darwin': subprocess.Popen(['open', '--', path]) elif sys.platform == 'linux2': subprocess.Popen(['gnome-open', '--', path]) elif sys.platform == 'win32': subprocess.Popen(['explorer', path]) # add path to list of hits hits.add(entity.getName()) # Add entity to fails list if no folder could be openned for it if entity.getName() not in hits: fails.append(entity.getName()) # Inform user of the result if len(hits) == 0: return { 'success': False, 'message': 'No folders found for: {}'.format(', '.join(fails)) } if len(fails) > 0: return { 'success': True, 'message': 'No folders found for: {}'.format(', '.join(fails)) } return {'success': True, 'message': 'Opening folders'}
def process(self, instance, context): # skipping if not launched from ftrack if not context.has_data('ftrackData'): return ftrack_data = context.data('ftrackData') parent = ftrack.Project(ftrack_data['Project']['id']) parent_path = [parent.getName()] if 'Episode' in ftrack_data: parent = ftrack.Sequence(ftrack_data['Episode']['id']) parent_path.append(parent.getName()) naming = '([a-z]+[0-9]{3})' for item in instance: [sequence_name, shot_name] = re.findall(naming, item.name()) path = list(parent_path) path.append(sequence_name) path.append(item.name()) shot = ftrack.getShot(path) path = self.get_path(shot, context) if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) if os.path.exists(path): msg = 'Audio file already exists. Please delete manually first.' self.log.warning(msg) else: item.sequence().writeAudioToFile(path, item.sourceIn(), item.sourceOut()) asset = shot.createAsset(item.name(), 'audio') version = None for v in asset.getVersions(): if v.getVersion() == context.data('version'): version = v if not version: version = asset.createVersion() version.set('version', value=context.data('version')) version.publish() try: version.createComponent(name='main', path=path) version.createComponent(name='wav', path=path) except: msg = 'Components "main" and "wav" already exists. ' msg += 'Please delete them manually first.' self.log.warning(msg)
def get_data(self, task_id): task_codes = { 'Animation': 'anim', 'Layout': 'layout', 'FX': 'fx', 'Compositing': 'comp', 'Motion Graphics': 'mograph', 'Lighting': 'light', 'Modelling': 'geo', 'Rigging': 'rig', 'Art': 'art', } try: task = ftrack.Task(id=task_id) except ValueError: task = None parents = task.getParents() project = ftrack.Project(task.get('showid')) task_type = task.getType().getName() entity_type = task.getObjectType() ctx = { 'Project': { 'name': project.get('fullname'), 'code': project.get('name'), 'id': task.get('showid'), 'root': project.getRoot(), }, entity_type: { 'type': task_type, 'name': task.getName(), 'id': task.getId(), 'code': task_codes.get(task_type, None) } } for parent in parents: tempdic = {} if parent.get('entityType') == 'task' and parent.getObjectType(): object_type = parent.getObjectType() tempdic['name'] = parent.getName() tempdic['description'] = parent.getDescription() tempdic['id'] = parent.getId() if object_type == 'Asset Build': tempdic['type'] = parent.getType().get('name') object_type = object_type.replace(' ', '_') ctx[object_type] = tempdic return ctx
def process(self, context): import os import json import ftrack job = context.data("deadlineJob") value = job.GetJobExtraInfoKeyValueWithDefault("PyblishInstanceData", "") if not value: return instance_data = json.loads(value) version = instance_data["ftrackAssetVersion"] if not instance_data["ftrackStatusUpdate"]: return # since "render" families will always produce a secondary job if os.path.splitext(instance_data["family"])[1] in [".ifd"]: return event = context.data["deadlineEvent"] event_dict = { "OnJobSubmitted": "Render Queued", "OnJobStarted": "Render", "OnJobFinished": "Render Complete", "OnJobRequeued": "Render Queued", "OnJobFailed": "Render Failed", "OnJobSuspended": "Render Queued", "OnJobResumed": "Render", "OnJobPended": "Render Queued", "OnJobReleased": "Render Queued" } if event in event_dict.keys(): project_id = context.data["ftrackData"]["Project"]["id"] ft_project = ftrack.Project(project_id) statuses = ft_project.getVersionStatuses() # Need to find the status by name ft_status = None for status in statuses: if status.getName().lower() == event_dict[event].lower(): ft_status = status break ftrack.AssetVersion(version["id"]).setStatus(ft_status) self.log.info("Setting ftrack version to %s" % event_dict[event])
def launch(self, event): selection = event['data'].get('selection', []) project = ftrack.Project(selection[0]['entityId']) projectFolder = self.getProjectFolder(project) templateFolder = os.path.join(projectFolder, 'template_files') projectFolder = os.path.join(projectFolder, 'shots') if 'values' in event['data']: values = event['data']['values'] if 'number_of_tasks' in values: self.numberOfTasks = int(values['number_of_tasks']) self.structureType = values['structure_type'] form = get_form( int(values['number_of_tasks']), values['structure_type'] ) return form else: structure = generate_structure(values) logging.debug('Creating structure "{0}"'.format(str(structure))) create(project, structure, projectFolder, projectFolder, values['create_template'], templateFolder) if values['create_a_seq'] == 'Yes': form = get_form( self.numberOfTasks, self.structureType ) return form else: return { 'success': True, 'message': 'Action completed successfully' } return { 'items': [{ 'label': 'Structure', 'type': 'enumerator', 'value': 'sequence', 'name': 'structure_type', 'data': [{ 'label': 'Sequence, Shot', 'value': 'sequence' }] },{ 'label': 'Number of tasks', 'type': 'number', 'name': 'number_of_tasks', 'value': 2 }] }
def launch(self, event): '''Callback method for action.''' selection = event['data'].get('selection', []) project = ftrack.Project(selection[0]['entityId']) if 'values' in event['data']: values = event['data']['values'] if 'number_of_tasks' in values: form = get_form(int(values['number_of_tasks']), values['structure_type']) return form else: structure = generate_structure(values) logging.info('Creating structure "{0}"'.format(str(structure))) create(project, structure) return { 'success': True, 'message': 'Action completed successfully' } return { 'items': [{ 'label': 'Select structure', 'type': 'enumerator', 'value': 'sequence', 'name': 'structure_type', 'data': [{ 'label': 'Episode, Sequence, Shot', 'value': 'episode' }, { 'label': 'Sequence, Shot', 'value': 'sequence' }, { 'label': 'Shot', 'value': 'shot' }] }, { 'label': 'Number of tasks', 'type': 'number', 'name': 'number_of_tasks', 'value': 2 }] }
def getEntity(entityType=None, entityId=None): if entityType is None or entityId is None: return None if entityType == 'user': return ftrack.User(entityId) if entityType == 'show': return ftrack.Project(entityId) elif entityType == 'task': return ftrack.Task(entityId) elif entityType == 'list': return ftrack.List(entityId) elif entityType == 'reviewsession': return ftrack.ReviewSession(entityId) else: return None
def getEntity(entityId, entityType): '''Return entity based on *entityId* and *entityType*.''' entity = None if entityType == ftrack.Project._type: entity = ftrack.Project(entityId) elif entityType == ftrack.Task._type: entity = ftrack.Task(entityId) elif entityType == 'assetversion': entity = ftrack.AssetVersion(entityId) if not entity: logging.warning( u'Entity ({0}, {1}) not a valid type, skipping..'.format( entityId, entityType)) return entity
def get_path(self, instance): ftrack_data = instance.context.data('ftrackData') shot_name = ftrack_data['Shot']['name'] project = ftrack.Project(id=ftrack_data['Project']['id']) root = project.getRoot() file_name = os.path.basename(instance.data('currentFile')) file_name = os.path.splitext(file_name)[0] task_name = ftrack_data['Task']['name'].replace(' ', '_').lower() version_number = instance.context.data('version') version_name = 'v%s' % (str(version_number).zfill(3)) filename = '.'.join([shot_name, task_name, version_name, str(instance), '%04d']) output = os.path.join(root, 'renders', 'img_sequences', shot_name, task_name, version_name, str(instance), filename) return output
def launch(self, event): '''Callback method for action.''' project_id = event['data']['selection'][0]['entityId'] project = ftrack.Project(project_id) try: input_values = event['data']['values'] except KeyError: input_values = None if not self.validate_input(input_values): return { 'items': [{ 'type': 'label', 'value': ''' This action will batch import thumbnails to selected project. Specify a *folder path* to a folder on your disk which contains images you want to use. The images should be named to match the entity path in ftrack. For example: 0010.png 0010.010.png 0010.010.generic.png This will set the thumbnail for the *sequence*, *shot* and the *generic task*. ''' }, { 'type': 'text', 'label': 'Folder path', 'name': 'folder_path' }] } files = self.get_files(input_values['folder_path'], project.getName()) self.upload_files_as_thumbnails(files) return {'success': True, 'message': 'Action completed successfully'}
def get_path(context): import ftrack ftrack_data = context.data('ftrackData') project = ftrack.Project(id=ftrack_data['Project']['id']) root = project.getRoot() task_name = ftrack_data['Task']['name'].replace(' ', '_').lower() version_number = context.data('version') version_name = 'v%s' % (str(version_number).zfill(3)) path = [root, 'renders', 'img_sequences'] task = ftrack.Task(ftrack_data['Task']['id']) for p in reversed(task.getParents()[:-1]): path.append(p.getName()) path.append(task_name) path.append(version_name) return os.path.join(*path).replace('\\', '/')
def callback(event): """ This plugin creates a template folder structure on disk. """ for entity in event['data'].get('entities', []): if entity.get('entityType') == 'show' and entity['action'] == 'add': project = ftrack.Project(id=entity['entityId']) schemeId = project.get('projectschemeid') scheme = ftrack.ProjectScheme(schemeId) if scheme.get('name') == 'VFX Scheme': projFolder = project.get('root') if projFolder == '': disk = ftrack.Disk(project.get('diskid')) rootFolder = '' if sys.platform == 'win32': rootFolder = disk.get('windows') elif sys.platform == 'linux2': rootFolder = disk.get('unix') projFolder = os.path.join(rootFolder, project.getName()) makeDirs(projFolder) templateFolder = os.path.join(projFolder, 'template_files') copy_tree(TEMPLATE_FILES, templateFolder)
def discover(self, event): selection = event['data']['selection'] # Not interested when not selecting anything if not event['data']['selection']: return # Not interested in multi selections if len(selection) > 1: return # Only interested in show, episode or sequence entity = None object_type = 'Show' try: entity = ftrack.Project(selection[0]['entityId']) except: pass try: entity = ftrack.Task(selection[0]['entityId']) object_type = entity.getObjectType() except: pass if object_type.lower() not in ['show', 'episode', 'sequence']: return return { 'items': [{ 'actionIdentifier': self.identifier, 'label': self.label, 'icon': self.icon, 'description': self.description, 'variant': self.variant }] }
def objectById(identifier): '''Return object from *identifier*.''' obj = None if identifier != '': if 'ftrack://' in identifier: url = urlparse.urlparse(identifier) query = urlparse.parse_qs(url.query) entityType = query.get('entityType')[0] identifier = url.netloc if entityType == 'assettake': obj = ftrack.Component(identifier) elif entityType == 'asset_version': obj = ftrack.AssetVersion(identifier) elif entityType == 'asset': obj = ftrack.Asset(identifier) elif entityType == 'show': obj = ftrack.Project(identifier) elif entityType == 'task': obj = ftrack.Task(identifier) else: ftrackObjectClasses = [ ftrack.Task, ftrack.Asset, ftrack.AssetVersion, ftrack.Component, ftrack.Project ] for cls in ftrackObjectClasses: try: obj = cls(id=identifier) break except: pass return obj
def getLatestCompScript(self, task): filename = '' project = ftrack.Project(task.get('showid')) projectFolder = self.getProjectFolder(project) parent = task.getParent() if parent.get('objecttypename') == 'Asset Build': assetType = parent.getType().getName().lower() assetName = parent.getName() sceneFolder = os.path.join(projectFolder, 'assets', assetType, assetName) elif parent.get('objecttypename') == 'Shot': shotFolder = self.getParentFolders(task) sceneFolder = os.path.join(projectFolder, 'shots', shotFolder, 'scene') else: sceneFolder = projectFolder taskFolder = os.path.join(sceneFolder, task.getName().lower()) if task.getType().getName().lower() == 'modeling': taskFolder = os.path.join(taskFolder, 'maya') if os.path.exists(taskFolder): files = [ f for f in os.listdir(taskFolder) if os.path.isfile(os.path.join(taskFolder, f)) and not (f.endswith('.autosave') or f.endswith('~')) ] maxVersion = 1 if files: for f in files: try: version = int(self.version_get(f, 'v')[1]) except ValueError: version = 0 if version >= maxVersion: filename = f maxVersion = version filename = os.path.join(taskFolder, filename) return filename
def getEntityById(self, identifier, throw=True): '''Return an entity represented by the given *identifier*. If *throw* is True then raise :py:exc:`FnAssetAPI.exceptions.InvalidEntityReference` if no entity can be found, otherwise return None. ''' entity = None if identifier != '': if 'ftrack://' in identifier: url = urlparse.urlparse(identifier) query = urlparse.parse_qs(url.query) entityType = query.get('entityType')[0] identifier = url.netloc try: return self._memoiser.cache.get(identifier) except KeyError: pass try: if entityType == 'component': entity = ftrack.Component(identifier) elif entityType == 'asset_version': entity = ftrack.AssetVersion(identifier) elif entityType == 'asset': entity = ftrack.Asset(identifier) elif entityType == 'show': entity = ftrack.Project(identifier) elif entityType == 'task': entity = ftrack.Task(identifier) elif entityType == 'tasktype': entity = ftrack.TaskType(identifier) except: pass else: ftrackObjectClasses = [ ftrack.Task, ftrack.Asset, ftrack.AssetVersion, ftrack.Component, ftrack.Project, ftrack.TaskType ] try: return self._memoiser.cache.get(identifier) except KeyError: pass for cls in ftrackObjectClasses: try: entity = cls(id=identifier) break except ftrack.FTrackError as error: if error.message.find('was not found') == -1: raise pass except Exception, error: FnAssetAPI.logging.log( 'Exception caught trying to create {0}: {1}'. format(cls.__name__, error), FnAssetAPI.logging.kError) raise
def CreateFTrackVersion(job, ftrackKVPs): #Set up the environment needed to connect to FTrack config = RepositoryUtils.GetEventPluginConfig("FTrack") ftrackURL = config.GetConfigEntryWithDefault("FTrackURL", "").strip() ftrackKey = config.GetConfigEntryWithDefault("FTrackAPIKey", "").strip() ftrackProxy = config.GetConfigEntryWithDefault("FTrackProxy", "").strip() username = ftrackKVPs.get("FT_Username", "") os.environ["FTRACK_SERVER"] = ftrackURL os.environ["FTRACK_APIKEY"] = ftrackKey if ftrackProxy: os.environ["FTRACK_PROXY"] = ftrackProxy if username: os.environ["LOGNAME"] = username #Import FTrack API eggPath = ftrackPath = RepositoryUtils.GetRootDirectory( "events/FTrack/API") sys.path.append(eggPath) import ftrack ftrack.setup(False) #TODO: Handle errors in a nicer way projectID = ftrackKVPs.get("FT_ProjectId", "") project = ftrack.Project(id=projectID) #Fetch project with given ID taskID = ftrackKVPs.get("FT_TaskId", "") task = ftrack.Task(id=taskID) #Fetch task with given ID assetID = ftrackKVPs.get("FT_AssetId", "") asset = ftrack.Asset(id=assetID) #Fetch asset with given ID description = ftrackKVPs.get("FT_Description", "") version = asset.createVersion(comment=description, taskid=taskID) #Set version status based on the Deadline Job's status dlStatus = job.Status ftStatusName = "" if dlStatus == JobStatus.Active: if job.RenderingChunks > 0: ftStatusName = config.GetConfigEntryWithDefault( "VersionStatusStarted", "").strip() else: ftStatusName = config.GetConfigEntryWithDefault( "VersionStatusQueued", "").strip() elif dlStatus == JobStatus.Failed: ftStatusName = config.GetConfigEntryWithDefault( "VersionStatusFailed", "").strip() elif dlStatus == JobStatus.Completed: ftStatusName = config.GetConfigEntryWithDefault( "VersionStatusFinished", "").strip() #Set the components based on the Job's output (if available) for i in range(len(job.OutputDirectories)): outPath = os.path.normpath(job.OutputDirectories[i]) outPath = RepositoryUtils.CheckPathMapping(outPath, True) if i < len(job.OutputFileNames): outPath = os.path.join(outPath, job.OutputFileNames[i]) #Change out our '#' padding for python-style padding, which FTrack expects match = re.search("#+", outPath) if match: padding = match.group(0) outPath = "{0} [{1}]".format( outPath.replace(padding, "%%0%dd" % len(padding)), job.FramesList) ClientUtils.LogText( "Creating Component for Deadline output '{0}'...".format( outPath)) try: #Job's complete, so output should be present now, let FTrack pick a location for us version.createComponent(name=("Deadline_Output_%d" % i), path=outPath) except: #That failed =/ ClientUtils.LogText(traceback.format_exc()) ClientUtils.LogText( "Failed to create component for output '%s'. No component will be created." % outPath) ClientUtils.LogText("Done creating Components.") if ftStatusName: statuses = project.getVersionStatuses() ftStatus = None for status in statuses: if status.getName().lower() == ftStatusName.lower(): ftStatus = status break if ftStatus == None: ClientUtils.LogText( "Could not find valid Asset Version Status with name '%s'. The Version Status might not be set properly." % ftStatusName) else: ClientUtils.LogText("Setting Asset Version to status '%s'." % ftStatusName) version.setStatus(ftStatus) version.publish() return version.getId()
def launch(self, event): '''Callback method for action.''' selection = event['data'].get('selection', []) data = [{ 'label': 'Episode, Sequence, Shot', 'value': 'episode' }, { 'label': 'Sequence, Shot', 'value': 'sequence' }, { 'label': 'Shot', 'value': 'shot' }] entity = None data_value = 'episode' entity_name = '' try: entity = ftrack.Project(selection[0]['entityId']) entity_name = entity.getFullName() except: pass try: entity = ftrack.Task(selection[0]['entityId']) object_type = entity.getObjectType() entity_name = entity.getName() if object_type == 'Episode': del data[0] data_value = 'sequence' if object_type == 'Sequence': del data[0] del data[0] data_value = 'shot' except: pass if 'values' in event['data']: values = event['data']['values'] if 'number_of_tasks' in values: form = get_form(int(values['number_of_tasks']), values['structure_type'], entity_name + '_', int(values['padding_count'])) return form else: structure = generate_structure(values) logging.info('Creating structure "{0}"'.format(str(structure))) create(entity, structure) return { 'success': True, 'message': 'Action completed successfully' } return { 'items': [{ 'label': 'Select structure', 'type': 'enumerator', 'value': data_value, 'name': 'structure_type', 'data': data }, { 'label': 'Padding count', 'type': 'number', 'name': 'padding_count', 'value': 4 }, { 'label': 'Number of tasks', 'type': 'number', 'name': 'number_of_tasks', 'value': 2 }] }