Page 1 of 1

Clarisse and ftrack

Unread postPosted: Mon Feb 18, 2019 7:05 pm
by jandersunstar
I want to share a basic script I did and another I modify in order to connect ftrack with Clarisse.

First you need to install the ftrack python api script from here:
http://ftrack-python-api.rtd.ftrack.com ... installing

Then you need to create this script and put it into the ftrack plugin folder:
ftrack_plugin_folder.png
open your plugin floder
ftrack_plugin_folder.png (17.14 KiB) Viewed 2695 times

C:\Users\sunst\AppData\Local\ftrack\ftrack-connect-plugins\clarisse_hook\hook\example_clarisse_hook.py

Code: Select all
# :coding: utf-8
# :copyright: Copyright (c) 2015 ftrack

import getpass
import logging
import sys
import pprint
import re
import os

import ftrack_api
import ftrack_connect.application


class LaunchApplicationAction(object):
    '''Launch Clarisse action.'''

    # Unique action identifier.
    identifier = 'my-clarisse-launch-action'

    def __init__(self, applicationStore, launcher, session):
        '''Initialise action with *applicationStore* and *launcher*.

        *applicationStore* should be an instance of
        :class:`ftrack_connect.application.ApplicationStore`.

        *launcher* should be an instance of
        :class:`ftrack_connect.application.ApplicationLauncher`.

        '''
        super(LaunchApplicationAction, self).__init__()

        self.logger = logging.getLogger(
            __name__ + '.' + self.__class__.__name__
        )

        self.applicationStore = applicationStore
        self.launcher = launcher
        self.session = session

        if self.identifier is None:
            raise ValueError('The action must be given an identifier.')

    def is_valid_selection(self, selection):
        '''Return true if the selection is valid.'''
        if (
            len(selection) != 1 or
            selection[0]['entityType'] != 'task'
        ):
            return False

        entity = selection[0]

        task = self.session.get(
            'Task', entity['entityId']
        )


        if task is None:
            return False

        return True

    def register(self, session):
        '''Register action to respond to discover and launch events.'''
        session.event_hub.subscribe(
            'topic=ftrack.action.discover',
            self.discover
        )

        session.event_hub.subscribe(
            'topic=ftrack.action.launch and data.actionIdentifier={0}'.format(
                self.identifier
            ),
            self.launch
        )

    def discover(self, event):
        '''Return available actions based on *event*.

        Each action should contain

            actionIdentifier - Unique identifier for the action
            label - Nice name to display in ftrack
            variant - Variant or version of the application.
            icon(optional) - predefined icon or URL to an image
            applicationIdentifier - Unique identifier to identify application
                                    in store.

        '''

        if not self.is_valid_selection(
            event['data'].get('selection', [])
        ):
            return

        items = []
        applications = self.applicationStore.applications
        applications = sorted(
            applications, key=lambda application: application['label']
        )

        for application in applications:
            applicationIdentifier = application['identifier']
            label = application['label']
            items.append({
                'actionIdentifier': self.identifier,
                'label': label,
                'variant': application.get('variant', None),
                'description': application.get('description', None),
                'icon': application.get('icon', 'default'),
                'applicationIdentifier': applicationIdentifier
            })

        return {
            'items': items
        }

    def launch(self, event):
        '''Callback method for Clarisse action.'''


        if not self.is_valid_selection(
            event['data'].get('selection', [])
        ):
            return

        applicationIdentifier = (
            event['data']['applicationIdentifier']
        )

        context = event['data'].copy()

        return self.launcher.launch(
            applicationIdentifier, context
        )


class ApplicationStore(ftrack_connect.application.ApplicationStore):
    '''Store used to find and keep track of available applications.'''

    def _discoverApplications(self):
        '''Return a list of applications that can be launched from this host.
        '''
        applications = []

        if sys.platform == 'darwin':
            prefix = ['/', 'Applications']

            applications.extend(self._searchFilesystem(
                expression=prefix + [
                    'Clarisse*', 'Clarisee.app'
                ],
                label='Clarisse',
                variant='{version}',
                applicationIdentifier='clarisse_{version}'
            ))

        elif sys.platform == 'win32':
            prefix = ['C:\\', 'Program Files.*']

            applications.extend(self._searchFilesystem(
                expression=(
                    prefix +
                    # ['Isotropix', 'Clarisse iFX 3.6 SP3*', 'Clarisse', 'clarisse.exe']
                    ['Isotropix', 'Clarisse iFX*', 'Clarisse', 'clarisse.exe']
                ),
                label='Clarisse',
                variant='{version}',
                applicationIdentifier='clarisse_{version}'
            ))

        self.logger.debug(
            'Discovered applications:\n{0}'.format(
                pprint.pformat(applications)
            )
        )

        return applications


class ApplicationLauncher(ftrack_connect.application.ApplicationLauncher):
    '''Custom launcher to modify environment before launch.'''

    def __init__(self, applicationStore, session):
        '''.'''
        super(ApplicationLauncher, self).__init__(applicationStore)

        self.session = session

    def _getApplicationEnvironment(
        self, application, context=None
    ):
        '''Override to modify environment before launch.'''

        # Make sure to call super to retrieve original environment
        # which contains the selection and ftrack API.
        environment = super(
            ApplicationLauncher, self
        )._getApplicationEnvironment(application, context)

        # Append or Prepend values to the environment.
        # Note that if you assign manually you will overwrite any
        # existing values on that variable.

        entity = context['selection'][0]

        task = self.session.get(
            'Task', entity['entityId']
        )

        taskParent = task.get(
            'parent'
        )

        try:
            environment['FS'] = str(
                int(taskParent['custom_attributes'].get('fstart'))
            )

        except Exception:
            environment['FS'] = '1'

        try:
            environment['FE'] = str(
                int(taskParent['custom_attributes'].get('fend'))
            )

        except Exception:
            environment['FE'] = '1'

        environment['FTRACK_TASKID'] = task.get('id')
        environment['FTRACK_SHOTID'] = task.get('parent_id')


        # Add my custom path to the HOUDINI_SCRIPT_PATH.


        # Always return the environment at the end.
        return environment


