def pickLocation(copyFiles=False): '''Return a location based on *copyFiles*.''' location = None session = connect_session.get_shared_session() locations = session.query('select id, name from Location').all() sorted_locations = sorted(locations, key=lambda _location: _location.priority) visible_locations = filter( lambda _location: _location['name'] not in ('ftrack.origin', ), sorted_locations) for candidateLocation in visible_locations: if candidateLocation.accessor is not symbol.NOT_SET: # Can't copy files to an unmanaged location. if (copyFiles and isinstance( candidateLocation, ftrack_api.entity.location.UnmanagedLocationMixin)): continue location = candidateLocation break return location
def action_launch(event): if "values" not in event["data"]: return session = get_shared_session() status = session.query("Status where name is \"Internal Review\"").one() for key, value in event["data"]["values"].iteritems(): if value: session.get("AssetVersion", key)["status"] = status session.commit()
def modify_launch(event): """Return each entities in the selection in data dictionaries.""" data = event["data"] task = get_shared_session().get( "Task", event["data"]["context"]["selection"][0]["entityId"]) templates = lucidity.discover_templates() template_name = templates[0].get_template_name(task["parent"]) for template in templates: if template.name == template_name: # Return first valid path. This is up to the templates # definition to order what comes first. return data["command"].extend( ["--path", template.format(task["parent"])])
def __init__(self, componentId='', filePath='', componentName='', assetVersionId='', options={}, taskId=''): '''Instantiate asset object.''' super(FTAssetObject, self).__init__() self.componentId = componentId self.filePath = filePath self.componentName = componentName self.shared_session = connect_session.get_shared_session() self.options = options self.setTotalSteps = True self.taskId = taskId if assetVersionId != '': assetVersion = self.shared_session.query( 'select id, asset, asset.name,' ' asset.id, asset.type.short ' ' from AssetVersion where id is "{0}"'.format( assetVersionId)).one() self.assetVersionId = assetVersionId assetVersionStr = str(assetVersion['version']) self.assetVersion = assetVersionStr self.assetName = assetVersion['asset']['name'] self.assetType = assetVersion['asset']['type']['short'] self.assetId = assetVersion['asset']['id'] if self.componentId != '': component = self.shared_session.query( 'select name, version.asset.type.short, version.asset.name, ' 'version.asset.type.name, version.asset.versions.version, ' 'version.id, version.version, version.asset.versions, ' 'version.date, version.comment, version.asset.name, version, ' 'version_id, version.user.first_name, version.user.last_name ' ' from Component where id is {0}'.format( self.componentId)).one() self.metadata = [] for k, v in component['metadata'].items(): self.metadata.append((k, v)) try: self.zversion = assetVersionStr.zfill(3) except: self.zversion = '000'
def application_launch(event): """Return each entities in the selection in data dictionaries.""" session = get_shared_session() entity = session.get("Task", event["data"]["context"]["selection"][0]["entityId"]) entities = [] for link in entity["link"]: entities.append(session.get(link["type"], link["id"])) event = inject_paths(event, entities) for path in event["data"]["directories"]: os.makedirs(path) for src, dst in event["data"]["files"]: print "Copying \"{0}\" to \"{1}\"".format(src, dst) if not os.path.exists(os.path.dirname(dst)): os.makedirs(os.path.dirname(dst)) shutil.copy(src, dst)
def process_review(self, src_asset_version, preset, tempdir): session = get_shared_session() src_component = session.query( "Component where version.id is \"{0}\" and " "name is \"ftrackreview-mp4\"".format( src_asset_version["id"])).first() # Get ftrack.server location server_location = session.query( "Location where name is \"ftrack.server\"").one() movie_path = self.download_component(src_component, tempdir, server_location) [review_path, thumbnail_path] = self.process_preset(movie_path, preset) self.create_review_components(review_path, src_asset_version, server_location, src_component, thumbnail_path=thumbnail_path)
def process_review(self, src_asset_version, preset, tempdir): session = get_shared_session() src_component = session.query( "Component where version.id is \"{0}\" and " "name is \"ftrackreview-mp4\"".format(src_asset_version["id"]) ).first() # Get ftrack.server location server_location = session.query( "Location where name is \"ftrack.server\"" ).one() movie_path = self.download_component( src_component, tempdir, server_location ) [review_path, thumbnail_path] = self.process_preset(movie_path, preset) self.create_review_components( review_path, src_asset_version, server_location, src_component, thumbnail_path=thumbnail_path )
def modify_launch(event): """Return each entities in the selection in data dictionaries.""" session = get_shared_session() templates = lucidity.discover_templates() file_paths = [] paths_searched = [] for item in event["data"].get("selection", []): entity = session.get(item["entityType"].title(), item["entityId"]) template_name = templates[0].get_template_name(entity["parent"]) for template in templates: if template.name == template_name: path = template.format(entity["parent"]) for root, subFolder, files in os.walk(path): path = os.path.abspath(root) if path in paths_searched: continue else: paths_searched.append(path) for f in files: if not f.endswith(".exr"): continue file_paths.append( os.path.abspath(os.path.join(root, f))) collections = clique.assemble(list(set(file_paths)))[0] for collection in collections: event["data"]["items"].append({ "label": os.path.basename(collection.format()), "value": list(collection)[0] }) return event
def callback(event): """Status change updates.""" session = get_shared_session() for entity_data in event["data"].get("entities", []): if entity_data["action"] != "update": continue if "keys" not in entity_data: continue if "statusid" not in entity_data["keys"]: continue new_status = session.get( "Status", entity_data["changes"]["statusid"]["new"] ) # AssetVersion changes if entity_data["entityType"] == "assetversion": entity = session.get("AssetVersion", entity_data["entityId"]) if new_status["name"] == "Pending Changes": entity["task"]["status"] = new_status if new_status["name"] == "Internal Approval": entity["task"]["status"] = new_status if new_status["name"] == "External Review": entity["task"]["status"] = new_status if new_status["name"] == "External Approval": entity["task"]["status"] = new_status # Task changes if entity_data["entityType"] == "task": if new_status["name"] == "Internal Review": items = [] # Description items.append( { "value": "## Please select which version(s) you want " "to send for \"Internal Review\".", "type": "label" } ) items.append( { "value": "## The current selection are version(s) that" " are in \"In Progress\".", "type": "label" } ) assetversions = session.query( "select asset.name, version, id from AssetVersion where " "task.id is \"{0}\" and status.name is " "\"In Progress\"".format(entity_data["entityId"]) ) for assetversion in assetversions: items.append( { "value": "{0} - v{1:02d}".format( assetversion["asset"]["name"], assetversion["version"] ), "type": "label" } ) items.append( { "label": "", "name": assetversion["id"], "value": False, "type": "boolean" } ) assetversions = session.query( "select asset.name, version, id from AssetVersion where " "task.id is \"{0}\" and status.name is_not " "\"In Progress\"".format(entity_data["entityId"]) ) for assetversion in assetversions: items.append( { "value": "{0} - v{1:02d}".format( assetversion["asset"]["name"], assetversion["version"] ), "type": "label" } ) items.append( { "label": "", "name": assetversion["id"], "value": False, "type": "boolean" } ) event = ftrack_api.event.base.Event( topic="ftrack.action.trigger-user-interface", data={ "type": "form", "items": items, "title": "Internal Review" }, target=( "applicationId=ftrack.client.web and " "user.id={0}".format( event["source"]["user"]["id"] ) ) ) session.event_hub.publish(event) session.commit()
def session(self): '''Return ftrack session.''' return get_shared_session()
def create_review_components(self, movie_path, src_asset_version, server_location, src_component, thumbnail_path=""): session = get_shared_session() # Create Asset asset_data = { "name": src_asset_version["asset"]["name"] + "_review", "type": src_asset_version["asset"]["type"], "parent": src_asset_version["asset"]["parent"], } asset_entity = session.query( "Asset where name is \"{0}\" and type.id is \"{1}\" and parent.id " "is \"{2}\"".format(asset_data["name"], asset_data["type"]["id"], asset_data["parent"]["id"])).first() if not asset_entity: asset_entity = session.create("Asset", asset_data) # Create AssetVersion assetversion_data = { "version": src_asset_version["version"], "asset": asset_entity, "task": src_asset_version["task"] } dst_asset_version = session.query( "AssetVersion where version is \"{0}\" and asset.id is \"{1}\" " "and task.id is \"{2}\"".format( assetversion_data["version"], assetversion_data["asset"]["id"], assetversion_data["task"]["id"])).first() if not dst_asset_version: dst_asset_version = session.create("AssetVersion", assetversion_data) session.commit() # Recreate movie component component_data = { "name": "ftrackreview-mp4", "version": dst_asset_version } movie_component = session.query( "Component where name is \"{0}\" and version.id is \"{1}\"".format( component_data["name"], component_data["version"]["id"], )).first() if movie_component: session.delete(movie_component) movie_component = dst_asset_version.create_component( movie_path, data=component_data, location=server_location) # Add metadata movie_component["metadata"] = dict(src_component["metadata"]) session.commit() # Recreate thumbnail component if the file exists if not os.path.exists(thumbnail_path): return component_data = {"name": "thumbnail", "version": dst_asset_version} thumbnail_component = session.query( "Component where name is \"{0}\" and version.id is \"{1}\"".format( component_data["name"], component_data["version"]["id"], )).first() if thumbnail_component: session.delete(thumbnail_component) thumbnail_component = dst_asset_version.create_component( thumbnail_path, data=component_data, location=server_location) dst_asset_version["thumbnail_id"] = thumbnail_component["id"] session.commit()
def publishAssetFiles(publishedComponents, assetVersion, pubObj, moveFiles=False, copyFiles=True, progressCallback=None, startProgress=0, endProgress=100): '''Publish asset files.''' session = connect_session.get_shared_session() if progressCallback: progressCallback(startProgress) asset_version = session.get('AssetVersion', assetVersion.getId()) for componentNumber, ftComponent in enumerate(publishedComponents): path = HelpFunctions.safeString(ftComponent.path) if ftComponent.componentname != 'thumbnail': location = Connector.pickLocation(copyFiles=copyFiles) try: component = asset_version.create_component( path=path, data={'name': ftComponent.componentname}, location=location) session.commit() except Exception as error: errorMessage = ( 'A problem occurred while writing your files. It is ' 'possible the disk settings in ftrack are incorrect. If ' 'you are an administrator in ftrack you can check the ' 'settings in the Settings->Disks section from the web ' 'interface. If you are not an administrator then please ' 'ask your administrator to check the settings for you ' 'or drop us a line at [email protected].') QtWidgets.QMessageBox.critical( None, 'ftrack: Failed to publish.', errorMessage) print traceback.format_exc() print error return else: thumb = assetVersion.createThumbnail(path) try: currentTask = assetVersion.getTask() currentTask.setThumbnail(thumb) except Exception: print 'no task' try: shot = assetVersion.getAsset().getParent() shot.setThumbnail(thumb) except Exception: print 'no shot for some reason' if len(ftComponent.metadata) > 0: for k, v in ftComponent.metadata: component['metadata'][k] = v if progressCallback: progressStep = (endProgress - startProgress) / len(publishedComponents) progressCallback(startProgress + progressStep * (componentNumber + 1)) asset_version['is_published'] = True session.commit() Connector.postPublish(pubObj, publishedComponents) if progressCallback: progressCallback(endProgress)
def callback(event): session = get_shared_session() for entity_data in event["data"].get("entities", []): # Filter to tasks if entity_data.get('entityType') != 'task': continue # Filter to updates if entity_data['action'] != 'update': continue # Filter to status changes if 'statusid' not in entity_data.get('keys'): continue # Filter to "Pending Changes" new_status = session.get("Status", entity_data["changes"]["statusid"]["new"]) if new_status["name"].lower() != "pending changes": continue task = session.get("Task", entity_data["entityId"]) user = session.get("User", event["source"]["user"]["id"]) job = session.create( "Job", { "user": user, "status": "running", "data": json.dumps({"description": "Version Up Scene."}) }) session.commit() try: versions = session.query( "select version,components,asset.name,asset.parent," "asset.type.id,asset.parent.id,asset.type.id from AssetVersion" " where task.id is \"{0}\" and asset.type.short is " "\"scene\"".format(task["id"])) latest_version = {"version": 0} for version in versions: if latest_version["version"] < version["version"]: latest_version = version # Skip if no scene version was found if latest_version["version"] == 0: job["status"] = "done" continue # Skip if an empty scene version exists if len(latest_version["components"]) == 0: job["status"] = "done" continue # Create Asset asset_data = { "name": latest_version["asset"]["name"], "type": latest_version["asset"]["type"], "parent": latest_version["asset"]["parent"], } asset_entity = session.query( "Asset where name is \"{0}\" and type.id is \"{1}\" and " "parent.id is \"{2}\"".format( asset_data["name"], asset_data["type"]["id"], asset_data["parent"]["id"])).first() if not asset_entity: asset_entity = session.create("Asset", asset_data) # Create AssetVersion assetversion_data = { "version": latest_version["version"] + 1, "asset": asset_entity, "task": task } dst_asset_version = session.query( "AssetVersion where version is \"{0}\" and asset.id is " "\"{1}\" and task.id is \"{2}\"".format( assetversion_data["version"], assetversion_data["asset"]["id"], assetversion_data["task"]["id"])).first() if not dst_asset_version: dst_asset_version = session.create("AssetVersion", assetversion_data) session.commit() except: job["status"] = "failed" else: job["status"] = "done" session.commit()
def __init__(self, parent=None): '''Initiate a publish view.''' super(Publisher, self).__init__(parent) self.session = get_shared_session() self.logger = logging.getLogger(__name__ + '.' + self.__class__.__name__) self._entity = None layout = QtWidgets.QVBoxLayout() self.setLayout(layout) self.browser = _data_drop_zone.DataDropZone() layout.addWidget(self.browser) self.browser.dataSelected.connect(self._onDataSelected) # Create a components list widget. self.componentsList = _components_list.ComponentsList() self.componentsList.setObjectName('publisher-componentlist') self.componentsList.itemsChanged.connect( self._onComponentListItemsChanged) layout.addWidget(self.componentsList, stretch=1) self.componentsList.hide() # Create form layout to keep track of publish form items. formLayout = QtWidgets.QFormLayout() layout.addLayout(formLayout, stretch=0) # Add entity selector. self.entitySelector = EntitySelector() formLayout.addRow('Linked to', self.entitySelector) # Add asset options. self.assetOptions = _asset_options.AssetOptions() self.entitySelector.entityChanged.connect(self.assetOptions.setEntity) self.assetCreated.connect(self.assetOptions.setAsset) formLayout.addRow('Asset', self.assetOptions.radioButtonFrame) formLayout.addRow('Existing asset', self.assetOptions.existingAssetSelector) formLayout.addRow('Type', self.assetOptions.assetTypeSelector) formLayout.addRow('Name', self.assetOptions.assetNameLineEdit) self.assetOptions.initializeFieldLabels(formLayout) # Add preview selector. self.previewSelector = _item_selector.ItemSelector( labelField='componentName', defaultLabel='Unnamed component', emptyLabel='Select component to use') formLayout.addRow('Web playable', self.previewSelector) self.thumbnailDropZone = _thumbnail_drop_zone.ThumbnailDropZone() formLayout.addRow('Thumbnail', self.thumbnailDropZone) # Add version description component. self.versionDescription = QtWidgets.QTextEdit() formLayout.addRow('Description', self.versionDescription) publishButton = QtWidgets.QPushButton(text='Publish') publishButton.setObjectName('primary') publishButton.clicked.connect(self.publish) layout.addWidget(publishButton, alignment=QtCore.Qt.AlignCenter, stretch=0)
def __init__(self, session=None): '''Instantiate base connector.''' super(Connector, self).__init__() self.session = session or connect_session.get_shared_session()
def create_review_components(self, movie_path, src_asset_version, server_location, src_component, thumbnail_path=""): session = get_shared_session() # Create Asset asset_data = { "name": src_asset_version["asset"]["name"] + "_review", "type": src_asset_version["asset"]["type"], "parent": src_asset_version["asset"]["parent"], } asset_entity = session.query( "Asset where name is \"{0}\" and type.id is \"{1}\" and parent.id " "is \"{2}\"".format( asset_data["name"], asset_data["type"]["id"], asset_data["parent"]["id"] ) ).first() if not asset_entity: asset_entity = session.create("Asset", asset_data) # Create AssetVersion assetversion_data = { "version": src_asset_version["version"], "asset": asset_entity, "task": src_asset_version["task"] } dst_asset_version = session.query( "AssetVersion where version is \"{0}\" and asset.id is \"{1}\" " "and task.id is \"{2}\"".format( assetversion_data["version"], assetversion_data["asset"]["id"], assetversion_data["task"]["id"] ) ).first() if not dst_asset_version: dst_asset_version = session.create( "AssetVersion", assetversion_data ) session.commit() # Recreate movie component component_data = { "name": "ftrackreview-mp4", "version": dst_asset_version } movie_component = session.query( "Component where name is \"{0}\" and version.id is \"{1}\"".format( component_data["name"], component_data["version"]["id"], ) ).first() if movie_component: session.delete(movie_component) movie_component = dst_asset_version.create_component( movie_path, data=component_data, location=server_location ) # Add metadata movie_component["metadata"] = dict(src_component["metadata"]) session.commit() # Recreate thumbnail component if the file exists if not os.path.exists(thumbnail_path): return component_data = { "name": "thumbnail", "version": dst_asset_version } thumbnail_component = session.query( "Component where name is \"{0}\" and version.id is \"{1}\"".format( component_data["name"], component_data["version"]["id"], ) ).first() if thumbnail_component: session.delete(thumbnail_component) thumbnail_component = dst_asset_version.create_component( thumbnail_path, data=component_data, location=server_location ) dst_asset_version["thumbnail_id"] = thumbnail_component["id"] session.commit()
def launch(self, event): """Callback method for DJVView action.""" # Launching application if "values" in event["data"]: applicationIdentifier = event["data"]["applicationIdentifier"] application = self.applicationStore.getApplication( applicationIdentifier ) context = event["data"].copy() context["source"] = event["source"] command = self.launcher._getApplicationLaunchCommand( application, context ) success = True message = '{0} application started.'.format(application['label']) command.append(event["data"]["values"]["path"]) try: options = dict( env={}, close_fds=True ) # Ensure subprocess is detached so closing connect will not # also close launched applications. if sys.platform == 'win32': options['creationflags'] = subprocess.CREATE_NEW_CONSOLE else: options['preexec_fn'] = os.setsid self.logger.debug( 'Launching {0} with options {1}'.format(command, options) ) process = subprocess.Popen(command, **options) except (OSError, TypeError): self.logger.exception( '{0} application could not be started with command "{1}".' .format(applicationIdentifier, command) ) success = False message = '{0} application could not be started.'.format( application['label'] ) else: self.logger.debug( '{0} application started. (pid={1})'.format( applicationIdentifier, process.pid ) ) return { 'success': success, 'message': message } data = event["data"] data["items"] = [] # Starting a job to show user the progress of scanning for files. job = ftrack.createJob("DJV: Scanning for files.", "queued", ftrack.User(id=event["source"]["user"]["id"])) job.setStatus("running") try: ftrack.EVENT_HUB.publish( ftrack.Event( topic='djvview.launch', data=data ), synchronous=True ) session = get_shared_session() session.event_hub.publish( ftrack_api.event.base.Event( topic='djvview.launch', data=data ), synchronous=True ) except: job.setStatus("failed") else: job.setStatus("done") return { "items": [ { "label": "Items to view", "type": "enumerator", "name": "path", "data": sorted( data["items"], key=itemgetter("label"), reverse=True ) } ] }
# :coding: utf-8 # :copyright: Copyright (c) 2018 ftrack import hiero.core import lucidity import lucidity.error import ftrack_api import ftrack_connect_nuke_studio.exception from ftrack_connect.session import get_shared_session session = get_shared_session() def available_templates(project): '''Return available templates for *project*. If a template has been saved on the project using :meth:`save_project_template` that template will contain a `default` key set to True. ''' templates = [] responses = session.event_hub.publish( ftrack_api.event.base.Event( topic='ftrack.connect.nuke-studio.get-context-templates' ),