Merge branch 'develop' into bugfix/AY-5725_hiero-loader-is-not-offering-if-not-in-workfile-or-saved-file

This commit is contained in:
Jakub Ježek 2024-06-05 13:59:33 +02:00 committed by GitHub
commit 832ab1cc81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
116 changed files with 281 additions and 236 deletions

View file

@ -55,6 +55,7 @@ MOVED_ADDON_MILESTONE_VERSIONS = {
"clockify": VersionInfo(0, 2, 0),
"flame": VersionInfo(0, 2, 0),
"fusion": VersionInfo(0, 2, 0),
"harmony": VersionInfo(0, 2, 0),
"hiero": VersionInfo(0, 2, 0),
"max": VersionInfo(0, 2, 0),
"photoshop": VersionInfo(0, 2, 0),

View file

@ -1,4 +1,5 @@
from .version import __version__
from .structures import HostMsgAction
from .webserver_module import (
WebServerAddon
)
@ -7,5 +8,6 @@ from .webserver_module import (
__all__ = (
"__version__",
"HostMsgAction",
"WebServerAddon",
)

View file

@ -9,22 +9,18 @@ from qtpy import QtWidgets
from ayon_core.addon import ITrayService
from ayon_core.tools.stdout_broker.window import ConsoleDialog
from .structures import HostMsgAction
log = logging.getLogger(__name__)
# Host listener icon type
class IconType:
IDLE = "idle"
RUNNING = "running"
FAILED = "failed"
class MsgAction:
CONNECTING = "connecting"
INITIALIZED = "initialized"
ADD = "add"
CLOSE = "close"
class HostListener:
def __init__(self, webserver, module):
self._window_per_id = {}
@ -96,22 +92,22 @@ class HostListener:
if msg.type == aiohttp.WSMsgType.TEXT:
host_name, action, text = self._parse_message(msg)
if action == MsgAction.CONNECTING:
if action == HostMsgAction.CONNECTING:
self._action_per_id[host_name] = None
# must be sent to main thread, or action wont trigger
self.module.execute_in_main_thread(
lambda: self._host_is_connecting(host_name, text))
elif action == MsgAction.CLOSE:
elif action == HostMsgAction.CLOSE:
# clean close
self._close(host_name)
await ws.close()
elif action == MsgAction.INITIALIZED:
elif action == HostMsgAction.INITIALIZED:
self.module.execute_in_main_thread(
# must be queued as _host_is_connecting might not
# be triggered/finished yet
lambda: self._set_host_icon(host_name,
IconType.RUNNING))
elif action == MsgAction.ADD:
elif action == HostMsgAction.ADD:
self.module.execute_in_main_thread(
lambda: self._add_text(host_name, text))
elif msg.type == aiohttp.WSMsgType.ERROR:

View file

@ -0,0 +1,6 @@
# Host listener message actions
class HostMsgAction:
CONNECTING = "connecting"
INITIALIZED = "initialized"
ADD = "add"
CLOSE = "close"

View file

@ -0,0 +1,5 @@
from .broker import StdOutBroker
__all__ = (
"StdOutBroker",
)

View file

@ -1,173 +1,12 @@
import os
import sys
import threading
import collections
import websocket
import json
from datetime import datetime
import warnings
from .broker import StdOutBroker
from ayon_core.lib import Logger
from openpype_modules.webserver.host_console_listener import MsgAction
warnings.warn(
(
"Import of 'StdOutBroker' from 'ayon_core.tools.stdout_broker.app'"
" is deprecated. Please use 'ayon_core.tools.stdout_broker' instead."
),
DeprecationWarning
)
log = Logger.get_logger(__name__)
class StdOutBroker:
"""
Application showing console in Services tray for non python hosts
instead of cmd window.
"""
MAX_LINES = 10000
TIMER_TIMEOUT = 0.200
def __init__(self, host_name):
self.host_name = host_name
self.webserver_client = None
self.original_stdout_write = None
self.original_stderr_write = None
self.log_queue = collections.deque()
date_str = datetime.now().strftime("%d%m%Y%H%M%S")
self.host_id = "{}_{}".format(self.host_name, date_str)
self._std_available = False
self._is_running = False
self._catch_std_outputs()
self._timer = None
@property
def send_to_tray(self):
"""Checks if connected to tray and have access to logs."""
return self.webserver_client and self._std_available
def start(self):
"""Start app, create and start timer"""
if not self._std_available or self._is_running:
return
self._is_running = True
self._create_timer()
self._connect_to_tray()
def stop(self):
"""Disconnect from Tray, process last logs"""
if not self._is_running:
return
self._is_running = False
self._process_queue()
self._disconnect_from_tray()
def host_connected(self):
"""Send to Tray console that host is ready - icon change. """
log.info("Host {} connected".format(self.host_id))
payload = {
"host": self.host_id,
"action": MsgAction.INITIALIZED,
"text": "Integration with {}".format(
str.capitalize(self.host_name))
}
self._send(payload)
def _create_timer(self):
timer = threading.Timer(self.TIMER_TIMEOUT, self._timer_callback)
timer.start()
self._timer = timer
def _timer_callback(self):
if not self._is_running:
return
self._process_queue()
self._create_timer()
def _connect_to_tray(self):
"""Connect to Tray webserver to pass console output. """
if not self._std_available: # not content to log
return
ws = websocket.WebSocket()
webserver_url = os.environ.get("AYON_WEBSERVER_URL")
if not webserver_url:
print("Unknown webserver url, cannot connect to pass log")
return
webserver_url = webserver_url.replace("http", "ws")
ws.connect("{}/ws/host_listener".format(webserver_url))
self.webserver_client = ws
payload = {
"host": self.host_id,
"action": MsgAction.CONNECTING,
"text": "Integration with {}".format(
str.capitalize(self.host_name))
}
self._send(payload)
def _disconnect_from_tray(self):
"""Send to Tray that host is closing - remove from Services. """
print("Host {} closing".format(self.host_name))
if not self.webserver_client:
return
payload = {
"host": self.host_id,
"action": MsgAction.CLOSE,
"text": "Integration with {}".format(
str.capitalize(self.host_name))
}
self._send(payload)
self.webserver_client.close()
def _catch_std_outputs(self):
"""Redirects standard out and error to own functions"""
if sys.stdout:
self.original_stdout_write = sys.stdout.write
sys.stdout.write = self._my_stdout_write
self._std_available = True
if sys.stderr:
self.original_stderr_write = sys.stderr.write
sys.stderr.write = self._my_stderr_write
self._std_available = True
def _my_stdout_write(self, text):
"""Appends outputted text to queue, keep writing to original stdout"""
if self.original_stdout_write is not None:
self.original_stdout_write(text)
if self.send_to_tray:
self.log_queue.append(text)
def _my_stderr_write(self, text):
"""Appends outputted text to queue, keep writing to original stderr"""
if self.original_stderr_write is not None:
self.original_stderr_write(text)
if self.send_to_tray:
self.log_queue.append(text)
def _process_queue(self):
"""Sends lines and purges queue"""
if not self.send_to_tray:
return
lines = tuple(self.log_queue)
self.log_queue.clear()
if lines:
payload = {
"host": self.host_id,
"action": MsgAction.ADD,
"text": "\n".join(lines)
}
self._send(payload)
def _send(self, payload):
"""Worker method to send to existing websocket connection."""
if not self.send_to_tray:
return
try:
self.webserver_client.send(json.dumps(payload))
except ConnectionResetError: # Tray closed
self._connect_to_tray()
__all__ = ("StdOutBroker", )

View file

@ -0,0 +1,174 @@
import os
import sys
import threading
import collections
import json
from datetime import datetime
import websocket
from ayon_core.lib import Logger
from ayon_core.modules.webserver import HostMsgAction
log = Logger.get_logger(__name__)
class StdOutBroker:
"""
Application showing console in Services tray for non python hosts
instead of cmd window.
"""
MAX_LINES = 10000
TIMER_TIMEOUT = 0.200
def __init__(self, host_name):
self.host_name = host_name
self.webserver_client = None
self.original_stdout_write = None
self.original_stderr_write = None
self.log_queue = collections.deque()
date_str = datetime.now().strftime("%d%m%Y%H%M%S")
self.host_id = "{}_{}".format(self.host_name, date_str)
self._std_available = False
self._is_running = False
self._catch_std_outputs()
self._timer = None
@property
def send_to_tray(self):
"""Checks if connected to tray and have access to logs."""
return self.webserver_client and self._std_available
def start(self):
"""Start app, create and start timer"""
if not self._std_available or self._is_running:
return
self._is_running = True
self._create_timer()
self._connect_to_tray()
def stop(self):
"""Disconnect from Tray, process last logs"""
if not self._is_running:
return
self._is_running = False
self._process_queue()
self._disconnect_from_tray()
def host_connected(self):
"""Send to Tray console that host is ready - icon change. """
log.info("Host {} connected".format(self.host_id))
payload = {
"host": self.host_id,
"action": HostMsgAction.INITIALIZED,
"text": "Integration with {}".format(
str.capitalize(self.host_name))
}
self._send(payload)
def _create_timer(self):
timer = threading.Timer(self.TIMER_TIMEOUT, self._timer_callback)
timer.start()
self._timer = timer
def _timer_callback(self):
if not self._is_running:
return
self._process_queue()
self._create_timer()
def _connect_to_tray(self):
"""Connect to Tray webserver to pass console output. """
if not self._std_available: # not content to log
return
ws = websocket.WebSocket()
webserver_url = os.environ.get("AYON_WEBSERVER_URL")
if not webserver_url:
print("Unknown webserver url, cannot connect to pass log")
return
webserver_url = webserver_url.replace("http", "ws")
ws.connect("{}/ws/host_listener".format(webserver_url))
self.webserver_client = ws
payload = {
"host": self.host_id,
"action": HostMsgAction.CONNECTING,
"text": "Integration with {}".format(
str.capitalize(self.host_name))
}
self._send(payload)
def _disconnect_from_tray(self):
"""Send to Tray that host is closing - remove from Services. """
print("Host {} closing".format(self.host_name))
if not self.webserver_client:
return
payload = {
"host": self.host_id,
"action": HostMsgAction.CLOSE,
"text": "Integration with {}".format(
str.capitalize(self.host_name))
}
self._send(payload)
self.webserver_client.close()
def _catch_std_outputs(self):
"""Redirects standard out and error to own functions"""
if sys.stdout:
self.original_stdout_write = sys.stdout.write
sys.stdout.write = self._my_stdout_write
self._std_available = True
if sys.stderr:
self.original_stderr_write = sys.stderr.write
sys.stderr.write = self._my_stderr_write
self._std_available = True
def _my_stdout_write(self, text):
"""Appends outputted text to queue, keep writing to original stdout"""
if self.original_stdout_write is not None:
self.original_stdout_write(text)
if self.send_to_tray:
self.log_queue.append(text)
def _my_stderr_write(self, text):
"""Appends outputted text to queue, keep writing to original stderr"""
if self.original_stderr_write is not None:
self.original_stderr_write(text)
if self.send_to_tray:
self.log_queue.append(text)
def _process_queue(self):
"""Sends lines and purges queue"""
if not self.send_to_tray:
return
lines = tuple(self.log_queue)
self.log_queue.clear()
if lines:
payload = {
"host": self.host_id,
"action": HostMsgAction.ADD,
"text": "\n".join(lines)
}
self._send(payload)
def _send(self, payload):
"""Worker method to send to existing websocket connection."""
if not self.send_to_tray:
return
try:
self.webserver_client.send(json.dumps(payload))
except ConnectionResetError: # Tray closed
self._connect_to_tray()

View file

@ -1,3 +1,4 @@
from .version import __version__
from .addon import (
HARMONY_ADDON_ROOT,
HarmonyAddon,
@ -6,6 +7,8 @@ from .addon import (
__all__ = (
"__version__",
"HARMONY_ADDON_ROOT",
"HarmonyAddon",
"get_launch_script_path",

View file

@ -1,11 +1,14 @@
import os
from ayon_core.addon import AYONAddon, IHostAddon
from .version import __version__
HARMONY_ADDON_ROOT = os.path.dirname(os.path.abspath(__file__))
class HarmonyAddon(AYONAddon, IHostAddon):
name = "harmony"
version = __version__
host_name = "harmony"
def add_implementation_envs(self, env, _app):

View file

@ -5,7 +5,7 @@
The easiest way to setup for using Toon Boom Harmony is to use the built-in launch:
```
python -c "import ayon_core.hosts.harmony.api as harmony;harmony.launch("path/to/harmony/executable")"
python -c "import ayon_harmony.api as harmony;harmony.launch("path/to/harmony/executable")"
```
Communication with Harmony happens with a server/client relationship where the server is in the Python process and the client is in the Harmony process. Messages between Python and Harmony are required to be dictionaries, which are serialized to strings:
@ -59,7 +59,7 @@ You can show the Workfiles app when Harmony launches by setting environment vari
### Low level messaging
To send from Python to Harmony you can use the exposed method:
```python
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from uuid import uuid4
@ -75,7 +75,7 @@ print(harmony.send({"function": func, "args": ["Python"]})["result"])
To send a function with multiple arguments its best to declare the arguments within the function:
```python
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from uuid import uuid4
signature = str(uuid4()).replace("-", "_")
@ -114,7 +114,7 @@ PypeHarmony.myAwesomeFunction = function() {
Then you can call that javascript code from your Python like:
```Python
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
harmony.send({"function": "PypeHarmony.myAwesomeFunction"});
@ -159,7 +159,7 @@ Now in python, just read all those files and send them to Harmony.
```python
from pathlib import Path
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
path_to_js = Path('/path/to/my/js')
script_to_send = ""
@ -178,7 +178,7 @@ harmony.send({"function": "Master.Boo.B"})
### Scene Save
Instead of sending a request to Harmony with `scene.saveAll` please use:
```python
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
harmony.save_scene()
```
@ -195,7 +195,7 @@ These plugins were made with the [polly config](https://github.com/mindbender-st
#### Creator Plugin
```python
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from uuid import uuid4
@ -213,7 +213,7 @@ class CreateComposite(harmony.Creator):
The creator plugin can be configured to use other node types. For example here is a write node creator:
```python
from uuid import uuid4
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class CreateRender(harmony.Creator):
@ -244,7 +244,7 @@ class CreateRender(harmony.Creator):
```python
import pyblish.api
from ayon_core.pipeline import AYON_INSTANCE_ID, AVALON_INSTANCE_ID
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class CollectInstances(pyblish.api.ContextPlugin):
@ -292,7 +292,7 @@ import os
from uuid import uuid4
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
import clique
@ -423,7 +423,7 @@ class ExtractImage(pyblish.api.InstancePlugin):
import os
from uuid import uuid4
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
signature = str(uuid4()).replace("-", "_")
copy_files = """function copyFile(srcFilename, dstFilename)

View file

@ -387,7 +387,7 @@ function start() {
*/
self.onCreator = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['creator']
}, false);
@ -402,7 +402,7 @@ function start() {
*/
self.onWorkfiles = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['workfiles']
}, false);
@ -417,7 +417,7 @@ function start() {
*/
self.onLoad = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['loader']
}, false);
@ -433,7 +433,7 @@ function start() {
*/
self.onPublish = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['publish']
}, false);
@ -449,7 +449,7 @@ function start() {
*/
self.onManage = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['sceneinventory']
}, false);
@ -465,7 +465,7 @@ function start() {
*/
self.onSubsetManage = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['subsetmanager']
}, false);
@ -482,7 +482,7 @@ function start() {
self.onSetSceneSettings = function() {
app.avalonClient.send(
{
"module": "ayon_core.hosts.harmony.api",
"module": "ayon_harmony.api",
"method": "ensure_scene_settings",
"args": []
},
@ -500,7 +500,7 @@ function start() {
*/
self.onExperimentalTools = function() {
app.avalonClient.send({
'module': 'ayon_core.hosts.harmony.api.lib',
'module': 'ayon_harmony.api.lib',
'method': 'show',
'args': ['experimental_tools']
}, false);
@ -550,7 +550,7 @@ function ensureSceneSettings() {
var app = QCoreApplication.instance();
app.avalonClient.send(
{
"module": "ayon_core.hosts.harmony.api",
"module": "ayon_harmony.api",
"method": "ensure_scene_settings",
"args": []
},

View file

@ -8,7 +8,7 @@ workfile or others.
import os
import sys
from ayon_core.hosts.harmony.api.lib import main as host_main
from ayon_harmony.api.lib import main as host_main
# Get current file to locate start point of sys.argv
CURRENT_FILE = os.path.abspath(__file__)

View file

@ -20,7 +20,7 @@ import collections
from qtpy import QtWidgets, QtCore, QtGui
from ayon_core.lib import is_using_ayon_console
from ayon_core.tools.stdout_broker.app import StdOutBroker
from ayon_core.tools.stdout_broker import StdOutBroker
from ayon_core.tools.utils import host_tools
from ayon_core import style
@ -186,7 +186,7 @@ def launch(application_path, *args):
"""
from ayon_core.pipeline import install_host
from ayon_core.hosts.harmony import api as harmony
from ayon_harmony import api as harmony
install_host(harmony)
@ -486,7 +486,7 @@ def imprint(node_id, data, remove=False):
remove (bool): Removes the data from the scene.
Example:
>>> from ayon_core.hosts.harmony.api import lib
>>> from ayon_harmony.api import lib
>>> node = "Top/Display"
>>> data = {"str": "something", "int": 1, "float": 0.32, "bool": True}
>>> lib.imprint(layer, data)

View file

@ -15,11 +15,11 @@ from ayon_core.pipeline import (
from ayon_core.pipeline.load import get_outdated_containers
from ayon_core.pipeline.context_tools import get_current_folder_entity
from ayon_core.hosts.harmony import HARMONY_ADDON_ROOT
import ayon_core.hosts.harmony.api as harmony
from ayon_harmony import HARMONY_ADDON_ROOT
import ayon_harmony.api as harmony
log = logging.getLogger("ayon_core.hosts.harmony")
log = logging.getLogger("ayon_harmony")
PLUGINS_DIR = os.path.join(HARMONY_ADDON_ROOT, "plugins")
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")

View file

@ -1,5 +1,5 @@
from ayon_core.pipeline import LegacyCreator
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class Creator(LegacyCreator):

View file

@ -69,6 +69,8 @@ class Server(threading.Thread):
self.log.debug(
f"[{self.timestamp()}] Processing request:\n{pretty}")
# TODO javascript should not define which module is imported and
# which function is called. It should send predefined requests.
try:
module = importlib.import_module(request["module"])
method = getattr(module, request["method"])

View file

@ -7,7 +7,7 @@ from ayon_core.lib import (
is_using_ayon_console,
)
from ayon_applications import PreLaunchHook, LaunchTypes
from ayon_core.hosts.harmony import get_launch_script_path
from ayon_harmony import get_launch_script_path
def get_launch_kwargs(kwargs):

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""Create Composite node for render on farm."""
import ayon_core.hosts.harmony.api as harmony
from ayon_core.hosts.harmony.api import plugin
import ayon_harmony.api as harmony
from ayon_harmony.api import plugin
class CreateFarmRender(plugin.Creator):

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""Create render node."""
import ayon_core.hosts.harmony.api as harmony
from ayon_core.hosts.harmony.api import plugin
import ayon_harmony.api as harmony
from ayon_harmony.api import plugin
class CreateRender(plugin.Creator):

View file

@ -1,4 +1,4 @@
from ayon_core.hosts.harmony.api import plugin
from ayon_harmony.api import plugin
class CreateTemplate(plugin.Creator):

View file

@ -2,7 +2,7 @@ from ayon_core.pipeline import (
load,
get_representation_path,
)
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
sig = harmony.signature()
func = """

View file

@ -6,7 +6,7 @@ from ayon_core.pipeline import (
get_representation_path,
)
from ayon_core.pipeline.context_tools import is_representation_from_latest
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
copy_files = """function copyFile(srcFilename, dstFilename)

View file

@ -11,7 +11,7 @@ from ayon_core.pipeline import (
get_representation_path,
)
from ayon_core.pipeline.context_tools import is_representation_from_latest
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class ImageSequenceLoader(load.LoaderPlugin):
@ -30,6 +30,7 @@ class ImageSequenceLoader(load.LoaderPlugin):
}
representations = {"*"}
extensions = {"jpeg", "png", "jpg"}
settings_category = "harmony"
def load(self, context, name=None, namespace=None, data=None):
"""Plugin entry point.

View file

@ -5,7 +5,7 @@ from ayon_core.pipeline import (
load,
get_representation_path,
)
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class ImportPaletteLoader(load.LoaderPlugin):

View file

@ -11,7 +11,7 @@ from ayon_core.pipeline import (
get_representation_path,
)
from ayon_core.pipeline.context_tools import is_representation_from_latest
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class TemplateLoader(load.LoaderPlugin):

View file

@ -7,7 +7,7 @@ from ayon_core.pipeline import (
load,
get_representation_path,
)
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class ImportTemplateLoader(load.LoaderPlugin):

View file

@ -3,7 +3,7 @@
import os
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class CollectCurrentFile(pyblish.api.ContextPlugin):

View file

@ -7,7 +7,7 @@ import attr
from ayon_core.lib import get_formatted_current_time
from ayon_core.pipeline import publish
from ayon_core.pipeline.publish import RenderInstance
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
@attr.s

View file

@ -3,7 +3,7 @@
import json
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class CollectInstances(pyblish.api.ContextPlugin):

View file

@ -4,7 +4,7 @@ import json
import re
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class CollectPalettes(pyblish.api.ContextPlugin):
@ -14,6 +14,8 @@ class CollectPalettes(pyblish.api.ContextPlugin):
order = pyblish.api.CollectorOrder + 0.003
hosts = ["harmony"]
settings_category = "harmony"
# list of regexes for task names where collecting should happen
allowed_tasks = []

View file

@ -3,7 +3,7 @@
import os
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class CollectScene(pyblish.api.ContextPlugin):

View file

@ -5,7 +5,7 @@ import csv
from PIL import Image, ImageDraw, ImageFont
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from ayon_core.pipeline import publish

View file

@ -3,7 +3,7 @@ import tempfile
import subprocess
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
import ayon_core.lib
import clique

View file

@ -1,5 +1,5 @@
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class ExtractSaveScene(pyblish.api.ContextPlugin):

View file

@ -4,7 +4,7 @@ import os
import shutil
from ayon_core.pipeline import publish
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class ExtractTemplate(publish.Extractor):

View file

@ -3,7 +3,7 @@ import os
import pyblish.api
from ayon_core.pipeline.publish import get_errored_plugins_from_context
from ayon_core.lib import version_up
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
class IncrementWorkfile(pyblish.api.InstancePlugin):

View file

@ -2,7 +2,7 @@ import os
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from ayon_core.pipeline import PublishXmlValidationError
@ -18,6 +18,7 @@ class ValidateAudio(pyblish.api.InstancePlugin):
label = "Validate Audio"
families = ["render"]
hosts = ["harmony"]
settings_category = "harmony"
optional = True
def process(self, instance):

View file

@ -1,6 +1,6 @@
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from ayon_core.pipeline import get_current_folder_path
from ayon_core.pipeline.publish import (
ValidateContentsOrder,

View file

@ -6,7 +6,7 @@ import re
import pyblish.api
import ayon_core.hosts.harmony.api as harmony
import ayon_harmony.api as harmony
from ayon_core.pipeline import PublishXmlValidationError
@ -42,6 +42,7 @@ class ValidateSceneSettings(pyblish.api.InstancePlugin):
families = ["workfile"]
hosts = ["harmony"]
actions = [ValidateSceneSettingsRepair]
settings_category = "harmony"
optional = True
# skip frameEnd check if asset contains any of:

View file

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 303 KiB

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more