def register(session, **kw):
    '''Register hooks.'''

    # 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):
        return

    # Create store containing applications.
    applicationStore = ApplicationStore()

    # Create a launcher with the store containing applications.
    launcher = ApplicationLauncher(
        applicationStore,
        session=session
    )

    # Create action and register to respond to discover and launch actions.
    action = LaunchApplicationAction(applicationStore, launcher, session)
    action.register(session)


action.gif

The previous script will make Clarisse available on your ftrack Actions section. Only under a task.
Note: The script is similar at the one it comes as an example for connecting with Houdini.

Once you launch Clarisse using actions you will need to run the following script in order to get the frame range and resolution of the shot.

Code: Select all
import sys

import PySide
from PySide.QtGui import QApplication
from PySide.QtGui import QMessageBox


import ftrack_api
import os
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
app = None

session = ftrack_api.Session(
    server_url='https://XXX.ftrackapp.com',
    api_user='XXXX',
    api_key='XXXXX-XXXX-XXXX-XXXX-XXXXXXX',
    auto_connect_event_hub=False)

# print session.types.items()
# users = session.types['User']
# print users
# print user.keys()

taskid = os.environ['FTRACK_TASKID']
shotid = os.environ['FTRACK_SHOTID']

fstart = os.environ['FS']
fend = os.environ['FE']

tasks = session.query(
    'Task where id is {}'.format(taskid)
)
print "INFO:"
print "\nTasks:"
for task in tasks:
    print task['name']

shots = session.query(
    'Shot where id is {}'.format(shotid)
)

# test = session.query('Shot')
try:
    projectName = shots[0]['_link'][0]['name']
except Exception:
    projectName = "Assets"
   
try:
    projectId = shots[0]['_link'][0]['id']
except Exception:
    projectId = '0'
   
print 'project: ' + projectName + ' project ID: ' + projectId

query = session.query(
    'Project where id is {}'.format(projectId)
)
metadata = query[0]['metadata']
resolution = metadata['resolution']
resolution = resolution.split()
resolution_x = resolution[0]
resolution_y = resolution[1]
print resolution_y


print "\nShot:"
for shot in shots:
    print shot['name']

print 'Frame Start: ' + fstart
print 'Frame End: ' + fend

# print shot['custom_attributes'].items()
fps = shot['custom_attributes']['fps']
print 'Fps: ' + str(fps)

fstart = int(fstart)
fend = int(fend)
fps = float(fps)

ix.cmds.SetFps(fps)
ix.cmds.SetCurrentFrameRange(fstart, fend)
ix.cmds.SetValues(["project://scene/image.resolution[0]"], [str(resolution_x)])
ix.cmds.SetValues(["project://scene/image.resolution[1]"], [str(resolution_y)])
ix.cmds.SetValues(["project://scene/image.resolution_multiplier"], ["1"])




# Create the application object
app = None
if not QApplication.instance(): #QtApplication doesn't exist
    app = QApplication(sys.argv)
else:
    app = QApplication.instance()
 
# Create a simple dialog box
msgBox = QMessageBox()
msgBox.setText("Project " + projectName)
msgBox.exec_()


exampleRunningScript.gif

The previous script is still in work in progress, I am just sharing it just in case anyone wants to start making some changes and do a better job.

You can find more info on how to do ftrack queries:
http://ftrack-python-api.rtd.ftrack.com ... rying.html

Cheers!

-Luis

Re: Clarisse and ftrack

Unread postPosted: Tue Feb 19, 2019 8:34 am
by desmond
Thanks for sharing Luis!

Re: Clarisse and ftrack

Unread postPosted: Tue Feb 19, 2019 9:37 am
by dboude
Yes, Thanks for sharing !

Re: Clarisse and ftrack

Unread postPosted: Wed Feb 20, 2019 5:35 pm
by pipelinesolutions
hi @jandersunstar,
It's great to see interest (and code!) on integrating ftrack and clarisse !

If you feel like, you can have a look how to package the hook and the rest of the code as plugin here:
https://bitbucket.org/ftrack/ftrack-con ... r/setup.py

It would be great if you could share the code somewhere in bitbucket (ftrack-connect-clarisse ? )so we try to help improving it.
If I can be of any help with it or if you just have questions, please ping me at support@ftrack.com anytime !

Cheers!
Lorenzo Angeli.

Re: Clarisse and ftrack

Unread postPosted: Sat Feb 23, 2019 5:08 pm
by desmond
Hi all and ftrack guys @pipelinesolutions,
ive uplodaed Luis stuff to bitbucket as you asked, so you can contribute here : https://bitbucket.org/desmondd/ftrack-connect-clarisse/
thanks to luis and Ftrack guys

Re: Clarisse and ftrack

Unread postPosted: Tue Feb 11, 2020 4:32 pm
by pipelinesolutions
That's great ! Thanks for sharing!