Jump to content

ftrack-RV integration and query entity information


EHonda

Recommended Posts

Hi all,

I was testing ftrack integration with RV and encountered some difficulties to handle the data between them.
Hope that someone knows any workarounds.

Before anything, the long story short:
Is it possible to query real entityId and entityType from tempdata?


To explain what I tested and what are my thoughts, I made an simple graph showing a flow chart of how ftrack-RV integration works.
It is important to say that those tests are based on how RV works in Windows 10 environment with an normal RV installation.

---

Windows 10
RV 7.5.1
ftrack-connect 1.1.2

---

 

 ,─────,
(   ftrack   )
 '─────'
      ├───────────────────────────────────────────────────────┐
      ↓                                                                                                              ↓
┌──────────┐                                                                                         ┌─────┐
│ play in RV button  │                                                                                         │ Actions  │
└──────────┘                                                                                         └─────┘
      │                                                                                                              ↓
      ↓                                                                                                         ┌───────────┐
┌─────────┐                                                                                           │ ftrack Connect -> RV │
│ RVLINK  protocol │                                                                                           └───────────┘
└─────────┘                                                                                                ↓
      │                                                                                ,────────────────────────────────────────,
      ↓                                                                               ( "C:\Program Files\Shotgun\RV-7.5.1\bin\rv.exe" rvlink://baked/...(assetVersion)  ) defined in ftrack_connect_rv_hook.py
┌──────────────────────────────┐                        '────────────────────────────────────────'
│ call registry  HKEY_CLASSES_ROOT\rvlink\shell\open\command │
└──────────────────────────────┘
      │
      ↓
┌──────────────────────────────────────────────────┐
│ "C:\Program Files\Shotgun\RV-7.5.1\bin\rvpush.exe" -tag rvlink url "rvlink://baked/...(tempdata)"  │ or whatever is in the registry
└──────────────────────────────────────────────────┘
      │
     /  \
    < rvpush could find a rv.exe instance with networkTag rvlink already running?
     \  /
      │
      ├───────────────┐
      │                              │
      │ YES                          │ NO
      ↓                              │
 ,─────────────────, │
( connect to already running rv.exe  )│
 '─────────────────' │
                                     /  \
                                    < RVPUSH_RV_EXECUTABLE_PATH  is defined?
                                     \  /
                                      │
                                      ├─────┐
                                      │          │
                                      │ YES      │ NO
                                      │          ↓
                                      │   ,────────────────────────────────────────────────────,
                                      │  ( "C:\Program Files\Shotgun\RV-7.5.1\bin\rv.exe" -networkTag rvlink -network rvlink://baked/...(tempdata)  )
                                      ↓   '────────────────────────────────────────────────────'
                              ,────────────────,
                             ( call  RVPUSH_RV_EXECUTABLE_PATH  )
                              '────────────────'

 

When a user selects an AssetVersion and pushes the "play selection in RV button", a rvlink protocol is called, rvpush.exe runs and rv.exe is launched.
In this chain of executions, the rvlink url(passed to rv.exe as an argument) includes a tempdata information, instead of the information from selected entity.

This tempdata info is read by RV, passed to FtrackMode.generateUrl, which generates and returns an temporary url.
something like below:
https://DOMAIN.ftrackapp.com/widget?view=freview_nav_v1&itemId=freview&theme=dark&auth_token=AUTHTOKEN&entityId=ENTITYID&entityType=tempdata
This url is accessible from any browser, but I couldn't query entityId nor entityType of the item selected in the ftrack's webUI.

On the other hand, when launching RV using Actions and ftrack-connect, real entityId and entityType are passed to RV, allowing me to handle those information easily.
However, it has its cons:
 a.) to use it, I need an running instance of ftrack-connect
 b.) it always launches a new instance of RV

