AYON: Addon settings in OpenPype (#5347)

* copied addons from 'ayon-addon-settings'

* added AE, photoshop and harmony addon

* moved openpype to subfolder

* cleanup repository files

* updated create package script and README.md

* formatting fixes

* added cli flags to be able keep server structure

* print progress and output dir

* another formatting fixes
This commit is contained in:
Jakub Trllo 2023-07-26 14:08:42 +02:00 committed by GitHub
parent e6d9697e23
commit 2b37b8af48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
167 changed files with 15525 additions and 146 deletions

2
.gitignore vendored
View file

@ -37,7 +37,7 @@ Temporary Items
###########
/build
/dist/
/server_addon/package/*
/server_addon/packages/*
/vendor/bin/*
/vendor/python/*

View file

@ -1,5 +1,5 @@
# OpenPype addon for AYON server
Convert openpype into AYON addon which can be installed on AYON server. The versioning of the addon is following versioning of OpenPype.
# Addons for AYON server
Preparation of AYON addons based on OpenPype codebase. The output is a bunch of zip files in `./packages` directory that can be uploaded to AYON server. One of the packages is `openpype` which is OpenPype code converted to AYON addon. The addon is must have requirement to be able to use `ayon-launcher`. The versioning of `openpype` addon is following versioning of OpenPype. The other addons contain only settings models.
## Intro
OpenPype is transitioning to AYON, a dedicated server with its own database, moving away from MongoDB. During this transition period, OpenPype will remain compatible with both MongoDB and AYON. However, we will gradually update the codebase to align with AYON's data structure and separate individual components into addons.
@ -11,11 +11,24 @@ Since the implementation of the AYON Launcher is not yet fully completed, we wil
During this transitional period, the AYON Launcher addon will be a requirement as the entry point for using the AYON Launcher.
## How to start
There is a `create_ayon_addon.py` python file which contains logic how to create server addon from OpenPype codebase. Just run the code.
There is a `create_ayon_addons.py` python file which contains logic how to create server addon from OpenPype codebase. Just run the code.
```shell
./.poetry/bin/poetry run python ./server_addon/create_ayon_addon.py
./.poetry/bin/poetry run python ./server_addon/create_ayon_addons.py
```
It will create directory `./package/openpype/<OpenPype version>/*` folder with all files necessary for AYON server. You can then copy `./package/openpype/` to server addons, or zip the folder and upload it to AYON server. Restart server to update addons information, add the addon version to server bundle and set the bundle for production or staging usage.
It will create directory `./packages/<addon name>.zip` files for AYON server. You can then copy upload the zip files to AYON server. Restart server to update addons information, add the addon version to server bundle and set the bundle for production or staging usage.
Once addon is on server and is enabled, you can just run AYON launcher. Content will be downloaded and used automatically.
### Additional arguments
Additional arguments are useful for development purposes.
To skip zip creation to keep only server ready folder structure, pass `--skip-zip` argument.
```shell
./.poetry/bin/poetry run python ./server_addon/create_ayon_addons.py --skip-zip
```
To create both zips and keep folder structure, pass `--keep-sources` argument.
```shell
./.poetry/bin/poetry run python ./server_addon/create_ayon_addons.py --keep-sources
```

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,4 @@
AfterEffects Addon
===============
Integration with Adobe AfterEffects.

View file

@ -0,0 +1,15 @@
from ayon_server.addons import BaseServerAddon
from .settings import AfterEffectsSettings, DEFAULT_AFTEREFFECTS_SETTING
from .version import __version__
class AfterEffects(BaseServerAddon):
name = "aftereffects"
version = __version__
settings_model = AfterEffectsSettings
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_AFTEREFFECTS_SETTING)

View file

@ -0,0 +1,10 @@
from .main import (
AfterEffectsSettings,
DEFAULT_AFTEREFFECTS_SETTING,
)
__all__ = (
"AfterEffectsSettings",
"DEFAULT_AFTEREFFECTS_SETTING",
)

View file

@ -0,0 +1,16 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CreateRenderPlugin(BaseSettingsModel):
mark_for_review: bool = Field(True, title="Review")
defaults: list[str] = Field(default_factory=list,
title="Default Variants")
class AfterEffectsCreatorPlugins(BaseSettingsModel):
RenderCreator: CreateRenderPlugin = Field(
title="Create Render",
default_factory=CreateRenderPlugin,
)

View file

@ -0,0 +1,48 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings.validators import ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class AfterEffectsImageIOModel(BaseSettingsModel):
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)

View file

@ -0,0 +1,62 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
from .imageio import AfterEffectsImageIOModel
from .creator_plugins import AfterEffectsCreatorPlugins
from .publish_plugins import AfterEffectsPublishPlugins
from .workfile_builder import WorkfileBuilderPlugin
class AfterEffectsSettings(BaseSettingsModel):
"""AfterEffects Project Settings."""
imageio: AfterEffectsImageIOModel = Field(
default_factory=AfterEffectsImageIOModel,
title="OCIO config"
)
create: AfterEffectsCreatorPlugins = Field(
default_factory=AfterEffectsCreatorPlugins,
title="Creator plugins"
)
publish: AfterEffectsPublishPlugins = Field(
default_factory=AfterEffectsPublishPlugins,
title="Publish plugins"
)
workfile_builder: WorkfileBuilderPlugin = Field(
default_factory=WorkfileBuilderPlugin,
title="Workfile Builder"
)
DEFAULT_AFTEREFFECTS_SETTING = {
"create": {
"RenderCreator": {
"mark_for_review": True,
"defaults": [
"Main"
]
}
},
"publish": {
"CollectReview": {
"enabled": True
},
"ValidateSceneSettings": {
"enabled": True,
"optional": True,
"active": True,
"skip_resolution_check": [
".*"
],
"skip_timelines_check": [
".*"
]
}
},
"workfile_builder": {
"create_first_version": False,
"custom_templates": []
}
}

View file

@ -0,0 +1,36 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CollectReviewPluginModel(BaseSettingsModel):
enabled: bool = Field(True, title="Enabled")
class ValidateSceneSettingsPlugin(BaseSettingsModel):
"""Validate naming of products and layers""" #
_isGroup = True
enabled: bool = True
optional: bool = Field(False, title="Optional")
active: bool = Field(True, title="Active")
skip_resolution_check: list[str] = Field(
default_factory=list,
title="Skip Resolution Check for Tasks"
)
skip_timelines_check: list[str] = Field(
default_factory=list,
title="Skip Timeline Check for Tasks"
)
class AfterEffectsPublishPlugins(BaseSettingsModel):
CollectReview: CollectReviewPluginModel = Field(
default_facotory=CollectReviewPluginModel,
title="Collect Review"
)
ValidateSceneSettings: ValidateSceneSettingsPlugin = Field(
title="Validate Scene Settings",
default_factory=ValidateSceneSettingsPlugin,
)

View file

@ -0,0 +1,25 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel, MultiplatformPathModel
class CustomBuilderTemplate(BaseSettingsModel):
task_types: list[str] = Field(
default_factory=list,
title="Task types",
)
template_path: MultiplatformPathModel = Field(
default_factory=MultiplatformPathModel
)
class WorkfileBuilderPlugin(BaseSettingsModel):
_title = "Workfile Builder"
create_first_version: bool = Field(
False,
title="Create first workfile"
)
custom_templates: list[CustomBuilderTemplate] = Field(
default_factory=CustomBuilderTemplate
)

View file

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring addon version."""
__version__ = "0.1.0"

View file

@ -0,0 +1,153 @@
import os
import json
import copy
from ayon_server.addons import BaseServerAddon
from ayon_server.lib.postgres import Postgres
from .version import __version__
from .settings import ApplicationsAddonSettings, DEFAULT_VALUES
def get_enum_items_from_groups(groups):
label_by_name = {}
for group in groups:
group_name = group["name"]
group_label = group["label"] or group_name
for variant in group["variants"]:
variant_name = variant["name"]
if not variant_name:
continue
variant_label = variant["label"] or variant_name
full_name = f"{group_name}/{variant_name}"
full_label = f"{group_label} {variant_label}"
label_by_name[full_name] = full_label
enum_items = []
for full_name in sorted(label_by_name):
enum_items.append(
{"value": full_name, "label": label_by_name[full_name]}
)
return enum_items
class ApplicationsAddon(BaseServerAddon):
name = "applications"
version = __version__
settings_model = ApplicationsAddonSettings
async def get_default_settings(self):
applications_path = os.path.join(self.addon_dir, "applications.json")
tools_path = os.path.join(self.addon_dir, "tools.json")
default_values = copy.deepcopy(DEFAULT_VALUES)
with open(applications_path, "r") as stream:
default_values.update(json.load(stream))
with open(tools_path, "r") as stream:
default_values.update(json.load(stream))
return self.get_settings_model()(**default_values)
async def setup(self):
need_restart = await self.create_applications_attribute()
if need_restart:
self.request_server_restart()
async def create_applications_attribute(self) -> bool:
"""Make sure there are required attributes which ftrack addon needs.
Returns:
bool: 'True' if an attribute was created or updated.
"""
settings_model = await self.get_studio_settings()
studio_settings = settings_model.dict()
applications = studio_settings["applications"]
_applications = applications.pop("additional_apps")
for name, value in applications.items():
value["name"] = name
_applications.append(value)
query = "SELECT name, position, scope, data from public.attributes"
apps_attrib_name = "applications"
tools_attrib_name = "tools"
apps_enum = get_enum_items_from_groups(_applications)
tools_enum = get_enum_items_from_groups(studio_settings["tool_groups"])
apps_attribute_data = {
"type": "list_of_strings",
"title": "Applications",
"enum": apps_enum
}
tools_attribute_data = {
"type": "list_of_strings",
"title": "Tools",
"enum": tools_enum
}
apps_scope = ["project"]
tools_scope = ["project", "folder", "task"]
apps_match_position = None
apps_matches = False
tools_match_position = None
tools_matches = False
position = 1
async for row in Postgres.iterate(query):
position += 1
if row["name"] == apps_attrib_name:
# Check if scope is matching ftrack addon requirements
if (
set(row["scope"]) == set(apps_scope)
and row["data"].get("enum") == apps_enum
):
apps_matches = True
apps_match_position = row["position"]
elif row["name"] == tools_attrib_name:
if (
set(row["scope"]) == set(tools_scope)
and row["data"].get("enum") == tools_enum
):
tools_matches = True
tools_match_position = row["position"]
if apps_matches and tools_matches:
return False
postgre_query = "\n".join((
"INSERT INTO public.attributes",
" (name, position, scope, data)",
"VALUES",
" ($1, $2, $3, $4)",
"ON CONFLICT (name)",
"DO UPDATE SET",
" scope = $3,",
" data = $4",
))
if not apps_matches:
# Reuse position from found attribute
if apps_match_position is None:
apps_match_position = position
position += 1
await Postgres.execute(
postgre_query,
apps_attrib_name,
apps_match_position,
apps_scope,
apps_attribute_data,
)
if not tools_matches:
if tools_match_position is None:
tools_match_position = position
position += 1
await Postgres.execute(
postgre_query,
tools_attrib_name,
tools_match_position,
tools_scope,
tools_attribute_data,
)
return True

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
import json
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
from ayon_server.exceptions import BadRequestException
def validate_json_dict(value):
if not value.strip():
return "{}"
try:
converted_value = json.loads(value)
success = isinstance(converted_value, dict)
except json.JSONDecodeError as exc:
print(exc)
success = False
if not success:
raise BadRequestException(
"Environment's can't be parsed as json object"
)
return value
class MultiplatformStrList(BaseSettingsModel):
windows: list[str] = Field(default_factory=list, title="Windows")
linux: list[str] = Field(default_factory=list, title="Linux")
darwin: list[str] = Field(default_factory=list, title="MacOS")
class AppVariant(BaseSettingsModel):
name: str = Field("", title="Name")
label: str = Field("", title="Label")
executables: MultiplatformStrList = Field(
default_factory=MultiplatformStrList, title="Executables"
)
arguments: MultiplatformStrList = Field(
default_factory=MultiplatformStrList, title="Arguments"
)
environment: str = Field("{}", title="Environment", widget="textarea")
@validator("environment")
def validate_json(cls, value):
return validate_json_dict(value)
class AppVariantWithPython(AppVariant):
use_python_2: bool = Field(False, title="Use Python 2")
class AppGroup(BaseSettingsModel):
enabled: bool = Field(True)
label: str = Field("", title="Label")
host_name: str = Field("", title="Host name")
icon: str = Field("", title="Icon")
environment: str = Field("{}", title="Environment", widget="textarea")
variants: list[AppVariant] = Field(
default_factory=list,
title="Variants",
description="Different variants of the applications",
section="Variants",
)
@validator("variants")
def validate_unique_name(cls, value):
ensure_unique_names(value)
return value
class AppGroupWithPython(AppGroup):
variants: list[AppVariantWithPython] = Field(
default_factory=list,
title="Variants",
description="Different variants of the applications",
section="Variants",
)
class AdditionalAppGroup(BaseSettingsModel):
enabled: bool = Field(True)
name: str = Field("", title="Name")
label: str = Field("", title="Label")
host_name: str = Field("", title="Host name")
icon: str = Field("", title="Icon")
environment: str = Field("{}", title="Environment", widget="textarea")
variants: list[AppVariantWithPython] = Field(
default_factory=list,
title="Variants",
description="Different variants of the applications",
section="Variants",
)
@validator("variants")
def validate_unique_name(cls, value):
ensure_unique_names(value)
return value
class ToolVariantModel(BaseSettingsModel):
name: str = Field("", title="Name")
label: str = Field("", title="Label")
host_names: list[str] = Field(default_factory=list, title="Hosts")
# TODO use applications enum if possible
app_variants: list[str] = Field(default_factory=list, title="Applications")
environment: str = Field("{}", title="Environments", widget="textarea")
@validator("environment")
def validate_json(cls, value):
return validate_json_dict(value)
class ToolGroupModel(BaseSettingsModel):
name: str = Field("", title="Name")
label: str = Field("", title="Label")
environment: str = Field("{}", title="Environments", widget="textarea")
variants: list[ToolVariantModel] = Field(
default_factory=ToolVariantModel
)
@validator("environment")
def validate_json(cls, value):
return validate_json_dict(value)
@validator("variants")
def validate_unique_name(cls, value):
ensure_unique_names(value)
return value
class ApplicationsSettings(BaseSettingsModel):
"""Applications settings"""
maya: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Autodesk Maya")
adsk_3dsmax: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Autodesk 3ds Max")
flame: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Autodesk Flame")
nuke: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Nuke")
nukeassist: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Nuke Assist")
nukex: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Nuke X")
nukestudio: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Nuke Studio")
hiero: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Hiero")
fusion: AppGroup = Field(
default_factory=AppGroupWithPython, title="Fusion")
resolve: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Resolve")
houdini: AppGroupWithPython = Field(
default_factory=AppGroupWithPython, title="Houdini")
blender: AppGroup = Field(
default_factory=AppGroupWithPython, title="Blender")
harmony: AppGroup = Field(
default_factory=AppGroupWithPython, title="Harmony")
tvpaint: AppGroup = Field(
default_factory=AppGroupWithPython, title="TVPaint")
photoshop: AppGroup = Field(
default_factory=AppGroupWithPython, title="Adobe Photoshop")
aftereffects: AppGroup = Field(
default_factory=AppGroupWithPython, title="Adobe After Effects")
celaction: AppGroup = Field(
default_factory=AppGroupWithPython, title="Celaction 2D")
unreal: AppGroup = Field(
default_factory=AppGroupWithPython, title="Unreal Editor")
additional_apps: list[AdditionalAppGroup] = Field(
default_factory=list, title="Additional Applications")
@validator("additional_apps")
def validate_unique_name(cls, value):
ensure_unique_names(value)
return value
class ApplicationsAddonSettings(BaseSettingsModel):
applications: ApplicationsSettings = Field(
default_factory=ApplicationsSettings,
title="Applications",
scope=["studio"]
)
tool_groups: list[ToolGroupModel] = Field(
default_factory=list,
scope=["studio"]
)
only_available: bool = Field(
True, title="Show only available applications")
@validator("tool_groups")
def validate_unique_name(cls, value):
ensure_unique_names(value)
return value
DEFAULT_VALUES = {
"only_available": False
}

View file

@ -0,0 +1,55 @@
{
"tool_groups": [
{
"environment": "{\n \"MTOA\": \"{STUDIO_SOFTWARE}/arnold/mtoa_{MAYA_VERSION}_{MTOA_VERSION}\",\n \"MAYA_RENDER_DESC_PATH\": \"{MTOA}\",\n \"MAYA_MODULE_PATH\": \"{MTOA}\",\n \"ARNOLD_PLUGIN_PATH\": \"{MTOA}/shaders\",\n \"MTOA_EXTENSIONS_PATH\": {\n \"darwin\": \"{MTOA}/extensions\",\n \"linux\": \"{MTOA}/extensions\",\n \"windows\": \"{MTOA}/extensions\"\n },\n \"MTOA_EXTENSIONS\": {\n \"darwin\": \"{MTOA}/extensions\",\n \"linux\": \"{MTOA}/extensions\",\n \"windows\": \"{MTOA}/extensions\"\n },\n \"DYLD_LIBRARY_PATH\": {\n \"darwin\": \"{MTOA}/bin\"\n },\n \"PATH\": {\n \"windows\": \"{PATH};{MTOA}/bin\"\n }\n}",
"name": "mtoa",
"label": "Autodesk Arnold",
"variants": [
{
"host_names": [],
"app_variants": [],
"environment": "{\n \"MTOA_VERSION\": \"3.2\"\n}",
"name": "3-2",
"label": "3.2"
},
{
"host_names": [],
"app_variants": [],
"environment": "{\n \"MTOA_VERSION\": \"3.1\"\n}",
"name": "3-1",
"label": "3.1"
}
]
},
{
"environment": "{}",
"name": "vray",
"label": "Chaos Group Vray",
"variants": []
},
{
"environment": "{}",
"name": "yeti",
"label": "Peregrine Labs Yeti",
"variants": []
},
{
"environment": "{}",
"name": "renderman",
"label": "Pixar Renderman",
"variants": [
{
"host_names": [
"maya"
],
"app_variants": [
"maya/2022"
],
"environment": "{\n \"RFMTREE\": {\n \"windows\": \"C:\\\\Program Files\\\\Pixar\\\\RenderManForMaya-24.3\",\n \"darwin\": \"/Applications/Pixar/RenderManForMaya-24.3\",\n \"linux\": \"/opt/pixar/RenderManForMaya-24.3\"\n },\n \"RMANTREE\": {\n \"windows\": \"C:\\\\Program Files\\\\Pixar\\\\RenderManProServer-24.3\",\n \"darwin\": \"/Applications/Pixar/RenderManProServer-24.3\",\n \"linux\": \"/opt/pixar/RenderManProServer-24.3\"\n }\n}",
"name": "24-3-maya",
"label": "24.3 RFM"
}
]
}
]
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,19 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import BlenderSettings, DEFAULT_VALUES
class BlenderAddon(BaseServerAddon):
name = "blender"
title = "Blender"
version = __version__
settings_model: Type[BlenderSettings] = BlenderSettings
frontend_scopes = {}
services = {}
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,10 @@
from .main import (
BlenderSettings,
DEFAULT_VALUES,
)
__all__ = (
"BlenderSettings",
"DEFAULT_VALUES",
)

View file

@ -0,0 +1,48 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings.validators import ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class BlenderImageIOModel(BaseSettingsModel):
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)

View file

@ -0,0 +1,53 @@
from pydantic import Field
from ayon_server.settings import (
BaseSettingsModel,
TemplateWorkfileBaseOptions,
)
from .imageio import BlenderImageIOModel
from .publish_plugins import (
PublishPuginsModel,
DEFAULT_BLENDER_PUBLISH_SETTINGS
)
class UnitScaleSettingsModel(BaseSettingsModel):
enabled: bool = Field(True, title="Enabled")
apply_on_opening: bool = Field(
False, title="Apply on Opening Existing Files")
base_file_unit_scale: float = Field(
1.0, title="Base File Unit Scale"
)
class BlenderSettings(BaseSettingsModel):
unit_scale_settings: UnitScaleSettingsModel = Field(
default_factory=UnitScaleSettingsModel,
title="Set Unit Scale"
)
imageio: BlenderImageIOModel = Field(
default_factory=BlenderImageIOModel,
title="Color Management (ImageIO)"
)
workfile_builder: TemplateWorkfileBaseOptions = Field(
default_factory=TemplateWorkfileBaseOptions,
title="Workfile Builder"
)
publish: PublishPuginsModel = Field(
default_factory=PublishPuginsModel,
title="Publish Plugins"
)
DEFAULT_VALUES = {
"unit_scale_settings": {
"enabled": True,
"apply_on_opening": False,
"base_file_unit_scale": 0.01
},
"publish": DEFAULT_BLENDER_PUBLISH_SETTINGS,
"workfile_builder": {
"create_first_version": False,
"custom_templates": []
}
}

View file

@ -0,0 +1,273 @@
import json
from pydantic import Field, validator
from ayon_server.exceptions import BadRequestException
from ayon_server.settings import BaseSettingsModel
def validate_json_dict(value):
if not value.strip():
return "{}"
try:
converted_value = json.loads(value)
success = isinstance(converted_value, dict)
except json.JSONDecodeError:
success = False
if not success:
raise BadRequestException(
"Environment's can't be parsed as json object"
)
return value
class ValidatePluginModel(BaseSettingsModel):
enabled: bool = Field(True)
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
class ExtractBlendModel(BaseSettingsModel):
enabled: bool = Field(True)
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
families: list[str] = Field(
default_factory=list,
title="Families"
)
class ExtractPlayblastModel(BaseSettingsModel):
enabled: bool = Field(True)
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
presets: str = Field("", title="Presets", widget="textarea")
@validator("presets")
def validate_json(cls, value):
return validate_json_dict(value)
class PublishPuginsModel(BaseSettingsModel):
ValidateCameraZeroKeyframe: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Validate Camera Zero Keyframe",
section="Validators"
)
ValidateMeshHasUvs: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Validate Mesh Has Uvs"
)
ValidateMeshNoNegativeScale: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Validate Mesh No Negative Scale"
)
ValidateTransformZero: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Validate Transform Zero"
)
ValidateNoColonsInName: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Validate No Colons In Name"
)
ExtractBlend: ExtractBlendModel = Field(
default_factory=ExtractBlendModel,
title="Extract Blend",
section="Extractors"
)
ExtractFBX: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Extract FBX"
)
ExtractABC: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Extract ABC"
)
ExtractBlendAnimation: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Extract Blend Animation"
)
ExtractAnimationFBX: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Extract Animation FBX"
)
ExtractCamera: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Extract Camera"
)
ExtractLayout: ValidatePluginModel = Field(
default_factory=ValidatePluginModel,
title="Extract Layout"
)
ExtractThumbnail: ExtractPlayblastModel = Field(
default_factory=ExtractPlayblastModel,
title="Extract Thumbnail"
)
ExtractPlayblast: ExtractPlayblastModel = Field(
default_factory=ExtractPlayblastModel,
title="Extract Playblast"
)
DEFAULT_BLENDER_PUBLISH_SETTINGS = {
"ValidateCameraZeroKeyframe": {
"enabled": True,
"optional": True,
"active": True
},
"ValidateMeshHasUvs": {
"enabled": True,
"optional": True,
"active": True
},
"ValidateMeshNoNegativeScale": {
"enabled": True,
"optional": False,
"active": True
},
"ValidateTransformZero": {
"enabled": True,
"optional": False,
"active": True
},
"ValidateNoColonsInName": {
"enabled": True,
"optional": False,
"active": True
},
"ExtractBlend": {
"enabled": True,
"optional": True,
"active": True,
"families": [
"model",
"camera",
"rig",
"action",
"layout"
]
},
"ExtractFBX": {
"enabled": True,
"optional": True,
"active": False
},
"ExtractABC": {
"enabled": True,
"optional": True,
"active": False
},
"ExtractBlendAnimation": {
"enabled": True,
"optional": True,
"active": True
},
"ExtractAnimationFBX": {
"enabled": True,
"optional": True,
"active": False
},
"ExtractCamera": {
"enabled": True,
"optional": True,
"active": True
},
"ExtractLayout": {
"enabled": True,
"optional": True,
"active": False
},
"ExtractThumbnail": {
"enabled": True,
"optional": True,
"active": True,
"presets": json.dumps(
{
"model": {
"image_settings": {
"file_format": "JPEG",
"color_mode": "RGB",
"quality": 100
},
"display_options": {
"shading": {
"light": "STUDIO",
"studio_light": "Default",
"type": "SOLID",
"color_type": "OBJECT",
"show_xray": False,
"show_shadows": False,
"show_cavity": True
},
"overlay": {
"show_overlays": False
}
}
},
"rig": {
"image_settings": {
"file_format": "JPEG",
"color_mode": "RGB",
"quality": 100
},
"display_options": {
"shading": {
"light": "STUDIO",
"studio_light": "Default",
"type": "SOLID",
"color_type": "OBJECT",
"show_xray": True,
"show_shadows": False,
"show_cavity": False
},
"overlay": {
"show_overlays": True,
"show_ortho_grid": False,
"show_floor": False,
"show_axis_x": False,
"show_axis_y": False,
"show_axis_z": False,
"show_text": False,
"show_stats": False,
"show_cursor": False,
"show_annotation": False,
"show_extras": False,
"show_relationship_lines": False,
"show_outline_selected": False,
"show_motion_paths": False,
"show_object_origins": False,
"show_bones": True
}
}
}
},
indent=4,
)
},
"ExtractPlayblast": {
"enabled": True,
"optional": True,
"active": True,
"presets": json.dumps(
{
"default": {
"image_settings": {
"file_format": "PNG",
"color_mode": "RGB",
"color_depth": "8",
"compression": 15
},
"display_options": {
"shading": {
"type": "MATERIAL",
"render_pass": "COMBINED"
},
"overlay": {
"show_overlays": False
}
}
}
},
indent=4
)
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,19 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import CelActionSettings, DEFAULT_VALUES
class CelActionAddon(BaseServerAddon):
name = "celaction"
title = "CelAction"
version = __version__
settings_model: Type[CelActionSettings] = CelActionSettings
frontend_scopes = {}
services = {}
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,48 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings.validators import ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class CelActionImageIOModel(BaseSettingsModel):
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)

View file

@ -0,0 +1,92 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
from .imageio import CelActionImageIOModel
class CollectRenderPathModel(BaseSettingsModel):
output_extension: str = Field(
"",
title="Output render file extension"
)
anatomy_template_key_render_files: str = Field(
"",
title="Anatomy template key: render files"
)
anatomy_template_key_metadata: str = Field(
"",
title="Anatomy template key: metadata job file"
)
def _workfile_submit_overrides():
return [
{
"value": "render_chunk",
"label": "Pass chunk size"
},
{
"value": "frame_range",
"label": "Pass frame range"
},
{
"value": "resolution",
"label": "Pass resolution"
}
]
class WorkfileModel(BaseSettingsModel):
submission_overrides: list[str] = Field(
default_factory=list,
title="Submission workfile overrides",
enum_resolver=_workfile_submit_overrides
)
class PublishPuginsModel(BaseSettingsModel):
CollectRenderPath: CollectRenderPathModel = Field(
default_factory=CollectRenderPathModel,
title="Collect Render Path"
)
class CelActionSettings(BaseSettingsModel):
imageio: CelActionImageIOModel = Field(
default_factory=CelActionImageIOModel,
title="Color Management (ImageIO)"
)
workfile: WorkfileModel = Field(
title="Workfile"
)
publish: PublishPuginsModel = Field(
default_factory=PublishPuginsModel,
title="Publish plugins",
)
DEFAULT_VALUES = {
"imageio": {
"ocio_config": {
"enabled": False,
"filepath": []
},
"file_rules": {
"enabled": False,
"rules": []
}
},
"workfile": {
"submission_overrides": [
"render_chunk",
"frame_range",
"resolution"
]
},
"publish": {
"CollectRenderPath": {
"output_extension": "png",
"anatomy_template_key_render_files": "render",
"anatomy_template_key_metadata": "render"
}
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,15 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import ClockifySettings
class ClockifyAddon(BaseServerAddon):
name = "clockify"
title = "Clockify"
version = __version__
settings_model: Type[ClockifySettings] = ClockifySettings
frontend_scopes = {}
services = {}

View file

@ -0,0 +1,9 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class ClockifySettings(BaseSettingsModel):
workspace_name: str = Field(
"",
title="Workspace name"
)

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,14 @@
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import CoreSettings, DEFAULT_VALUES
class CoreAddon(BaseServerAddon):
name = "core"
version = __version__
settings_model = CoreSettings
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,7 @@
from .main import CoreSettings, DEFAULT_VALUES
__all__ = (
"CoreSettings",
"DEFAULT_VALUES",
)

View file

@ -0,0 +1,160 @@
import json
from pydantic import Field, validator
from ayon_server.settings import (
BaseSettingsModel,
MultiplatformPathListModel,
ensure_unique_names,
)
from ayon_server.exceptions import BadRequestException
from .publish_plugins import PublishPuginsModel, DEFAULT_PUBLISH_VALUES
from .tools import GlobalToolsModel, DEFAULT_TOOLS_VALUES
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class CoreImageIOFileRulesModel(BaseSettingsModel):
activate_global_file_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class CoreImageIOConfigModel(BaseSettingsModel):
filepath: list[str] = Field(default_factory=list, title="Config path")
class CoreImageIOBaseModel(BaseSettingsModel):
activate_global_color_management: bool = Field(
False,
title="Override global OCIO config"
)
ocio_config: CoreImageIOConfigModel = Field(
default_factory=CoreImageIOConfigModel, title="OCIO config"
)
file_rules: CoreImageIOFileRulesModel = Field(
default_factory=CoreImageIOFileRulesModel, title="File Rules"
)
class CoreSettings(BaseSettingsModel):
studio_name: str = Field("", title="Studio name")
studio_code: str = Field("", title="Studio code")
environments: str = Field(
"{}",
title="Global environment variables",
widget="textarea",
scope=["studio"],
)
tools: GlobalToolsModel = Field(
default_factory=GlobalToolsModel,
title="Tools"
)
imageio: CoreImageIOBaseModel = Field(
default_factory=CoreImageIOBaseModel,
title="Color Management (ImageIO)"
)
publish: PublishPuginsModel = Field(
default_factory=PublishPuginsModel,
title="Publish plugins"
)
project_plugins: MultiplatformPathListModel = Field(
default_factory=MultiplatformPathListModel,
title="Additional Project Plugin Paths",
)
project_folder_structure: str = Field(
"{}",
widget="textarea",
title="Project folder structure",
section="---"
)
project_environments: str = Field(
"{}",
widget="textarea",
title="Project environments",
section="---"
)
@validator(
"environments",
"project_folder_structure",
"project_environments")
def validate_json(cls, value):
if not value.strip():
return "{}"
try:
converted_value = json.loads(value)
success = isinstance(converted_value, dict)
except json.JSONDecodeError:
success = False
if not success:
raise BadRequestException(
"Environment's can't be parsed as json object"
)
return value
DEFAULT_VALUES = {
"imageio": {
"activate_global_color_management": False,
"ocio_config": {
"filepath": [
"{BUILTIN_OCIO_ROOT}/aces_1.2/config.ocio",
"{BUILTIN_OCIO_ROOT}/nuke-default/config.ocio"
]
},
"file_rules": {
"activate_global_file_rules": False,
"rules": [
{
"name": "example",
"pattern": ".*(beauty).*",
"colorspace": "ACES - ACEScg",
"ext": "exr"
}
]
}
},
"studio_name": "",
"studio_code": "",
"environments": "{}",
"tools": DEFAULT_TOOLS_VALUES,
"publish": DEFAULT_PUBLISH_VALUES,
"project_folder_structure": json.dumps({
"__project_root__": {
"prod": {},
"resources": {
"footage": {
"plates": {},
"offline": {}
},
"audio": {},
"art_dept": {}
},
"editorial": {},
"assets": {
"characters": {},
"locations": {}
},
"shots": {}
}
}, indent=4),
"project_plugins": {
"windows": [],
"darwin": [],
"linux": []
},
"project_environments": "{}"
}

View file

@ -0,0 +1,959 @@
from pydantic import Field, validator
from ayon_server.settings import (
BaseSettingsModel,
MultiplatformPathModel,
normalize_name,
ensure_unique_names,
task_types_enum,
)
from ayon_server.types import ColorRGBA_uint8
class ValidateBaseModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
optional: bool = Field(True, title="Optional")
active: bool = Field(True, title="Active")
class CollectAnatomyInstanceDataModel(BaseSettingsModel):
_isGroup = True
follow_workfile_version: bool = Field(
True, title="Collect Anatomy Instance Data"
)
class CollectAudioModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
audio_product_name: str = Field(
"", title="Name of audio variant"
)
class CollectSceneVersionModel(BaseSettingsModel):
_isGroup = True
hosts: list[str] = Field(
default_factory=list,
title="Host names"
)
skip_hosts_headless_publish: list[str] = Field(
default_factory=list,
title="Skip for host if headless publish"
)
class CollectCommentPIModel(BaseSettingsModel):
enabled: bool = Field(True)
families: list[str] = Field(default_factory=list, title="Families")
class CollectFramesFixDefModel(BaseSettingsModel):
enabled: bool = Field(True)
rewrite_version_enable: bool = Field(
True,
title="Show 'Rewrite latest version' toggle"
)
class ValidateIntentProfile(BaseSettingsModel):
_layout = "expanded"
hosts: list[str] = Field(default_factory=list, title="Host names")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(default_factory=list, title="Task names")
# TODO This was 'validate' in v3
validate_intent: bool = Field(True, title="Validate")
class ValidateIntentModel(BaseSettingsModel):
"""Validate if Publishing intent was selected.
It is possible to disable validation for specific publishing context
with profiles.
"""
_isGroup = True
enabled: bool = Field(False)
profiles: list[ValidateIntentProfile] = Field(default_factory=list)
class ExtractThumbnailFFmpegModel(BaseSettingsModel):
_layout = "expanded"
input: list[str] = Field(
default_factory=list,
title="FFmpeg input arguments"
)
output: list[str] = Field(
default_factory=list,
title="FFmpeg input arguments"
)
class ExtractThumbnailModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
ffmpeg_args: ExtractThumbnailFFmpegModel = Field(
default_factory=ExtractThumbnailFFmpegModel
)
def _extract_oiio_transcoding_type():
return [
{"value": "colorspace", "label": "Use Colorspace"},
{"value": "display", "label": "Use Display&View"}
]
class OIIOToolArgumentsModel(BaseSettingsModel):
additional_command_args: list[str] = Field(
default_factory=list, title="Arguments")
class ExtractOIIOTranscodeOutputModel(BaseSettingsModel):
extension: str = Field("", title="Extension")
transcoding_type: str = Field(
"colorspace",
title="Transcoding type",
enum_resolver=_extract_oiio_transcoding_type
)
colorspace: str = Field("", title="Colorspace")
display: str = Field("", title="Display")
view: str = Field("", title="View")
oiiotool_args: OIIOToolArgumentsModel = Field(
default_factory=OIIOToolArgumentsModel,
title="OIIOtool arguments")
tags: list[str] = Field(default_factory=list, title="Tags")
custom_tags: list[str] = Field(default_factory=list, title="Custom Tags")
class ExtractOIIOTranscodeProfileModel(BaseSettingsModel):
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
hosts: list[str] = Field(
default_factory=list,
title="Host names"
)
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(
default_factory=list,
title="Task names"
)
product_names: list[str] = Field(
default_factory=list,
title="Product names"
)
delete_original: bool = Field(
True,
title="Delete Original Representation"
)
outputs: list[ExtractOIIOTranscodeOutputModel] = Field(
default_factory=list,
title="Output Definitions",
)
class ExtractOIIOTranscodeModel(BaseSettingsModel):
enabled: bool = Field(True)
profiles: list[ExtractOIIOTranscodeProfileModel] = Field(
default_factory=list, title="Profiles"
)
# --- [START] Extract Review ---
class ExtractReviewFFmpegModel(BaseSettingsModel):
video_filters: list[str] = Field(
default_factory=list,
title="Video filters"
)
audio_filters: list[str] = Field(
default_factory=list,
title="Audio filters"
)
input: list[str] = Field(
default_factory=list,
title="Input arguments"
)
output: list[str] = Field(
default_factory=list,
title="Output arguments"
)
def extract_review_filter_enum():
return [
{
"value": "everytime",
"label": "Always"
},
{
"value": "single_frame",
"label": "Only if input has 1 image frame"
},
{
"value": "multi_frame",
"label": "Only if input is video or sequence of frames"
}
]
class ExtractReviewFilterModel(BaseSettingsModel):
families: list[str] = Field(default_factory=list, title="Families")
product_names: list[str] = Field(
default_factory=list, title="Product names")
custom_tags: list[str] = Field(default_factory=list, title="Custom Tags")
single_frame_filter: str = Field(
"everytime",
description=(
"Use output <b>always</b> / only if input <b>is 1 frame</b>"
" image / only if has <b>2+ frames</b> or <b>is video</b>"
),
enum_resolver=extract_review_filter_enum
)
class ExtractReviewLetterBox(BaseSettingsModel):
enabled: bool = Field(True)
ratio: float = Field(
0.0,
title="Ratio",
ge=0.0,
le=10000.0
)
fill_color: ColorRGBA_uint8 = Field(
(0, 0, 0, 0.0),
title="Fill Color"
)
line_thickness: int = Field(
0,
title="Line Thickness",
ge=0,
le=1000
)
line_color: ColorRGBA_uint8 = Field(
(0, 0, 0, 0.0),
title="Line Color"
)
class ExtractReviewOutputDefModel(BaseSettingsModel):
_layout = "expanded"
name: str = Field("", title="Name")
ext: str = Field("", title="Output extension")
# TODO use some different source of tags
tags: list[str] = Field(default_factory=list, title="Tags")
burnins: list[str] = Field(
default_factory=list, title="Link to a burnin by name"
)
ffmpeg_args: ExtractReviewFFmpegModel = Field(
default_factory=ExtractReviewFFmpegModel,
title="FFmpeg arguments"
)
filter: ExtractReviewFilterModel = Field(
default_factory=ExtractReviewFilterModel,
title="Additional output filtering"
)
overscan_crop: str = Field(
"",
title="Overscan crop",
description=(
"Crop input overscan. See the documentation for more information."
)
)
overscan_color: ColorRGBA_uint8 = Field(
(0, 0, 0, 0.0),
title="Overscan color",
description=(
"Overscan color is used when input aspect ratio is not"
" same as output aspect ratio."
)
)
width: int = Field(
0,
ge=0,
le=100000,
title="Output width",
description=(
"Width and Height must be both set to higher"
" value than 0 else source resolution is used."
)
)
height: int = Field(
0,
title="Output height",
ge=0,
le=100000,
)
scale_pixel_aspect: bool = Field(
True,
title="Scale pixel aspect",
description=(
"Rescale input when it's pixel aspect ratio is not 1."
" Usefull for anamorph reviews."
)
)
bg_color: ColorRGBA_uint8 = Field(
(0, 0, 0, 0.0),
description=(
"Background color is used only when input have transparency"
" and Alpha is higher than 0."
),
title="Background color",
)
letter_box: ExtractReviewLetterBox = Field(
default_factory=ExtractReviewLetterBox,
title="Letter Box"
)
@validator("name")
def validate_name(cls, value):
"""Ensure name does not contain weird characters"""
return normalize_name(value)
class ExtractReviewProfileModel(BaseSettingsModel):
_layout = "expanded"
product_types: list[str] = Field(
default_factory=list, title="Product types"
)
# TODO use hosts enum
hosts: list[str] = Field(
default_factory=list, title="Host names"
)
outputs: list[ExtractReviewOutputDefModel] = Field(
default_factory=list, title="Output Definitions"
)
@validator("outputs")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class ExtractReviewModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
profiles: list[ExtractReviewProfileModel] = Field(
default_factory=list,
title="Profiles"
)
# --- [END] Extract Review ---
# --- [Start] Extract Burnin ---
class ExtractBurninOptionsModel(BaseSettingsModel):
font_size: int = Field(0, ge=0, title="Font size")
font_color: ColorRGBA_uint8 = Field(
(255, 255, 255, 1.0),
title="Font color"
)
bg_color: ColorRGBA_uint8 = Field(
(0, 0, 0, 1.0),
title="Background color"
)
x_offset: int = Field(0, title="X Offset")
y_offset: int = Field(0, title="Y Offset")
bg_padding: int = Field(0, title="Padding around text")
font_filepath: MultiplatformPathModel = Field(
default_factory=MultiplatformPathModel,
title="Font file path"
)
class ExtractBurninDefFilter(BaseSettingsModel):
families: list[str] = Field(
default_factory=list,
title="Families"
)
tags: list[str] = Field(
default_factory=list,
title="Tags"
)
class ExtractBurninDef(BaseSettingsModel):
_isGroup = True
_layout = "expanded"
name: str = Field("")
TOP_LEFT: str = Field("", topic="Top Left")
TOP_CENTERED: str = Field("", topic="Top Centered")
TOP_RIGHT: str = Field("", topic="Top Right")
BOTTOM_LEFT: str = Field("", topic="Bottom Left")
BOTTOM_CENTERED: str = Field("", topic="Bottom Centered")
BOTTOM_RIGHT: str = Field("", topic="Bottom Right")
filter: ExtractBurninDefFilter = Field(
default_factory=ExtractBurninDefFilter,
title="Additional filtering"
)
@validator("name")
def validate_name(cls, value):
"""Ensure name does not contain weird characters"""
return normalize_name(value)
class ExtractBurninProfile(BaseSettingsModel):
_layout = "expanded"
product_types: list[str] = Field(
default_factory=list,
title="Produt types"
)
hosts: list[str] = Field(
default_factory=list,
title="Host names"
)
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(
default_factory=list,
title="Task names"
)
product_names: list[str] = Field(
default_factory=list,
title="Product names"
)
burnins: list[ExtractBurninDef] = Field(
default_factory=list,
title="Burnins"
)
@validator("burnins")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class ExtractBurninModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
options: ExtractBurninOptionsModel = Field(
default_factory=ExtractBurninOptionsModel,
title="Burnin formatting options"
)
profiles: list[ExtractBurninProfile] = Field(
default_factory=list,
title="Profiles"
)
# --- [END] Extract Burnin ---
class PreIntegrateThumbnailsProfile(BaseSettingsModel):
_isGroup = True
product_types: list[str] = Field(
default_factory=list,
title="Product types",
)
hosts: list[str] = Field(
default_factory=list,
title="Hosts",
)
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
product_names: list[str] = Field(
default_factory=list,
title="Product names",
)
integrate_thumbnail: bool = Field(True)
class PreIntegrateThumbnailsModel(BaseSettingsModel):
"""Explicitly set if Thumbnail representation should be integrated.
If no matching profile set, existing state from Host implementation
is kept.
"""
_isGroup = True
enabled: bool = Field(True)
integrate_profiles: list[PreIntegrateThumbnailsProfile] = Field(
default_factory=list,
title="Integrate profiles"
)
class IntegrateProductGroupProfile(BaseSettingsModel):
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(default_factory=list, title="Task names")
template: str = Field("", title="Template")
class IntegrateProductGroupModel(BaseSettingsModel):
"""Group published products by filtering logic.
Set all published instances as a part of specific group named according
to 'Template'.
Implemented all variants of placeholders '{task}', '{product[type]}',
'{host}', '{product[name]}', '{renderlayer}'.
"""
_isGroup = True
product_grouping_profiles: list[IntegrateProductGroupProfile] = Field(
default_factory=list,
title="Product group profiles"
)
class IntegrateANProductGroupProfileModel(BaseSettingsModel):
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
hosts: list[str] = Field(
default_factory=list,
title="Hosts"
)
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(
default_factory=list,
title="Task names"
)
template: str = Field("", title="Template")
class IntegrateANTemplateNameProfileModel(BaseSettingsModel):
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
hosts: list[str] = Field(
default_factory=list,
title="Hosts"
)
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(
default_factory=list,
title="Task names"
)
template_name: str = Field("", title="Template name")
class IntegrateHeroTemplateNameProfileModel(BaseSettingsModel):
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
hosts: list[str] = Field(
default_factory=list,
title="Hosts"
)
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(
default_factory=list,
title="Task names"
)
template_name: str = Field("", title="Template name")
class IntegrateHeroVersionModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
optional: bool = Field(False, title="Optional")
active: bool = Field(True, title="Active")
families: list[str] = Field(default_factory=list, title="Families")
# TODO remove when removed from client code
template_name_profiles: list[IntegrateHeroTemplateNameProfileModel] = (
Field(
default_factory=list,
title="Template name profiles"
)
)
class CleanUpModel(BaseSettingsModel):
_isGroup = True
paterns: list[str] = Field(
default_factory=list,
title="Patterns (regex)"
)
remove_temp_renders: bool = Field(False, title="Remove Temp renders")
class CleanUpFarmModel(BaseSettingsModel):
_isGroup = True
enabled: bool = Field(True)
class PublishPuginsModel(BaseSettingsModel):
CollectAnatomyInstanceData: CollectAnatomyInstanceDataModel = Field(
default_factory=CollectAnatomyInstanceDataModel,
title="Collect Anatomy Instance Data"
)
CollectAudio: CollectAudioModel = Field(
default_factory=CollectAudioModel,
title="Collect Audio"
)
CollectSceneVersion: CollectSceneVersionModel = Field(
default_factory=CollectSceneVersionModel,
title="Collect Version from Workfile"
)
collect_comment_per_instance: CollectCommentPIModel = Field(
default_factory=CollectCommentPIModel,
title="Collect comment per instance",
)
CollectFramesFixDef: CollectFramesFixDefModel = Field(
default_factory=CollectFramesFixDefModel,
title="Collect Frames to Fix",
)
ValidateEditorialAssetName: ValidateBaseModel = Field(
default_factory=ValidateBaseModel,
title="Validate Editorial Asset Name"
)
ValidateVersion: ValidateBaseModel = Field(
default_factory=ValidateBaseModel,
title="Validate Version"
)
ValidateIntent: ValidateIntentModel = Field(
default_factory=ValidateIntentModel,
title="Validate Intent"
)
ExtractThumbnail: ExtractThumbnailModel = Field(
default_factory=ExtractThumbnailModel,
title="Extract Thumbnail"
)
ExtractOIIOTranscode: ExtractOIIOTranscodeModel = Field(
default_factory=ExtractOIIOTranscodeModel,
title="Extract OIIO Transcode"
)
ExtractReview: ExtractReviewModel = Field(
default_factory=ExtractReviewModel,
title="Extract Review"
)
ExtractBurnin: ExtractBurninModel = Field(
default_factory=ExtractBurninModel,
title="Extract Burnin"
)
PreIntegrateThumbnails: PreIntegrateThumbnailsModel = Field(
default_factory=PreIntegrateThumbnailsModel,
title="Override Integrate Thumbnail Representations"
)
IntegrateProductGroup: IntegrateProductGroupModel = Field(
default_factory=IntegrateProductGroupModel,
title="Integrate Product Group"
)
IntegrateHeroVersion: IntegrateHeroVersionModel = Field(
default_factory=IntegrateHeroVersionModel,
title="Integrate Hero Version"
)
CleanUp: CleanUpModel = Field(
default_factory=CleanUpModel,
title="Clean Up"
)
CleanUpFarm: CleanUpFarmModel = Field(
default_factory=CleanUpFarmModel,
title="Clean Up Farm"
)
DEFAULT_PUBLISH_VALUES = {
"CollectAnatomyInstanceData": {
"follow_workfile_version": False
},
"CollectAudio": {
"enabled": False,
"audio_product_name": "audioMain"
},
"CollectSceneVersion": {
"hosts": [
"aftereffects",
"blender",
"celaction",
"fusion",
"harmony",
"hiero",
"houdini",
"maya",
"nuke",
"photoshop",
"resolve",
"tvpaint"
],
"skip_hosts_headless_publish": []
},
"collect_comment_per_instance": {
"enabled": False,
"families": []
},
"CollectFramesFixDef": {
"enabled": True,
"rewrite_version_enable": True
},
"ValidateEditorialAssetName": {
"enabled": True,
"optional": False,
"active": True
},
"ValidateVersion": {
"enabled": True,
"optional": False,
"active": True
},
"ValidateIntent": {
"enabled": False,
"profiles": []
},
"ExtractThumbnail": {
"enabled": True,
"ffmpeg_args": {
"input": [
"-apply_trc gamma22"
],
"output": []
}
},
"ExtractOIIOTranscode": {
"enabled": True,
"profiles": []
},
"ExtractReview": {
"enabled": True,
"profiles": [
{
"product_types": [],
"hosts": [],
"outputs": [
{
"name": "png",
"ext": "png",
"tags": [
"ftrackreview",
"kitsureview"
],
"burnins": [],
"ffmpeg_args": {
"video_filters": [],
"audio_filters": [],
"input": [],
"output": []
},
"filter": {
"families": [
"render",
"review",
"ftrack"
],
"product_names": [],
"custom_tags": [],
"single_frame_filter": "single_frame"
},
"overscan_crop": "",
"overscan_color": [0, 0, 0, 1.0],
"width": 1920,
"height": 1080,
"scale_pixel_aspect": True,
"bg_color": [0, 0, 0, 0.0],
"letter_box": {
"enabled": False,
"ratio": 0.0,
"fill_color": [0, 0, 0, 1.0],
"line_thickness": 0,
"line_color": [255, 0, 0, 1.0]
}
},
{
"name": "h264",
"ext": "mp4",
"tags": [
"burnin",
"ftrackreview",
"kitsureview"
],
"burnins": [],
"ffmpeg_args": {
"video_filters": [],
"audio_filters": [],
"input": [
"-apply_trc gamma22"
],
"output": [
"-pix_fmt yuv420p",
"-crf 18",
"-intra"
]
},
"filter": {
"families": [
"render",
"review",
"ftrack"
],
"product_names": [],
"custom_tags": [],
"single_frame_filter": "multi_frame"
},
"overscan_crop": "",
"overscan_color": [0, 0, 0, 1.0],
"width": 0,
"height": 0,
"scale_pixel_aspect": True,
"bg_color": [0, 0, 0, 0.0],
"letter_box": {
"enabled": False,
"ratio": 0.0,
"fill_color": [0, 0, 0, 1.0],
"line_thickness": 0,
"line_color": [255, 0, 0, 1.0]
}
}
]
}
]
},
"ExtractBurnin": {
"enabled": True,
"options": {
"font_size": 42,
"font_color": [255, 255, 255, 1.0],
"bg_color": [0, 0, 0, 0.5],
"x_offset": 5,
"y_offset": 5,
"bg_padding": 5,
"font_filepath": {
"windows": "",
"darwin": "",
"linux": ""
}
},
"profiles": [
{
"product_types": [],
"hosts": [],
"task_types": [],
"task_names": [],
"product_names": [],
"burnins": [
{
"name": "burnin",
"TOP_LEFT": "{yy}-{mm}-{dd}",
"TOP_CENTERED": "",
"TOP_RIGHT": "{anatomy[version]}",
"BOTTOM_LEFT": "{username}",
"BOTTOM_CENTERED": "{folder[name]}",
"BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}",
"filter": {
"families": [],
"tags": []
}
},
]
},
{
"product_types": ["review"],
"hosts": [
"maya",
"houdini",
"max"
],
"task_types": [],
"task_names": [],
"product_names": [],
"burnins": [
{
"name": "focal_length_burnin",
"TOP_LEFT": "{yy}-{mm}-{dd}",
"TOP_CENTERED": "{focalLength:.2f} mm",
"TOP_RIGHT": "{anatomy[version]}",
"BOTTOM_LEFT": "{username}",
"BOTTOM_CENTERED": "{folder[name]}",
"BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}",
"filter": {
"families": [],
"tags": []
}
}
]
}
]
},
"PreIntegrateThumbnails": {
"enabled": True,
"integrate_profiles": []
},
"IntegrateProductGroup": {
"product_grouping_profiles": [
{
"product_types": [],
"hosts": [],
"task_types": [],
"tasks": [],
"template": ""
}
]
},
"IntegrateHeroVersion": {
"enabled": True,
"optional": True,
"active": True,
"families": [
"model",
"rig",
"look",
"pointcache",
"animation",
"setdress",
"layout",
"mayaScene",
"simpleUnrealTexture"
],
"template_name_profiles": [
{
"product_types": [
"simpleUnrealTexture"
],
"hosts": [
"standalonepublisher"
],
"task_types": [],
"task_names": [],
"template_name": "simpleUnrealTextureHero"
}
]
},
"CleanUp": {
"paterns": [],
"remove_temp_renders": False
},
"CleanUpFarm": {
"enabled": False
}
}

View file

@ -0,0 +1,506 @@
from pydantic import Field, validator
from ayon_server.settings import (
BaseSettingsModel,
normalize_name,
ensure_unique_names,
task_types_enum,
)
class ProductTypeSmartSelectModel(BaseSettingsModel):
_layout = "expanded"
name: str = Field("", title="Product type")
task_names: list[str] = Field(default_factory=list, title="Task names")
@validator("name")
def normalize_value(cls, value):
return normalize_name(value)
class ProductNameProfile(BaseSettingsModel):
_layout = "expanded"
product_types: list[str] = Field(
default_factory=list, title="Product types"
)
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(default_factory=list, title="Task names")
template: str = Field("", title="Template")
class CreatorToolModel(BaseSettingsModel):
# TODO this was dynamic dictionary '{name: task_names}'
product_types_smart_select: list[ProductTypeSmartSelectModel] = Field(
default_factory=list,
title="Create Smart Select"
)
product_name_profiles: list[ProductNameProfile] = Field(
default_factory=list,
title="Product name profiles"
)
@validator("product_types_smart_select")
def validate_unique_name(cls, value):
ensure_unique_names(value)
return value
class WorkfileTemplateProfile(BaseSettingsModel):
_layout = "expanded"
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
# TODO this should use hosts enum
hosts: list[str] = Field(default_factory=list, title="Hosts")
# TODO this was using project anatomy template name
workfile_template: str = Field("", title="Workfile template")
class LastWorkfileOnStartupProfile(BaseSettingsModel):
_layout = "expanded"
# TODO this should use hosts enum
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(default_factory=list, title="Task names")
enabled: bool = Field(True, title="Enabled")
use_last_published_workfile: bool = Field(
True, title="Use last published workfile"
)
class WorkfilesToolOnStartupProfile(BaseSettingsModel):
_layout = "expanded"
# TODO this should use hosts enum
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
tasks: list[str] = Field(default_factory=list, title="Task names")
enabled: bool = Field(True, title="Enabled")
class ExtraWorkFoldersProfile(BaseSettingsModel):
_layout = "expanded"
# TODO this should use hosts enum
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(default_factory=list, title="Task names")
folders: list[str] = Field(default_factory=list, title="Folders")
class WorkfilesLockProfile(BaseSettingsModel):
_layout = "expanded"
# TODO this should use hosts enum
host_names: list[str] = Field(default_factory=list, title="Hosts")
enabled: bool = Field(True, title="Enabled")
class WorkfilesToolModel(BaseSettingsModel):
workfile_template_profiles: list[WorkfileTemplateProfile] = Field(
default_factory=list,
title="Workfile template profiles"
)
last_workfile_on_startup: list[LastWorkfileOnStartupProfile] = Field(
default_factory=list,
title="Open last workfile on launch"
)
open_workfile_tool_on_startup: list[WorkfilesToolOnStartupProfile] = Field(
default_factory=list,
title="Open workfile tool on launch"
)
extra_folders: list[ExtraWorkFoldersProfile] = Field(
default_factory=list,
title="Extra work folders"
)
workfile_lock_profiles: list[WorkfilesLockProfile] = Field(
default_factory=list,
title="Workfile lock profiles"
)
def _product_types_enum():
return [
"action",
"animation",
"assembly",
"audio",
"backgroundComp",
"backgroundLayout",
"camera",
"editorial",
"gizmo",
"image",
"layout",
"look",
"matchmove",
"mayaScene",
"model",
"nukenodes",
"plate",
"pointcache",
"prerender",
"redshiftproxy",
"reference",
"render",
"review",
"rig",
"setdress",
"take",
"usdShade",
"vdbcache",
"vrayproxy",
"workfile",
"xgen",
"yetiRig",
"yeticache"
]
class LoaderProductTypeFilterProfile(BaseSettingsModel):
_layout = "expanded"
# TODO this should use hosts enum
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
is_include: bool = Field(True, title="Exclude / Include")
filter_product_types: list[str] = Field(
default_factory=list,
enum_resolver=_product_types_enum
)
class LoaderToolModel(BaseSettingsModel):
product_type_filter_profiles: list[LoaderProductTypeFilterProfile] = Field(
default_factory=list,
title="Product type filtering"
)
class PublishTemplateNameProfile(BaseSettingsModel):
_layout = "expanded"
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
# TODO this should use hosts enum
hosts: list[str] = Field(default_factory=list, title="Hosts")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(default_factory=list, title="Task names")
template_name: str = Field("", title="Template name")
class CustomStagingDirProfileModel(BaseSettingsModel):
active: bool = Field(True, title="Is active")
hosts: list[str] = Field(default_factory=list, title="Host names")
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(
default_factory=list, title="Task names"
)
product_types: list[str] = Field(
default_factory=list, title="Product types"
)
product_names: list[str] = Field(
default_factory=list, title="Product names"
)
custom_staging_dir_persistent: bool = Field(
False, title="Custom Staging Folder Persistent"
)
template_name: str = Field("", title="Template Name")
class PublishToolModel(BaseSettingsModel):
template_name_profiles: list[PublishTemplateNameProfile] = Field(
default_factory=list,
title="Template name profiles"
)
hero_template_name_profiles: list[PublishTemplateNameProfile] = Field(
default_factory=list,
title="Hero template name profiles"
)
custom_staging_dir_profiles: list[CustomStagingDirProfileModel] = Field(
default_factory=list,
title="Custom Staging Dir Profiles"
)
class GlobalToolsModel(BaseSettingsModel):
creator: CreatorToolModel = Field(
default_factory=CreatorToolModel,
title="Creator"
)
Workfiles: WorkfilesToolModel = Field(
default_factory=WorkfilesToolModel,
title="Workfiles"
)
loader: LoaderToolModel = Field(
default_factory=LoaderToolModel,
title="Loader"
)
publish: PublishToolModel = Field(
default_factory=PublishToolModel,
title="Publish"
)
DEFAULT_TOOLS_VALUES = {
"creator": {
"product_types_smart_select": [
{
"name": "Render",
"task_names": [
"light",
"render"
]
},
{
"name": "Model",
"task_names": [
"model"
]
},
{
"name": "Layout",
"task_names": [
"layout"
]
},
{
"name": "Look",
"task_names": [
"look"
]
},
{
"name": "Rig",
"task_names": [
"rigging",
"rig"
]
}
],
"product_name_profiles": [
{
"product_types": [],
"hosts": [],
"task_types": [],
"tasks": [],
"template": "{product[type]}{variant}"
},
{
"product_types": [
"workfile"
],
"hosts": [],
"task_types": [],
"tasks": [],
"template": "{product[type]}{Task[name]}"
},
{
"product_types": [
"render"
],
"hosts": [],
"task_types": [],
"tasks": [],
"template": "{product[type]}{Task[name]}{Variant}"
},
{
"product_types": [
"renderLayer",
"renderPass"
],
"hosts": [
"tvpaint"
],
"task_types": [],
"tasks": [],
"template": "{product[type]}{Task[name]}_{Renderlayer}_{Renderpass}"
},
{
"product_types": [
"review",
"workfile"
],
"hosts": [
"aftereffects",
"tvpaint"
],
"task_types": [],
"tasks": [],
"template": "{product[type]}{Task[name]}"
},
{
"product_types": ["render"],
"hosts": [
"aftereffects"
],
"task_types": [],
"tasks": [],
"template": "{product[type]}{Task[name]}{Composition}{Variant}"
},
{
"product_types": [
"staticMesh"
],
"hosts": [
"maya"
],
"task_types": [],
"tasks": [],
"template": "S_{folder[name]}{variant}"
},
{
"product_types": [
"skeletalMesh"
],
"hosts": [
"maya"
],
"task_types": [],
"tasks": [],
"template": "SK_{folder[name]}{variant}"
}
]
},
"Workfiles": {
"workfile_template_profiles": [
{
"task_types": [],
"hosts": [],
"workfile_template": "work"
},
{
"task_types": [],
"hosts": [
"unreal"
],
"workfile_template": "work_unreal"
}
],
"last_workfile_on_startup": [
{
"hosts": [],
"task_types": [],
"tasks": [],
"enabled": True,
"use_last_published_workfile": False
}
],
"open_workfile_tool_on_startup": [
{
"hosts": [],
"task_types": [],
"tasks": [],
"enabled": False
}
],
"extra_folders": [],
"workfile_lock_profiles": []
},
"loader": {
"product_type_filter_profiles": [
{
"hosts": [],
"task_types": [],
"is_include": True,
"filter_product_types": []
}
]
},
"publish": {
"template_name_profiles": [
{
"product_types": [],
"hosts": [],
"task_types": [],
"task_names": [],
"template_name": "publish"
},
{
"product_types": [
"review",
"render",
"prerender"
],
"hosts": [],
"task_types": [],
"task_names": [],
"template_name": "publish_render"
},
{
"product_types": [
"simpleUnrealTexture"
],
"hosts": [
"standalonepublisher"
],
"task_types": [],
"task_names": [],
"template_name": "publish_simpleUnrealTexture"
},
{
"product_types": [
"staticMesh",
"skeletalMesh"
],
"hosts": [
"maya"
],
"task_types": [],
"task_names": [],
"template_name": "publish_maya2unreal"
},
{
"product_types": [
"online"
],
"hosts": [
"traypublisher"
],
"task_types": [],
"task_names": [],
"template_name": "publish_online"
}
],
"hero_template_name_profiles": [
{
"product_types": [
"simpleUnrealTexture"
],
"hosts": [
"standalonepublisher"
],
"task_types": [],
"task_names": [],
"template_name": "hero_simpleUnrealTextureHero"
}
]
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -1,140 +0,0 @@
import os
import re
import shutil
import zipfile
import collections
from pathlib import Path
from typing import Any, Optional, Iterable
# Patterns of directories to be skipped for server part of addon
IGNORE_DIR_PATTERNS: list[re.Pattern] = [
re.compile(pattern)
for pattern in {
# Skip directories starting with '.'
r"^\.",
# Skip any pycache folders
"^__pycache__$"
}
]
# Patterns of files to be skipped for server part of addon
IGNORE_FILE_PATTERNS: list[re.Pattern] = [
re.compile(pattern)
for pattern in {
# Skip files starting with '.'
# NOTE this could be an issue in some cases
r"^\.",
# Skip '.pyc' files
r"\.pyc$"
}
]
def _value_match_regexes(value: str, regexes: Iterable[re.Pattern]) -> bool:
return any(
regex.search(value)
for regex in regexes
)
def find_files_in_subdir(
src_path: str,
ignore_file_patterns: Optional[list[re.Pattern]] = None,
ignore_dir_patterns: Optional[list[re.Pattern]] = None
):
"""Find all files to copy in subdirectories of given path.
All files that match any of the patterns in 'ignore_file_patterns' will
be skipped and any directories that match any of the patterns in
'ignore_dir_patterns' will be skipped with all subfiles.
Args:
src_path (str): Path to directory to search in.
ignore_file_patterns (Optional[list[re.Pattern]]): List of regexes
to match files to ignore.
ignore_dir_patterns (Optional[list[re.Pattern]]): List of regexes
to match directories to ignore.
Returns:
list[tuple[str, str]]: List of tuples with path to file and parent
directories relative to 'src_path'.
"""
if ignore_file_patterns is None:
ignore_file_patterns = IGNORE_FILE_PATTERNS
if ignore_dir_patterns is None:
ignore_dir_patterns = IGNORE_DIR_PATTERNS
output: list[tuple[str, str]] = []
hierarchy_queue = collections.deque()
hierarchy_queue.append((src_path, []))
while hierarchy_queue:
item: tuple[str, str] = hierarchy_queue.popleft()
dirpath, parents = item
for name in os.listdir(dirpath):
path = os.path.join(dirpath, name)
if os.path.isfile(path):
if not _value_match_regexes(name, ignore_file_patterns):
items = list(parents)
items.append(name)
output.append((path, os.path.sep.join(items)))
continue
if not _value_match_regexes(name, ignore_dir_patterns):
items = list(parents)
items.append(name)
hierarchy_queue.append((path, items))
return output
def main():
openpype_addon_dir = Path(os.path.dirname(os.path.abspath(__file__)))
server_dir = openpype_addon_dir / "server"
package_root = openpype_addon_dir / "package"
pyproject_path = openpype_addon_dir / "client" / "pyproject.toml"
root_dir = openpype_addon_dir.parent
openpype_dir = root_dir / "openpype"
version_path = openpype_dir / "version.py"
# Read version
version_content: dict[str, Any] = {}
with open(str(version_path), "r") as stream:
exec(stream.read(), version_content)
addon_version: str = version_content["__version__"]
output_dir = package_root / "openpype" / addon_version
private_dir = output_dir / "private"
# Make sure package dir is empty
if package_root.exists():
shutil.rmtree(str(package_root))
# Make sure output dir is created
output_dir.mkdir(parents=True)
# Copy version
shutil.copy(str(version_path), str(output_dir))
for subitem in server_dir.iterdir():
shutil.copy(str(subitem), str(output_dir / subitem.name))
# Make sure private dir exists
private_dir.mkdir(parents=True)
# Copy pyproject.toml
shutil.copy(
str(pyproject_path),
(private_dir / pyproject_path.name)
)
# Zip client
zip_filepath = private_dir / "client.zip"
with zipfile.ZipFile(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
# Add client code content to zip
for path, sub_path in find_files_in_subdir(str(openpype_dir)):
zipf.write(path, f"{openpype_dir.name}/{sub_path}")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,279 @@
import os
import sys
import re
import json
import shutil
import zipfile
import platform
import collections
from pathlib import Path
from typing import Any, Optional, Iterable
# Patterns of directories to be skipped for server part of addon
IGNORE_DIR_PATTERNS: list[re.Pattern] = [
re.compile(pattern)
for pattern in {
# Skip directories starting with '.'
r"^\.",
# Skip any pycache folders
"^__pycache__$"
}
]
# Patterns of files to be skipped for server part of addon
IGNORE_FILE_PATTERNS: list[re.Pattern] = [
re.compile(pattern)
for pattern in {
# Skip files starting with '.'
# NOTE this could be an issue in some cases
r"^\.",
# Skip '.pyc' files
r"\.pyc$"
}
]
class ZipFileLongPaths(zipfile.ZipFile):
"""Allows longer paths in zip files.
Regular DOS paths are limited to MAX_PATH (260) characters, including
the string's terminating NUL character.
That limit can be exceeded by using an extended-length path that
starts with the '\\?\' prefix.
"""
_is_windows = platform.system().lower() == "windows"
def _extract_member(self, member, tpath, pwd):
if self._is_windows:
tpath = os.path.abspath(tpath)
if tpath.startswith("\\\\"):
tpath = "\\\\?\\UNC\\" + tpath[2:]
else:
tpath = "\\\\?\\" + tpath
return super(ZipFileLongPaths, self)._extract_member(
member, tpath, pwd
)
def _value_match_regexes(value: str, regexes: Iterable[re.Pattern]) -> bool:
return any(
regex.search(value)
for regex in regexes
)
def find_files_in_subdir(
src_path: str,
ignore_file_patterns: Optional[list[re.Pattern]] = None,
ignore_dir_patterns: Optional[list[re.Pattern]] = None
):
"""Find all files to copy in subdirectories of given path.
All files that match any of the patterns in 'ignore_file_patterns' will
be skipped and any directories that match any of the patterns in
'ignore_dir_patterns' will be skipped with all subfiles.
Args:
src_path (str): Path to directory to search in.
ignore_file_patterns (Optional[list[re.Pattern]]): List of regexes
to match files to ignore.
ignore_dir_patterns (Optional[list[re.Pattern]]): List of regexes
to match directories to ignore.
Returns:
list[tuple[str, str]]: List of tuples with path to file and parent
directories relative to 'src_path'.
"""
if ignore_file_patterns is None:
ignore_file_patterns = IGNORE_FILE_PATTERNS
if ignore_dir_patterns is None:
ignore_dir_patterns = IGNORE_DIR_PATTERNS
output: list[tuple[str, str]] = []
hierarchy_queue = collections.deque()
hierarchy_queue.append((src_path, []))
while hierarchy_queue:
item: tuple[str, str] = hierarchy_queue.popleft()
dirpath, parents = item
for name in os.listdir(dirpath):
path = os.path.join(dirpath, name)
if os.path.isfile(path):
if not _value_match_regexes(name, ignore_file_patterns):
items = list(parents)
items.append(name)
output.append((path, os.path.sep.join(items)))
continue
if not _value_match_regexes(name, ignore_dir_patterns):
items = list(parents)
items.append(name)
hierarchy_queue.append((path, items))
return output
def read_addon_version(version_path: Path) -> str:
# Read version
version_content: dict[str, Any] = {}
with open(str(version_path), "r") as stream:
exec(stream.read(), version_content)
return version_content["__version__"]
def get_addon_version(addon_dir: Path) -> str:
return read_addon_version(addon_dir / "server" / "version.py")
def create_addon_zip(
output_dir: Path,
addon_name: str,
addon_version: str,
keep_source: bool
):
zip_filepath = output_dir / f"{addon_name}.zip"
addon_output_dir = output_dir / addon_name / addon_version
with ZipFileLongPaths(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
zipf.writestr(
"manifest.json",
json.dumps({
"addon_name": addon_name,
"addon_version": addon_version
})
)
# Add client code content to zip
src_root = os.path.normpath(str(addon_output_dir.absolute()))
src_root_offset = len(src_root) + 1
for root, _, filenames in os.walk(str(addon_output_dir)):
rel_root = ""
if root != src_root:
rel_root = root[src_root_offset:]
for filename in filenames:
src_path = os.path.join(root, filename)
if rel_root:
dst_path = os.path.join("addon", rel_root, filename)
else:
dst_path = os.path.join("addon", filename)
zipf.write(src_path, dst_path)
if not keep_source:
shutil.rmtree(str(output_dir / addon_name))
def create_openpype_package(
addon_dir: Path,
output_dir: Path,
root_dir: Path,
create_zip: bool,
keep_source: bool
):
server_dir = addon_dir / "server"
pyproject_path = addon_dir / "client" / "pyproject.toml"
openpype_dir = root_dir / "openpype"
version_path = openpype_dir / "version.py"
addon_version = read_addon_version(version_path)
addon_output_dir = output_dir / "openpype" / addon_version
private_dir = addon_output_dir / "private"
# Make sure dir exists
addon_output_dir.mkdir(parents=True)
private_dir.mkdir(parents=True)
# Copy version
shutil.copy(str(version_path), str(addon_output_dir))
for subitem in server_dir.iterdir():
shutil.copy(str(subitem), str(addon_output_dir / subitem.name))
# Copy pyproject.toml
shutil.copy(
str(pyproject_path),
(private_dir / pyproject_path.name)
)
# Zip client
zip_filepath = private_dir / "client.zip"
with ZipFileLongPaths(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
# Add client code content to zip
for path, sub_path in find_files_in_subdir(str(openpype_dir)):
zipf.write(path, f"{openpype_dir.name}/{sub_path}")
if create_zip:
create_addon_zip(output_dir, "openpype", addon_version, keep_source)
def create_addon_package(
addon_dir: Path,
output_dir: Path,
create_zip: bool,
keep_source: bool
):
server_dir = addon_dir / "server"
addon_version = get_addon_version(addon_dir)
addon_output_dir = output_dir / addon_dir.name / addon_version
if addon_output_dir.exists():
shutil.rmtree(str(addon_output_dir))
addon_output_dir.mkdir(parents=True)
# Copy server content
src_root = os.path.normpath(str(server_dir.absolute()))
src_root_offset = len(src_root) + 1
for root, _, filenames in os.walk(str(server_dir)):
dst_root = addon_output_dir
if root != src_root:
rel_root = root[src_root_offset:]
dst_root = dst_root / rel_root
dst_root.mkdir(parents=True, exist_ok=True)
for filename in filenames:
src_path = os.path.join(root, filename)
shutil.copy(src_path, str(dst_root))
if create_zip:
create_addon_zip(
output_dir, addon_dir.name, addon_version, keep_source
)
def main(create_zip=True, keep_source=False):
current_dir = Path(os.path.dirname(os.path.abspath(__file__)))
root_dir = current_dir.parent
output_dir = current_dir / "packages"
print("Package creation started...")
# Make sure package dir is empty
if output_dir.exists():
shutil.rmtree(str(output_dir))
# Make sure output dir is created
output_dir.mkdir(parents=True)
for addon_dir in current_dir.iterdir():
if not addon_dir.is_dir():
continue
server_dir = addon_dir / "server"
if not server_dir.exists():
continue
if addon_dir.name == "openpype":
create_openpype_package(
addon_dir, output_dir, root_dir, create_zip, keep_source
)
else:
create_addon_package(
addon_dir, output_dir, create_zip, keep_source
)
print(f"- package '{addon_dir.name}' created")
print(f"Package creation finished. Output directory: {output_dir}")
if __name__ == "__main__":
create_zip = "--skip-zip" not in sys.argv
keep_sources = "--keep-sources" in sys.argv
main(create_zip, keep_sources)

View file

@ -0,0 +1,17 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import DeadlineSettings, DEFAULT_VALUES
class Deadline(BaseServerAddon):
name = "deadline"
title = "Deadline"
version = __version__
settings_model: Type[DeadlineSettings] = DeadlineSettings
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,10 @@
from .main import (
DeadlineSettings,
DEFAULT_VALUES,
)
__all__ = (
"DeadlineSettings",
"DEFAULT_VALUES",
)

View file

@ -0,0 +1,48 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
from .publish_plugins import (
PublishPluginsModel,
DEFAULT_DEADLINE_PLUGINS_SETTINGS
)
class ServerListSubmodel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Name")
value: str = Field(title="Value")
class DeadlineSettings(BaseSettingsModel):
deadline_urls: list[ServerListSubmodel] = Field(
default_factory=list,
title="System Deadline Webservice URLs",
)
deadline_servers: list[str] = Field(
title="Project deadline servers",
section="---")
publish: PublishPluginsModel = Field(
default_factory=PublishPluginsModel,
title="Publish Plugins",
)
@validator("deadline_urls")
def validate_unique_names(cls, value):
ensure_unique_names(value)
return value
DEFAULT_VALUES = {
"deadline_urls": [
{
"name": "default",
"value": "http://127.0.0.1:8082"
}
],
# TODO: this needs to be dynamic from "deadline_urls"
"deadline_servers": [],
"publish": DEFAULT_DEADLINE_PLUGINS_SETTINGS
}

View file

@ -0,0 +1,435 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
class CollectDefaultDeadlineServerModel(BaseSettingsModel):
"""Settings for event handlers running in ftrack service."""
pass_mongo_url: bool = Field(title="Pass Mongo url to job")
class CollectDeadlinePoolsModel(BaseSettingsModel):
"""Settings Deadline default pools."""
primary_pool: str = Field(title="Primary Pool")
secondary_pool: str = Field(title="Secondary Pool")
class ValidateExpectedFilesModel(BaseSettingsModel):
enabled: bool = Field(True, title="Enabled")
active: bool = Field(True, title="Active")
allow_user_override: bool = Field(
True, title="Allow user change frame range"
)
families: list[str] = Field(
default_factory=list, title="Trigger on families"
)
targets: list[str] = Field(
default_factory=list, title="Trigger for plugins"
)
def tile_assembler_enum():
"""Return a list of value/label dicts for the enumerator.
Returning a list of dicts is used to allow for a custom label to be
displayed in the UI.
"""
return [
{
"value": "DraftTileAssembler",
"label": "Draft Tile Assembler"
},
{
"value": "OpenPypeTileAssembler",
"label": "Open Image IO"
}
]
class ScenePatchesSubmodel(BaseSettingsModel):
_layout = "expanded"
name: str = Field(title="Patch name")
regex: str = Field(title="Patch regex")
line: str = Field(title="Patch line")
class MayaSubmitDeadlineModel(BaseSettingsModel):
"""Maya deadline submitter settings."""
enabled: bool = Field(title="Enabled")
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
use_published: bool = Field(title="Use Published scene")
import_reference: bool = Field(title="Use Scene with Imported Reference")
asset_dependencies: bool = Field(title="Use Asset dependencies")
priority: int = Field(title="Priority")
tile_priority: int = Field(title="Tile Priority")
group: str = Field(title="Group")
limit: list[str] = Field(
default_factory=list,
title="Limit Groups"
)
tile_assembler_plugin: str = Field(
title="Tile Assembler Plugin",
enum_resolver=tile_assembler_enum,
)
jobInfo: str = Field(
title="Additional JobInfo data",
widget="textarea",
)
pluginInfo: str = Field(
title="Additional PluginInfo data",
widget="textarea",
)
scene_patches: list[ScenePatchesSubmodel] = Field(
default_factory=list,
title="Scene patches",
)
strict_error_checking: bool = Field(
title="Disable Strict Error Check profiles"
)
@validator("limit", "scene_patches")
def validate_unique_names(cls, value):
ensure_unique_names(value)
return value
class MaxSubmitDeadlineModel(BaseSettingsModel):
enabled: bool = Field(True)
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
use_published: bool = Field(title="Use Published scene")
priority: int = Field(title="Priority")
chunk_size: int = Field(title="Frame per Task")
group: str = Field("", title="Group Name")
class EnvSearchReplaceSubmodel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Name")
value: str = Field(title="Value")
class LimitGroupsSubmodel(BaseSettingsModel):
_layout = "expanded"
name: str = Field(title="Name")
value: list[str] = Field(
default_factory=list,
title="Limit Groups"
)
class FusionSubmitDeadlineModel(BaseSettingsModel):
enabled: bool = Field(True, title="Enabled")
optional: bool = Field(False, title="Optional")
active: bool = Field(True, title="Active")
priority: int = Field(50, title="Priority")
chunk_size: int = Field(10, title="Frame per Task")
concurrent_tasks: int = Field(1, title="Number of concurrent tasks")
group: str = Field("", title="Group Name")
class NukeSubmitDeadlineModel(BaseSettingsModel):
"""Nuke deadline submitter settings."""
enabled: bool = Field(title="Enabled")
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
priority: int = Field(title="Priority")
chunk_size: int = Field(title="Chunk Size")
concurrent_tasks: int = Field(title="Number of concurrent tasks")
group: str = Field(title="Group")
department: str = Field(title="Department")
use_gpu: bool = Field(title="Use GPU")
env_allowed_keys: list[str] = Field(
default_factory=list,
title="Allowed environment keys"
)
env_search_replace_values: list[EnvSearchReplaceSubmodel] = Field(
default_factory=list,
title="Search & replace in environment values",
)
limit_groups: list[LimitGroupsSubmodel] = Field(
default_factory=list,
title="Limit Groups",
)
@validator("limit_groups", "env_allowed_keys", "env_search_replace_values")
def validate_unique_names(cls, value):
ensure_unique_names(value)
return value
class HarmonySubmitDeadlineModel(BaseSettingsModel):
"""Harmony deadline submitter settings."""
enabled: bool = Field(title="Enabled")
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
use_published: bool = Field(title="Use Published scene")
priority: int = Field(title="Priority")
chunk_size: int = Field(title="Chunk Size")
group: str = Field(title="Group")
department: str = Field(title="Department")
class AfterEffectsSubmitDeadlineModel(BaseSettingsModel):
"""After Effects deadline submitter settings."""
enabled: bool = Field(title="Enabled")
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
use_published: bool = Field(title="Use Published scene")
priority: int = Field(title="Priority")
chunk_size: int = Field(title="Chunk Size")
group: str = Field(title="Group")
department: str = Field(title="Department")
multiprocess: bool = Field(title="Optional")
class CelactionSubmitDeadlineModel(BaseSettingsModel):
enabled: bool = Field(True, title="Enabled")
deadline_department: str = Field("", title="Deadline apartment")
deadline_priority: int = Field(50, title="Deadline priority")
deadline_pool: str = Field("", title="Deadline pool")
deadline_pool_secondary: str = Field("", title="Deadline pool (secondary)")
deadline_group: str = Field("", title="Deadline Group")
deadline_chunk_size: int = Field(10, title="Deadline Chunk size")
deadline_job_delay: str = Field(
"", title="Delay job (timecode dd:hh:mm:ss)"
)
class AOVFilterSubmodel(BaseSettingsModel):
_layout = "expanded"
name: str = Field(title="Host")
value: list[str] = Field(
default_factory=list,
title="AOV regex"
)
class ProcessSubmittedJobOnFarmModel(BaseSettingsModel):
"""Process submitted job on farm."""
enabled: bool = Field(title="Enabled")
deadline_department: str = Field(title="Department")
deadline_pool: str = Field(title="Pool")
deadline_group: str = Field(title="Group")
deadline_chunk_size: int = Field(title="Chunk Size")
deadline_priority: int = Field(title="Priority")
publishing_script: str = Field(title="Publishing script path")
skip_integration_repre_list: list[str] = Field(
default_factory=list,
title="Skip integration of representation with ext"
)
aov_filter: list[AOVFilterSubmodel] = Field(
default_factory=list,
title="Reviewable products filter",
)
@validator("aov_filter", "skip_integration_repre_list")
def validate_unique_names(cls, value):
ensure_unique_names(value)
return value
class PublishPluginsModel(BaseSettingsModel):
CollectDefaultDeadlineServer: CollectDefaultDeadlineServerModel = Field(
default_factory=CollectDefaultDeadlineServerModel,
title="Default Deadline Webservice")
CollectDefaultDeadlineServer: CollectDefaultDeadlineServerModel = Field(
default_factory=CollectDefaultDeadlineServerModel,
title="Default Deadline Webservice")
CollectDeadlinePools: CollectDeadlinePoolsModel = Field(
default_factory=CollectDeadlinePoolsModel,
title="Default Pools")
ValidateExpectedFiles: ValidateExpectedFilesModel = Field(
default_factory=ValidateExpectedFilesModel,
title="Validate Expected Files"
)
MayaSubmitDeadline: MayaSubmitDeadlineModel = Field(
default_factory=MayaSubmitDeadlineModel,
title="Maya Submit to deadline")
MaxSubmitDeadline: MaxSubmitDeadlineModel = Field(
default_factory=MaxSubmitDeadlineModel,
title="Max Submit to deadline")
FusionSubmitDeadline: FusionSubmitDeadlineModel = Field(
default_factory=FusionSubmitDeadlineModel,
title="Fusion submit to Deadline")
NukeSubmitDeadline: NukeSubmitDeadlineModel = Field(
default_factory=NukeSubmitDeadlineModel,
title="Nuke Submit to deadline")
HarmonySubmitDeadline: HarmonySubmitDeadlineModel = Field(
default_factory=HarmonySubmitDeadlineModel,
title="Harmony Submit to deadline")
AfterEffectsSubmitDeadline: AfterEffectsSubmitDeadlineModel = Field(
default_factory=AfterEffectsSubmitDeadlineModel,
title="After Effects to deadline")
CelactionSubmitDeadline: CelactionSubmitDeadlineModel = Field(
default_factory=CelactionSubmitDeadlineModel,
title="Celaction Submit Deadline"
)
ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = Field(
default_factory=ProcessSubmittedJobOnFarmModel,
title="Process submitted job on farm.")
DEFAULT_DEADLINE_PLUGINS_SETTINGS = {
"CollectDefaultDeadlineServer": {
"pass_mongo_url": True
},
"CollectDeadlinePools": {
"primary_pool": "",
"secondary_pool": ""
},
"ValidateExpectedFiles": {
"enabled": True,
"active": True,
"allow_user_override": True,
"families": [
"render"
],
"targets": [
"deadline"
]
},
"MayaSubmitDeadline": {
"enabled": True,
"optional": False,
"active": True,
"tile_assembler_plugin": "DraftTileAssembler",
"use_published": True,
"import_reference": False,
"asset_dependencies": True,
"strict_error_checking": True,
"priority": 50,
"tile_priority": 50,
"group": "none",
"limit": [],
# this used to be empty dict
"jobInfo": "",
# this used to be empty dict
"pluginInfo": "",
"scene_patches": []
},
"MaxSubmitDeadline": {
"enabled": True,
"optional": False,
"active": True,
"use_published": True,
"priority": 50,
"chunk_size": 10,
"group": "none"
},
"FusionSubmitDeadline": {
"enabled": True,
"optional": False,
"active": True,
"priority": 50,
"chunk_size": 10,
"concurrent_tasks": 1,
"group": ""
},
"NukeSubmitDeadline": {
"enabled": True,
"optional": False,
"active": True,
"priority": 50,
"chunk_size": 10,
"concurrent_tasks": 1,
"group": "",
"department": "",
"use_gpu": True,
"env_allowed_keys": [],
"env_search_replace_values": [],
"limit_groups": []
},
"HarmonySubmitDeadline": {
"enabled": True,
"optional": False,
"active": True,
"use_published": True,
"priority": 50,
"chunk_size": 10000,
"group": "",
"department": ""
},
"AfterEffectsSubmitDeadline": {
"enabled": True,
"optional": False,
"active": True,
"use_published": True,
"priority": 50,
"chunk_size": 10000,
"group": "",
"department": "",
"multiprocess": True
},
"CelactionSubmitDeadline": {
"enabled": True,
"deadline_department": "",
"deadline_priority": 50,
"deadline_pool": "",
"deadline_pool_secondary": "",
"deadline_group": "",
"deadline_chunk_size": 10,
"deadline_job_delay": "00:00:00:00"
},
"ProcessSubmittedJobOnFarm": {
"enabled": True,
"deadline_department": "",
"deadline_pool": "",
"deadline_group": "",
"deadline_chunk_size": 1,
"deadline_priority": 50,
"publishing_script": "",
"skip_integration_repre_list": [],
"aov_filter": [
{
"name": "maya",
"value": [
".*([Bb]eauty).*"
]
},
{
"name": "aftereffects",
"value": [
".*"
]
},
{
"name": "celaction",
"value": [
".*"
]
},
{
"name": "harmony",
"value": [
".*"
]
},
{
"name": "max",
"value": [
".*"
]
},
{
"name": "fusion",
"value": [
".*"
]
}
]
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,19 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import FlameSettings, DEFAULT_VALUES
class FlameAddon(BaseServerAddon):
name = "flame"
title = "Flame"
version = __version__
settings_model: Type[FlameSettings] = FlameSettings
frontend_scopes = {}
services = {}
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,10 @@
from .main import (
FlameSettings,
DEFAULT_VALUES,
)
__all__ = (
"FlameSettings",
"DEFAULT_VALUES",
)

View file

@ -0,0 +1,120 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CreateShotClipModel(BaseSettingsModel):
hierarchy: str = Field(
"shot",
title="Shot parent hierarchy",
section="Shot Hierarchy And Rename Settings"
)
useShotName: bool = Field(
True,
title="Use Shot Name",
)
clipRename: bool = Field(
False,
title="Rename clips",
)
clipName: str = Field(
"{sequence}{shot}",
title="Clip name template"
)
segmentIndex: bool = Field(
True,
title="Accept segment order"
)
countFrom: int = Field(
10,
title="Count sequence from"
)
countSteps: int = Field(
10,
title="Stepping number"
)
folder: str = Field(
"shots",
title="{folder}",
section="Shot Template Keywords"
)
episode: str = Field(
"ep01",
title="{episode}"
)
sequence: str = Field(
"a",
title="{sequence}"
)
track: str = Field(
"{_track_}",
title="{track}"
)
shot: str = Field(
"####",
title="{shot}"
)
vSyncOn: bool = Field(
False,
title="Enable Vertical Sync",
section="Vertical Synchronization Of Attributes"
)
workfileFrameStart: int = Field(
1001,
title="Workfiles Start Frame",
section="Shot Attributes"
)
handleStart: int = Field(
10,
title="Handle start (head)"
)
handleEnd: int = Field(
10,
title="Handle end (tail)"
)
includeHandles: bool = Field(
False,
title="Enable handles including"
)
retimedHandles: bool = Field(
True,
title="Enable retimed handles"
)
retimedFramerange: bool = Field(
True,
title="Enable retimed shot frameranges"
)
class CreatePuginsModel(BaseSettingsModel):
CreateShotClip: CreateShotClipModel = Field(
default_factory=CreateShotClipModel,
title="Create Shot Clip"
)
DEFAULT_CREATE_SETTINGS = {
"CreateShotClip": {
"hierarchy": "{folder}/{sequence}",
"useShotName": True,
"clipRename": False,
"clipName": "{sequence}{shot}",
"segmentIndex": True,
"countFrom": 10,
"countSteps": 10,
"folder": "shots",
"episode": "ep01",
"sequence": "a",
"track": "{_track_}",
"shot": "####",
"vSyncOn": False,
"workfileFrameStart": 1001,
"handleStart": 5,
"handleEnd": 5,
"includeHandles": False,
"retimedHandles": True,
"retimedFramerange": True
}
}

View file

@ -0,0 +1,130 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class ImageIORemappingRulesModel(BaseSettingsModel):
host_native_name: str = Field(
title="Application native colorspace name"
)
ocio_name: str = Field(title="OCIO colorspace name")
class ImageIORemappingModel(BaseSettingsModel):
rules: list[ImageIORemappingRulesModel] = Field(
default_factory=list
)
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ProfileNamesMappingInputsModel(BaseSettingsModel):
_layout = "expanded"
flameName: str = Field("", title="Flame name")
ocioName: str = Field("", title="OCIO name")
class ProfileNamesMappingModel(BaseSettingsModel):
_layout = "expanded"
inputs: list[ProfileNamesMappingInputsModel] = Field(
default_factory=list,
title="Profile names mapping"
)
class ImageIOProjectModel(BaseSettingsModel):
colourPolicy: str = Field(
"ACES 1.1",
title="Colour Policy (name or path)",
section="Project"
)
frameDepth: str = Field(
"16-bit fp",
title="Image Depth"
)
fieldDominance: str = Field(
"PROGRESSIVE",
title="Field Dominance"
)
class FlameImageIOModel(BaseSettingsModel):
_isGroup = True
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
remapping: ImageIORemappingModel = Field(
title="Remapping colorspace names",
default_factory=ImageIORemappingModel
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)
# NOTE 'project' attribute was expanded to this model but that caused
# inconsistency with v3 settings and harder conversion handling
# - it can be moved back but keep in mind that it must be handled in v3
# conversion script too
project: ImageIOProjectModel = Field(
default_factory=ImageIOProjectModel,
title="Project"
)
profilesMapping: ProfileNamesMappingModel = Field(
default_factory=ProfileNamesMappingModel,
title="Profile names mapping"
)
DEFAULT_IMAGEIO_SETTINGS = {
"project": {
"colourPolicy": "ACES 1.1",
"frameDepth": "16-bit fp",
"fieldDominance": "PROGRESSIVE"
},
"profilesMapping": {
"inputs": [
{
"flameName": "ACEScg",
"ocioName": "ACES - ACEScg"
},
{
"flameName": "Rec.709 video",
"ocioName": "Output - Rec.709"
}
]
}
}

View file

@ -0,0 +1,99 @@
from ayon_server.settings import Field, BaseSettingsModel
class LoadClipModel(BaseSettingsModel):
enabled: bool = Field(True)
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
reel_group_name: str = Field(
"OpenPype_Reels",
title="Reel group name"
)
reel_name: str = Field(
"Loaded",
title="Reel name"
)
clip_name_template: str = Field(
"{folder[name]}_{product[name]}<_{output}>",
title="Clip name template"
)
layer_rename_template: str = Field("", title="Layer name template")
layer_rename_patterns: list[str] = Field(
default_factory=list,
title="Layer rename patters",
)
class LoadClipBatchModel(BaseSettingsModel):
enabled: bool = Field(True)
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
reel_name: str = Field(
"OP_LoadedReel",
title="Reel name"
)
clip_name_template: str = Field(
"{batch}_{folder[name]}_{product[name]}<_{output}>",
title="Clip name template"
)
layer_rename_template: str = Field("", title="Layer name template")
layer_rename_patterns: list[str] = Field(
default_factory=list,
title="Layer rename patters",
)
class LoaderPluginsModel(BaseSettingsModel):
LoadClip: LoadClipModel = Field(
default_factory=LoadClipModel,
title="Load Clip"
)
LoadClipBatch: LoadClipBatchModel = Field(
default_factory=LoadClipBatchModel,
title="Load as clip to current batch"
)
DEFAULT_LOADER_SETTINGS = {
"LoadClip": {
"enabled": True,
"product_types": [
"render2d",
"source",
"plate",
"render",
"review"
],
"reel_group_name": "OpenPype_Reels",
"reel_name": "Loaded",
"clip_name_template": "{folder[name]}_{product[name]}<_{output}>",
"layer_rename_template": "{folder[name]}_{product[name]}<_{output}>",
"layer_rename_patterns": [
"rgb",
"rgba"
]
},
"LoadClipBatch": {
"enabled": True,
"product_types": [
"render2d",
"source",
"plate",
"render",
"review"
],
"reel_name": "OP_LoadedReel",
"clip_name_template": "{batch}_{folder[name]}_{product[name]}<_{output}>",
"layer_rename_template": "{folder[name]}_{product[name]}<_{output}>",
"layer_rename_patterns": [
"rgb",
"rgba"
]
}
}

View file

@ -0,0 +1,33 @@
from ayon_server.settings import Field, BaseSettingsModel
from .imageio import FlameImageIOModel, DEFAULT_IMAGEIO_SETTINGS
from .create_plugins import CreatePuginsModel, DEFAULT_CREATE_SETTINGS
from .publish_plugins import PublishPuginsModel, DEFAULT_PUBLISH_SETTINGS
from .loader_plugins import LoaderPluginsModel, DEFAULT_LOADER_SETTINGS
class FlameSettings(BaseSettingsModel):
imageio: FlameImageIOModel = Field(
default_factory=FlameImageIOModel,
title="Color Management (ImageIO)"
)
create: CreatePuginsModel = Field(
default_factory=CreatePuginsModel,
title="Create plugins"
)
publish: PublishPuginsModel = Field(
default_factory=PublishPuginsModel,
title="Publish plugins"
)
load: LoaderPluginsModel = Field(
default_factory=LoaderPluginsModel,
title="Loader plugins"
)
DEFAULT_VALUES = {
"imageio": DEFAULT_IMAGEIO_SETTINGS,
"create": DEFAULT_CREATE_SETTINGS,
"publish": DEFAULT_PUBLISH_SETTINGS,
"load": DEFAULT_LOADER_SETTINGS
}

View file

@ -0,0 +1,190 @@
from ayon_server.settings import Field, BaseSettingsModel, task_types_enum
class XMLPresetAttrsFromCommentsModel(BaseSettingsModel):
_layout = "expanded"
name: str = Field("", title="Attribute name")
type: str = Field(
default_factory=str,
title="Attribute type",
enum_resolver=lambda: ["number", "float", "string"]
)
class AddTasksModel(BaseSettingsModel):
_layout = "expanded"
name: str = Field("", title="Task name")
type: str = Field(
default_factory=str,
title="Task type",
enum_resolver=task_types_enum
)
create_batch_group: bool = Field(
True,
title="Create batch group"
)
class CollectTimelineInstancesModel(BaseSettingsModel):
_isGroup = True
xml_preset_attrs_from_comments: list[XMLPresetAttrsFromCommentsModel] = Field(
default_factory=list,
title="XML presets attributes parsable from segment comments"
)
add_tasks: list[AddTasksModel] = Field(
default_factory=list,
title="Add tasks"
)
class ExportPresetsMappingModel(BaseSettingsModel):
_layout = "expanded"
name: str = Field(
...,
title="Name"
)
active: bool = Field(True, title="Is active")
export_type: str = Field(
"File Sequence",
title="Eport clip type",
enum_resolver=lambda: ["Movie", "File Sequence", "Sequence Publish"]
)
ext: str = Field("exr", title="Output extension")
xml_preset_file: str = Field(
"OpenEXR (16-bit fp DWAA).xml",
title="XML preset file (with ext)"
)
colorspace_out: str = Field(
"ACES - ACEScg",
title="Output color (imageio)"
)
# TODO remove when resolved or v3 is not a thing anymore
# NOTE next 4 attributes were grouped under 'other_parameters' but that
# created inconsistency with v3 settings and harder conversion handling
# - it can be moved back but keep in mind that it must be handled in v3
# conversion script too
xml_preset_dir: str = Field(
"",
title="XML preset directory"
)
parsed_comment_attrs: bool = Field(
True,
title="Parsed comment attributes"
)
representation_add_range: bool = Field(
True,
title="Add range to representation name"
)
representation_tags: list[str] = Field(
default_factory=list,
title="Representation tags"
)
load_to_batch_group: bool = Field(
True,
title="Load to batch group reel"
)
batch_group_loader_name: str = Field(
"LoadClipBatch",
title="Use loader name"
)
filter_path_regex: str = Field(
".*",
title="Regex in clip path"
)
class ExtractProductResourcesModel(BaseSettingsModel):
_isGroup = True
keep_original_representation: bool = Field(
False,
title="Publish clip's original media"
)
export_presets_mapping: list[ExportPresetsMappingModel] = Field(
default_factory=list,
title="Export presets mapping"
)
class IntegrateBatchGroupModel(BaseSettingsModel):
enabled: bool = Field(
False,
title="Enabled"
)
class PublishPuginsModel(BaseSettingsModel):
CollectTimelineInstances: CollectTimelineInstancesModel = Field(
default_factory=CollectTimelineInstancesModel,
title="Collect Timeline Instances"
)
ExtractProductResources: ExtractProductResourcesModel = Field(
default_factory=ExtractProductResourcesModel,
title="Extract Product Resources"
)
IntegrateBatchGroup: IntegrateBatchGroupModel = Field(
default_factory=IntegrateBatchGroupModel,
title="IntegrateBatchGroup"
)
DEFAULT_PUBLISH_SETTINGS = {
"CollectTimelineInstances": {
"xml_preset_attrs_from_comments": [
{
"name": "width",
"type": "number"
},
{
"name": "height",
"type": "number"
},
{
"name": "pixelRatio",
"type": "float"
},
{
"name": "resizeType",
"type": "string"
},
{
"name": "resizeFilter",
"type": "string"
}
],
"add_tasks": [
{
"name": "compositing",
"type": "Compositing",
"create_batch_group": True
}
]
},
"ExtractProductResources": {
"keep_original_representation": False,
"export_presets_mapping": [
{
"name": "exr16fpdwaa",
"active": True,
"export_type": "File Sequence",
"ext": "exr",
"xml_preset_file": "OpenEXR (16-bit fp DWAA).xml",
"colorspace_out": "ACES - ACEScg",
"xml_preset_dir": "",
"parsed_comment_attrs": True,
"representation_add_range": True,
"representation_tags": [],
"load_to_batch_group": True,
"batch_group_loader_name": "LoadClipBatch",
"filter_path_regex": ".*"
}
]
},
"IntegrateBatchGroup": {
"enabled": False
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,19 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import FusionSettings, DEFAULT_VALUES
class FusionAddon(BaseServerAddon):
name = "fusion"
title = "Fusion"
version = __version__
settings_model: Type[FusionSettings] = FusionSettings
frontend_scopes = {}
services = {}
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,48 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings.validators import ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class FusionImageIOModel(BaseSettingsModel):
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)

View file

@ -0,0 +1,95 @@
from pydantic import Field
from ayon_server.settings import (
BaseSettingsModel,
)
from .imageio import FusionImageIOModel
class CopyFusionSettingsModel(BaseSettingsModel):
copy_path: str = Field("", title="Local Fusion profile directory")
copy_status: bool = Field(title="Copy profile on first launch")
force_sync: bool = Field(title="Resync profile on each launch")
def _create_saver_instance_attributes_enum():
return [
{
"value": "reviewable",
"label": "Reviewable"
},
{
"value": "farm_rendering",
"label": "Farm rendering"
}
]
class CreateSaverPluginModel(BaseSettingsModel):
_isGroup = True
temp_rendering_path_template: str = Field(
"", title="Temporary rendering path template"
)
default_variants: list[str] = Field(
default_factory=list,
title="Default variants"
)
instance_attributes: list[str] = Field(
default_factory=list,
enum_resolver=_create_saver_instance_attributes_enum,
title="Instance attributes"
)
class CreatPluginsModel(BaseSettingsModel):
CreateSaver: CreateSaverPluginModel = Field(
default_factory=CreateSaverPluginModel,
title="Create Saver"
)
class FusionSettings(BaseSettingsModel):
imageio: FusionImageIOModel = Field(
default_factory=FusionImageIOModel,
title="Color Management (ImageIO)"
)
copy_fusion_settings: CopyFusionSettingsModel = Field(
default_factory=CopyFusionSettingsModel,
title="Local Fusion profile settings"
)
create: CreatPluginsModel = Field(
default_factory=CreatPluginsModel,
title="Creator plugins"
)
DEFAULT_VALUES = {
"imageio": {
"ocio_config": {
"enabled": False,
"filepath": []
},
"file_rules": {
"enabled": False,
"rules": []
}
},
"copy_fusion_settings": {
"copy_path": "~/.openpype/hosts/fusion/profiles",
"copy_status": False,
"force_sync": False
},
"create": {
"CreateSaver": {
"temp_rendering_path_template": "{workdir}/renders/fusion/{product[name]}/{product[name]}.{frame}.{ext}",
"default_variants": [
"Main",
"Mask"
],
"instance_attributes": [
"reviewable",
"farm_rendering"
]
}
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,4 @@
ToonBoom Harmony Addon
===============
Integration with ToonBoom Harmony.

View file

@ -0,0 +1,15 @@
from ayon_server.addons import BaseServerAddon
from .settings import HarmonySettings, DEFAULT_HARMONY_SETTING
from .version import __version__
class Harmony(BaseServerAddon):
name = "harmony"
version = __version__
settings_model = HarmonySettings
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_HARMONY_SETTING)

View file

@ -0,0 +1,10 @@
from .main import (
HarmonySettings,
DEFAULT_HARMONY_SETTING,
)
__all__ = (
"HarmonySettings",
"DEFAULT_HARMONY_SETTING",
)

View file

@ -0,0 +1,55 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings.validators import ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class ImageIORemappingRulesModel(BaseSettingsModel):
host_native_name: str = Field(
title="Application native colorspace name"
)
ocio_name: str = Field(title="OCIO colorspace name")
class HarmonyImageIOModel(BaseSettingsModel):
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)

View file

@ -0,0 +1,20 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class ImageSequenceLoaderModel(BaseSettingsModel):
family: list[str] = Field(
default_factory=list,
title="Families"
)
representations: list[str] = Field(
default_factory=list,
title="Representations"
)
class HarmonyLoadModel(BaseSettingsModel):
ImageSequenceLoader: ImageSequenceLoaderModel = Field(
default_factory=ImageSequenceLoaderModel,
title="Load Image Sequence"
)

View file

@ -0,0 +1,68 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
from .imageio import HarmonyImageIOModel
from .load import HarmonyLoadModel
from .publish_plugins import HarmonyPublishPlugins
class HarmonySettings(BaseSettingsModel):
"""Harmony Project Settings."""
imageio: HarmonyImageIOModel = Field(
default_factory=HarmonyImageIOModel,
title="OCIO config"
)
load: HarmonyLoadModel = Field(
default_factory=HarmonyLoadModel,
title="Loader plugins"
)
publish: HarmonyPublishPlugins = Field(
default_factory=HarmonyPublishPlugins,
title="Publish plugins"
)
DEFAULT_HARMONY_SETTING = {
"load": {
"ImageSequenceLoader": {
"family": [
"shot",
"render",
"image",
"plate",
"reference"
],
"representations": [
"jpeg",
"png",
"jpg"
]
}
},
"publish": {
"CollectPalettes": {
"allowed_tasks": [
".*"
]
},
"ValidateAudio": {
"enabled": True,
"optional": True,
"active": True
},
"ValidateContainers": {
"enabled": True,
"optional": True,
"active": True
},
"ValidateSceneSettings": {
"enabled": True,
"optional": True,
"active": True,
"frame_check_filter": [],
"skip_resolution_check": [],
"skip_timelines_check": []
}
}
}

View file

@ -0,0 +1,76 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CollectPalettesPlugin(BaseSettingsModel):
"""Set regular expressions to filter triggering on specific task names. '.*' means on all.""" # noqa
allowed_tasks: list[str] = Field(
default_factory=list,
title="Allowed tasks"
)
class ValidateAudioPlugin(BaseSettingsModel):
"""Check if scene contains audio track.""" #
_isGroup = True
enabled: bool = True
optional: bool = Field(False, title="Optional")
active: bool = Field(True, title="Active")
class ValidateContainersPlugin(BaseSettingsModel):
"""Check if loaded container is scene are latest versions."""
_isGroup = True
enabled: bool = True
optional: bool = Field(False, title="Optional")
active: bool = Field(True, title="Active")
class ValidateSceneSettingsPlugin(BaseSettingsModel):
"""Validate if FrameStart, FrameEnd and Resolution match shot data in DB.
Use regular expressions to limit validations only on particular asset
or task names."""
_isGroup = True
enabled: bool = True
optional: bool = Field(False, title="Optional")
active: bool = Field(True, title="Active")
frame_check_filter: list[str] = Field(
default_factory=list,
title="Skip Frame check for Assets with name containing"
)
skip_resolution_check: list[str] = Field(
default_factory=list,
title="Skip Resolution Check for Tasks"
)
skip_timelines_check: list[str] = Field(
default_factory=list,
title="Skip Timeline Check for Tasks"
)
class HarmonyPublishPlugins(BaseSettingsModel):
CollectPalettes: CollectPalettesPlugin = Field(
title="Collect Palettes",
default_factory=CollectPalettesPlugin,
)
ValidateAudio: ValidateAudioPlugin = Field(
title="Validate Audio",
default_factory=ValidateAudioPlugin,
)
ValidateContainers: ValidateContainersPlugin = Field(
title="Validate Containers",
default_factory=ValidateContainersPlugin,
)
ValidateSceneSettings: ValidateSceneSettingsPlugin = Field(
title="Validate Scene Settings",
default_factory=ValidateSceneSettingsPlugin,
)

View file

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring addon version."""
__version__ = "0.1.1"

View file

@ -0,0 +1,19 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import HieroSettings, DEFAULT_VALUES
class HieroAddon(BaseServerAddon):
name = "hiero"
title = "Hiero"
version = __version__
settings_model: Type[HieroSettings] = HieroSettings
frontend_scopes = {}
services = {}
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,10 @@
from .main import (
HieroSettings,
DEFAULT_VALUES,
)
__all__ = (
"HieroSettings",
"DEFAULT_VALUES",
)

View file

@ -0,0 +1,98 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
from ayon_server.types import (
ColorRGBA_float,
ColorRGB_uint8
)
class Vector2d(BaseSettingsModel):
_layout = "compact"
x: float = Field(1.0, title="X")
y: float = Field(1.0, title="Y")
class Vector3d(BaseSettingsModel):
_layout = "compact"
x: float = Field(1.0, title="X")
y: float = Field(1.0, title="Y")
z: float = Field(1.0, title="Z")
def formatable_knob_type_enum():
return [
{"value": "text", "label": "Text"},
{"value": "number", "label": "Number"},
{"value": "decimal_number", "label": "Decimal number"},
{"value": "2d_vector", "label": "2D vector"},
# "3D vector"
]
class Formatable(BaseSettingsModel):
_layout = "compact"
template: str = Field(
"",
placeholder="""{{key}} or {{key}};{{key}}""",
title="Template"
)
to_type: str = Field(
"Text",
title="To Knob type",
enum_resolver=formatable_knob_type_enum,
)
knob_types_enum = [
{"value": "text", "label": "Text"},
{"value": "formatable", "label": "Formate from template"},
{"value": "color_gui", "label": "Color GUI"},
{"value": "boolean", "label": "Boolean"},
{"value": "number", "label": "Number"},
{"value": "decimal_number", "label": "Decimal number"},
{"value": "vector_2d", "label": "2D vector"},
{"value": "vector_3d", "label": "3D vector"},
{"value": "color", "label": "Color"}
]
class KnobModel(BaseSettingsModel):
_layout = "expanded"
type: str = Field(
title="Type",
description="Switch between different knob types",
enum_resolver=lambda: knob_types_enum,
conditionalEnum=True
)
name: str = Field(
title="Name",
placeholder="Name"
)
text: str = Field("", title="Value")
color_gui: ColorRGB_uint8 = Field(
(0, 0, 255),
title="RGB Uint8",
)
boolean: bool = Field(False, title="Value")
number: int = Field(0, title="Value")
decimal_number: float = Field(0.0, title="Value")
vector_2d: Vector2d = Field(
default_factory=Vector2d,
title="Value"
)
vector_3d: Vector3d = Field(
default_factory=Vector3d,
title="Value"
)
color: ColorRGBA_float = Field(
(0.0, 0.0, 1.0, 1.0),
title="RGBA Float"
)
formatable: Formatable = Field(
default_factory=Formatable,
title="Value"
)

View file

@ -0,0 +1,97 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CreateShotClipModels(BaseSettingsModel):
hierarchy: str = Field(
"{folder}/{sequence}",
title="Shot parent hierarchy",
section="Shot Hierarchy And Rename Settings"
)
clipRename: bool = Field(
True,
title="Rename clips"
)
clipName: str = Field(
"{track}{sequence}{shot}",
title="Clip name template"
)
countFrom: int = Field(
10,
title="Count sequence from"
)
countSteps: int = Field(
10,
title="Stepping number"
)
folder: str = Field(
"shots",
title="{folder}",
section="Shot Template Keywords"
)
episode: str = Field(
"ep01",
title="{episode}"
)
sequence: str = Field(
"sq01",
title="{sequence}"
)
track: str = Field(
"{_track_}",
title="{track}"
)
shot: str = Field(
"sh###",
title="{shot}"
)
vSyncOn: bool = Field(
False,
title="Enable Vertical Sync",
section="Vertical Synchronization Of Attributes"
)
workfileFrameStart: int = Field(
1001,
title="Workfiles Start Frame",
section="Shot Attributes"
)
handleStart: int = Field(
10,
title="Handle start (head)"
)
handleEnd: int = Field(
10,
title="Handle end (tail)"
)
class CreatorPluginsSettings(BaseSettingsModel):
CreateShotClip: CreateShotClipModels = Field(
default_factory=CreateShotClipModels,
title="Create Shot Clip"
)
DEFAULT_CREATE_SETTINGS = {
"create": {
"CreateShotClip": {
"hierarchy": "{folder}/{sequence}",
"clipRename": True,
"clipName": "{track}{sequence}{shot}",
"countFrom": 10,
"countSteps": 10,
"folder": "shots",
"episode": "ep01",
"sequence": "sq01",
"track": "{_track_}",
"shot": "sh###",
"vSyncOn": False,
"workfileFrameStart": 1001,
"handleStart": 10,
"handleEnd": 10
}
}
}

View file

@ -0,0 +1,19 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
class PublishGUIFilterItemModel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Name")
value: bool = Field(True, title="Active")
class PublishGUIFiltersModel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Name")
value: list[PublishGUIFilterItemModel] = Field(default_factory=list)
@validator("value")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value

View file

@ -0,0 +1,169 @@
from pydantic import Field, validator
from ayon_server.settings import (
BaseSettingsModel,
ensure_unique_names,
)
def ocio_configs_switcher_enum():
return [
{"value": "nuke-default", "label": "nuke-default"},
{"value": "spi-vfx", "label": "spi-vfx"},
{"value": "spi-anim", "label": "spi-anim"},
{"value": "aces_0.1.1", "label": "aces_0.1.1"},
{"value": "aces_0.7.1", "label": "aces_0.7.1"},
{"value": "aces_1.0.1", "label": "aces_1.0.1"},
{"value": "aces_1.0.3", "label": "aces_1.0.3"},
{"value": "aces_1.1", "label": "aces_1.1"},
{"value": "aces_1.2", "label": "aces_1.2"},
{"value": "aces_1.3", "label": "aces_1.3"},
{"value": "custom", "label": "custom"}
]
class WorkfileColorspaceSettings(BaseSettingsModel):
"""Hiero workfile colorspace preset. """
"""# TODO: enhance settings with host api:
we need to add mapping to resolve properly keys.
Hiero is excpecting camel case key names,
but for better code consistency we are using snake_case:
ocio_config = ocioConfigName
working_space_name = workingSpace
int_16_name = sixteenBitLut
int_8_name = eightBitLut
float_name = floatLut
log_name = logLut
viewer_name = viewerLut
thumbnail_name = thumbnailLut
"""
ocioConfigName: str = Field(
title="OpenColorIO Config",
description="Switch between OCIO configs",
enum_resolver=ocio_configs_switcher_enum,
conditionalEnum=True
)
workingSpace: str = Field(
title="Working Space"
)
viewerLut: str = Field(
title="Viewer"
)
eightBitLut: str = Field(
title="8-bit files"
)
sixteenBitLut: str = Field(
title="16-bit files"
)
logLut: str = Field(
title="Log files"
)
floatLut: str = Field(
title="Float files"
)
thumbnailLut: str = Field(
title="Thumnails"
)
monitorOutLut: str = Field(
title="Monitor"
)
class ClipColorspaceRulesItems(BaseSettingsModel):
_layout = "expanded"
regex: str = Field("", title="Regex expression")
colorspace: str = Field("", title="Colorspace")
class RegexInputsModel(BaseSettingsModel):
inputs: list[ClipColorspaceRulesItems] = Field(
default_factory=list,
title="Inputs"
)
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class ImageIOSettings(BaseSettingsModel):
"""Hiero color management project settings. """
_isGroup: bool = True
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)
workfile: WorkfileColorspaceSettings = Field(
default_factory=WorkfileColorspaceSettings,
title="Workfile"
)
"""# TODO: enhance settings with host api:
- old settings are using `regexInputs` key but we
need to rename to `regex_inputs`
- no need for `inputs` middle part. It can stay
directly on `regex_inputs`
"""
regexInputs: RegexInputsModel = Field(
default_factory=RegexInputsModel,
title="Assign colorspace to clips via rules"
)
DEFAULT_IMAGEIO_SETTINGS = {
"workfile": {
"ocioConfigName": "nuke-default",
"workingSpace": "linear",
"viewerLut": "sRGB",
"eightBitLut": "sRGB",
"sixteenBitLut": "sRGB",
"logLut": "Cineon",
"floatLut": "linear",
"thumbnailLut": "sRGB",
"monitorOutLut": "sRGB"
},
"regexInputs": {
"inputs": [
{
"regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)",
"colorspace": "sRGB"
}
]
}
}

View file

@ -0,0 +1,38 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class LoadClipModel(BaseSettingsModel):
enabled: bool = Field(
True,
title="Enabled"
)
product_types: list[str] = Field(
default_factory=list,
title="Product types"
)
clip_name_template: str = Field(
title="Clip name template"
)
class LoaderPuginsModel(BaseSettingsModel):
LoadClip: LoadClipModel = Field(
default_factory=LoadClipModel,
title="Load Clip"
)
DEFAULT_LOADER_PLUGINS_SETTINGS = {
"LoadClip": {
"enabled": True,
"product_types": [
"render2d",
"source",
"plate",
"render",
"review"
],
"clip_name_template": "{folder[name]}_{product[name]}_{representation}"
}
}

View file

@ -0,0 +1,64 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
from .imageio import (
ImageIOSettings,
DEFAULT_IMAGEIO_SETTINGS
)
from .create_plugins import (
CreatorPluginsSettings,
DEFAULT_CREATE_SETTINGS
)
from .loader_plugins import (
LoaderPuginsModel,
DEFAULT_LOADER_PLUGINS_SETTINGS
)
from .publish_plugins import (
PublishPuginsModel,
DEFAULT_PUBLISH_PLUGIN_SETTINGS
)
from .scriptsmenu import (
ScriptsmenuSettings,
DEFAULT_SCRIPTSMENU_SETTINGS
)
from .filters import PublishGUIFilterItemModel
class HieroSettings(BaseSettingsModel):
"""Nuke addon settings."""
imageio: ImageIOSettings = Field(
default_factory=ImageIOSettings,
title="Color Management (imageio)",
)
create: CreatorPluginsSettings = Field(
default_factory=CreatorPluginsSettings,
title="Creator Plugins",
)
load: LoaderPuginsModel = Field(
default_factory=LoaderPuginsModel,
title="Loader plugins"
)
publish: PublishPuginsModel = Field(
default_factory=PublishPuginsModel,
title="Publish plugins"
)
scriptsmenu: ScriptsmenuSettings = Field(
default_factory=ScriptsmenuSettings,
title="Scripts Menu Definition",
)
filters: list[PublishGUIFilterItemModel] = Field(
default_factory=list
)
DEFAULT_VALUES = {
"imageio": DEFAULT_IMAGEIO_SETTINGS,
"create": DEFAULT_CREATE_SETTINGS,
"load": DEFAULT_LOADER_PLUGINS_SETTINGS,
"publish": DEFAULT_PUBLISH_PLUGIN_SETTINGS,
"scriptsmenu": DEFAULT_SCRIPTSMENU_SETTINGS,
"filters": [],
}

View file

@ -0,0 +1,48 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CollectInstanceVersionModel(BaseSettingsModel):
enabled: bool = Field(
True,
title="Enabled"
)
class ExtractReviewCutUpVideoModel(BaseSettingsModel):
enabled: bool = Field(
True,
title="Enabled"
)
tags_addition: list[str] = Field(
default_factory=list,
title="Additional tags"
)
class PublishPuginsModel(BaseSettingsModel):
CollectInstanceVersion: CollectInstanceVersionModel = Field(
default_factory=CollectInstanceVersionModel,
title="Collect Instance Version"
)
"""# TODO: enhance settings with host api:
Rename class name and plugin name
to match title (it makes more sense)
"""
ExtractReviewCutUpVideo: ExtractReviewCutUpVideoModel = Field(
default_factory=ExtractReviewCutUpVideoModel,
title="Exctract Review Trim"
)
DEFAULT_PUBLISH_PLUGIN_SETTINGS = {
"CollectInstanceVersion": {
"enabled": False,
},
"ExtractReviewCutUpVideo": {
"enabled": True,
"tags_addition": [
"review"
]
}
}

View file

@ -0,0 +1,41 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class ScriptsmenuSubmodel(BaseSettingsModel):
"""Item Definition"""
_isGroup = True
type: str = Field(title="Type")
command: str = Field(title="Command")
sourcetype: str = Field(title="Source Type")
title: str = Field(title="Title")
tooltip: str = Field(title="Tooltip")
class ScriptsmenuSettings(BaseSettingsModel):
"""Nuke script menu project settings."""
_isGroup = True
"""# TODO: enhance settings with host api:
- in api rename key `name` to `menu_name`
"""
name: str = Field(title="Menu name")
definition: list[ScriptsmenuSubmodel] = Field(
default_factory=list,
title="Definition",
description="Scriptmenu Items Definition")
DEFAULT_SCRIPTSMENU_SETTINGS = {
"name": "OpenPype Tools",
"definition": [
{
"type": "action",
"sourcetype": "python",
"title": "OpenPype Docs",
"command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_hiero')",
"tooltip": "Open the OpenPype Hiero user doc page"
}
]
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,17 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import HoudiniSettings, DEFAULT_VALUES
class Houdini(BaseServerAddon):
name = "houdini"
title = "Houdini"
version = __version__
settings_model: Type[HoudiniSettings] = HoudiniSettings
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,10 @@
from .main import (
HoudiniSettings,
DEFAULT_VALUES,
)
__all__ = (
"HoudiniSettings",
"DEFAULT_VALUES",
)

View file

@ -0,0 +1,48 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings.validators import ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class HoudiniImageIOModel(BaseSettingsModel):
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)

View file

@ -0,0 +1,79 @@
from pydantic import Field
from ayon_server.settings import (
BaseSettingsModel,
MultiplatformPathModel,
MultiplatformPathListModel,
)
from .imageio import HoudiniImageIOModel
from .publish_plugins import (
PublishPluginsModel,
CreatePluginsModel,
DEFAULT_HOUDINI_PUBLISH_SETTINGS,
DEFAULT_HOUDINI_CREATE_SETTINGS
)
class ShelfToolsModel(BaseSettingsModel):
name: str = Field(title="Name")
help: str = Field(title="Help text")
script: MultiplatformPathModel = Field(
default_factory=MultiplatformPathModel,
title="Script Path "
)
icon: MultiplatformPathModel = Field(
default_factory=MultiplatformPathModel,
title="Icon Path "
)
class ShelfDefinitionModel(BaseSettingsModel):
_layout = "expanded"
shelf_name: str = Field(title="Shelf name")
tools_list: list[ShelfToolsModel] = Field(
default_factory=list,
title="Shelf Tools"
)
class ShelvesModel(BaseSettingsModel):
_layout = "expanded"
shelf_set_name: str = Field(title="Shelfs set name")
shelf_set_source_path: MultiplatformPathListModel = Field(
default_factory=MultiplatformPathListModel,
title="Shelf Set Path (optional)"
)
shelf_definition: list[ShelfDefinitionModel] = Field(
default_factory=list,
title="Shelf Definitions"
)
class HoudiniSettings(BaseSettingsModel):
imageio: HoudiniImageIOModel = Field(
default_factory=HoudiniImageIOModel,
title="Color Management (ImageIO)"
)
shelves: list[ShelvesModel] = Field(
default_factory=list,
title="Houdini Scripts Shelves",
)
publish: PublishPluginsModel = Field(
default_factory=PublishPluginsModel,
title="Publish Plugins",
)
create: CreatePluginsModel = Field(
default_factory=CreatePluginsModel,
title="Creator Plugins",
)
DEFAULT_VALUES = {
"shelves": [],
"create": DEFAULT_HOUDINI_CREATE_SETTINGS,
"publish": DEFAULT_HOUDINI_PUBLISH_SETTINGS
}

View file

@ -0,0 +1,150 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
# Creator Plugins
class CreatorModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
defaults: list[str] = Field(title="Default Products")
class CreateArnoldAssModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
defaults: list[str] = Field(title="Default Products")
ext: str = Field(Title="Extension")
class CreatePluginsModel(BaseSettingsModel):
CreateArnoldAss: CreateArnoldAssModel = Field(
default_factory=CreateArnoldAssModel,
title="Create Alembic Camera")
CreateAlembicCamera: CreatorModel = Field(
default_factory=CreatorModel,
title="Create Alembic Camera")
CreateCompositeSequence: CreatorModel = Field(
default_factory=CreatorModel,
title="Create Composite Sequence")
CreatePointCache: CreatorModel = Field(
default_factory=CreatorModel,
title="Create Point Cache")
CreateRedshiftROP: CreatorModel = Field(
default_factory=CreatorModel,
title="Create RedshiftROP")
CreateRemotePublish: CreatorModel = Field(
default_factory=CreatorModel,
title="Create Remote Publish")
CreateVDBCache: CreatorModel = Field(
default_factory=CreatorModel,
title="Create VDB Cache")
CreateUSD: CreatorModel = Field(
default_factory=CreatorModel,
title="Create USD")
CreateUSDModel: CreatorModel = Field(
default_factory=CreatorModel,
title="Create USD model")
USDCreateShadingWorkspace: CreatorModel = Field(
default_factory=CreatorModel,
title="Create USD shading workspace")
CreateUSDRender: CreatorModel = Field(
default_factory=CreatorModel,
title="Create USD render")
DEFAULT_HOUDINI_CREATE_SETTINGS = {
"CreateArnoldAss": {
"enabled": True,
"defaults": [],
"ext": ".ass"
},
"CreateAlembicCamera": {
"enabled": True,
"defaults": []
},
"CreateCompositeSequence": {
"enabled": True,
"defaults": []
},
"CreatePointCache": {
"enabled": True,
"defaults": []
},
"CreateRedshiftROP": {
"enabled": True,
"defaults": []
},
"CreateRemotePublish": {
"enabled": True,
"defaults": []
},
"CreateVDBCache": {
"enabled": True,
"defaults": []
},
"CreateUSD": {
"enabled": False,
"defaults": []
},
"CreateUSDModel": {
"enabled": False,
"defaults": []
},
"USDCreateShadingWorkspace": {
"enabled": False,
"defaults": []
},
"CreateUSDRender": {
"enabled": False,
"defaults": []
}
}
# Publish Plugins
class ValidateWorkfilePathsModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
optional: bool = Field(title="Optional")
node_types: list[str] = Field(
default_factory=list,
title="Node Types"
)
prohibited_vars: list[str] = Field(
default_factory=list,
title="Prohibited Variables"
)
class ValidateContainersModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
optional: bool = Field(title="Optional")
active: bool = Field(title="Active")
class PublishPluginsModel(BaseSettingsModel):
ValidateWorkfilePaths: ValidateWorkfilePathsModel = Field(
default_factory=ValidateWorkfilePathsModel,
title="Validate workfile paths settings.")
ValidateContainers: ValidateContainersModel = Field(
default_factory=ValidateContainersModel,
title="Validate Latest Containers.")
DEFAULT_HOUDINI_PUBLISH_SETTINGS = {
"ValidateWorkfilePaths": {
"enabled": True,
"optional": True,
"node_types": [
"file",
"alembic"
],
"prohibited_vars": [
"$HIP",
"$JOB"
]
},
"ValidateContainers": {
"enabled": True,
"optional": True,
"active": True
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,19 @@
from typing import Type
from ayon_server.addons import BaseServerAddon
from .version import __version__
from .settings import KitsuSettings, DEFAULT_VALUES
class KitsuAddon(BaseServerAddon):
name = "kitsu"
title = "Kitsu"
version = __version__
settings_model: Type[KitsuSettings] = KitsuSettings
frontend_scopes = {}
services = {}
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_VALUES)

View file

@ -0,0 +1,111 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class EntityPattern(BaseSettingsModel):
episode: str = Field(title="Episode")
sequence: str = Field(title="Sequence")
shot: str = Field(title="Shot")
def _status_change_cond_enum():
return [
{"value": "equal", "label": "Equal"},
{"value": "not_equal", "label": "Not equal"}
]
class StatusChangeCondition(BaseSettingsModel):
condition: str = Field(
"equal",
enum_resolver=_status_change_cond_enum,
title="Condition"
)
short_name: str = Field("", title="Short name")
class StatusChangeProductTypeRequirementModel(BaseSettingsModel):
condition: str = Field(
"equal",
enum_resolver=_status_change_cond_enum,
title="Condition"
)
product_type: str = Field("", title="Product type")
class StatusChangeConditionsModel(BaseSettingsModel):
status_conditions: list[StatusChangeCondition] = Field(
default_factory=list,
title="Status conditions"
)
product_type_requirements: list[StatusChangeProductTypeRequirementModel] = Field(
default_factory=list,
title="Product type requirements")
class CustomCommentTemplateModel(BaseSettingsModel):
enabled: bool = Field(True)
comment_template: str = Field("", title="Custom comment")
class IntegrateKitsuNotes(BaseSettingsModel):
"""Kitsu supports markdown and here you can create a custom comment template.
You can use data from your publishing instance's data.
"""
set_status_note: bool = Field(title="Set status on note")
note_status_shortname: str = Field(title="Note shortname")
status_change_conditions: StatusChangeConditionsModel = Field(
default_factory=StatusChangeConditionsModel,
title="Status change conditions"
)
custom_comment_template: CustomCommentTemplateModel = Field(
default_factory=CustomCommentTemplateModel,
title="Custom Comment Template",
)
class PublishPlugins(BaseSettingsModel):
IntegrateKitsuNote: IntegrateKitsuNotes = Field(
default_factory=IntegrateKitsuNotes,
title="Integrate Kitsu Note"
)
class KitsuSettings(BaseSettingsModel):
server: str = Field(
"",
title="Kitsu Server"
)
entities_naming_pattern: EntityPattern = Field(
default_factory=EntityPattern,
title="Entities naming pattern"
)
publish: PublishPlugins = Field(
default_factory=PublishPlugins,
title="Publish plugins"
)
DEFAULT_VALUES = {
"entities_naming_pattern": {
"episode": "E##",
"sequence": "SQ##",
"shot": "SH##"
},
"publish": {
"IntegrateKitsuNote": {
"set_status_note": False,
"note_status_shortname": "wfa",
"status_change_conditions": {
"status_conditions": [],
"product_type_requirements": []
},
"custom_comment_template": {
"enabled": False,
"comment_template": "{comment}\n\n| | |\n|--|--|\n| version| `{version}` |\n| product type | `{product[type]}` |\n| name | `{name}` |"
}
}
}
}

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

201
server_addon/maya/LICENCE Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,4 @@
Maya Integration Addon
======================
WIP

View file

@ -0,0 +1,16 @@
"""Maya Addon Module"""
from ayon_server.addons import BaseServerAddon
from .settings.main import MayaSettings, DEFAULT_MAYA_SETTING
from .version import __version__
class MayaAddon(BaseServerAddon):
name = "maya"
title = "Maya"
version = __version__
settings_model = MayaSettings
async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
return settings_model_cls(**DEFAULT_MAYA_SETTING)

View file

@ -0,0 +1,408 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class CreateLookModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
make_tx: bool = Field(title="Make tx files")
rs_tex: bool = Field(title="Make Redshift texture files")
defaults: list[str] = Field(
default_factory=["Main"], title="Default Products"
)
class BasicCreatorModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
defaults: list[str] = Field(
default_factory=list,
title="Default Products"
)
class CreateUnrealStaticMeshModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
defaults: list[str] = Field(
default_factory=["", "_Main"],
title="Default Products"
)
static_mesh_prefixes: str = Field("S", title="Static Mesh Prefix")
collision_prefixes: list[str] = Field(
default_factory=["UBX", "UCP", "USP", "UCX"],
title="Collision Prefixes"
)
class CreateUnrealSkeletalMeshModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
defaults: list[str] = Field(default_factory=[], title="Default Products")
joint_hints: str = Field("jnt_org", title="Joint root hint")
class CreateMultiverseLookModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
publish_mip_map: bool = Field(title="publish_mip_map")
class BasicExportMeshModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
write_color_sets: bool = Field(title="Write Color Sets")
write_face_sets: bool = Field(title="Write Face Sets")
defaults: list[str] = Field(
default_factory=list,
title="Default Products"
)
class CreateAnimationModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
write_color_sets: bool = Field(title="Write Color Sets")
write_face_sets: bool = Field(title="Write Face Sets")
include_parent_hierarchy: bool = Field(
title="Include Parent Hierarchy")
include_user_defined_attributes: bool = Field(
title="Include User Defined Attributes")
defaults: list[str] = Field(
default_factory=list,
title="Default Products"
)
class CreatePointCacheModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
write_color_sets: bool = Field(title="Write Color Sets")
write_face_sets: bool = Field(title="Write Face Sets")
include_user_defined_attributes: bool = Field(
title="Include User Defined Attributes"
)
defaults: list[str] = Field(
default_factory=["Main"],
title="Default Products"
)
class CreateProxyAlembicModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
write_color_sets: bool = Field(title="Write Color Sets")
write_face_sets: bool = Field(title="Write Face Sets")
defaults: list[str] = Field(
default_factory=["Main"],
title="Default Products"
)
class CreateAssModel(BasicCreatorModel):
expandProcedurals: bool = Field(title="Expand Procedurals")
motionBlur: bool = Field(title="Motion Blur")
motionBlurKeys: int = Field(2, title="Motion Blur Keys")
motionBlurLength: float = Field(0.5, title="Motion Blur Length")
maskOptions: bool = Field(title="Mask Options")
maskCamera: bool = Field(title="Mask Camera")
maskLight: bool = Field(title="Mask Light")
maskShape: bool = Field(title="Mask Shape")
maskShader: bool = Field(title="Mask Shader")
maskOverride: bool = Field(title="Mask Override")
maskDriver: bool = Field(title="Mask Driver")
maskFilter: bool = Field(title="Mask Filter")
maskColor_manager: bool = Field(title="Mask Color Manager")
maskOperator: bool = Field(title="Mask Operator")
class CreateReviewModel(BasicCreatorModel):
useMayaTimeline: bool = Field(title="Use Maya Timeline for Frame Range.")
class CreateVrayProxyModel(BaseSettingsModel):
enabled: bool = Field(True)
vrmesh: bool = Field(title="VrMesh")
alembic: bool = Field(title="Alembic")
defaults: list[str] = Field(default_factory=list, title="Default Products")
class CreatorsModel(BaseSettingsModel):
CreateLook: CreateLookModel = Field(
default_factory=CreateLookModel,
title="Create Look"
)
CreateRender: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Render"
)
# "-" is not compatible in the new model
CreateUnrealStaticMesh: CreateUnrealStaticMeshModel = Field(
default_factory=CreateUnrealStaticMeshModel,
title="Create Unreal_Static Mesh"
)
# "-" is not compatible in the new model
CreateUnrealSkeletalMesh: CreateUnrealSkeletalMeshModel = Field(
default_factory=CreateUnrealSkeletalMeshModel,
title="Create Unreal_Skeletal Mesh"
)
CreateMultiverseLook: CreateMultiverseLookModel = Field(
default_factory=CreateMultiverseLookModel,
title="Create Multiverse Look"
)
CreateAnimation: CreateAnimationModel = Field(
default_factory=CreateAnimationModel,
title="Create Animation"
)
CreateModel: BasicExportMeshModel = Field(
default_factory=BasicExportMeshModel,
title="Create Model"
)
CreatePointCache: CreatePointCacheModel = Field(
default_factory=CreatePointCacheModel,
title="Create Point Cache"
)
CreateProxyAlembic: CreateProxyAlembicModel = Field(
default_factory=CreateProxyAlembicModel,
title="Create Proxy Alembic"
)
CreateMultiverseUsd: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Multiverse USD"
)
CreateMultiverseUsdComp: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Multiverse USD Composition"
)
CreateMultiverseUsdOver: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Multiverse USD Override"
)
CreateAss: CreateAssModel = Field(
default_factory=CreateAssModel,
title="Create Ass"
)
CreateAssembly: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Assembly"
)
CreateCamera: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Camera"
)
CreateLayout: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Layout"
)
CreateMayaScene: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Maya Scene"
)
CreateRenderSetup: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Render Setup"
)
CreateReview: CreateReviewModel = Field(
default_factory=CreateReviewModel,
title="Create Review"
)
CreateRig: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Rig"
)
CreateSetDress: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Set Dress"
)
CreateVrayProxy: CreateVrayProxyModel = Field(
default_factory=CreateVrayProxyModel,
title="Create VRay Proxy"
)
CreateVRayScene: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create VRay Scene"
)
CreateYetiRig: BasicCreatorModel = Field(
default_factory=BasicCreatorModel,
title="Create Yeti Rig"
)
DEFAULT_CREATORS_SETTINGS = {
"CreateLook": {
"enabled": True,
"make_tx": True,
"rs_tex": False,
"defaults": [
"Main"
]
},
"CreateRender": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateUnrealStaticMesh": {
"enabled": True,
"defaults": [
"",
"_Main"
],
"static_mesh_prefix": "S",
"collision_prefixes": [
"UBX",
"UCP",
"USP",
"UCX"
]
},
"CreateUnrealSkeletalMesh": {
"enabled": True,
"defaults": [],
"joint_hints": "jnt_org"
},
"CreateMultiverseLook": {
"enabled": True,
"publish_mip_map": True
},
"CreateAnimation": {
"enabled": False,
"write_color_sets": False,
"write_face_sets": False,
"include_parent_hierarchy": False,
"include_user_defined_attributes": False,
"defaults": [
"Main"
]
},
"CreateModel": {
"enabled": True,
"write_color_sets": False,
"write_face_sets": False,
"defaults": [
"Main",
"Proxy",
"Sculpt"
]
},
"CreatePointCache": {
"enabled": True,
"write_color_sets": False,
"write_face_sets": False,
"include_user_defined_attributes": False,
"defaults": [
"Main"
]
},
"CreateProxyAlembic": {
"enabled": True,
"write_color_sets": False,
"write_face_sets": False,
"defaults": [
"Main"
]
},
"CreateMultiverseUsd": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateMultiverseUsdComp": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateMultiverseUsdOver": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateAss": {
"enabled": True,
"defaults": [
"Main"
],
"expandProcedurals": False,
"motionBlur": True,
"motionBlurKeys": 2,
"motionBlurLength": 0.5,
"maskOptions": False,
"maskCamera": False,
"maskLight": False,
"maskShape": False,
"maskShader": False,
"maskOverride": False,
"maskDriver": False,
"maskFilter": False,
"maskColor_manager": False,
"maskOperator": False
},
"CreateAssembly": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateCamera": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateLayout": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateMayaScene": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateRenderSetup": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateReview": {
"enabled": True,
"defaults": [
"Main"
],
"useMayaTimeline": True
},
"CreateRig": {
"enabled": True,
"defaults": [
"Main",
"Sim",
"Cloth"
]
},
"CreateSetDress": {
"enabled": True,
"defaults": [
"Main",
"Anim"
]
},
"CreateVrayProxy": {
"enabled": True,
"vrmesh": True,
"alembic": True,
"defaults": [
"Main"
]
},
"CreateVRayScene": {
"enabled": True,
"defaults": [
"Main"
]
},
"CreateYetiRig": {
"enabled": True,
"defaults": [
"Main"
]
}
}

View file

@ -0,0 +1,429 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class PluginsModel(BaseSettingsModel):
_layout = "expanded"
enabled: bool = Field(title="Enabled")
name: str = Field("", title="Name")
class ExplicitPluginsLoadingModel(BaseSettingsModel):
"""Maya Explicit Plugins Loading."""
_isGroup: bool = True
enabled: bool = Field(title="enabled")
plugins_to_load: list[PluginsModel] = Field(
default_factory=list, title="Plugins To Load"
)
DEFAULT_EXPLITCIT_PLUGINS_LOADING_SETTINGS = {
"enabled": False,
"plugins_to_load": [
{
"enabled": False,
"name": "AbcBullet"
},
{
"enabled": True,
"name": "AbcExport"
},
{
"enabled": True,
"name": "AbcImport"
},
{
"enabled": False,
"name": "animImportExport"
},
{
"enabled": False,
"name": "ArubaTessellator"
},
{
"enabled": False,
"name": "ATFPlugin"
},
{
"enabled": False,
"name": "atomImportExport"
},
{
"enabled": False,
"name": "AutodeskPacketFile"
},
{
"enabled": False,
"name": "autoLoader"
},
{
"enabled": False,
"name": "bifmeshio"
},
{
"enabled": False,
"name": "bifrostGraph"
},
{
"enabled": False,
"name": "bifrostshellnode"
},
{
"enabled": False,
"name": "bifrostvisplugin"
},
{
"enabled": False,
"name": "blast2Cmd"
},
{
"enabled": False,
"name": "bluePencil"
},
{
"enabled": False,
"name": "Boss"
},
{
"enabled": False,
"name": "bullet"
},
{
"enabled": True,
"name": "cacheEvaluator"
},
{
"enabled": False,
"name": "cgfxShader"
},
{
"enabled": False,
"name": "cleanPerFaceAssignment"
},
{
"enabled": False,
"name": "clearcoat"
},
{
"enabled": False,
"name": "convertToComponentTags"
},
{
"enabled": False,
"name": "curveWarp"
},
{
"enabled": False,
"name": "ddsFloatReader"
},
{
"enabled": True,
"name": "deformerEvaluator"
},
{
"enabled": False,
"name": "dgProfiler"
},
{
"enabled": False,
"name": "drawUfe"
},
{
"enabled": False,
"name": "dx11Shader"
},
{
"enabled": False,
"name": "fbxmaya"
},
{
"enabled": False,
"name": "fltTranslator"
},
{
"enabled": False,
"name": "freeze"
},
{
"enabled": False,
"name": "Fur"
},
{
"enabled": False,
"name": "gameFbxExporter"
},
{
"enabled": False,
"name": "gameInputDevice"
},
{
"enabled": False,
"name": "GamePipeline"
},
{
"enabled": False,
"name": "gameVertexCount"
},
{
"enabled": False,
"name": "geometryReport"
},
{
"enabled": False,
"name": "geometryTools"
},
{
"enabled": False,
"name": "glslShader"
},
{
"enabled": True,
"name": "GPUBuiltInDeformer"
},
{
"enabled": False,
"name": "gpuCache"
},
{
"enabled": False,
"name": "hairPhysicalShader"
},
{
"enabled": False,
"name": "ik2Bsolver"
},
{
"enabled": False,
"name": "ikSpringSolver"
},
{
"enabled": False,
"name": "invertShape"
},
{
"enabled": False,
"name": "lges"
},
{
"enabled": False,
"name": "lookdevKit"
},
{
"enabled": False,
"name": "MASH"
},
{
"enabled": False,
"name": "matrixNodes"
},
{
"enabled": False,
"name": "mayaCharacterization"
},
{
"enabled": False,
"name": "mayaHIK"
},
{
"enabled": False,
"name": "MayaMuscle"
},
{
"enabled": False,
"name": "mayaUsdPlugin"
},
{
"enabled": False,
"name": "mayaVnnPlugin"
},
{
"enabled": False,
"name": "melProfiler"
},
{
"enabled": False,
"name": "meshReorder"
},
{
"enabled": True,
"name": "modelingToolkit"
},
{
"enabled": False,
"name": "mtoa"
},
{
"enabled": False,
"name": "mtoh"
},
{
"enabled": False,
"name": "nearestPointOnMesh"
},
{
"enabled": True,
"name": "objExport"
},
{
"enabled": False,
"name": "OneClick"
},
{
"enabled": False,
"name": "OpenEXRLoader"
},
{
"enabled": False,
"name": "pgYetiMaya"
},
{
"enabled": False,
"name": "pgyetiVrayMaya"
},
{
"enabled": False,
"name": "polyBoolean"
},
{
"enabled": False,
"name": "poseInterpolator"
},
{
"enabled": False,
"name": "quatNodes"
},
{
"enabled": False,
"name": "randomizerDevice"
},
{
"enabled": False,
"name": "redshift4maya"
},
{
"enabled": True,
"name": "renderSetup"
},
{
"enabled": False,
"name": "retargeterNodes"
},
{
"enabled": False,
"name": "RokokoMotionLibrary"
},
{
"enabled": False,
"name": "rotateHelper"
},
{
"enabled": False,
"name": "sceneAssembly"
},
{
"enabled": False,
"name": "shaderFXPlugin"
},
{
"enabled": False,
"name": "shotCamera"
},
{
"enabled": False,
"name": "snapTransform"
},
{
"enabled": False,
"name": "stage"
},
{
"enabled": True,
"name": "stereoCamera"
},
{
"enabled": False,
"name": "stlTranslator"
},
{
"enabled": False,
"name": "studioImport"
},
{
"enabled": False,
"name": "Substance"
},
{
"enabled": False,
"name": "substancelink"
},
{
"enabled": False,
"name": "substancemaya"
},
{
"enabled": False,
"name": "substanceworkflow"
},
{
"enabled": False,
"name": "svgFileTranslator"
},
{
"enabled": False,
"name": "sweep"
},
{
"enabled": False,
"name": "testify"
},
{
"enabled": False,
"name": "tiffFloatReader"
},
{
"enabled": False,
"name": "timeSliderBookmark"
},
{
"enabled": False,
"name": "Turtle"
},
{
"enabled": False,
"name": "Type"
},
{
"enabled": False,
"name": "udpDevice"
},
{
"enabled": False,
"name": "ufeSupport"
},
{
"enabled": False,
"name": "Unfold3D"
},
{
"enabled": False,
"name": "VectorRender"
},
{
"enabled": False,
"name": "vrayformaya"
},
{
"enabled": False,
"name": "vrayvolumegrid"
},
{
"enabled": False,
"name": "xgenToolkit"
},
{
"enabled": False,
"name": "xgenVray"
}
]
}

View file

@ -0,0 +1,126 @@
"""Providing models and setting values for image IO in Maya.
Note: Names were changed to get rid of the versions in class names.
"""
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
class ImageIOConfigModel(BaseSettingsModel):
override_global_config: bool = Field(
False,
title="Override global OCIO config"
)
filepath: list[str] = Field(
default_factory=list,
title="Config path"
)
class ImageIOFileRuleModel(BaseSettingsModel):
name: str = Field("", title="Rule name")
pattern: str = Field("", title="Regex pattern")
colorspace: str = Field("", title="Colorspace name")
ext: str = Field("", title="File extension")
class ImageIOFileRulesModel(BaseSettingsModel):
activate_host_rules: bool = Field(False)
rules: list[ImageIOFileRuleModel] = Field(
default_factory=list,
title="Rules"
)
@validator("rules")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class ColorManagementPreferenceV2Model(BaseSettingsModel):
"""Color Management Preference v2 (Maya 2022+)."""
_layout = "expanded"
enabled: bool = Field(True, title="Use Color Management Preference v2")
renderSpace: str = Field(title="Rendering Space")
displayName: str = Field(title="Display")
viewName: str = Field(title="View")
class ColorManagementPreferenceModel(BaseSettingsModel):
"""Color Management Preference (legacy)."""
_layout = "expanded"
renderSpace: str = Field(title="Rendering Space")
viewTransform: str = Field(title="Viewer Transform ")
class WorkfileImageIOModel(BaseSettingsModel):
enabled: bool = Field(True, title="Enabled")
renderSpace: str = Field(title="Rendering Space")
displayName: str = Field(title="Display")
viewName: str = Field(title="View")
class ImageIOSettings(BaseSettingsModel):
"""Maya color management project settings.
Todo: What to do with color management preferences version?
"""
_isGroup: bool = True
activate_host_color_management: bool = Field(
True, title="Enable Color Management"
)
ocio_config: ImageIOConfigModel = Field(
default_factory=ImageIOConfigModel,
title="OCIO config"
)
file_rules: ImageIOFileRulesModel = Field(
default_factory=ImageIOFileRulesModel,
title="File Rules"
)
workfile: WorkfileImageIOModel = Field(
default_factory=WorkfileImageIOModel,
title="Workfile"
)
# Deprecated
colorManagementPreference_v2: ColorManagementPreferenceV2Model = Field(
default_factory=ColorManagementPreferenceV2Model,
title="Color Management Preference v2 (Maya 2022+)"
)
colorManagementPreference: ColorManagementPreferenceModel = Field(
default_factory=ColorManagementPreferenceModel,
title="Color Management Preference (legacy)"
)
DEFAULT_IMAGEIO_SETTINGS = {
"activate_host_color_management": True,
"ocio_config": {
"override_global_config": False,
"filepath": []
},
"file_rules": {
"activate_host_rules": False,
"rules": []
},
"workfile": {
"enabled": False,
"renderSpace": "ACES - ACEScg",
"displayName": "ACES",
"viewName": "sRGB"
},
"colorManagementPreference_v2": {
"enabled": True,
"renderSpace": "ACEScg",
"displayName": "sRGB",
"viewName": "ACES 1.0 SDR-video"
},
"colorManagementPreference": {
"renderSpace": "scene-linear Rec 709/sRGB",
"viewTransform": "sRGB gamma"
}
}

View file

@ -0,0 +1,30 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel, task_types_enum
class IncludeByTaskTypeModel(BaseSettingsModel):
task_type: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
include_handles: bool = Field(True, title="Include handles")
class IncludeHandlesModel(BaseSettingsModel):
"""Maya dirmap settings."""
# _layout = "expanded"
include_handles_default: bool = Field(
True, title="Include handles by default"
)
per_task_type: list[IncludeByTaskTypeModel] = Field(
default_factory=list,
title="Include/exclude handles by task type"
)
DEFAULT_INCLUDE_HANDLES = {
"include_handles_default": False,
"per_task_type": []
}

View file

@ -0,0 +1,115 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
from ayon_server.types import ColorRGBA_uint8
class ColorsSetting(BaseSettingsModel):
model: ColorRGBA_uint8 = Field(
(209, 132, 30, 1.0), title="Model:")
rig: ColorRGBA_uint8 = Field(
(59, 226, 235, 1.0), title="Rig:")
pointcache: ColorRGBA_uint8 = Field(
(94, 209, 30, 1.0), title="Pointcache:")
animation: ColorRGBA_uint8 = Field(
(94, 209, 30, 1.0), title="Animation:")
ass: ColorRGBA_uint8 = Field(
(249, 135, 53, 1.0), title="Arnold StandIn:")
camera: ColorRGBA_uint8 = Field(
(136, 114, 244, 1.0), title="Camera:")
fbx: ColorRGBA_uint8 = Field(
(215, 166, 255, 1.0), title="FBX:")
mayaAscii: ColorRGBA_uint8 = Field(
(67, 174, 255, 1.0), title="Maya Ascii:")
mayaScene: ColorRGBA_uint8 = Field(
(67, 174, 255, 1.0), title="Maya Scene:")
setdress: ColorRGBA_uint8 = Field(
(255, 250, 90, 1.0), title="Set Dress:")
layout: ColorRGBA_uint8 = Field((
255, 250, 90, 1.0), title="Layout:")
vdbcache: ColorRGBA_uint8 = Field(
(249, 54, 0, 1.0), title="VDB Cache:")
vrayproxy: ColorRGBA_uint8 = Field(
(255, 150, 12, 1.0), title="VRay Proxy:")
vrayscene_layer: ColorRGBA_uint8 = Field(
(255, 150, 12, 1.0), title="VRay Scene:")
yeticache: ColorRGBA_uint8 = Field(
(99, 206, 220, 1.0), title="Yeti Cache:")
yetiRig: ColorRGBA_uint8 = Field(
(0, 205, 125, 1.0), title="Yeti Rig:")
class ReferenceLoaderModel(BaseSettingsModel):
namespace: str = Field(title="Namespace")
group_name: str = Field(title="Group name")
display_handle: bool = Field(title="Display Handle On Load References")
class LoadersModel(BaseSettingsModel):
colors: ColorsSetting = Field(
default_factory=ColorsSetting,
title="Loaded Products Outliner Colors")
reference_loader: ReferenceLoaderModel = Field(
default_factory=ReferenceLoaderModel,
title="Reference Loader"
)
DEFAULT_LOADERS_SETTING = {
"colors": {
"model": [
209, 132, 30, 1.0
],
"rig": [
59, 226, 235, 1.0
],
"pointcache": [
94, 209, 30, 1.0
],
"animation": [
94, 209, 30, 1.0
],
"ass": [
249, 135, 53, 1.0
],
"camera": [
136, 114, 244, 1.0
],
"fbx": [
215, 166, 255, 1.0
],
"mayaAscii": [
67, 174, 255, 1.0
],
"mayaScene": [
67, 174, 255, 1.0
],
"setdress": [
255, 250, 90, 1.0
],
"layout": [
255, 250, 90, 1.0
],
"vdbcache": [
249, 54, 0, 1.0
],
"vrayproxy": [
255, 150, 12, 1.0
],
"vrayscene_layer": [
255, 150, 12, 1.0
],
"yeticache": [
99, 206, 220, 1.0
],
"yetiRig": [
0, 205, 125, 1.0
]
},
"reference_loader": {
"namespace": "{folder[name]}_{product[name]}_##_",
"group_name": "_GRP",
"display_handle": True
}
}

View file

@ -0,0 +1,139 @@
from pydantic import Field, validator
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
from .imageio import ImageIOSettings, DEFAULT_IMAGEIO_SETTINGS
from .maya_dirmap import MayaDirmapModel, DEFAULT_MAYA_DIRMAP_SETTINGS
from .include_handles import IncludeHandlesModel, DEFAULT_INCLUDE_HANDLES
from .explicit_plugins_loading import (
ExplicitPluginsLoadingModel, DEFAULT_EXPLITCIT_PLUGINS_LOADING_SETTINGS
)
from .scriptsmenu import ScriptsmenuModel, DEFAULT_SCRIPTSMENU_SETTINGS
from .render_settings import RenderSettingsModel, DEFAULT_RENDER_SETTINGS
from .creators import CreatorsModel, DEFAULT_CREATORS_SETTINGS
from .publishers import PublishersModel, DEFAULT_PUBLISH_SETTINGS
from .loaders import LoadersModel, DEFAULT_LOADERS_SETTING
from .workfile_build_settings import ProfilesModel, DEFAULT_WORKFILE_SETTING
from .templated_workfile_settings import (
TemplatedProfilesModel, DEFAULT_TEMPLATED_WORKFILE_SETTINGS
)
class ExtMappingItemModel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Product type")
value: str = Field(title="Extension")
class PublishGUIFilterItemModel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Name")
value: bool = Field(True, title="Active")
class PublishGUIFiltersModel(BaseSettingsModel):
_layout = "compact"
name: str = Field(title="Name")
value: list[PublishGUIFilterItemModel] = Field(default_factory=list)
@validator("value")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
class MayaSettings(BaseSettingsModel):
"""Maya Project Settings."""
open_workfile_post_initialization: bool = Field(
True, title="Open Workfile Post Initialization")
explicit_plugins_loading: ExplicitPluginsLoadingModel = Field(
default_factory=ExplicitPluginsLoadingModel,
title="Explicit Plugins Loading")
imageio: ImageIOSettings = Field(
default_factory=ImageIOSettings, title="Color Management (imageio)")
mel_workspace: str = Field(title="Maya MEL Workspace", widget="textarea")
ext_mapping: list[ExtMappingItemModel] = Field(
default_factory=list, title="Extension Mapping")
maya_dirmap: MayaDirmapModel = Field(
default_factory=MayaDirmapModel, title="Maya dirmap Settings")
include_handles: IncludeHandlesModel = Field(
default_factory=IncludeHandlesModel,
title="Include/Exclude Handles in default playback & render range"
)
scriptsmenu: ScriptsmenuModel = Field(
default_factory=ScriptsmenuModel, title="Scriptsmenu Settings")
render_settings: RenderSettingsModel = Field(
default_factory=RenderSettingsModel, title="Render Settings")
create: CreatorsModel = Field(
default_factory=CreatorsModel, title="Creators")
publish: PublishersModel = Field(
default_factory=PublishersModel, title="Publishers")
load: LoadersModel = Field(
default_factory=LoadersModel, title="Loaders")
workfile_build: ProfilesModel = Field(
default_factory=ProfilesModel, title="Workfile Build Settings")
templated_workfile_build: TemplatedProfilesModel = Field(
default_factory=TemplatedProfilesModel,
title="Templated Workfile Build Settings")
filters: list[PublishGUIFiltersModel] = Field(
default_factory=list,
title="Publish GUI Filters")
@validator("filters", "ext_mapping")
def validate_unique_outputs(cls, value):
ensure_unique_names(value)
return value
DEFAULT_MEL_WORKSPACE_SETTINGS = "\n".join((
'workspace -fr "shaders" "renderData/shaders";',
'workspace -fr "images" "renders/maya";',
'workspace -fr "particles" "particles";',
'workspace -fr "mayaAscii" "";',
'workspace -fr "mayaBinary" "";',
'workspace -fr "scene" "";',
'workspace -fr "alembicCache" "cache/alembic";',
'workspace -fr "renderData" "renderData";',
'workspace -fr "sourceImages" "sourceimages";',
'workspace -fr "fileCache" "cache/nCache";',
'',
))
DEFAULT_MAYA_SETTING = {
"open_workfile_post_initialization": False,
"explicit_plugins_loading": DEFAULT_EXPLITCIT_PLUGINS_LOADING_SETTINGS,
"imageio": DEFAULT_IMAGEIO_SETTINGS,
"mel_workspace": DEFAULT_MEL_WORKSPACE_SETTINGS,
"ext_mapping": [
{"name": "model", "value": "ma"},
{"name": "mayaAscii", "value": "ma"},
{"name": "camera", "value": "ma"},
{"name": "rig", "value": "ma"},
{"name": "workfile", "value": "ma"},
{"name": "yetiRig", "value": "ma"}
],
# `maya_dirmap` was originally with dash - `maya-dirmap`
"maya_dirmap": DEFAULT_MAYA_DIRMAP_SETTINGS,
"include_handles": DEFAULT_INCLUDE_HANDLES,
"scriptsmenu": DEFAULT_SCRIPTSMENU_SETTINGS,
"render_settings": DEFAULT_RENDER_SETTINGS,
"create": DEFAULT_CREATORS_SETTINGS,
"publish": DEFAULT_PUBLISH_SETTINGS,
"load": DEFAULT_LOADERS_SETTING,
"workfile_build": DEFAULT_WORKFILE_SETTING,
"templated_workfile_build": DEFAULT_TEMPLATED_WORKFILE_SETTINGS,
"filters": [
{
"name": "preset 1",
"value": [
{"name": "ValidateNoAnimation", "value": False},
{"name": "ValidateShapeDefaultNames", "value": False},
]
},
{
"name": "preset 2",
"value": [
{"name": "ValidateNoAnimation", "value": False},
]
},
]
}

View file

@ -0,0 +1,40 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class MayaDirmapPathsSubmodel(BaseSettingsModel):
_layout = "compact"
source_path: list[str] = Field(
default_factory=list, title="Source Paths"
)
destination_path: list[str] = Field(
default_factory=list, title="Destination Paths"
)
class MayaDirmapModel(BaseSettingsModel):
"""Maya dirmap settings."""
# _layout = "expanded"
_isGroup: bool = True
enabled: bool = Field(title="enabled")
# Use ${} placeholder instead of absolute value of a root in
# referenced filepaths.
use_env_var_as_root: bool = Field(
title="Use env var placeholder in referenced paths"
)
paths: MayaDirmapPathsSubmodel = Field(
default_factory=MayaDirmapPathsSubmodel,
title="Dirmap Paths"
)
DEFAULT_MAYA_DIRMAP_SETTINGS = {
"use_env_var_as_root": False,
"enabled": False,
"paths": {
"source-path": [],
"destination-path": []
}
}

View file

@ -0,0 +1,382 @@
from pydantic import Field, validator
from ayon_server.settings import (
BaseSettingsModel,
ensure_unique_names,
task_types_enum,
)
from ayon_server.types import ColorRGBA_uint8
def hardware_falloff_enum():
return [
{"label": "Linear", "value": "0"},
{"label": "Exponential", "value": "1"},
{"label": "Exponential Squared", "value": "2"}
]
def renderer_enum():
return [
{"label": "Viewport 2.0", "value": "vp2Renderer"}
]
def displayLights_enum():
return [
{"label": "Default Lighting", "value": "default"},
{"label": "All Lights", "value": "all"},
{"label": "Selected Lights", "value": "selected"},
{"label": "Flat Lighting", "value": "flat"},
{"label": "No Lights", "value": "nolights"}
]
def plugin_objects_default():
return [
{
"name": "gpuCacheDisplayFilter",
"value": False
}
]
class CodecSetting(BaseSettingsModel):
_layout = "expanded"
compression: str = Field("png", title="Encoding")
format: str = Field("image", title="Format")
quality: int = Field(95, title="Quality", ge=0, le=100)
class DisplayOptionsSetting(BaseSettingsModel):
_layout = "expanded"
override_display: bool = Field(True, title="Override display options")
background: ColorRGBA_uint8 = Field(
(125, 125, 125, 1.0), title="Background Color"
)
displayGradient: bool = Field(True, title="Display background gradient")
backgroundTop: ColorRGBA_uint8 = Field(
(125, 125, 125, 1.0), title="Background Top"
)
backgroundBottom: ColorRGBA_uint8 = Field(
(125, 125, 125, 1.0), title="Background Bottom"
)
class GenericSetting(BaseSettingsModel):
_layout = "expanded"
isolate_view: bool = Field(True, title="Isolate View")
off_screen: bool = Field(True, title="Off Screen")
pan_zoom: bool = Field(False, title="2D Pan/Zoom")
class RendererSetting(BaseSettingsModel):
_layout = "expanded"
rendererName: str = Field(
"vp2Renderer",
enum_resolver=renderer_enum,
title="Renderer name"
)
class ResolutionSetting(BaseSettingsModel):
_layout = "expanded"
width: int = Field(0, title="Width")
height: int = Field(0, title="Height")
class PluginObjectsModel(BaseSettingsModel):
name: str = Field("", title="Name")
value: bool = Field(True, title="Enabled")
class ViewportOptionsSetting(BaseSettingsModel):
override_viewport_options: bool = Field(
True, title="Override viewport options"
)
displayLights: str = Field(
"default", enum_resolver=displayLights_enum, title="Display Lights"
)
displayTextures: bool = Field(True, title="Display Textures")
textureMaxResolution: int = Field(1024, title="Texture Clamp Resolution")
renderDepthOfField: bool = Field(
True, title="Depth of Field", section="Depth of Field"
)
shadows: bool = Field(True, title="Display Shadows")
twoSidedLighting: bool = Field(True, title="Two Sided Lighting")
lineAAEnable: bool = Field(
True, title="Enable Anti-Aliasing", section="Anti-Aliasing"
)
multiSample: int = Field(8, title="Anti Aliasing Samples")
useDefaultMaterial: bool = Field(False, title="Use Default Material")
wireframeOnShaded: bool = Field(False, title="Wireframe On Shaded")
xray: bool = Field(False, title="X-Ray")
jointXray: bool = Field(False, title="X-Ray Joints")
backfaceCulling: bool = Field(False, title="Backface Culling")
ssaoEnable: bool = Field(
False, title="Screen Space Ambient Occlusion", section="SSAO"
)
ssaoAmount: int = Field(1, title="SSAO Amount")
ssaoRadius: int = Field(16, title="SSAO Radius")
ssaoFilterRadius: int = Field(16, title="SSAO Filter Radius")
ssaoSamples: int = Field(16, title="SSAO Samples")
fogging: bool = Field(False, title="Enable Hardware Fog", section="Fog")
hwFogFalloff: str = Field(
"0", enum_resolver=hardware_falloff_enum, title="Hardware Falloff"
)
hwFogDensity: float = Field(0.0, title="Fog Density")
hwFogStart: int = Field(0, title="Fog Start")
hwFogEnd: int = Field(100, title="Fog End")
hwFogAlpha: int = Field(0, title="Fog Alpha")
hwFogColorR: float = Field(1.0, title="Fog Color R")
hwFogColorG: float = Field(1.0, title="Fog Color G")
hwFogColorB: float = Field(1.0, title="Fog Color B")
motionBlurEnable: bool = Field(
False, title="Enable Motion Blur", section="Motion Blur"
)
motionBlurSampleCount: int = Field(8, title="Motion Blur Sample Count")
motionBlurShutterOpenFraction: float = Field(
0.2, title="Shutter Open Fraction"
)
cameras: bool = Field(False, title="Cameras", section="Show")
clipGhosts: bool = Field(False, title="Clip Ghosts")
deformers: bool = Field(False, title="Deformers")
dimensions: bool = Field(False, title="Dimensions")
dynamicConstraints: bool = Field(False, title="Dynamic Constraints")
dynamics: bool = Field(False, title="Dynamics")
fluids: bool = Field(False, title="Fluids")
follicles: bool = Field(False, title="Follicles")
greasePencils: bool = Field(False, title="Grease Pencils")
grid: bool = Field(False, title="Grid")
hairSystems: bool = Field(True, title="Hair Systems")
handles: bool = Field(False, title="Handles")
headsUpDisplay: bool = Field(False, title="HUD")
ikHandles: bool = Field(False, title="IK Handles")
imagePlane: bool = Field(True, title="Image Plane")
joints: bool = Field(False, title="Joints")
lights: bool = Field(False, title="Lights")
locators: bool = Field(False, title="Locators")
manipulators: bool = Field(False, title="Manipulators")
motionTrails: bool = Field(False, title="Motion Trails")
nCloths: bool = Field(False, title="nCloths")
nParticles: bool = Field(False, title="nParticles")
nRigids: bool = Field(False, title="nRigids")
controlVertices: bool = Field(False, title="NURBS CVs")
nurbsCurves: bool = Field(False, title="NURBS Curves")
hulls: bool = Field(False, title="NURBS Hulls")
nurbsSurfaces: bool = Field(False, title="NURBS Surfaces")
particleInstancers: bool = Field(False, title="Particle Instancers")
pivots: bool = Field(False, title="Pivots")
planes: bool = Field(False, title="Planes")
pluginShapes: bool = Field(False, title="Plugin Shapes")
polymeshes: bool = Field(True, title="Polygons")
strokes: bool = Field(False, title="Strokes")
subdivSurfaces: bool = Field(False, title="Subdiv Surfaces")
textures: bool = Field(False, title="Texture Placements")
pluginObjects: list[PluginObjectsModel] = Field(
default_factory=plugin_objects_default,
title="Plugin Objects"
)
@validator("pluginObjects")
def validate_unique_plugin_objects(cls, value):
ensure_unique_names(value)
return value
class CameraOptionsSetting(BaseSettingsModel):
displayGateMask: bool = Field(False, title="Display Gate Mask")
displayResolution: bool = Field(False, title="Display Resolution")
displayFilmGate: bool = Field(False, title="Display Film Gate")
displayFieldChart: bool = Field(False, title="Display Field Chart")
displaySafeAction: bool = Field(False, title="Display Safe Action")
displaySafeTitle: bool = Field(False, title="Display Safe Title")
displayFilmPivot: bool = Field(False, title="Display Film Pivot")
displayFilmOrigin: bool = Field(False, title="Display Film Origin")
overscan: int = Field(1.0, title="Overscan")
class CapturePresetSetting(BaseSettingsModel):
Codec: CodecSetting = Field(
default_factory=CodecSetting,
title="Codec",
section="Codec")
DisplayOptions: DisplayOptionsSetting = Field(
default_factory=DisplayOptionsSetting,
title="Display Options",
section="Display Options")
Generic: GenericSetting = Field(
default_factory=GenericSetting,
title="Generic",
section="Generic")
Renderer: RendererSetting = Field(
default_factory=RendererSetting,
title="Renderer",
section="Renderer")
Resolution: ResolutionSetting = Field(
default_factory=ResolutionSetting,
title="Resolution",
section="Resolution")
ViewportOptions: ViewportOptionsSetting = Field(
default_factory=ViewportOptionsSetting,
title="Viewport Options")
CameraOptions: CameraOptionsSetting = Field(
default_factory=CameraOptionsSetting,
title="Camera Options")
class ProfilesModel(BaseSettingsModel):
_layout = "expanded"
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(default_factory=list, title="Task names")
product_names: list[str] = Field(default_factory=list, title="Products names")
capture_preset: CapturePresetSetting = Field(
default_factory=CapturePresetSetting,
title="Capture Preset"
)
class ExtractPlayblastSetting(BaseSettingsModel):
capture_preset: CapturePresetSetting = Field(
default_factory=CapturePresetSetting,
title="DEPRECATED! Please use \"Profiles\" below. Capture Preset"
)
profiles: list[ProfilesModel] = Field(
default_factory=list,
title="Profiles"
)
DEFAULT_PLAYBLAST_SETTING = {
"capture_preset": {
"Codec": {
"compression": "png",
"format": "image",
"quality": 95
},
"DisplayOptions": {
"override_display": True,
"background": [
125,
125,
125,
1.0
],
"backgroundBottom": [
125,
125,
125,
1.0
],
"backgroundTop": [
125,
125,
125,
1.0
],
"displayGradient": True
},
"Generic": {
"isolate_view": True,
"off_screen": True,
"pan_zoom": False
},
"Renderer": {
"rendererName": "vp2Renderer"
},
"Resolution": {
"width": 1920,
"height": 1080
},
"ViewportOptions": {
"override_viewport_options": True,
"displayLights": "default",
"displayTextures": True,
"textureMaxResolution": 1024,
"renderDepthOfField": True,
"shadows": True,
"twoSidedLighting": True,
"lineAAEnable": True,
"multiSample": 8,
"useDefaultMaterial": False,
"wireframeOnShaded": False,
"xray": False,
"jointXray": False,
"backfaceCulling": False,
"ssaoEnable": False,
"ssaoAmount": 1,
"ssaoRadius": 16,
"ssaoFilterRadius": 16,
"ssaoSamples": 16,
"fogging": False,
"hwFogFalloff": "0",
"hwFogDensity": 0.0,
"hwFogStart": 0,
"hwFogEnd": 100,
"hwFogAlpha": 0,
"hwFogColorR": 1.0,
"hwFogColorG": 1.0,
"hwFogColorB": 1.0,
"motionBlurEnable": False,
"motionBlurSampleCount": 8,
"motionBlurShutterOpenFraction": 0.2,
"cameras": False,
"clipGhosts": False,
"deformers": False,
"dimensions": False,
"dynamicConstraints": False,
"dynamics": False,
"fluids": False,
"follicles": False,
"greasePencils": False,
"grid": False,
"hairSystems": True,
"handles": False,
"headsUpDisplay": False,
"ikHandles": False,
"imagePlane": True,
"joints": False,
"lights": False,
"locators": False,
"manipulators": False,
"motionTrails": False,
"nCloths": False,
"nParticles": False,
"nRigids": False,
"controlVertices": False,
"nurbsCurves": False,
"hulls": False,
"nurbsSurfaces": False,
"particleInstancers": False,
"pivots": False,
"planes": False,
"pluginShapes": False,
"polymeshes": True,
"strokes": False,
"subdivSurfaces": False,
"textures": False,
"pluginObjects": [
{
"name": "gpuCacheDisplayFilter",
"value": False
}
]
},
"CameraOptions": {
"displayGateMask": False,
"displayResolution": False,
"displayFilmGate": False,
"displayFieldChart": False,
"displaySafeAction": False,
"displaySafeTitle": False,
"displayFilmPivot": False,
"displayFilmOrigin": False,
"overscan": 1.0
}
},
"profiles": []
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,500 @@
"""Providing models and values for Maya Render Settings."""
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
def aov_separators_enum():
return [
{"value": "dash", "label": "- (dash)"},
{"value": "underscore", "label": "_ (underscore)"},
{"value": "dot", "label": ". (dot)"}
]
def arnold_image_format_enum():
"""Return enumerator for Arnold output formats."""
return [
{"label": "jpeg", "value": "jpeg"},
{"label": "png", "value": "png"},
{"label": "deepexr", "value": "deep exr"},
{"label": "tif", "value": "tif"},
{"label": "exr", "value": "exr"},
{"label": "maya", "value": "maya"},
{"label": "mtoa_shaders", "value": "mtoa_shaders"}
]
def arnold_aov_list_enum():
"""Return enumerator for Arnold AOVs.
Note: Key is value, Value in this case is Label. This
was taken from v3 settings.
"""
return [
{"value": "empty", "label": "< empty >"},
{"value": "ID", "label": "ID"},
{"value": "N", "label": "N"},
{"value": "P", "label": "P"},
{"value": "Pref", "label": "Pref"},
{"value": "RGBA", "label": "RGBA"},
{"value": "Z", "label": "Z"},
{"value": "albedo", "label": "albedo"},
{"value": "background", "label": "background"},
{"value": "coat", "label": "coat"},
{"value": "coat_albedo", "label": "coat_albedo"},
{"value": "coat_direct", "label": "coat_direct"},
{"value": "coat_indirect", "label": "coat_indirect"},
{"value": "cputime", "label": "cputime"},
{"value": "crypto_asset", "label": "crypto_asset"},
{"value": "crypto_material", "label": "cypto_material"},
{"value": "crypto_object", "label": "crypto_object"},
{"value": "diffuse", "label": "diffuse"},
{"value": "diffuse_albedo", "label": "diffuse_albedo"},
{"value": "diffuse_direct", "label": "diffuse_direct"},
{"value": "diffuse_indirect", "label": "diffuse_indirect"},
{"value": "direct", "label": "direct"},
{"value": "emission", "label": "emission"},
{"value": "highlight", "label": "highlight"},
{"value": "indirect", "label": "indirect"},
{"value": "motionvector", "label": "motionvector"},
{"value": "opacity", "label": "opacity"},
{"value": "raycount", "label": "raycount"},
{"value": "rim_light", "label": "rim_light"},
{"value": "shadow", "label": "shadow"},
{"value": "shadow_diff", "label": "shadow_diff"},
{"value": "shadow_mask", "label": "shadow_mask"},
{"value": "shadow_matte", "label": "shadow_matte"},
{"value": "sheen", "label": "sheen"},
{"value": "sheen_albedo", "label": "sheen_albedo"},
{"value": "sheen_direct", "label": "sheen_direct"},
{"value": "sheen_indirect", "label": "sheen_indirect"},
{"value": "specular", "label": "specular"},
{"value": "specular_albedo", "label": "specular_albedo"},
{"value": "specular_direct", "label": "specular_direct"},
{"value": "specular_indirect", "label": "specular_indirect"},
{"value": "sss", "label": "sss"},
{"value": "sss_albedo", "label": "sss_albedo"},
{"value": "sss_direct", "label": "sss_direct"},
{"value": "sss_indirect", "label": "sss_indirect"},
{"value": "transmission", "label": "transmission"},
{"value": "transmission_albedo", "label": "transmission_albedo"},
{"value": "transmission_direct", "label": "transmission_direct"},
{"value": "transmission_indirect", "label": "transmission_indirect"},
{"value": "volume", "label": "volume"},
{"value": "volume_Z", "label": "volume_Z"},
{"value": "volume_albedo", "label": "volume_albedo"},
{"value": "volume_direct", "label": "volume_direct"},
{"value": "volume_indirect", "label": "volume_indirect"},
{"value": "volume_opacity", "label": "volume_opacity"},
]
def vray_image_output_enum():
"""Return output format for Vray enumerator."""
return [
{"label": "png", "value": "png"},
{"label": "jpg", "value": "jpg"},
{"label": "vrimg", "value": "vrimg"},
{"label": "hdr", "value": "hdr"},
{"label": "exr", "value": "exr"},
{"label": "exr (multichannel)", "value": "exr (multichannel)"},
{"label": "exr (deep)", "value": "exr (deep)"},
{"label": "tga", "value": "tga"},
{"label": "bmp", "value": "bmp"},
{"label": "sgi", "value": "sgi"}
]
def vray_aov_list_enum():
"""Return enumerator for Vray AOVs.
Note: Key is value, Value in this case is Label. This
was taken from v3 settings.
"""
return [
{"value": "empty", "label": "< empty >"},
{"value": "atmosphereChannel", "label": "atmosphere"},
{"value": "backgroundChannel", "label": "background"},
{"value": "bumpNormalsChannel", "label": "bumpnormals"},
{"value": "causticsChannel", "label": "caustics"},
{"value": "coatFilterChannel", "label": "coat_filter"},
{"value": "coatGlossinessChannel", "label": "coatGloss"},
{"value": "coatReflectionChannel", "label": "coat_reflection"},
{"value": "vrayCoatChannel", "label": "coat_specular"},
{"value": "CoverageChannel", "label": "coverage"},
{"value": "cryptomatteChannel", "label": "cryptomatte"},
{"value": "customColor", "label": "custom_color"},
{"value": "drBucketChannel", "label": "DR"},
{"value": "denoiserChannel", "label": "denoiser"},
{"value": "diffuseChannel", "label": "diffuse"},
{"value": "ExtraTexElement", "label": "extraTex"},
{"value": "giChannel", "label": "GI"},
{"value": "LightMixElement", "label": "None"},
{"value": "lightingChannel", "label": "lighting"},
{"value": "LightingAnalysisChannel", "label": "LightingAnalysis"},
{"value": "materialIDChannel", "label": "materialID"},
{"value": "MaterialSelectElement", "label": "materialSelect"},
{"value": "matteShadowChannel", "label": "matteShadow"},
{"value": "MultiMatteElement", "label": "multimatte"},
{"value": "multimatteIDChannel", "label": "multimatteID"},
{"value": "normalsChannel", "label": "normals"},
{"value": "nodeIDChannel", "label": "objectId"},
{"value": "objectSelectChannel", "label": "objectSelect"},
{"value": "rawCoatFilterChannel", "label": "raw_coat_filter"},
{"value": "rawCoatReflectionChannel", "label": "raw_coat_reflection"},
{"value": "rawDiffuseFilterChannel", "label": "rawDiffuseFilter"},
{"value": "rawGiChannel", "label": "rawGI"},
{"value": "rawLightChannel", "label": "rawLight"},
{"value": "rawReflectionChannel", "label": "rawReflection"},
{
"value": "rawReflectionFilterChannel",
"label": "rawReflectionFilter"
},
{"value": "rawRefractionChannel", "label": "rawRefraction"},
{
"value": "rawRefractionFilterChannel",
"label": "rawRefractionFilter"
},
{"value": "rawShadowChannel", "label": "rawShadow"},
{"value": "rawSheenFilterChannel", "label": "raw_sheen_filter"},
{
"value": "rawSheenReflectionChannel",
"label": "raw_sheen_reflection"
},
{"value": "rawTotalLightChannel", "label": "rawTotalLight"},
{"value": "reflectIORChannel", "label": "reflIOR"},
{"value": "reflectChannel", "label": "reflect"},
{"value": "reflectionFilterChannel", "label": "reflectionFilter"},
{"value": "reflectGlossinessChannel", "label": "reflGloss"},
{"value": "refractChannel", "label": "refract"},
{"value": "refractionFilterChannel", "label": "refractionFilter"},
{"value": "refractGlossinessChannel", "label": "refrGloss"},
{"value": "renderIDChannel", "label": "renderId"},
{"value": "FastSSS2Channel", "label": "SSS"},
{"value": "sampleRateChannel", "label": "sampleRate"},
{"value": "samplerInfo", "label": "samplerInfo"},
{"value": "selfIllumChannel", "label": "selfIllum"},
{"value": "shadowChannel", "label": "shadow"},
{"value": "sheenFilterChannel", "label": "sheen_filter"},
{"value": "sheenGlossinessChannel", "label": "sheenGloss"},
{"value": "sheenReflectionChannel", "label": "sheen_reflection"},
{"value": "vraySheenChannel", "label": "sheen_specular"},
{"value": "specularChannel", "label": "specular"},
{"value": "Toon", "label": "Toon"},
{"value": "toonLightingChannel", "label": "toonLighting"},
{"value": "toonSpecularChannel", "label": "toonSpecular"},
{"value": "totalLightChannel", "label": "totalLight"},
{"value": "unclampedColorChannel", "label": "unclampedColor"},
{"value": "VRScansPaintMaskChannel", "label": "VRScansPaintMask"},
{"value": "VRScansZoneMaskChannel", "label": "VRScansZoneMask"},
{"value": "velocityChannel", "label": "velocity"},
{"value": "zdepthChannel", "label": "zDepth"},
{"value": "LightSelectElement", "label": "lightselect"},
]
def redshift_engine_enum():
"""Get Redshift engine type enumerator."""
return [
{"value": "0", "label": "None"},
{"value": "1", "label": "Photon Map"},
{"value": "2", "label": "Irradiance Cache"},
{"value": "3", "label": "Brute Force"}
]
def redshift_image_output_enum():
"""Return output format for Redshift enumerator."""
return [
{"value": "iff", "label": "Maya IFF"},
{"value": "exr", "label": "OpenEXR"},
{"value": "tif", "label": "TIFF"},
{"value": "png", "label": "PNG"},
{"value": "tga", "label": "Targa"},
{"value": "jpg", "label": "JPEG"}
]
def redshift_aov_list_enum():
"""Return enumerator for Vray AOVs.
Note: Key is value, Value in this case is Label. This
was taken from v3 settings.
"""
return [
{"value": "empty", "label": "< none >"},
{"value": "AO", "label": "Ambient Occlusion"},
{"value": "Background", "label": "Background"},
{"value": "Beauty", "label": "Beauty"},
{"value": "BumpNormals", "label": "Bump Normals"},
{"value": "Caustics", "label": "Caustics"},
{"value": "CausticsRaw", "label": "Caustics Raw"},
{"value": "Cryptomatte", "label": "Cryptomatte"},
{"value": "Custom", "label": "Custom"},
{"value": "Z", "label": "Depth"},
{"value": "DiffuseFilter", "label": "Diffuse Filter"},
{"value": "DiffuseLighting", "label": "Diffuse Lighting"},
{"value": "DiffuseLightingRaw", "label": "Diffuse Lighting Raw"},
{"value": "Emission", "label": "Emission"},
{"value": "GI", "label": "Global Illumination"},
{"value": "GIRaw", "label": "Global Illumination Raw"},
{"value": "Matte", "label": "Matte"},
{"value": "MotionVectors", "label": "Ambient Occlusion"},
{"value": "N", "label": "Normals"},
{"value": "ID", "label": "ObjectID"},
{"value": "ObjectBumpNormal", "label": "Object-Space Bump Normals"},
{"value": "ObjectPosition", "label": "Object-Space Positions"},
{"value": "PuzzleMatte", "label": "Puzzle Matte"},
{"value": "Reflections", "label": "Reflections"},
{"value": "ReflectionsFilter", "label": "Reflections Filter"},
{"value": "ReflectionsRaw", "label": "Reflections Raw"},
{"value": "Refractions", "label": "Refractions"},
{"value": "RefractionsFilter", "label": "Refractions Filter"},
{"value": "RefractionsRaw", "label": "Refractions Filter"},
{"value": "Shadows", "label": "Shadows"},
{"value": "SpecularLighting", "label": "Specular Lighting"},
{"value": "SSS", "label": "Sub Surface Scatter"},
{"value": "SSSRaw", "label": "Sub Surface Scatter Raw"},
{
"value": "TotalDiffuseLightingRaw",
"label": "Total Diffuse Lighting Raw"
},
{
"value": "TotalTransLightingRaw",
"label": "Total Translucency Filter"
},
{"value": "TransTint", "label": "Translucency Filter"},
{"value": "TransGIRaw", "label": "Translucency Lighting Raw"},
{"value": "VolumeFogEmission", "label": "Volume Fog Emission"},
{"value": "VolumeFogTint", "label": "Volume Fog Tint"},
{"value": "VolumeLighting", "label": "Volume Lighting"},
{"value": "P", "label": "World Position"},
]
class AdditionalOptionsModel(BaseSettingsModel):
"""Additional Option"""
_layout = "compact"
attribute: str = Field("", title="Attribute name")
value: str = Field("", title="Value")
class ArnoldSettingsModel(BaseSettingsModel):
image_prefix: str = Field(title="Image prefix template")
image_format: str = Field(
enum_resolver=arnold_image_format_enum, title="Output Image Format")
multilayer_exr: bool = Field(title="Multilayer (exr)")
tiled: bool = Field(title="Tiled (tif, exr)")
aov_list: list[str] = Field(
default_factory=list,
enum_resolver=arnold_aov_list_enum,
title="AOVs to create"
)
additional_options: list[AdditionalOptionsModel] = Field(
default_factory=list,
title="Additional Arnold Options",
description=(
"Add additional options - put attribute and value, like AASamples"
)
)
class VraySettingsModel(BaseSettingsModel):
image_prefix: str = Field(title="Image prefix template")
# engine was str because of JSON limitation (key must be string)
engine: str = Field(
enum_resolver=lambda: [
{"label": "V-Ray", "value": "1"},
{"label": "V-Ray GPU", "value": "2"}
],
title="Production Engine"
)
image_format: str = Field(
enum_resolver=vray_image_output_enum,
title="Output Image Format"
)
aov_list: list[str] = Field(
default_factory=list,
enum_resolver=vray_aov_list_enum,
title="AOVs to create"
)
additional_options: list[AdditionalOptionsModel] = Field(
default_factory=list,
title="Additional Vray Options",
description=(
"Add additional options - put attribute and value,"
" like aaFilterSize"
)
)
class RedshiftSettingsModel(BaseSettingsModel):
image_prefix: str = Field(title="Image prefix template")
# both engines are using the same enumerator,
# both were originally str because of JSON limitation.
primary_gi_engine: str = Field(
enum_resolver=redshift_engine_enum,
title="Primary GI Engine"
)
secondary_gi_engine: str = Field(
enum_resolver=redshift_engine_enum,
title="Secondary GI Engine"
)
image_format: str = Field(
enum_resolver=redshift_image_output_enum,
title="Output Image Format"
)
multilayer_exr: bool = Field(title="Multilayer (exr)")
force_combine: bool = Field(title="Force combine beauty and AOVs")
aov_list: list[str] = Field(
default_factory=list,
enum_resolver=redshift_aov_list_enum,
title="AOVs to create"
)
additional_options: list[AdditionalOptionsModel] = Field(
default_factory=list,
title="Additional Vray Options",
description=(
"Add additional options - put attribute and value,"
" like reflectionMaxTraceDepth"
)
)
def renderman_display_filters():
return [
"PxrBackgroundDisplayFilter",
"PxrCopyAOVDisplayFilter",
"PxrEdgeDetect",
"PxrFilmicTonemapperDisplayFilter",
"PxrGradeDisplayFilter",
"PxrHalfBufferErrorFilter",
"PxrImageDisplayFilter",
"PxrLightSaturation",
"PxrShadowDisplayFilter",
"PxrStylizedHatching",
"PxrStylizedLines",
"PxrStylizedToon",
"PxrWhitePointDisplayFilter"
]
def renderman_sample_filters_enum():
return [
"PxrBackgroundSampleFilter",
"PxrCopyAOVSampleFilter",
"PxrCryptomatte",
"PxrFilmicTonemapperSampleFilter",
"PxrGradeSampleFilter",
"PxrShadowFilter",
"PxrWatermarkFilter",
"PxrWhitePointSampleFilter"
]
class RendermanSettingsModel(BaseSettingsModel):
image_prefix: str = Field(
"", title="Image prefix template")
image_dir: str = Field(
"", title="Image Output Directory")
display_filters: list[str] = Field(
default_factory=list,
title="Display Filters",
enum_resolver=renderman_display_filters
)
imageDisplay_dir: str = Field(
"", title="Image Display Filter Directory")
sample_filters: list[str] = Field(
default_factory=list,
title="Sample Filters",
enum_resolver=renderman_sample_filters_enum
)
cryptomatte_dir: str = Field(
"", title="Cryptomatte Output Directory")
watermark_dir: str = Field(
"", title="Watermark Filter Directory")
additional_options: list[AdditionalOptionsModel] = Field(
default_factory=list,
title="Additional Renderer Options"
)
class RenderSettingsModel(BaseSettingsModel):
apply_render_settings: bool = Field(
title="Apply Render Settings on creation"
)
default_render_image_folder: str = Field(
title="Default render image folder"
)
enable_all_lights: bool = Field(
title="Include all lights in Render Setup Layers by default"
)
aov_separator: str = Field(
"underscore",
title="AOV Separator character",
enum_resolver=aov_separators_enum
)
reset_current_frame: bool = Field(
title="Reset Current Frame")
remove_aovs: bool = Field(
title="Remove existing AOVs")
arnold_renderer: ArnoldSettingsModel = Field(
default_factory=ArnoldSettingsModel,
title="Arnold Renderer")
vray_renderer: VraySettingsModel = Field(
default_factory=VraySettingsModel,
title="Vray Renderer")
redshift_renderer: RedshiftSettingsModel = Field(
default_factory=RedshiftSettingsModel,
title="Redshift Renderer")
renderman_renderer: RendermanSettingsModel = Field(
default_factory=RendermanSettingsModel,
title="Renderman Renderer")
DEFAULT_RENDER_SETTINGS = {
"apply_render_settings": True,
"default_render_image_folder": "renders/maya",
"enable_all_lights": True,
"aov_separator": "underscore",
"reset_current_frame": False,
"remove_aovs": False,
"arnold_renderer": {
"image_prefix": "<Scene>/<RenderLayer>/<RenderLayer>_<RenderPass>",
"image_format": "exr",
"multilayer_exr": True,
"tiled": True,
"aov_list": [],
"additional_options": []
},
"vray_renderer": {
"image_prefix": "<scene>/<Layer>/<Layer>",
"engine": "1",
"image_format": "exr",
"aov_list": [],
"additional_options": []
},
"redshift_renderer": {
"image_prefix": "<Scene>/<RenderLayer>/<RenderLayer>",
"primary_gi_engine": "0",
"secondary_gi_engine": "0",
"image_format": "exr",
"multilayer_exr": True,
"force_combine": True,
"aov_list": [],
"additional_options": []
},
"renderman_renderer": {
"image_prefix": "<layer>{aov_separator}<aov>.<f4>.<ext>",
"image_dir": "<scene>/<layer>",
"display_filters": [],
"imageDisplay_dir": "<imagedir>/<layer>{aov_separator}imageDisplayFilter.<f4>.<ext>",
"sample_filters": [],
"cryptomatte_dir": "<imagedir>/<layer>{aov_separator}cryptomatte.<f4>.<ext>",
"watermark_dir": "<imagedir>/<layer>{aov_separator}watermarkFilter.<f4>.<ext>",
"additional_options": []
}
}

View file

@ -0,0 +1,43 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel
class ScriptsmenuSubmodel(BaseSettingsModel):
"""Item Definition"""
_isGroup = True
type: str = Field(title="Type")
command: str = Field(title="Command")
sourcetype: str = Field(title="Source Type")
title: str = Field(title="Title")
tooltip: str = Field(title="Tooltip")
tags: list[str] = Field(default_factory=list, title="A list of tags")
class ScriptsmenuModel(BaseSettingsModel):
_isGroup = True
name: str = Field(title="Menu Name")
definition: list[ScriptsmenuSubmodel] = Field(
default_factory=list,
title="Menu Definition",
description="Scriptmenu Items Definition"
)
DEFAULT_SCRIPTSMENU_SETTINGS = {
"name": "OpenPype Tools",
"definition": [
{
"type": "action",
"command": "import openpype.hosts.maya.api.commands as op_cmds; op_cmds.edit_shader_definitions()",
"sourcetype": "python",
"title": "Edit shader name definitions",
"tooltip": "Edit shader name definitions used in validation and renaming.",
"tags": [
"pipeline",
"shader"
]
}
]
}

View file

@ -0,0 +1,25 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel, task_types_enum
class WorkfileBuildProfilesModel(BaseSettingsModel):
_layout = "expanded"
task_types: list[str] = Field(
default_factory=list,
title="Task types",
enum_resolver=task_types_enum
)
task_names: list[str] = Field(default_factory=list, title="Task names")
path: str = Field("", title="Path to template")
class TemplatedProfilesModel(BaseSettingsModel):
profiles: list[WorkfileBuildProfilesModel] = Field(
default_factory=list,
title="Profiles"
)
DEFAULT_TEMPLATED_WORKFILE_SETTINGS = {
"profiles": []
}

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