Tim Edelmann

Members
  • Content Count

    61
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Tim Edelmann

  1. I'd love to read that answer as well... We'd like to publish .exr image-sequences and have ftrack server (ours is self-hosted) encode it to an .mp4 for reviewing. Since we didn't find a description on how to do this, we thought of doing this on our own (via ffmpeg).
  2. Hey, I wanted to complete this thread, to halp anyone, who might stumble into this... To make sure ftrack understands files with different filenames AND different versions, we ended up manually naming the associated asset and omit the part where the files differ! example: if we want to publish a file called "my_awsome_file_v001.jpg" and "my_awsome_file_v002.jpg", the created asset gets the name "my_awsome_file". So both files are linked to this asset, which make ftrack understand, that these are both just different versions of the 'same' file. Thanks for your help Tim
  3. Hey Mattias, thanks for the quick answer! Am I correct, that its only concidered the same asset, when the name is equal? As I said, out filenames for rendering hold a version-string like 'v001', 'v002', etc. So each of our versions is treated as a new asset and no versions are shown. Is there a way to get around this, while still having these version-string inside the filenames? Thanks again Tim
  4. Good afternoon, we would like to use the Autodesk RV Player to review AssetVersions linked to a task. These are opened by launching the corresponding hook via web-ui on a selected task. "ftrack_rv_api.py", which comes with the ftrack-plugin for RV, loads two widgets from ftrack (images added as attachments). We noticed, that the 'versions' tab is not showing other versions, if the AssetVersions linked to the task, have different names. As soon as the names is equal and only the 'verion'-field for the AssetVersion differs, the version-field in the RV-widget works as expected. The problem is, that we need our renderings to have the version as part of the filename, resulting in a broken widget, that never shows possible other versions. Is there a way to have assets/assetversions beeing named without our version-tag but the filenames still contain them? So that reviewing with rv would give us a list of versions? We well keep playing around with this, thank you for any hints? Tim
  5. ok. we found it. The error was in an other class and hard to find..(ignored whitespace and indentation, which was ignored by the python interpreter). It looks like, that errors, when happening in custom accessors and or structures, arent addressed properly by error-debug-log.
  6. What we tried so far... We are getting this error: ftrack_connect.ui.widget.publisher.Publisher - ERROR - Failed to publish: Failed to transfer component <FileComponent(ccfee77a-266c-4248-9431-bc573e7cc3f4)> data to location <Location("Infected_custom_location", 96865d31-ddb8-4ef9-bbde-79fdc5a7e8dd)> due to error: 'Session' object has no attribute '__getitem__' Transferred component data that may require cleanup: [] Traceback (most recent call last): File "c:\python27\lib\site-packages\ftrack_connect-1.1.3-py2.7.egg\ftrack_connect\ui\widget\publisher.py", line 298, in _publish component, source=origin_location File "c:\python27\lib\site-packages\ftrack_python_api-1.4.0-py2.7.egg\ftrack_api\entity\location.py", line 78, in add_component [component], sources=source, recursive=recursive File "c:\python27\lib\site-packages\ftrack_python_api-1.4.0-py2.7.egg\ftrack_api\entity\location.py", line 211, in add_components transferred=transferred LocationError: Failed to transfer component <FileComponent(ccfee77a-266c-4248-9431-bc573e7cc3f4)> data to location <Location("Infected_custom_location", 96865d31-ddb8-4ef9-bbde-79fdc5a7e8dd)> due to error: 'Session' object has no attribute '__getitem__' Transferred component data that may require cleanup: [] 2018-08-09 13:23:25,811 - root - ERROR - Logging an uncaught exception Traceback (most recent call last): File "c:\python27\lib\site-packages\ftrack_connect-1.1.3-py2.7.egg\ftrack_connect\asynchronous.py", line 21, in exceptHookWrapper method(*args, **kwargs) File "c:\python27\lib\site-packages\ftrack_connect-1.1.3-py2.7.egg\ftrack_connect\ui\widget\publisher.py", line 298, in _publish component, source=origin_location File "c:\python27\lib\site-packages\ftrack_python_api-1.4.0-py2.7.egg\ftrack_api\entity\location.py", line 78, in add_component [component], sources=source, recursive=recursive File "c:\python27\lib\site-packages\ftrack_python_api-1.4.0-py2.7.egg\ftrack_api\entity\location.py", line 211, in add_components transferred=transferred LocationError: Failed to transfer component <FileComponent(ccfee77a-266c-4248-9431-bc573e7cc3f4)> data to location <Location("Infected_custom_location", 96865d31-ddb8-4ef9-bbde-79fdc5a7e8dd)> due to error: 'Session' object has no attribute '__getitem__' Transferred component data that may require cleanup: [] We setup a customized version of the Resolver.py, doing this: The Resolver.py listens to: session.event_hub.subscribe('topic=ftrack.storage-scenario.activate', resolver.activate_storage_scenario) session.event_hub.subscribe('topic=ftrack.api.session.configure-location', resolver.configure_location) session.event_hub.subscribe('topic=ftrack.location.request-resolve and source.user.username="{0}"'.format(session.api_user), resolver) in activate_storage_scenario we do the following: def activate_storage_scenario(self, event): self.logger.info('activate_storage_scenario was called...\n{0}'.format(event)) scenario_name = 'Infected_custom_storage_scenario' location = self.get_or_create_location() mount_points = {} mount_points['windows'] = '\\\\infsan\\FTrack' mount_points['osx'] = '/Volumes/FTrack' mount_points['linux'] = '/mnt/FTrack' setting_value = json.dumps({ 'scenario': scenario_name, 'data': { 'location_id': location['id'], 'location_name': location['name'], 'accessor': { 'mount_points': { 'linux': mount_points['linux'], 'osx': mount_points['osx'], 'windows': mount_points['windows'] } } } }) self.storage_scenario['value'] = setting_value self.session.commit() # Broadcast an event that storage scenario has been configured. self.session.event_hub.publish(ftrack_api.event.base.Event(topic='ftrack.storage-scenario.configure-done')) self.logger.info('activate_storage_scenario - done. ') This is essentially a copy of the code from "_centralized_storage_scenario.py" from the ftrack_api, but changed to our needs (is ths propably the cause for the error?) configure_location does this: def configure_location(self, event): # location = event['data']['session'].query('Location where name is "studio.central-storage-location"').one() # location = event['data']['session'].query('Location where name is "Infected_custom_location"').one() location = self.get_or_create_location() location.structure = InfectedStructure.Structure.InfectedStructure(session=event['data']['session']) location.accessor = ftrack_api.accessor.disk.DiskAccessor(prefix='') location.priority = 0 self.logger.info('configure_location - done. ') When the Resolver gets called, it executes this: def __call__(self, event): self.session.reset() self.logger.info('Resolver got called with event: {0}'.format(event)) #event['data']['locationName'] = 'Infected_custom_location' # override location name... location_name = event['data'].get('locationName') component_id = event['data']['componentId'] location = None if location_name is None: component = self.session.get('Component', component_id) self.logger.info('component keys: {0}'.format(component.keys())) location = self.session.pick_location(component) self.logger.error( u'No location name given, picked location {0!r} for {1!r}.'.format( location, component ) ) if location is None: self.logger.error(u'Location cannot be found') return location_name = location['name'] if not self.filter_locations(location_name): self.logger.error( u'Skipping resolve for location {0}.'.format( location_name ) ) return if location is None: location = self.session.query( 'Location where name is "{0}"'.format( location_name ) ).one() if not location.accessor: self.logger.error(u'Skipping resolve for location without accessor: {0!r}.'.format( location ) ) return component = self.session.get('Component', component_id) resource_identifier = location.get_resource_identifier(component) path = None try: project = self.getProjectFromComponent(component) if not project: self.logger.info('no project found to load location_mapping') return self.logger.info('PROJECT_Location: {0}'.format(project['custom_attributes']['PROJECT_Location'][0])) location.accessor.prefix = location.structure.location_mapping[project['custom_attributes']['PROJECT_Location'][0]] path = location.accessor.get_filesystem_path(resource_identifier) except ftrack_api.exception.AccessorUnsupportedOperationError: try: path = location.accessor.get_url(resource_identifier) except ftrack_api.exception.AccessorUnsupportedOperationError: self.logger.error(u'Unable to get URL from accessor. Unsupported operation') pass if path is None: raise ValueError(u'Could not resolve {0!r} and {1!r} to a file system path or URL.'.format( component, location ) ) self.logger.error(u'Could not resolve {0!r} and {1!r} to a file system path or URL.'.format( component, location )) self.logger.info(u'Successfully resolved {0!r}.'.format(path)) return dict(path=path) and finally get_or_create_location does this: def get_or_create_location(self): location = self.session.ensure('Location', { 'name': 'Infected_custom_location', 'label': 'Infected_custom_location_label', 'description': ('Infected_custom_location_description') }) return location I hope this is all information regarding the error above. If anybody has an idea, some insights or has seen this before -> let us know. Until then, we're trying to get our head around this... Thanks Tim
  7. Hey there again, its been a while since my last post.. We currently exploring, whats the best way to tell a project, thats all its files, components, asset versions are now stored somewhere else. The background for this is, that we want to be able to move a project after its creation. For this we could listen to "ftrack.api.session.configure-location" and configure a custom location. But how can access the storage scenario to setup new mount-points? Is it even possible to set the storage scenario via ftrack_api? thanks in advance Tim
  8. ah.. ok thats good to know! I'm glad, this work around does the trick. thank you.
  9. any news on this? we also would like to use this functionality A question that is very close to this: We have multiple multi-selection, hierarchical custom attributes. One of them triggers ftrack.update when changing its values (and clicking somewhere outside), the others don't!?!? Can anybody explain this? This is confusing. Thanks in advance Tim
  10. Additional information: We noticed, that the ids look different and we don't know why?? normal ids look like this: '75b59aae-e1bb-11e7-ad88-7ab7a47c9dda' while the one retrieved here looks something like this: '75b59aae-e1bb-11e7-ad88-7ab7a47c9dda_48' this '_48' breaks it! PLUS: The 'entityType' given in 'event['data']['recordData']['entity']['entityType']' is not starting with a Capital letter, which breaks it too! So if we remove the '_48' and use 'TypedContext' instead of the given type, we're able to query the object. Could anybody give us some more insight here? Thanks again
  11. Hey everybody, while setting up a dynamic-enumerator-action, we noticed, that the information on the currently selected element doesn't help to retrieve an actual object. We always get 'None' as a result. This is the event, that comes in: { "topic": "ftrack.dynamic-enumerator", "source": { "id": "c73c09beff154613ba61300782bb836e", "user": { "username": "TEdelmann", "id": "75b59aae-e1bb-11e7-ad88-7ab7a47c9dda" } }, "target": "", "data": { "attributeName": "Briefing_Workflows_00_Maya_Config", "sorters": [], "filters": [ { "disabled": "True", "property": "name", "root": "data", "initialConfig": { "disabled": "True", "property": "name", "root": "data", "id": "ft-dynamicenumerator-2000671-query-filter" }, "id": "ft-dynamicenumerator-2000671-query-filter" } ], "query": "", "groupers": [], "recordData": { "changes": {}, "entity": { "entityId": "883b74ea-132b-11e8-ae79-7ab7a47c9dda_15", "entityType": "task" } } }, "in_reply_to_event": "None", "id": "27304c3ea333491fa793b457e91f7966", "sent": "None" } As you can see, there is given an entity in 'recordData'. But for some reason, we can't query or get the actual object from it. This is what we tried so far.. obj_type = event['data']['recordData']['entity']['entityType'] obj_id = event['data']['recordData']['entity']['entityId'] # obj_id = event['source']['id'] # selected_object = self.session.get('TypedContext', obj_id) # selected_object = self.session.query('Task where id is "{0}"'.format(obj_id)).first() selected_object = self.session.query('{0} where id is "{1}"'.format(obj_type, obj_id)).first() selected_object is always None. any suggestions? How are we supposed to get the current selection, when reacting on 'topic=ftrack.dynamic-enumerator'? Alternatively, it would be very helpful, if the information on what is currently selected, coulde be retrieved in a general way (i.e. like session.getCurrentSelection()) thanks a lot in advance Tim
  12. yeah, adding a 'custom' date manually is a good idea. thanks a lot Tim
  13. Hey ftrackers, we recently tried to add notes to a task in a sorted order. We read a number of question from a json which looks like this: [ { "index": 1, "content": "Q1" }, { "index": 2, "content": "Q2" }, { "index": 3, "content": "Q3" }, { "index": 4, "content": "Q4" } ] ..and we would like these questions, to appear in the order given by index. But for some reason, we always get the order visible in attachment: ftrack_question_ordering.PNG Could this be the same problem we have with custom attributes being not sorted? Thanks in advance Tim EDIT: The note, which was altered latest is shown upmost automatically, which implies, that we cannot change the order, right?
  14. Hey Mattias, thanks for getting back on this. Good to hear, that I'm not the only one running into this (so its not just my fault)..
  15. Hey, another thing we noticed: We use a custom attribute of type: dynamic enum which is hierarchical. If the project is selected and we change its values, no 'ftrack.update' gets triggered! On the other hand, if we select a folder (or any other object under project), changes to our custom attribute, do trigger 'ftrack.update'. Is this behavior wanted? For our workflow, it would be great, if the custom attribute changes trigger 'ftrack.update' no matter what is selected. thanks again
  16. yep. my bad I had another action (on another pc) registering for 'topic=ftrack.dynamic-enumerator' as well... So they seem to have interfered. It works when each registering instance makes use of 'event.stop()' if its to be handled here. Thanks for looking into this! Tim
  17. Hey Mattias, here a short test: # :coding: utf-8 import os import sys import ftrack_api class DynamicEnumMayaPlugins(object): label = "Dynamic Enumerator Plugins" description = 'Returns a list of all plugins for maya' identifier = "DynamicEnumMayaPlugins" def __init__(self, session): super(DynamicEnumMayaPlugins, self).__init__() self.session = session def register(self): self.session.event_hub.subscribe('topic=ftrack.dynamic-enumerator', self.launch) def launch(self, event): if 'Maya_Plugins' not in event['data']['attributeName']: return return [{'name':'Plugin1 - 8.0.572','value':'C:\\Path\\to\\Plugin1\\Plugin1_8.0.572'}, {'name':'Plugin2 - 8.0.572','value':'C:\\Path\\to\\Plugin2\\Plugin2_8.0.572'}, {'name':'Plugin3 - 8.0.572','value':'C:\\Path\\to\\Plugin3\\Plugin3_8.0.572'}] def register(session, **kw): action = DynamicEnumMayaPlugins(session) action.register() # startup os.environ['FTRACK_SERVER'] = '<YOUR_SERVER_URL>' os.environ['FTRACK_APIKEY'] = '<YOUR_APIKEY>' os.environ['FTRACK_EVENT_PLUGIN_PATH'] = '.' session = ftrack_api.Session() register(session) print('Waiting for events') session.event_hub.wait() You need to note your server-url and apikey.. Seems to work in about 30% of my tests. I setup a custom attribute "Briefing_Workflows_04_Maya_Plugins" in its own group of custom attributes. Its a multi selection field were every role can read and write despite our 'Artist'-Role which is not allowed to write. When I click the dropdown, it simply doesn't show the returned list of entries. If I click it about 3-7 times, it comes up (in 30% of my tests). So its working .. somehow.. but not reliably hope this helps Little addition: It seems as if the returned list is read from a folder and created first (instead of just returning a fixed sample -- as seen above) its working even less.. Litte addition2: When I cache the created list of plugins, the dropdown gets populated but still not every time clicked (about every 5th-15th click.)
  18. Hi Remus, we're using: python-API: 1.4.0 javascript: 0.4.5 Server: 3.5.20.4615
  19. Hello again, we would like to use Dynamic Enums to let our team-members select maya plugins from a drop-down which is populated from a folder containing all plugins available. For this we prepare the dropdown contents like described here: http://ftrack.rtd.ftrack.com/en/3.3.7/developing/dynamic_enumerator.html The resulting list looks like this: [{'name': '3Delight - 8.0.572', 'value': 'C:\\ConfigurationSync\\Maya\\3Delight\\3Delight_8.0.572'}, {'name': 'abcToA - 3.0.0 - 2018 - 2.0.1', 'value': 'C:\\ConfigurationSync\\Maya\\abcToA\\3.0.0_2018_2.0.1'}, {'name': 'abcToA - 3.0.1 - 2018 - 2.1.0.1', 'value': 'C:\\ConfigurationSync\\Maya\\abcToA\\3.0.1_2018_2.1.0.1'}, {'name': 'aTools - 2.0.1', 'value': 'C:\\ConfigurationSync\\Maya\\aTools\\2.0.1'}, {'name': 'aTools - 2.0.2', 'value': 'C:\\ConfigurationSync\\Maya\\aTools\\2.0.2'}, {'name': 'bonusTools - 2018', 'value': 'C:\\ConfigurationSync\\Maya\\bonusTools\\2018'}, {'name': 'cosmos - 1.0', 'value': 'C:\\ConfigurationSync\\Maya\\cosmos\\1.0'}, {'name': 'exocortex - crate - 1.1.153', 'value': 'C:\\ConfigurationSync\\Maya\\exocortex_crate\\1.1.153'}] This list has about 150 entries in the end. We noticed, that having 2-3 entries sometimes works and sometimes not. We Cannot figure out, what the problem with this might be. Are we missing anything here? Why is this not working? Thanks very much in advance Tim
  20. Hey there, we are currently trying to 'find' our custom attributes.. We set them up being 'Hierarchical' and when having selected a task, they can be retrieved via task['custom_attributes']['attribute_name']. In the web-ui they are visible when selecting a users profile in the overview. Now we would like to access these attributes via user['custom_attributes']['attribute_name'], but 'attribute_name' is not listed as a member in user['custom_attributes'] (Non-hierarchical attributes, which are added to 'User', are listed ). Are we missing something here? Thanks alot in advance
  21. Hey there, we are currently trying to send custom events via the javascript api (as the title might let you guess... ) In a Node-style js-file we're testing the following code, which is sadly not working... var EventSender = function(server, user, key) { require('isomorphic-fetch') var ftrack = require('ftrack-javascript-api'); this.session = new ftrack.Session(server, user, key); if (this.session==null) { console.log('Error creating session'); return; } this.DoStuff = function() { // TODO: find another way to solve this // make session available to all subfunctions by creating a 'locally scoped' variable // otherwise 'this.session' is only available at the outermost usage (i.e. only on line 28) // the nested functions below line 28 don't know about 'this.session' var session = this.session; if (session==null) { console.log('Error - No active Session'); return; } return session.initializing.then(function() { var event = new ftrack.Event('infected.custom-event', {foo: 'bar', xyz: true}); console.log('sending...'); return session.eventHub.publish(event); }).catch(error => {console.log(error);}); } } sender = new EventSender('http://192.168.5.14', 'Admin', 'f22192fc-0cb6-11e8-b2cb-7ab7a47c9dda'); sender.DoStuff(); The resulting error-msg is: TypeError: Cannot read property 'socket' of null at EventHub._runWhenConnected (C:\dev\javascript\ftrack.OS.management\node_modules\ftrack-javascript-api\lib\event_hub.js:307:32) at C:\dev\javascript\ftrack.OS.management\node_modules\ftrack-javascript-api\lib\event_hub.js:224:23 at new Promise (<anonymous>) at EventHub.publish (C:\dev\javascript\ftrack.OS.management\node_modules\ftrack-javascript-api\lib\event_hub.js:223:31) at C:\dev\javascript\ftrack.OS.management\sendEventTest.js:30:28 at <anonymous> at process._tickCallback (internal/process/next_tick.js:188:7) So for some reason, the local property '_socketIo' in event_hub.js is still null inside the method '_runWhenConnected', which is called in 'publish()' on line 224. Can you tell me why that is the case? having the same setup, we already successfully created calendar-events and other objects. Side-Question: Is it possible to send a custom event via javascript-api and receive it via the python-api? Thanks in advance Tim
  22. Hi Eric, thanks for the very fast answer! We found a solution to this right before I read it. It looks different, but doesn't seem to be slower/faster.. however your solution is shorter this was ours: search_key = '2_Client_Meeting' tmp = session.query('CustomAttributeConfiguration').all() for entry in tmp: if 'data' in entry['config']: json_obj = json.loads(entry['config']) data_obj = json.loads(json_obj['data']) for subentry in data_obj: if search_key == subentry['value']: print 'found:"',subentry['menu'],'" for key:',search_key,'in',entry['key'] We decided to use the 'menu' entries of the attributes. we take these from config/data which is both json saved as plain text. Is there a better way to do this? thanks again
  23. Hey everybody, we would like to use our custom_attributes' labels (that get setup when creating a custom_attribute-entry) when creating folders in the project. In javascript we access these via the projects' custom_properties like so: response.data[0].custom_attributes; with response.data[0] being the project. And from here each attribute has a 'configuration' containing a 'config'. In here we found 'data' and finally 'menu' which contains a pretty printable name of the attribute. But via the python api we're not able to find an equivalent. Are we looking in the wrong place? We would be greatfull for some insight. Since all the attributes have a 'label' containing a well formatted string in the system-settings, we thought, this would be accessible somehow.. Tim