About b.), customizing ftrack_rv_hook.ApplicationLauncher._getApplicationLaunchCommand function seems to solve the problem.
Here is a sample code that shows how I implemented a custom launch process.

    def _getApplicationLaunchCommand(self, application, context=None):
        command = None
        if sys.platform in ('win32', ):
            # command = [application['path']]
            # ======================================================================================== #
            # CUSTOM LAUNCH PROCESS
            environment = self._getApplicationEnvironment(application, context)
            server = environment.get('FTRACK_SERVER')
            event = environment.get('FTRACK_CONNECT_EVENT')
            event_decode = base64.b64decode(event)
            event_obj = json.loads(event_decode)
            selection = event_obj.get('selection', '')
            rvlink_str = "-flags ModeManagerPreload=ftrack ftrackUrl=%s params='%s'" % (
                server,
                selection
            )
            rvlink_encoded = codecs.encode(rvlink_str, 'hex')
            # do not use normal command that calls rv.exe
            # instead, call an instance of cmd, start a rvlink protocol and call rvpush
            command = [
                "cmd.exe", "/c",
                'start', "", "rvlink://baked/%s" % rvlink_encoded
            ]
            # ======================================================================================== #
        else:
            self.logger.warning(
                'Unable to find launch command for {0} on this platform.'
                .format(application['identifier'])
            )
        return command

With this code, I could call rvlink protocol using ftrack-connect RV launcher, instead of launching new RV instances every time.

 

About a.), the only way I could solve was editing HKEY_CLASSES_ROOT\rvlink\shell\open\command in a way that launches RV with required environment variables.
This allows me to launch a RV that mimics a RV instance launched from ftrack-connect, without the need of a running ftrack-connect instance.

The problem is that, when calling RV from "play Selection in RV" button, I only have tempdata.
As so, solving a.) does not solves my problem at all.
I have the same problem as when I launched a ftrack instance without ftrack-connect, indeed.


So I return to my first question:
Is it possible to query real entityId and entityType from tempdata?


I've already checked other posts in the forum:
https://forum.ftrack.com/topic/987-ftrack-rv-integration
https://forum.ftrack.com/topic/26-installation-guide-for-rv
And some helps pages:
https://help.ftrack.com/en/articles/1040451-review
https://help.ftrack.com/en/articles/1040536-reviewing-in-hiero-player-or-rv

Maybe I'm missing something or misunderstanding how integration works.
I'll be glad if anyone could correct me or show me any workaround to reach entityId when using ftrack-RV integration without ftrack-connect's Actions.
Thanks in advance.

Best Regards,
Honda

Link to comment
Share on other sites

Hi Honda,

Here is a small snippet showing how to retrieve the real id and type from tempdata, and an example of the contents. I believe that the type attribute will be what I call legacy API form (e.g. "show" and "task" instead of "Project" and "TypedContext" as the new API).

results = session.call([{
    'action': '_get_tempdata',
    'id': tempdata_id,
}])
# results = [[
#     {
#         "type": "assetversion",
#         "id": "ab580b37-70a8-45c9-8008-09aa4e71b6b7"
#     },
#     {
#         "type": "assetversion",
#         "id": "6cefaf1c-f8e6-47df-bbe8-1e1801b1d571"
#     }
# ]]

Three variations on how to resolve paths for those AssetVersions. The first two assume that you've defined "componentName" to be something like "main" to match the value in system settings, for the particular Asset type that you're using. However, the third example shows how to query the Asset for the proper Component name.

# URLs will contain the session's API key.
for result in results[0]:
    if result['type'] != 'assetversion':
        continue
    playable_component = session.query(
        f'''Component where version_id is "{result['id']}" and name is {componentName}''').one()
    print(server_location.get_url(playable_component))

# URLs will be signed and expire after some time.
for result in results[0]:
    component_location = session.query(
        f'''select url from ComponentLocation where component.name is "{componentName}"'''
        f''' and component.version_id is "{result['id']}"''').one()
    print(component_location['url']['value'])

# This shows the resolver service used by the ftrack web UI.
for result in results[0]:
    av = session.query(
        f'''select asset.type.component, components.name from AssetVersion where id is "{result['id']}"'''
    ).one()
    comps = {
        comp['id']: comp
        for comp in av['components']
        if comp['name'] == av['asset']['type']['component']
    }
    for comp_id in comps:
        event = ftrack_api.event.base.Event(
            topic='ftrack.location.request-resolve',
            data={
                'componentId': comp_id,
            }
        )
        session.event_hub.publish(
            event=event,
            synchronous=False,
            on_reply=lambda event: print(event['data']['path']),
        )
        session.event_hub.wait()

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...