mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Merge branch 'develop' into feature/OP-3943_Photoshop-review-can-be-turned-off
This commit is contained in:
commit
82be8cd6a4
8 changed files with 175 additions and 32 deletions
|
|
@ -13,7 +13,7 @@ from maya import cmds # noqa
|
||||||
|
|
||||||
import pyblish.api
|
import pyblish.api
|
||||||
|
|
||||||
from openpype.lib import source_hash
|
from openpype.lib import source_hash, run_subprocess
|
||||||
from openpype.pipeline import legacy_io, publish
|
from openpype.pipeline import legacy_io, publish
|
||||||
from openpype.hosts.maya.api import lib
|
from openpype.hosts.maya.api import lib
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ def find_paths_by_hash(texture_hash):
|
||||||
return legacy_io.distinct(key, {"type": "version"})
|
return legacy_io.distinct(key, {"type": "version"})
|
||||||
|
|
||||||
|
|
||||||
def maketx(source, destination, *args):
|
def maketx(source, destination, args, logger):
|
||||||
"""Make `.tx` using `maketx` with some default settings.
|
"""Make `.tx` using `maketx` with some default settings.
|
||||||
|
|
||||||
The settings are based on default as used in Arnold's
|
The settings are based on default as used in Arnold's
|
||||||
|
|
@ -79,7 +79,8 @@ def maketx(source, destination, *args):
|
||||||
Args:
|
Args:
|
||||||
source (str): Path to source file.
|
source (str): Path to source file.
|
||||||
destination (str): Writing destination path.
|
destination (str): Writing destination path.
|
||||||
*args: Additional arguments for `maketx`.
|
args (list): Additional arguments for `maketx`.
|
||||||
|
logger (logging.Logger): Logger to log messages to.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Output of `maketx` command.
|
str: Output of `maketx` command.
|
||||||
|
|
@ -94,7 +95,7 @@ def maketx(source, destination, *args):
|
||||||
"OIIO tool not found in {}".format(maketx_path))
|
"OIIO tool not found in {}".format(maketx_path))
|
||||||
raise AssertionError("OIIO tool not found")
|
raise AssertionError("OIIO tool not found")
|
||||||
|
|
||||||
cmd = [
|
subprocess_args = [
|
||||||
maketx_path,
|
maketx_path,
|
||||||
"-v", # verbose
|
"-v", # verbose
|
||||||
"-u", # update mode
|
"-u", # update mode
|
||||||
|
|
@ -103,27 +104,20 @@ def maketx(source, destination, *args):
|
||||||
"--checknan",
|
"--checknan",
|
||||||
# use oiio-optimized settings for tile-size, planarconfig, metadata
|
# use oiio-optimized settings for tile-size, planarconfig, metadata
|
||||||
"--oiio",
|
"--oiio",
|
||||||
"--filter lanczos3",
|
"--filter", "lanczos3",
|
||||||
escape_space(source)
|
source
|
||||||
]
|
]
|
||||||
|
|
||||||
cmd.extend(args)
|
subprocess_args.extend(args)
|
||||||
cmd.extend(["-o", escape_space(destination)])
|
subprocess_args.extend(["-o", destination])
|
||||||
|
|
||||||
cmd = " ".join(cmd)
|
cmd = " ".join(subprocess_args)
|
||||||
|
logger.debug(cmd)
|
||||||
|
|
||||||
CREATE_NO_WINDOW = 0x08000000 # noqa
|
|
||||||
kwargs = dict(args=cmd, stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
if sys.platform == "win32":
|
|
||||||
kwargs["creationflags"] = CREATE_NO_WINDOW
|
|
||||||
try:
|
try:
|
||||||
out = subprocess.check_output(**kwargs)
|
out = run_subprocess(subprocess_args)
|
||||||
except subprocess.CalledProcessError as exc:
|
except Exception:
|
||||||
print(exc)
|
logger.error("Maketx converion failed", exc_info=True)
|
||||||
import traceback
|
|
||||||
|
|
||||||
traceback.print_exc()
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
@ -524,15 +518,17 @@ class ExtractLook(publish.Extractor):
|
||||||
if do_maketx and ext != ".tx":
|
if do_maketx and ext != ".tx":
|
||||||
# Produce .tx file in staging if source file is not .tx
|
# Produce .tx file in staging if source file is not .tx
|
||||||
converted = os.path.join(staging, "resources", fname + ".tx")
|
converted = os.path.join(staging, "resources", fname + ".tx")
|
||||||
|
additional_args = [
|
||||||
|
"--sattrib",
|
||||||
|
"sourceHash",
|
||||||
|
texture_hash
|
||||||
|
]
|
||||||
if linearize:
|
if linearize:
|
||||||
self.log.info("tx: converting sRGB -> linear")
|
self.log.info("tx: converting sRGB -> linear")
|
||||||
colorconvert = "--colorconvert sRGB linear"
|
additional_args.extend(["--colorconvert", "sRGB", "linear"])
|
||||||
else:
|
|
||||||
colorconvert = ""
|
|
||||||
|
|
||||||
config_path = get_ocio_config_path("nuke-default")
|
config_path = get_ocio_config_path("nuke-default")
|
||||||
color_config = "--colorconfig {0}".format(config_path)
|
additional_args.extend(["--colorconfig", config_path])
|
||||||
# Ensure folder exists
|
# Ensure folder exists
|
||||||
if not os.path.exists(os.path.dirname(converted)):
|
if not os.path.exists(os.path.dirname(converted)):
|
||||||
os.makedirs(os.path.dirname(converted))
|
os.makedirs(os.path.dirname(converted))
|
||||||
|
|
@ -541,12 +537,8 @@ class ExtractLook(publish.Extractor):
|
||||||
maketx(
|
maketx(
|
||||||
filepath,
|
filepath,
|
||||||
converted,
|
converted,
|
||||||
# Include `source-hash` as string metadata
|
additional_args,
|
||||||
"--sattrib",
|
self.log
|
||||||
"sourceHash",
|
|
||||||
escape_space(texture_hash),
|
|
||||||
colorconvert,
|
|
||||||
color_config
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return converted, COPY, texture_hash
|
return converted, COPY, texture_hash
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
"""Collects published version of workfile and increments it.
|
||||||
|
|
||||||
|
For synchronization of published image and workfile version it is required
|
||||||
|
to store workfile version from workfile file name in context.data["version"].
|
||||||
|
In remote publishing this name is unreliable (artist might not follow naming
|
||||||
|
convention etc.), last published workfile version for particular workfile
|
||||||
|
subset is used instead.
|
||||||
|
|
||||||
|
This plugin runs only in remote publishing (eg. Webpublisher).
|
||||||
|
|
||||||
|
Requires:
|
||||||
|
context.data["assetEntity"]
|
||||||
|
|
||||||
|
Provides:
|
||||||
|
context["version"] - incremented latest published workfile version
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pyblish.api
|
||||||
|
|
||||||
|
from openpype.client import get_last_version_by_subset_name
|
||||||
|
|
||||||
|
|
||||||
|
class CollectPublishedVersion(pyblish.api.ContextPlugin):
|
||||||
|
"""Collects published version of workfile and increments it."""
|
||||||
|
|
||||||
|
order = pyblish.api.CollectorOrder + 0.190
|
||||||
|
label = "Collect published version"
|
||||||
|
hosts = ["photoshop"]
|
||||||
|
targets = ["remotepublish"]
|
||||||
|
|
||||||
|
def process(self, context):
|
||||||
|
workfile_subset_name = None
|
||||||
|
for instance in context:
|
||||||
|
if instance.data["family"] == "workfile":
|
||||||
|
workfile_subset_name = instance.data["subset"]
|
||||||
|
break
|
||||||
|
|
||||||
|
if not workfile_subset_name:
|
||||||
|
self.log.warning("No workfile instance found, "
|
||||||
|
"synchronization of version will not work.")
|
||||||
|
return
|
||||||
|
|
||||||
|
project_name = context.data["projectName"]
|
||||||
|
asset_doc = context.data["assetEntity"]
|
||||||
|
asset_id = asset_doc["_id"]
|
||||||
|
|
||||||
|
version_doc = get_last_version_by_subset_name(project_name,
|
||||||
|
workfile_subset_name,
|
||||||
|
asset_id)
|
||||||
|
version_int = 1
|
||||||
|
if version_doc:
|
||||||
|
version_int += int(version_doc["name"])
|
||||||
|
|
||||||
|
self.log.debug(f"Setting {version_int} to context.")
|
||||||
|
context.data["version"] = version_int
|
||||||
24
openpype/hosts/photoshop/plugins/publish/collect_version.py
Normal file
24
openpype/hosts/photoshop/plugins/publish/collect_version.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import pyblish.api
|
||||||
|
|
||||||
|
|
||||||
|
class CollectVersion(pyblish.api.InstancePlugin):
|
||||||
|
"""Collect version for publishable instances.
|
||||||
|
|
||||||
|
Used to synchronize version from workfile to all publishable instances:
|
||||||
|
- image (manually created or color coded)
|
||||||
|
- review
|
||||||
|
|
||||||
|
Dev comment:
|
||||||
|
Explicit collector created to control this from single place and not from
|
||||||
|
3 different.
|
||||||
|
"""
|
||||||
|
order = pyblish.api.CollectorOrder + 0.200
|
||||||
|
label = 'Collect Version'
|
||||||
|
|
||||||
|
hosts = ["photoshop"]
|
||||||
|
families = ["image", "review"]
|
||||||
|
|
||||||
|
def process(self, instance):
|
||||||
|
workfile_version = instance.context.data["version"]
|
||||||
|
self.log.debug(f"Applying version {workfile_version}")
|
||||||
|
instance.data["version"] = workfile_version
|
||||||
|
|
@ -187,7 +187,7 @@ class PypeCommands:
|
||||||
(to choose validator for example)
|
(to choose validator for example)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from openpype.hosts.webpublisher.cli_functions import (
|
from openpype.hosts.webpublisher.publish_functions import (
|
||||||
cli_publish_from_app
|
cli_publish_from_app
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@
|
||||||
"CollectReview": {
|
"CollectReview": {
|
||||||
"publish": true
|
"publish": true
|
||||||
},
|
},
|
||||||
|
"CollectVersion": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
"ValidateContainers": {
|
"ValidateContainers": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,21 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"key": "publish",
|
"key": "publish",
|
||||||
"label": "Active"
|
"label": "Active"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "CollectVersion",
|
||||||
|
"label": "Collect Version",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"label": "Synchronize version for image and review instances by workfile version."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"key": "enabled",
|
||||||
|
"label": "Enabled"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,25 @@ from openpype.tools.utils.models import (
|
||||||
ProjectModel,
|
ProjectModel,
|
||||||
ProjectSortFilterProxy
|
ProjectSortFilterProxy
|
||||||
)
|
)
|
||||||
|
import appdirs
|
||||||
|
from openpype.lib import JSONSettingRegistry
|
||||||
|
|
||||||
|
|
||||||
|
class TrayPublisherRegistry(JSONSettingRegistry):
|
||||||
|
"""Class handling OpenPype general settings registry.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
vendor (str): Name used for path construction.
|
||||||
|
product (str): Additional name used for path construction.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.vendor = "pypeclub"
|
||||||
|
self.product = "openpype"
|
||||||
|
name = "tray_publisher"
|
||||||
|
path = appdirs.user_data_dir(self.product, self.vendor)
|
||||||
|
super(TrayPublisherRegistry, self).__init__(name, path)
|
||||||
|
|
||||||
|
|
||||||
class StandaloneOverlayWidget(QtWidgets.QFrame):
|
class StandaloneOverlayWidget(QtWidgets.QFrame):
|
||||||
|
|
@ -82,6 +101,7 @@ class StandaloneOverlayWidget(QtWidgets.QFrame):
|
||||||
|
|
||||||
self._projects_view = projects_view
|
self._projects_view = projects_view
|
||||||
self._projects_model = projects_model
|
self._projects_model = projects_model
|
||||||
|
self._projects_proxy = projects_proxy
|
||||||
self._cancel_btn = cancel_btn
|
self._cancel_btn = cancel_btn
|
||||||
self._confirm_btn = confirm_btn
|
self._confirm_btn = confirm_btn
|
||||||
|
|
||||||
|
|
@ -90,6 +110,24 @@ class StandaloneOverlayWidget(QtWidgets.QFrame):
|
||||||
|
|
||||||
def showEvent(self, event):
|
def showEvent(self, event):
|
||||||
self._projects_model.refresh()
|
self._projects_model.refresh()
|
||||||
|
|
||||||
|
setting_registry = TrayPublisherRegistry()
|
||||||
|
try:
|
||||||
|
project_name = setting_registry.get_item("project_name")
|
||||||
|
except ValueError:
|
||||||
|
project_name = None
|
||||||
|
|
||||||
|
if project_name:
|
||||||
|
index = None
|
||||||
|
src_index = self._projects_model.find_project(project_name)
|
||||||
|
if src_index is not None:
|
||||||
|
index = self._projects_proxy.mapFromSource(src_index)
|
||||||
|
if index:
|
||||||
|
mode = (
|
||||||
|
QtCore.QItemSelectionModel.Select
|
||||||
|
| QtCore.QItemSelectionModel.Rows)
|
||||||
|
self._projects_view.selectionModel().select(index, mode)
|
||||||
|
|
||||||
self._cancel_btn.setVisible(self._project_name is not None)
|
self._cancel_btn.setVisible(self._project_name is not None)
|
||||||
super(StandaloneOverlayWidget, self).showEvent(event)
|
super(StandaloneOverlayWidget, self).showEvent(event)
|
||||||
|
|
||||||
|
|
@ -119,6 +157,9 @@ class StandaloneOverlayWidget(QtWidgets.QFrame):
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
self.project_selected.emit(project_name)
|
self.project_selected.emit(project_name)
|
||||||
|
|
||||||
|
setting_registry = TrayPublisherRegistry()
|
||||||
|
setting_registry.set_item("project_name", project_name)
|
||||||
|
|
||||||
|
|
||||||
class TrayPublishWindow(PublisherWindow):
|
class TrayPublishWindow(PublisherWindow):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,19 @@ class ProjectModel(QtGui.QStandardItemModel):
|
||||||
if new_items:
|
if new_items:
|
||||||
root_item.appendRows(new_items)
|
root_item.appendRows(new_items)
|
||||||
|
|
||||||
|
def find_project(self, project_name):
|
||||||
|
"""
|
||||||
|
Get index of 'project_name' value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_name (str):
|
||||||
|
Returns:
|
||||||
|
(QModelIndex)
|
||||||
|
"""
|
||||||
|
val = self._items_by_name.get(project_name)
|
||||||
|
if val:
|
||||||
|
return self.indexFromItem(val)
|
||||||
|
|
||||||
|
|
||||||
class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
|
class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue