diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index 390ede39d9..e69de29bb2 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -1,213 +0,0 @@ -# -*- coding: utf-8 -*- -"""Pype Harmony Host implementation.""" -import os -from pathlib import Path - -from avalon import api, io, harmony -import avalon.tools.sceneinventory - -import pyblish.api - -from pype import lib -from pype.api import (get_current_project_settings) - - -def set_scene_settings(settings): - """Set correct scene settings in Harmony. - - Args: - settings (dict): Scene settings. - - Returns: - dict: Dictionary of settings to set. - - """ - harmony.send( - {"function": "PypeHarmony.setSceneSettings", "args": settings}) - - -def get_asset_settings(): - """Get settings on current asset from database. - - Returns: - dict: Scene data. - - """ - asset_data = lib.get_asset()["data"] - fps = asset_data.get("fps") - frame_start = asset_data.get("frameStart") - frame_end = asset_data.get("frameEnd") - resolution_width = asset_data.get("resolutionWidth") - resolution_height = asset_data.get("resolutionHeight") - entity_type = asset_data.get("entityType") - - scene_data = { - "fps": fps, - "frameStart": frame_start, - "frameEnd": frame_end, - "resolutionWidth": resolution_width, - "resolutionHeight": resolution_height - } - settings = get_current_project_settings() - - try: - skip_resolution_check = \ - settings["harmony"]["general"]["skip_resolution_check"] - skip_timelines_check = \ - settings["harmony"]["general"]["skip_timelines_check"] - except KeyError: - skip_resolution_check = [] - skip_timelines_check = [] - - if os.getenv('AVALON_TASK') in skip_resolution_check: - scene_data.pop("resolutionWidth") - scene_data.pop("resolutionHeight") - - if entity_type in skip_timelines_check: - scene_data.pop('frameStart', None) - scene_data.pop('frameEnd', None) - - return scene_data - - -def ensure_scene_settings(): - """Validate if Harmony scene has valid settings.""" - settings = get_asset_settings() - - invalid_settings = [] - valid_settings = {} - for key, value in settings.items(): - if value is None: - invalid_settings.append(key) - else: - valid_settings[key] = value - - # Warn about missing attributes. - if invalid_settings: - msg = "Missing attributes:" - for item in invalid_settings: - msg += f"\n{item}" - - harmony.send( - {"function": "PypeHarmony.message", "args": msg}) - - set_scene_settings(valid_settings) - - -def check_inventory(): - """Check is scene contains outdated containers. - - If it does it will colorize outdated nodes and display warning message - in Harmony. - """ - if not lib.any_outdated(): - return - - host = avalon.api.registered_host() - outdated_containers = [] - for container in host.ls(): - representation = container['representation'] - representation_doc = io.find_one( - { - "_id": io.ObjectId(representation), - "type": "representation" - }, - projection={"parent": True} - ) - if representation_doc and not lib.is_latest(representation_doc): - outdated_containers.append(container) - - # Colour nodes. - outdated_nodes = [] - for container in outdated_containers: - if container["loader"] == "ImageSequenceLoader": - outdated_nodes.append( - harmony.find_node_by_name(container["name"], "READ") - ) - harmony.send({"function": "PypeHarmony.setColor", "args": outdated_nodes}) - - # Warn about outdated containers. - msg = "There are outdated containers in the scene." - harmony.send({"function": "PypeHarmony.message", "args": msg}) - - -def application_launch(): - """Event that is executed after Harmony is launched.""" - # FIXME: This is breaking server <-> client communication. - # It is now moved so it it manually called. - # ensure_scene_settings() - # check_inventory() - pype_harmony_path = Path(__file__).parent / "js" / "PypeHarmony.js" - pype_harmony_js = pype_harmony_path.read_text() - - # go through js/creators, loaders and publish folders and load all scripts - script = "" - for item in ["creators", "loaders", "publish"]: - dir_to_scan = Path(__file__).parent / "js" / item - for child in dir_to_scan.iterdir(): - script += child.read_text() - - # send scripts to Harmony - harmony.send({"script": pype_harmony_js}) - harmony.send({"script": script}) - - -def export_template(backdrops, nodes, filepath): - """Export Template to file. - - Args: - backdrops (list): List of backdrops to export. - nodes (list): List of nodes to export. - filepath (str): Path where to save Template. - - """ - harmony.send({ - "function": "PypeHarmony.exportTemplate", - "args": [ - backdrops, - nodes, - os.path.basename(filepath), - os.path.dirname(filepath) - ] - }) - - -def install(): - """Install Pype as host config.""" - print("Installing Pype config ...") - - plugins_directory = os.path.join( - os.path.dirname(os.path.dirname(os.path.dirname(__file__))), - "plugins", - "harmony" - ) - - pyblish.api.register_plugin_path( - os.path.join(plugins_directory, "publish") - ) - api.register_plugin_path( - api.Loader, os.path.join(plugins_directory, "load") - ) - api.register_plugin_path( - api.Creator, os.path.join(plugins_directory, "create") - ) - - # Register callbacks. - pyblish.api.register_callback( - "instanceToggled", on_pyblish_instance_toggled - ) - - api.on("application.launched", application_launch) - - -def on_pyblish_instance_toggled(instance, old_value, new_value): - """Toggle node enabling on instance toggles.""" - try: - harmony.send( - { - "function": "PypeHarmony.toggleInstance", - "args": [instance[0], new_value] - } - ) - except IndexError: - print(f"Instance '{instance}' is missing node") diff --git a/pype/hosts/harmony/api/__init__.py b/pype/hosts/harmony/api/__init__.py new file mode 100644 index 0000000000..c76c306052 --- /dev/null +++ b/pype/hosts/harmony/api/__init__.py @@ -0,0 +1,221 @@ +# -*- coding: utf-8 -*- +"""Pype Harmony Host implementation.""" +import os +from pathlib import Path +import logging + +from pype import lib +from pype.api import (get_current_project_settings) +import pype.hosts.harmony + +import pyblish.api + +from avalon import io, harmony +import avalon.api +import avalon.tools.sceneinventory + + +log = logging.getLogger("pype.hosts.harmony") + +HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.harmony.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") + + +def set_scene_settings(settings): + """Set correct scene settings in Harmony. + + Args: + settings (dict): Scene settings. + + Returns: + dict: Dictionary of settings to set. + + """ + harmony.send( + {"function": "PypeHarmony.setSceneSettings", "args": settings}) + + +def get_asset_settings(): + """Get settings on current asset from database. + + Returns: + dict: Scene data. + + """ + asset_data = lib.get_asset()["data"] + fps = asset_data.get("fps") + frame_start = asset_data.get("frameStart") + frame_end = asset_data.get("frameEnd") + resolution_width = asset_data.get("resolutionWidth") + resolution_height = asset_data.get("resolutionHeight") + entity_type = asset_data.get("entityType") + + scene_data = { + "fps": fps, + "frameStart": frame_start, + "frameEnd": frame_end, + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height + } + settings = get_current_project_settings() + + try: + skip_resolution_check = \ + settings["harmony"]["general"]["skip_resolution_check"] + skip_timelines_check = \ + settings["harmony"]["general"]["skip_timelines_check"] + except KeyError: + skip_resolution_check = [] + skip_timelines_check = [] + + if os.getenv('AVALON_TASK') in skip_resolution_check: + scene_data.pop("resolutionWidth") + scene_data.pop("resolutionHeight") + + if entity_type in skip_timelines_check: + scene_data.pop('frameStart', None) + scene_data.pop('frameEnd', None) + + return scene_data + + +def ensure_scene_settings(): + """Validate if Harmony scene has valid settings.""" + settings = get_asset_settings() + + invalid_settings = [] + valid_settings = {} + for key, value in settings.items(): + if value is None: + invalid_settings.append(key) + else: + valid_settings[key] = value + + # Warn about missing attributes. + if invalid_settings: + msg = "Missing attributes:" + for item in invalid_settings: + msg += f"\n{item}" + + harmony.send( + {"function": "PypeHarmony.message", "args": msg}) + + set_scene_settings(valid_settings) + + +def check_inventory(): + """Check is scene contains outdated containers. + + If it does it will colorize outdated nodes and display warning message + in Harmony. + """ + if not lib.any_outdated(): + return + + host = avalon.api.registered_host() + outdated_containers = [] + for container in host.ls(): + representation = container['representation'] + representation_doc = io.find_one( + { + "_id": io.ObjectId(representation), + "type": "representation" + }, + projection={"parent": True} + ) + if representation_doc and not lib.is_latest(representation_doc): + outdated_containers.append(container) + + # Colour nodes. + outdated_nodes = [] + for container in outdated_containers: + if container["loader"] == "ImageSequenceLoader": + outdated_nodes.append( + harmony.find_node_by_name(container["name"], "READ") + ) + harmony.send({"function": "PypeHarmony.setColor", "args": outdated_nodes}) + + # Warn about outdated containers. + msg = "There are outdated containers in the scene." + harmony.send({"function": "PypeHarmony.message", "args": msg}) + + +def application_launch(): + """Event that is executed after Harmony is launched.""" + # FIXME: This is breaking server <-> client communication. + # It is now moved so it it manually called. + # ensure_scene_settings() + # check_inventory() + pype_harmony_path = Path(__file__).parent / "js" / "PypeHarmony.js" + pype_harmony_js = pype_harmony_path.read_text() + + # go through js/creators, loaders and publish folders and load all scripts + script = "" + for item in ["creators", "loaders", "publish"]: + dir_to_scan = Path(__file__).parent / "js" / item + for child in dir_to_scan.iterdir(): + script += child.read_text() + + # send scripts to Harmony + harmony.send({"script": pype_harmony_js}) + harmony.send({"script": script}) + + +def export_template(backdrops, nodes, filepath): + """Export Template to file. + + Args: + backdrops (list): List of backdrops to export. + nodes (list): List of nodes to export. + filepath (str): Path where to save Template. + + """ + harmony.send({ + "function": "PypeHarmony.exportTemplate", + "args": [ + backdrops, + nodes, + os.path.basename(filepath), + os.path.dirname(filepath) + ] + }) + + +def install(): + """Install Pype as host config.""" + print("Installing Pype config ...") + + pyblish.api.register_plugin_path(PUBLISH_PATH) + avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH) + log.info(PUBLISH_PATH) + + # Register callbacks. + pyblish.api.register_callback( + "instanceToggled", on_pyblish_instance_toggled + ) + + avalon.api.on("application.launched", application_launch) + + +def uninstall(): + pyblish.api.deregister_plugin_path(PUBLISH_PATH) + avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH) + + +def on_pyblish_instance_toggled(instance, old_value, new_value): + """Toggle node enabling on instance toggles.""" + try: + harmony.send( + { + "function": "PypeHarmony.toggleInstance", + "args": [instance[0], new_value] + } + ) + except IndexError: + print(f"Instance '{instance}' is missing node") diff --git a/pype/hosts/harmony/plugins/__init__.py b/pype/hosts/harmony/plugins/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/plugins/harmony/create/create_farm_render.py b/pype/hosts/harmony/plugins/create/create_farm_render.py similarity index 100% rename from pype/plugins/harmony/create/create_farm_render.py rename to pype/hosts/harmony/plugins/create/create_farm_render.py diff --git a/pype/plugins/harmony/create/create_render.py b/pype/hosts/harmony/plugins/create/create_render.py similarity index 100% rename from pype/plugins/harmony/create/create_render.py rename to pype/hosts/harmony/plugins/create/create_render.py diff --git a/pype/plugins/harmony/create/create_template.py b/pype/hosts/harmony/plugins/create/create_template.py similarity index 100% rename from pype/plugins/harmony/create/create_template.py rename to pype/hosts/harmony/plugins/create/create_template.py diff --git a/pype/plugins/harmony/load/load_audio.py b/pype/hosts/harmony/plugins/load/load_audio.py similarity index 100% rename from pype/plugins/harmony/load/load_audio.py rename to pype/hosts/harmony/plugins/load/load_audio.py diff --git a/pype/plugins/harmony/load/load_background.py b/pype/hosts/harmony/plugins/load/load_background.py similarity index 100% rename from pype/plugins/harmony/load/load_background.py rename to pype/hosts/harmony/plugins/load/load_background.py diff --git a/pype/plugins/harmony/load/load_imagesequence.py b/pype/hosts/harmony/plugins/load/load_imagesequence.py similarity index 100% rename from pype/plugins/harmony/load/load_imagesequence.py rename to pype/hosts/harmony/plugins/load/load_imagesequence.py diff --git a/pype/plugins/harmony/load/load_palette.py b/pype/hosts/harmony/plugins/load/load_palette.py similarity index 100% rename from pype/plugins/harmony/load/load_palette.py rename to pype/hosts/harmony/plugins/load/load_palette.py diff --git a/pype/plugins/harmony/load/load_template.py b/pype/hosts/harmony/plugins/load/load_template.py similarity index 100% rename from pype/plugins/harmony/load/load_template.py rename to pype/hosts/harmony/plugins/load/load_template.py diff --git a/pype/plugins/harmony/load/load_template_workfile.py b/pype/hosts/harmony/plugins/load/load_template_workfile.py similarity index 100% rename from pype/plugins/harmony/load/load_template_workfile.py rename to pype/hosts/harmony/plugins/load/load_template_workfile.py diff --git a/pype/plugins/harmony/publish/collect_audio.py b/pype/hosts/harmony/plugins/publish/collect_audio.py similarity index 100% rename from pype/plugins/harmony/publish/collect_audio.py rename to pype/hosts/harmony/plugins/publish/collect_audio.py diff --git a/pype/plugins/harmony/publish/collect_current_file.py b/pype/hosts/harmony/plugins/publish/collect_current_file.py similarity index 100% rename from pype/plugins/harmony/publish/collect_current_file.py rename to pype/hosts/harmony/plugins/publish/collect_current_file.py diff --git a/pype/plugins/harmony/publish/collect_farm_render.py b/pype/hosts/harmony/plugins/publish/collect_farm_render.py similarity index 100% rename from pype/plugins/harmony/publish/collect_farm_render.py rename to pype/hosts/harmony/plugins/publish/collect_farm_render.py diff --git a/pype/plugins/harmony/publish/collect_instances.py b/pype/hosts/harmony/plugins/publish/collect_instances.py similarity index 100% rename from pype/plugins/harmony/publish/collect_instances.py rename to pype/hosts/harmony/plugins/publish/collect_instances.py diff --git a/pype/plugins/harmony/publish/collect_palettes.py b/pype/hosts/harmony/plugins/publish/collect_palettes.py similarity index 100% rename from pype/plugins/harmony/publish/collect_palettes.py rename to pype/hosts/harmony/plugins/publish/collect_palettes.py diff --git a/pype/plugins/harmony/publish/collect_scene.py b/pype/hosts/harmony/plugins/publish/collect_scene.py similarity index 100% rename from pype/plugins/harmony/publish/collect_scene.py rename to pype/hosts/harmony/plugins/publish/collect_scene.py diff --git a/pype/plugins/harmony/publish/collect_workfile.py b/pype/hosts/harmony/plugins/publish/collect_workfile.py similarity index 100% rename from pype/plugins/harmony/publish/collect_workfile.py rename to pype/hosts/harmony/plugins/publish/collect_workfile.py diff --git a/pype/plugins/harmony/publish/extract_palette.py b/pype/hosts/harmony/plugins/publish/extract_palette.py similarity index 100% rename from pype/plugins/harmony/publish/extract_palette.py rename to pype/hosts/harmony/plugins/publish/extract_palette.py diff --git a/pype/plugins/harmony/publish/extract_render.py b/pype/hosts/harmony/plugins/publish/extract_render.py similarity index 100% rename from pype/plugins/harmony/publish/extract_render.py rename to pype/hosts/harmony/plugins/publish/extract_render.py diff --git a/pype/plugins/harmony/publish/extract_save_scene.py b/pype/hosts/harmony/plugins/publish/extract_save_scene.py similarity index 100% rename from pype/plugins/harmony/publish/extract_save_scene.py rename to pype/hosts/harmony/plugins/publish/extract_save_scene.py diff --git a/pype/plugins/harmony/publish/extract_template.py b/pype/hosts/harmony/plugins/publish/extract_template.py similarity index 100% rename from pype/plugins/harmony/publish/extract_template.py rename to pype/hosts/harmony/plugins/publish/extract_template.py diff --git a/pype/plugins/harmony/publish/extract_workfile.py b/pype/hosts/harmony/plugins/publish/extract_workfile.py similarity index 100% rename from pype/plugins/harmony/publish/extract_workfile.py rename to pype/hosts/harmony/plugins/publish/extract_workfile.py diff --git a/pype/plugins/harmony/publish/increment_workfile.py b/pype/hosts/harmony/plugins/publish/increment_workfile.py similarity index 100% rename from pype/plugins/harmony/publish/increment_workfile.py rename to pype/hosts/harmony/plugins/publish/increment_workfile.py diff --git a/pype/plugins/harmony/publish/submit_harmony_deadline..py b/pype/hosts/harmony/plugins/publish/submit_harmony_deadline..py similarity index 100% rename from pype/plugins/harmony/publish/submit_harmony_deadline..py rename to pype/hosts/harmony/plugins/publish/submit_harmony_deadline..py diff --git a/pype/plugins/harmony/publish/validate_audio.py b/pype/hosts/harmony/plugins/publish/validate_audio.py similarity index 100% rename from pype/plugins/harmony/publish/validate_audio.py rename to pype/hosts/harmony/plugins/publish/validate_audio.py diff --git a/pype/plugins/harmony/publish/validate_instances.py b/pype/hosts/harmony/plugins/publish/validate_instances.py similarity index 100% rename from pype/plugins/harmony/publish/validate_instances.py rename to pype/hosts/harmony/plugins/publish/validate_instances.py diff --git a/pype/plugins/harmony/publish/validate_scene_settings.py b/pype/hosts/harmony/plugins/publish/validate_scene_settings.py similarity index 100% rename from pype/plugins/harmony/publish/validate_scene_settings.py rename to pype/hosts/harmony/plugins/publish/validate_scene_settings.py diff --git a/pype/scripts/non_python_host_launch.py b/pype/scripts/non_python_host_launch.py index 1637eec7ed..506105d2ce 100644 --- a/pype/scripts/non_python_host_launch.py +++ b/pype/scripts/non_python_host_launch.py @@ -85,7 +85,7 @@ def main(argv): elif host_name == "aftereffects": from avalon.aftereffects.lib import launch elif host_name == "harmony": - from avalon.photoshop.lib import launch + from avalon.harmony.lib import launch else: title = "Unknown host name" message = ( diff --git a/pype/settings/defaults/system_settings/applications.json b/pype/settings/defaults/system_settings/applications.json index 930701bf1b..18e46a790c 100644 --- a/pype/settings/defaults/system_settings/applications.json +++ b/pype/settings/defaults/system_settings/applications.json @@ -1016,10 +1016,12 @@ "environment": { "AVALON_HARMONY_WORKFILES_ON_LAUNCH": "1", "PYBLISH_GUI_ALWAYS_EXEC": "1", + "LIB_OPENHARMONY_PATH": "{PYPE_ROOT}/pype/vendor/OpenHarmony", "__environment_keys__": { "harmony": [ "AVALON_HARMONY_WORKFILES_ON_LAUNCH", - "PYBLISH_GUI_ALWAYS_EXEC" + "PYBLISH_GUI_ALWAYS_EXEC", + "LIB_OPENHARMONY_PATH" ] } },