mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Action-handler returns full FT obj and added few restored actions
This commit is contained in:
parent
ab6f07e28c
commit
490bf1c3ff
16 changed files with 1169 additions and 128 deletions
131
pype/ftrack/actions/action_asset_delete.py
Normal file
131
pype/ftrack/actions/action_asset_delete.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import getpass
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
|
||||
class AssetDelete(BaseAction):
|
||||
'''Custom action.'''
|
||||
|
||||
#: Action identifier.
|
||||
identifier = 'asset.delete'
|
||||
#: Action label.
|
||||
label = 'Asset Delete'
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
if (len(entities) != 1 or entities[0].entity_type
|
||||
not in ['Shot', 'Asset Build']):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
|
||||
if not event['data'].get('values', {}):
|
||||
entity = entities[0]
|
||||
|
||||
items = []
|
||||
for asset in entity['assets']:
|
||||
# get asset name for label
|
||||
label = 'None'
|
||||
if asset['name']:
|
||||
label = asset['name']
|
||||
|
||||
items.append({
|
||||
'label':label,
|
||||
'name':label,
|
||||
'value':False,
|
||||
'type':'boolean'
|
||||
})
|
||||
|
||||
if len(items) < 1:
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'There are no assets to delete'
|
||||
}
|
||||
|
||||
return items
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
entity = entities[0]
|
||||
# if values were set remove those items
|
||||
if 'values' in event['data']:
|
||||
values = event['data']['values']
|
||||
# get list of assets to delete from form
|
||||
to_delete = []
|
||||
for key in values:
|
||||
if values[key]:
|
||||
to_delete.append(key)
|
||||
# delete them by name
|
||||
for asset in entity['assets']:
|
||||
if asset['name'] in to_delete:
|
||||
session.delete(asset)
|
||||
try:
|
||||
session.commit()
|
||||
except:
|
||||
session.rollback()
|
||||
raise
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'Asset deleted.'
|
||||
}
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = AssetDelete(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
|
|
@ -19,22 +19,10 @@ class ClientReviewSort(BaseAction):
|
|||
label = 'Sort Review'
|
||||
|
||||
|
||||
def validateSelection(self, entities):
|
||||
'''Return true if the selection is valid. '''
|
||||
|
||||
if len(entities) == 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return action config if triggered on a single selection.'''
|
||||
''' Validation '''
|
||||
|
||||
selection = event['data']['selection']
|
||||
# this action will only handle a single version.
|
||||
if (not self.validateSelection(entities) or
|
||||
selection[0]['entityType'] != 'reviewsession'):
|
||||
if (len(entities) == 0 or entities[0].entity_type != 'ReviewSession'):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
|
@ -42,8 +30,7 @@ class ClientReviewSort(BaseAction):
|
|||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
entity_type, entity_id = entities[0]
|
||||
entity = session.get(entity_type, entity_id)
|
||||
entity = entities[0]
|
||||
|
||||
# Get all objects from Review Session and all 'sort order' possibilities
|
||||
obj_list = []
|
||||
|
|
@ -53,8 +40,8 @@ class ClientReviewSort(BaseAction):
|
|||
sort_order_list.append(obj['sort_order'])
|
||||
|
||||
# Sort criteria
|
||||
obj_list = sorted(obj_list, key=lambda k: k['asset_version']['task']['name'])
|
||||
obj_list = sorted(obj_list, key=lambda k: k['version'])
|
||||
obj_list = sorted(obj_list, key=lambda k: k['asset_version']['task']['name'])
|
||||
obj_list = sorted(obj_list, key=lambda k: k['name'])
|
||||
|
||||
# Set 'sort order' to sorted list, so they are sorted in Ftrack also
|
||||
|
|
|
|||
119
pype/ftrack/actions/action_component_open.py
Normal file
119
pype/ftrack/actions/action_component_open.py
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# :coding: utf-8
|
||||
# :copyright: Copyright (c) 2015 Milan Kolar
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import getpass
|
||||
import subprocess
|
||||
import os
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
|
||||
class ComponentOpen(BaseAction):
|
||||
'''Custom action.'''
|
||||
|
||||
# Action identifier
|
||||
identifier = 'component.open'
|
||||
# Action label
|
||||
label = 'Open File'
|
||||
# Action icon
|
||||
icon = 'https://cdn4.iconfinder.com/data/icons/rcons-application/32/application_go_run-256.png',
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
if len(entities) != 1 or entities[0].entity_type != 'Component':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
entity = entities[0]
|
||||
|
||||
# Return error if component is on ftrack server
|
||||
if entity['component_locations'][0]['location']['name'] == 'ftrack.server':
|
||||
return {
|
||||
'success': False,
|
||||
'message': "This component is stored on ftrack server!"
|
||||
}
|
||||
|
||||
# Get component filepath
|
||||
fpath = entity['component_locations'][0]['resource_identifier']
|
||||
|
||||
if os.path.isfile(fpath):
|
||||
if sys.platform == 'win': # windows
|
||||
subprocess.Popen('explorer "%s"' % fpath)
|
||||
elif sys.platform == 'darwin': # macOS
|
||||
subprocess.Popen(['open', fpath])
|
||||
else: # linux
|
||||
try:
|
||||
subprocess.Popen(['xdg-open', fpath])
|
||||
except OSError:
|
||||
raise OSError('unsupported xdg-open call??')
|
||||
else:
|
||||
return {
|
||||
'success': False,
|
||||
'message': "Didn't found file: " + fpath
|
||||
}
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'Component Opened'
|
||||
}
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = ComponentOpen(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
|
|
@ -21,27 +21,16 @@ class AvalonIdAttribute(BaseAction):
|
|||
#: Action description.
|
||||
description = 'Creates Avalon/Mongo ID for double check'
|
||||
|
||||
def validate_selection(self, session, entities):
|
||||
'''Return if *entities* is a valid selection.'''
|
||||
# if (len(entities) != 1):
|
||||
# # If entities contains more than one item return early since
|
||||
# # metadata cannot be edited for several entites at the same time.
|
||||
# return False
|
||||
# entity_type, entity_id = entities[0]
|
||||
# if (
|
||||
# entity_type not in session.types
|
||||
# ):
|
||||
# # Return False if the target entity does not have a metadata
|
||||
# # attribute.
|
||||
# return False
|
||||
pass
|
||||
return True
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return True if action is valid.'''
|
||||
''' Validation '''
|
||||
|
||||
self.logger.info('Got selection: {0}'.format(entities))
|
||||
return self.validate_selection(session, entities)
|
||||
# userId = event['source']['user']['id']
|
||||
# user = session.query('User where id is ' + userId).one()
|
||||
# if user['user_security_roles'][0]['security_role']['name'] != 'Administrator':
|
||||
# return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def importToAvalon(self, session, entity):
|
||||
|
|
|
|||
96
pype/ftrack/actions/action_delete_unpublished.py
Normal file
96
pype/ftrack/actions/action_delete_unpublished.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import getpass
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
|
||||
class VersionsCleanup(BaseAction):
|
||||
'''Custom action.'''
|
||||
|
||||
# Action identifier
|
||||
identifier = 'versions.cleanup'
|
||||
# Action label
|
||||
label = 'Versions cleanup'
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
# Only 1 AssetVersion is allowed
|
||||
if len(entities) != 1 or entities[0].entity_type != 'AssetVersion':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
entity = entities[0]
|
||||
|
||||
# Go through all versions in asset
|
||||
for version in entity['asset']['versions']:
|
||||
if not version['is_published']:
|
||||
session.delete(version)
|
||||
try:
|
||||
session.commit()
|
||||
except:
|
||||
session.rollback()
|
||||
raise
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'removed hidden versions'
|
||||
}
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = VersionsCleanup(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
186
pype/ftrack/actions/action_folders_create_lucidity.py
Normal file
186
pype/ftrack/actions/action_folders_create_lucidity.py
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
import logging
|
||||
import os
|
||||
import getpass
|
||||
import argparse
|
||||
import errno
|
||||
import sys
|
||||
import threading
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
PLUGIN_DIRECTORY = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
if PLUGIN_DIRECTORY not in sys.path:
|
||||
sys.path.append(PLUGIN_DIRECTORY)
|
||||
|
||||
import ft_utils
|
||||
|
||||
|
||||
def async(fn):
|
||||
'''Run *fn* asynchronously.'''
|
||||
def wrapper(*args, **kwargs):
|
||||
thread = threading.Thread(target=fn, args=args, kwargs=kwargs)
|
||||
thread.start()
|
||||
return wrapper
|
||||
|
||||
|
||||
class CreateFolders(BaseAction):
|
||||
|
||||
#: Action identifier.
|
||||
identifier = 'create.folders'
|
||||
#: Action label.
|
||||
label = 'Create Folders'
|
||||
#: Action Icon.
|
||||
icon = 'https://cdn1.iconfinder.com/data/icons/rcons-folder-action/32/folder_add-512.png'
|
||||
|
||||
raise ValueError('Not working version of action')
|
||||
@async
|
||||
def createFoldersFromEntity(self, entity):
|
||||
'''Generate folder structure from *entity*.
|
||||
|
||||
Entity is assumed to be either a project, episode, sequence or shot.
|
||||
|
||||
'''
|
||||
|
||||
root = entity.getProject().getRoot()
|
||||
|
||||
self.logger.info(root)
|
||||
|
||||
if entity.getObjectType() in (
|
||||
'Episode', 'Sequence', 'Folder', 'Shot'):
|
||||
objects = entity.getChildren(objectType='Shot', depth=None)
|
||||
objects.append(entity)
|
||||
else:
|
||||
objects = entity.getChildren(depth=None)
|
||||
|
||||
for obj in objects:
|
||||
|
||||
tasks = obj.getTasks()
|
||||
paths_collected = set([])
|
||||
if obj.getObjectType() in (
|
||||
'Episode', 'Sequence', 'Shot', 'Folder'):
|
||||
task_mask = 'shot.task'
|
||||
else:
|
||||
task_mask = 'asset.task'
|
||||
|
||||
self.logger.info(task_mask)
|
||||
|
||||
for task in tasks:
|
||||
self.logger.info(task)
|
||||
paths = ft_utils.getAllPathsYaml(task)
|
||||
self.logger.info(paths)
|
||||
for path in paths:
|
||||
if task_mask in path[1].name:
|
||||
temppath = os.path.join(
|
||||
root, path[0].lower().replace(" ", '_').replace('\'', ''))
|
||||
paths_collected.add(temppath)
|
||||
|
||||
for path in paths_collected:
|
||||
self.logger.info(path)
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as error:
|
||||
if error.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
|
||||
if len(entities) == 0 or entities[0].entity_type not in [
|
||||
'Episode', 'Sequence', 'Shot', 'Folder', 'Asset Build']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
userId = event['source']['user']['id']
|
||||
user = session.query('User where id is ' + userId).one()
|
||||
|
||||
job = session.create('Job', {
|
||||
'user': user,
|
||||
'status': 'running',
|
||||
'data': json.dumps({
|
||||
'description': 'Creating Folders'
|
||||
})
|
||||
})
|
||||
|
||||
'''Callback method for custom action.'''
|
||||
|
||||
try:
|
||||
session.event_hub.publishReply(
|
||||
event,
|
||||
data={
|
||||
'success': True,
|
||||
'message': 'Folder Creation Job Started!'
|
||||
}
|
||||
)
|
||||
|
||||
for entity in entities:
|
||||
self.createFoldersFromEntity(entity)
|
||||
|
||||
job.setStatus('done')
|
||||
except:
|
||||
job.setStatus('failed')
|
||||
raise
|
||||
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'Created Folders Successfully!'
|
||||
}
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = CreateFolders(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
|
|
@ -20,20 +20,14 @@ class JobKiller(BaseAction):
|
|||
description = 'Killing all running jobs younger than day'
|
||||
|
||||
|
||||
def validate_selection(self, session, entities):
|
||||
'''Return if *entities* is a valid selection.'''
|
||||
pass
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
return True
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return True if action is valid.'''
|
||||
|
||||
self.logger.info('Got selection: {0}'.format(entities))
|
||||
return self.validate_selection(session, entities)
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
""" JOB SETTING """
|
||||
""" GET JOB """
|
||||
|
||||
yesterday = datetime.date.today() - datetime.timedelta(days=1)
|
||||
|
||||
|
|
@ -48,7 +42,10 @@ class JobKiller(BaseAction):
|
|||
print('Changing Job ({}) status: {} -> failed'.format(job['id'], job['status']))
|
||||
job['status'] = 'failed'
|
||||
|
||||
session.commit()
|
||||
try:
|
||||
session.commit()
|
||||
except:
|
||||
session.rollback()
|
||||
|
||||
print('All running jobs were killed Successfully!')
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -18,21 +18,16 @@ class openFolder(BaseAction):
|
|||
label = 'Open Folders'
|
||||
#: Action Icon.
|
||||
icon = "https://cdn3.iconfinder.com/data/icons/stroke/53/Open-Folder-256.png"
|
||||
raise ValueError('Not working version of action')
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
def validateSelection(self, selection):
|
||||
'''Return true if the selection is valid. '''
|
||||
|
||||
if len(selection) == 0 or selection[0]['entityType'] in ['assetversion', 'Component']:
|
||||
if len(entities) == 0 or entities[0].entity_type in ['assetversion', 'Component']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
selection = event['data']['selection']
|
||||
|
||||
# validate selection, and only return action if it is valid.
|
||||
return self.validateSelection(selection)
|
||||
|
||||
def get_paths(self, entity):
|
||||
'''Prepare all the paths for the entity.
|
||||
|
|
@ -72,8 +67,6 @@ class openFolder(BaseAction):
|
|||
hits = set([])
|
||||
|
||||
for entity in entities:
|
||||
entity_type, entity_id = entity
|
||||
entity = session.get(entity_type, entity_id)
|
||||
|
||||
# Get paths base on the entity.
|
||||
# This function needs to be chagned to fit your path logic
|
||||
|
|
|
|||
125
pype/ftrack/actions/action_set_version.py
Normal file
125
pype/ftrack/actions/action_set_version.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import getpass
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
|
||||
class SetVersion(BaseAction):
|
||||
'''Custom action.'''
|
||||
|
||||
#: Action identifier.
|
||||
identifier = 'version.set'
|
||||
|
||||
#: Action label.
|
||||
label = 'Version Set'
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
# Only 1 AssetVersion is allowed
|
||||
if len(entities) != 1 or entities[0].entity_type != 'AssetVersion':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
|
||||
if not event['data'].get('values', {}):
|
||||
entity = entities[0]
|
||||
|
||||
# Get actual version of asset
|
||||
act_ver = entity['version']
|
||||
# Set form
|
||||
items = [{
|
||||
'label': 'Version number',
|
||||
'type': 'number',
|
||||
'name': 'version_number',
|
||||
'value': act_ver
|
||||
}]
|
||||
|
||||
return items
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
entity = entities[0]
|
||||
|
||||
# Do something with the values or return a new form.
|
||||
values = event['data'].get('values', {})
|
||||
# Default is action True
|
||||
scs = True
|
||||
msg = 'Version was changed to v{0}'.format(values['version_number'])
|
||||
|
||||
if not values['version_number']:
|
||||
scs = False,
|
||||
msg = "You didn't enter any version."
|
||||
elif int(values['version_number']) <= 0:
|
||||
scs = False
|
||||
msg = 'Negative or zero version is not valid.'
|
||||
else:
|
||||
entity['version'] = values['version_number']
|
||||
|
||||
try:
|
||||
session.commit()
|
||||
except:
|
||||
session.rollback()
|
||||
raise
|
||||
|
||||
return {
|
||||
'success': scs,
|
||||
'message': msg
|
||||
}
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register action. Called when used as an event plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = SetVersion(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
|
|
@ -23,27 +23,11 @@ class SyncToAvalon(BaseAction):
|
|||
#: Action icon.
|
||||
icon = 'https://cdn1.iconfinder.com/data/icons/hawcons/32/699650-icon-92-inbox-download-512.png'
|
||||
|
||||
def validate_selection(self, session, entities):
|
||||
'''Return if *entities* is a valid selection.'''
|
||||
# if (len(entities) != 1):
|
||||
# # If entities contains more than one item return early since
|
||||
# # metadata cannot be edited for several entites at the same time.
|
||||
# return False
|
||||
# entity_type, entity_id = entities[0]
|
||||
# if (
|
||||
# entity_type not in session.types
|
||||
# ):
|
||||
# # Return False if the target entity does not have a metadata
|
||||
# # attribute.
|
||||
# return False
|
||||
pass
|
||||
return True
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return True if action is valid.'''
|
||||
''' Validation '''
|
||||
|
||||
self.logger.info('Got selection: {0}'.format(entities))
|
||||
return self.validate_selection(session, entities)
|
||||
return True
|
||||
|
||||
|
||||
def importToAvalon(self, session, entity):
|
||||
|
|
@ -51,6 +35,7 @@ class SyncToAvalon(BaseAction):
|
|||
custAttrName = 'avalon_mongo_id'
|
||||
# TODO read from file, which data are in scope???
|
||||
# get needed info of entity and all parents
|
||||
|
||||
for e in entity['link']:
|
||||
tmp = session.get(e['type'], e['id'])
|
||||
if e['name'].find(" ") == -1:
|
||||
|
|
@ -198,17 +183,15 @@ class SyncToAvalon(BaseAction):
|
|||
|
||||
# get all entities separately/unique
|
||||
for entity in entities:
|
||||
entity_type, entity_id = entity
|
||||
act_ent = session.get(entity_type, entity_id)
|
||||
getShotAsset(act_ent)
|
||||
getShotAsset(entity)
|
||||
|
||||
for e in importable:
|
||||
self.importToAvalon(session, e)
|
||||
|
||||
job['status'] = 'done'
|
||||
session.commit()
|
||||
|
||||
print('Synchronization to Avalon was successfull!')
|
||||
|
||||
except Exception as e:
|
||||
job['status'] = 'failed'
|
||||
print('During synchronization to Avalon went something wrong!')
|
||||
|
|
|
|||
|
|
@ -18,32 +18,22 @@ class TestAction(BaseAction):
|
|||
|
||||
#: Action identifier.
|
||||
identifier = 'test.action'
|
||||
|
||||
#: Action label.
|
||||
label = 'Test action'
|
||||
|
||||
#: Action description.
|
||||
description = 'Test action'
|
||||
|
||||
def validate_selection(self, session, entities):
|
||||
'''Return if *entities* is a valid selection.'''
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
|
||||
return True
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return True if action is valid.'''
|
||||
|
||||
self.logger.info('Got selection: {0}'.format(entities))
|
||||
return self.validate_selection(session, entities)
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
||||
for entity in entities:
|
||||
entity_type, entity_id = entity
|
||||
entity = session.get(entity_type, entity_id)
|
||||
|
||||
import ft_utils
|
||||
print(ft_utils.getNewContext(entity))
|
||||
print("TEST")
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -20,23 +20,14 @@ class ThumbToChildren(BaseAction):
|
|||
# Action icon
|
||||
icon = "https://cdn3.iconfinder.com/data/icons/transfers/100/239322-download_transfer-128.png"
|
||||
|
||||
def validateSelection(self, selection):
|
||||
'''Return true if the selection is valid.
|
||||
|
||||
Legacy plugins can only be started from a single Task. '''
|
||||
|
||||
if len(selection) > 0:
|
||||
if selection[0]['entityType'] in ['assetversion', 'task']:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return action config if triggered on asset versions.'''
|
||||
selection = event['data']['selection']
|
||||
''' Validation '''
|
||||
|
||||
# validate selection, and only return action if it is valid.
|
||||
return self.validateSelection(selection)
|
||||
if (len(entities) <= 0 or entities[0].entity_type in ['Project']):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
|
@ -55,9 +46,6 @@ class ThumbToChildren(BaseAction):
|
|||
|
||||
try:
|
||||
for entity in entities:
|
||||
entity_type, entity_id = entity
|
||||
entity = session.get(entity_type, entity_id)
|
||||
|
||||
thumbid = entity['thumbnail_id']
|
||||
if thumbid:
|
||||
for child in entity['children']:
|
||||
|
|
|
|||
|
|
@ -20,23 +20,13 @@ class ThumbToParent(BaseAction):
|
|||
icon = "https://cdn3.iconfinder.com/data/icons/transfers/100/239419-upload_transfer-512.png"
|
||||
|
||||
|
||||
def validateSelection(self, selection):
|
||||
'''Return true if the selection is valid.
|
||||
|
||||
Legacy plugins can only be started from a single Task.
|
||||
|
||||
'''
|
||||
if len(selection) > 0:
|
||||
if selection[0]['entityType'] in ['assetversion', 'task']:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return action config if triggered on asset versions.'''
|
||||
selection = event['data']['selection']
|
||||
# validate selection, and only return action if it is valid.
|
||||
return self.validateSelection(selection)
|
||||
|
||||
if len(entities) <= 0 or entities[0].entity_type in ['Project']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
|
@ -55,9 +45,6 @@ class ThumbToParent(BaseAction):
|
|||
|
||||
try:
|
||||
for entity in entities:
|
||||
entity_type, entity_id = entity
|
||||
entity = session.get(entity_type, entity_id)
|
||||
|
||||
if entity.entity_type.lower() == 'assetversion':
|
||||
try:
|
||||
parent = entity['task']
|
||||
|
|
@ -76,6 +63,7 @@ class ThumbToParent(BaseAction):
|
|||
# inform the user that the job is done
|
||||
job['status'] = 'done'
|
||||
session.commit()
|
||||
|
||||
except:
|
||||
# fail the job if something goes wrong
|
||||
job['status'] = 'failed'
|
||||
|
|
|
|||
349
pype/ftrack/actions/batch_create.py
Normal file
349
pype/ftrack/actions/batch_create.py
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
# :coding: utf-8
|
||||
# :copyright: Copyright (c) 2015 ftrack
|
||||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import collections
|
||||
import threading
|
||||
import getpass
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
STRUCTURE_NAMES = ['episode', 'sequence', 'shot']
|
||||
|
||||
|
||||
TASK_TYPE_ENUMERATOR_OPTIONS = [
|
||||
{'label': task_type.getName(), 'value': task_type.getId()}
|
||||
for task_type in ftrack.getTaskTypes()
|
||||
]
|
||||
|
||||
TASK_TYPE_LOOKUP = dict(
|
||||
(task_type.getId(), task_type.getName())
|
||||
for task_type in ftrack.getTaskTypes()
|
||||
)
|
||||
|
||||
|
||||
def async(fn):
|
||||
'''Run *fn* asynchronously.'''
|
||||
def wrapper(*args, **kwargs):
|
||||
thread = threading.Thread(target=fn, args=args, kwargs=kwargs)
|
||||
thread.start()
|
||||
return wrapper
|
||||
|
||||
|
||||
def get_names(base_name, padding, start, end, incremental):
|
||||
'''Return names from expression.'''
|
||||
names = []
|
||||
for part in range(start, end + incremental, incremental):
|
||||
names.append(
|
||||
base_name + str(part).zfill(padding)
|
||||
)
|
||||
return names
|
||||
|
||||
|
||||
def generate_structure(values):
|
||||
'''Return structure from *values*.'''
|
||||
structure = []
|
||||
|
||||
for structure_name in STRUCTURE_NAMES:
|
||||
if (structure_name + '_expression') not in values:
|
||||
continue
|
||||
|
||||
object_expression = values[structure_name + '_expression']
|
||||
object_incremental = values[structure_name + '_incremental']
|
||||
|
||||
padding = object_expression.count('#')
|
||||
_range, incremental = object_incremental.split(':')
|
||||
start, end = _range.split('-')
|
||||
|
||||
start = int(start)
|
||||
end = int(end)
|
||||
incremental = int(incremental)
|
||||
|
||||
base_name = object_expression.replace('#', '')
|
||||
|
||||
logging.info(
|
||||
(
|
||||
'Create from expression {expression} with {base_name}, '
|
||||
'{padding} and {start}-{end}:{incremental}'
|
||||
).format(
|
||||
expression=object_expression,
|
||||
base_name=base_name,
|
||||
padding=padding,
|
||||
start=start,
|
||||
end=end,
|
||||
incremental=incremental
|
||||
)
|
||||
)
|
||||
|
||||
names = get_names(
|
||||
base_name=base_name,
|
||||
padding=padding,
|
||||
start=start,
|
||||
end=end,
|
||||
incremental=incremental
|
||||
)
|
||||
|
||||
structure.append({
|
||||
'object_type': structure_name,
|
||||
'data': names
|
||||
})
|
||||
|
||||
tasks = collections.defaultdict(dict)
|
||||
for name, value in values.iteritems():
|
||||
if name.startswith('task_'):
|
||||
_, index, key = name.split('_')
|
||||
if key == 'bid' and value:
|
||||
value = float(value) * 3600
|
||||
tasks[index][key] = value
|
||||
|
||||
task_data = []
|
||||
structure.append({
|
||||
'object_type': 'task',
|
||||
'data': task_data
|
||||
})
|
||||
for task in tasks.values():
|
||||
task_data.append(task)
|
||||
|
||||
return structure
|
||||
|
||||
|
||||
@async
|
||||
def create(parent, structure):
|
||||
'''Create *structure* under *parent*.'''
|
||||
return create_from_structure(parent, structure)
|
||||
|
||||
|
||||
def create_from_structure(parent, structure):
|
||||
'''Create *structure* under *parent*.'''
|
||||
level = structure[0]
|
||||
children = structure[1:]
|
||||
object_type = level['object_type']
|
||||
|
||||
for data in level['data']:
|
||||
|
||||
if object_type == 'episode':
|
||||
new_object = parent.createEpisode(data)
|
||||
|
||||
if object_type == 'sequence':
|
||||
new_object = parent.createSequence(data)
|
||||
|
||||
if object_type == 'shot':
|
||||
new_object = parent.createShot(data)
|
||||
|
||||
if object_type == 'task':
|
||||
new_object = parent.createTask(
|
||||
TASK_TYPE_LOOKUP[data['typeid']]
|
||||
)
|
||||
new_object.set(data)
|
||||
|
||||
logging.info(
|
||||
'Created {new_object} on parent {parent}'.format(
|
||||
parent=parent, new_object=new_object
|
||||
)
|
||||
)
|
||||
if children:
|
||||
create_from_structure(new_object, children)
|
||||
|
||||
|
||||
def get_form(number_of_tasks, structure_type, prefix, padding_count):
|
||||
'''Return form from *number_of_tasks* and *structure_type*.'''
|
||||
mappings = {
|
||||
'episode': ['episode', 'sequence', 'shot'],
|
||||
'sequence': ['sequence', 'shot'],
|
||||
'shot': ['shot']
|
||||
}
|
||||
|
||||
items = []
|
||||
|
||||
for structure_name in mappings[structure_type]:
|
||||
items.extend(
|
||||
[
|
||||
{
|
||||
'value': '##{0}##'.format(structure_name.capitalize()),
|
||||
'type': 'label'
|
||||
}, {
|
||||
'label': 'Expression',
|
||||
'type': 'text',
|
||||
'value': prefix + '#' * padding_count,
|
||||
'name': '{0}_expression'.format(structure_name)
|
||||
}, {
|
||||
'label': 'Incremental',
|
||||
'type': 'text',
|
||||
'value': '10-20:10',
|
||||
'name': '{0}_incremental'.format(structure_name)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
for index in range(0, number_of_tasks):
|
||||
items.extend(
|
||||
[
|
||||
{
|
||||
'value': '##Template for Task{0}##'.format(index),
|
||||
'type': 'label'
|
||||
},
|
||||
{
|
||||
'label': 'Type',
|
||||
'type': 'enumerator',
|
||||
'name': 'task_{0}_typeid'.format(index),
|
||||
'data': TASK_TYPE_ENUMERATOR_OPTIONS
|
||||
},
|
||||
{
|
||||
'label': 'Bid',
|
||||
'type': 'number',
|
||||
'name': 'task_{0}_bid'.format(index)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
return {'items': items}
|
||||
|
||||
|
||||
class BatchCreate(BaseAction):
|
||||
'''Batch create objects in ftrack.'''
|
||||
|
||||
#: Action identifier.
|
||||
identifier = 'batch_create'
|
||||
#: Action label.
|
||||
label = 'Batch create'
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
|
||||
if (len(entities) != 1 or entities[0].entity_type.lower()
|
||||
not in ['project', 'episode', 'sequence']):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def interface(self, session, entities, event):
|
||||
if 'values' not in event['data']:
|
||||
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
|
||||
return [
|
||||
{
|
||||
'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
|
||||
}
|
||||
]
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
'''Callback method for action.'''
|
||||
selection = event['data'].get('selection', [])
|
||||
values = event['data'].get('values', {})
|
||||
if 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'
|
||||
}
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = BatchCreate(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
115
pype/ftrack/actions/djvview_launch.py
Normal file
115
pype/ftrack/actions/djvview_launch.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import os
|
||||
import logging
|
||||
import json
|
||||
|
||||
import ftrack
|
||||
import ftrack_api
|
||||
import clique
|
||||
import ftrack_template
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def modify_launch(session, event):
|
||||
"""Modify the application launch command with potential files to open"""
|
||||
|
||||
# Collect published paths
|
||||
data = {}
|
||||
for item in event["data"].get("selection", []):
|
||||
|
||||
versions = []
|
||||
|
||||
if entity.entity_type == "Assetversion":
|
||||
version = ftrack.AssetVersion(item["entityId"])
|
||||
if version.getAsset().getType().getShort() in ["img", "mov"]:
|
||||
versions.append(version)
|
||||
|
||||
# Add latest version of "img" and "mov" type from tasks.
|
||||
if item["entityType"] == "task":
|
||||
task = ftrack.Task(item["entityId"])
|
||||
for asset in task.getAssets(assetTypes=["img", "mov"]):
|
||||
versions.append(asset.getVersions()[-1])
|
||||
|
||||
for version in versions:
|
||||
for component in version.getComponents():
|
||||
component_list = data.get(component.getName(), [])
|
||||
component_list.append(component)
|
||||
data[component.getName()] = component_list
|
||||
|
||||
label = "v{0} - {1} - {2}"
|
||||
label = label.format(
|
||||
str(version.getVersion()).zfill(3),
|
||||
version.getAsset().getType().getName(),
|
||||
component.getName()
|
||||
)
|
||||
|
||||
file_path = component.getFilesystemPath()
|
||||
if component.isSequence():
|
||||
if component.getMembers():
|
||||
frame = int(component.getMembers()[0].getName())
|
||||
file_path = file_path % frame
|
||||
|
||||
event["data"]["items"].append(
|
||||
{"label": label, "value": file_path}
|
||||
)
|
||||
|
||||
# Collect workspace paths
|
||||
session = ftrack_api.Session()
|
||||
for item in event["data"].get("selection", []):
|
||||
if item["entityType"] == "task":
|
||||
templates = ftrack_template.discover_templates()
|
||||
task_area, template = ftrack_template.format(
|
||||
{}, templates, entity=session.get("Task", item["entityId"])
|
||||
)
|
||||
|
||||
# Traverse directory and collect collections from json files.
|
||||
instances = []
|
||||
for root, dirs, files in os.walk(task_area):
|
||||
for f in files:
|
||||
if f.endswith(".json"):
|
||||
with open(os.path.join(root, f)) as json_data:
|
||||
for data in json.load(json_data):
|
||||
instances.append(data)
|
||||
|
||||
check_values = []
|
||||
for data in instances:
|
||||
if "collection" in data:
|
||||
|
||||
# Check all files in the collection
|
||||
collection = clique.parse(data["collection"])
|
||||
for f in list(collection):
|
||||
if not os.path.exists(f):
|
||||
collection.remove(f)
|
||||
|
||||
if list(collection):
|
||||
value = list(collection)[0]
|
||||
|
||||
# Check if value already exists
|
||||
if value in check_values:
|
||||
continue
|
||||
else:
|
||||
check_values.append(value)
|
||||
|
||||
# Add workspace items
|
||||
event["data"]["items"].append(
|
||||
{
|
||||
"label": "{0} - {1}".format(
|
||||
data["name"],
|
||||
os.path.basename(collection.format())
|
||||
),
|
||||
"value": value
|
||||
}
|
||||
)
|
||||
|
||||
return event
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
# Validate session
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
session.event_hub.subscribe(
|
||||
'topic=djvview.launch',
|
||||
modify_launch(session)
|
||||
)
|
||||
|
|
@ -83,6 +83,7 @@ class AppAction(object):
|
|||
)
|
||||
|
||||
if accepts:
|
||||
self.logger.info('Selection is valid')
|
||||
return {
|
||||
'items': [{
|
||||
'label': self.label,
|
||||
|
|
@ -92,6 +93,8 @@ class AppAction(object):
|
|||
'icon': self.icon,
|
||||
}]
|
||||
}
|
||||
else:
|
||||
self.logger.info('Selection is _not_ valid')
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''Return true if we can handle the selected entities.
|
||||
|
|
@ -425,6 +428,7 @@ class BaseAction(object):
|
|||
)
|
||||
|
||||
if accepts:
|
||||
self.logger.info(u'Discovering action with selection: {0}'.format(args[1]['data'].get('selection', [])))
|
||||
return {
|
||||
'items': [{
|
||||
'label': self.label,
|
||||
|
|
@ -462,7 +466,8 @@ class BaseAction(object):
|
|||
for entity in _selection:
|
||||
_entities.append(
|
||||
(
|
||||
self._get_entity_type(entity), entity.get('entityId')
|
||||
session.get(self._get_entity_type(entity), entity.get('entityId'))
|
||||
# self._get_entity_type(entity), entity.get('entityId')
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue