Merge branch 'develop' into enhancement/add_shapefx_loki_support

This commit is contained in:
Jakub Trllo 2025-07-30 10:52:00 +02:00 committed by GitHub
commit 8ef42603b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 113 additions and 27 deletions

View file

@ -7,6 +7,10 @@ import opentimelineio as otio
from opentimelineio import opentime as _ot
# https://github.com/AcademySoftwareFoundation/OpenTimelineIO/issues/1822
OTIO_EPSILON = 1e-9
def otio_range_to_frame_range(otio_range):
start = _ot.to_frames(
otio_range.start_time, otio_range.start_time.rate)

View file

@ -5,6 +5,7 @@ import sys
import inspect
import copy
import warnings
import hashlib
import xml.etree.ElementTree
from typing import TYPE_CHECKING, Optional, Union, List
@ -243,32 +244,38 @@ def publish_plugins_discover(
for path in paths:
path = os.path.normpath(path)
if not os.path.isdir(path):
continue
filenames = []
if os.path.isdir(path):
filenames.extend(
name
for name in os.listdir(path)
if (
os.path.isfile(os.path.join(path, name))
and not name.startswith("_")
)
)
else:
filenames.append(os.path.basename(path))
path = os.path.dirname(path)
for fname in os.listdir(path):
if fname.startswith("_"):
continue
abspath = os.path.join(path, fname)
if not os.path.isfile(abspath):
continue
mod_name, mod_ext = os.path.splitext(fname)
if mod_ext != ".py":
dirpath_hash = hashlib.md5(path.encode("utf-8")).hexdigest()
for filename in filenames:
basename, ext = os.path.splitext(filename)
if ext.lower() != ".py":
continue
filepath = os.path.join(path, filename)
module_name = f"{dirpath_hash}.{basename}"
try:
module = import_filepath(
abspath, mod_name, sys_module_name=mod_name)
filepath, module_name, sys_module_name=module_name
)
except Exception as err: # noqa: BLE001
# we need broad exception to catch all possible errors.
result.crashed_file_paths[abspath] = sys.exc_info()
result.crashed_file_paths[filepath] = sys.exc_info()
log.debug('Skipped: "%s" (%s)', mod_name, err)
log.debug('Skipped: "%s" (%s)', filepath, err)
continue
for plugin in pyblish.plugin.plugins_from_module(module):
@ -354,12 +361,18 @@ def get_plugin_settings(plugin, project_settings, log, category=None):
# Use project settings based on a category name
if category:
try:
return (
output = (
project_settings
[category]
["publish"]
[plugin.__name__]
)
warnings.warn(
"Please fill 'settings_category'"
f" for plugin '{plugin.__name__}'.",
DeprecationWarning
)
return output
except KeyError:
pass
@ -384,12 +397,18 @@ def get_plugin_settings(plugin, project_settings, log, category=None):
category_from_file = "core"
try:
return (
output = (
project_settings
[category_from_file]
[plugin_kind]
[plugin.__name__]
)
warnings.warn(
"Please fill 'settings_category'"
f" for plugin '{plugin.__name__}'.",
DeprecationWarning
)
return output
except KeyError:
pass
return {}

View file

@ -38,6 +38,8 @@ class CleanUp(pyblish.api.InstancePlugin):
"webpublisher",
"shell"
]
settings_category = "core"
exclude_families = ["clip"]
optional = True
active = True

View file

@ -13,6 +13,8 @@ class CleanUpFarm(pyblish.api.ContextPlugin):
order = pyblish.api.IntegratorOrder + 11
label = "Clean Up Farm"
settings_category = "core"
enabled = True
# Keep "filesequence" for backwards compatibility of older jobs

View file

@ -46,6 +46,8 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin):
order = pyblish.api.CollectorOrder + 0.49
label = "Collect Anatomy Instance data"
settings_category = "core"
follow_workfile_version = False
def process(self, context):

View file

@ -41,6 +41,7 @@ class CollectAudio(pyblish.api.ContextPlugin):
"max",
"circuit",
]
settings_category = "core"
audio_product_name = "audioMain"

View file

@ -23,6 +23,7 @@ class CollectFramesFixDef(
targets = ["local"]
hosts = ["nuke"]
families = ["render", "prerender"]
settings_category = "core"
rewrite_version_enable = False

View file

@ -12,9 +12,10 @@ class CollectSceneVersion(pyblish.api.ContextPlugin):
"""
order = pyblish.api.CollectorOrder
label = 'Collect Scene Version'
label = "Collect Scene Version"
# configurable in Settings
hosts = ["*"]
settings_category = "core"
# in some cases of headless publishing (for example webpublisher using PS)
# you want to ignore version from name and let integrate use next version

View file

@ -57,6 +57,7 @@ class ExtractBurnin(publish.Extractor):
"unreal",
"circuit",
]
settings_category = "core"
optional = True

View file

@ -55,6 +55,8 @@ class ExtractOIIOTranscode(publish.Extractor):
label = "Transcode color spaces"
order = pyblish.api.ExtractorOrder + 0.019
settings_category = "core"
optional = True
# Supported extensions

View file

@ -7,6 +7,7 @@ from ayon_core.lib import (
get_ffmpeg_tool_args,
run_subprocess
)
from ayon_core.pipeline import editorial
class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
@ -172,6 +173,14 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
clip_start = otio_clip.source_range.start_time
fps = clip_start.rate
conformed_av_start = media_av_start.rescaled_to(fps)
# Avoid rounding issue on media available range.
if clip_start.almost_equal(
conformed_av_start,
editorial.OTIO_EPSILON
):
conformed_av_start = clip_start
# ffmpeg ignores embedded tc
start = clip_start - conformed_av_start
duration = otio_clip.source_range.duration

View file

@ -23,7 +23,11 @@ from ayon_core.lib import (
get_ffmpeg_tool_args,
run_subprocess,
)
from ayon_core.pipeline import publish
from ayon_core.pipeline import (
KnownPublishError,
editorial,
publish,
)
class ExtractOTIOReview(
@ -97,8 +101,11 @@ class ExtractOTIOReview(
# skip instance if no reviewable data available
if (
not isinstance(otio_review_clips[0], otio.schema.Clip)
and len(otio_review_clips) == 1
len(otio_review_clips) == 1
and (
not isinstance(otio_review_clips[0], otio.schema.Clip)
or otio_review_clips[0].media_reference.is_missing_reference
)
):
self.log.warning(
"Instance `{}` has nothing to process".format(instance))
@ -248,7 +255,7 @@ class ExtractOTIOReview(
# Single video way.
# Extraction via FFmpeg.
else:
elif hasattr(media_ref, "target_url"):
path = media_ref.target_url
# Set extract range from 0 (FFmpeg ignores
# embedded timecode).
@ -370,6 +377,13 @@ class ExtractOTIOReview(
avl_start = avl_range.start_time
# Avoid rounding issue on media available range.
if start.almost_equal(
avl_start,
editorial.OTIO_EPSILON
):
avl_start = start
# An additional gap is required before the available
# range to conform source start point and head handles.
if start < avl_start:
@ -388,6 +402,14 @@ class ExtractOTIOReview(
# (media duration is shorter then clip requirement).
end_point = start + duration
avl_end_point = avl_range.end_time_exclusive()
# Avoid rounding issue on media available range.
if end_point.almost_equal(
avl_end_point,
editorial.OTIO_EPSILON
):
avl_end_point = end_point
if end_point > avl_end_point:
gap_duration = end_point - avl_end_point
duration -= gap_duration
@ -444,7 +466,7 @@ class ExtractOTIOReview(
command = get_ffmpeg_tool_args("ffmpeg")
input_extension = None
if sequence:
if sequence is not None:
input_dir, collection, sequence_fps = sequence
in_frame_start = min(collection.indexes)
@ -478,7 +500,7 @@ class ExtractOTIOReview(
"-i", input_path
])
elif video:
elif video is not None:
video_path, otio_range = video
frame_start = otio_range.start_time.value
input_fps = otio_range.start_time.rate
@ -496,7 +518,7 @@ class ExtractOTIOReview(
"-i", video_path
])
elif gap:
elif gap is not None:
sec_duration = frames_to_seconds(gap, self.actual_fps)
# form command for rendering gap files
@ -510,6 +532,9 @@ class ExtractOTIOReview(
"-tune", "stillimage"
])
else:
raise KnownPublishError("Sequence, video or gap is required.")
if video or sequence:
command.extend([
"-vf", f"scale={self.to_width}:{self.to_height}:flags=lanczos",

View file

@ -165,6 +165,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
"photoshop"
]
settings_category = "core"
# Supported extensions
image_exts = {"exr", "jpg", "jpeg", "png", "dpx", "tga", "tiff", "tif"}
video_exts = {"mov", "mp4"}

View file

@ -43,6 +43,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
"houdini",
"circuit",
]
settings_category = "core"
enabled = False
integrate_thumbnail = False

View file

@ -256,6 +256,7 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin,
label = "Collect USD Layer Contributions (Asset/Shot)"
families = ["usd"]
enabled = True
settings_category = "core"
# A contribution defines a contribution into a (department) layer which
# will get layered into the target product, usually the asset or shot.
@ -633,6 +634,8 @@ class ExtractUSDLayerContribution(publish.Extractor):
label = "Extract USD Layer Contributions (Asset/Shot)"
order = pyblish.api.ExtractorOrder + 0.45
settings_category = "core"
use_ayon_entity_uri = False
def process(self, instance):
@ -795,6 +798,8 @@ class ExtractUSDAssetContribution(publish.Extractor):
label = "Extract USD Asset/Shot Contributions"
order = ExtractUSDLayerContribution.order + 0.01
settings_category = "core"
use_ayon_entity_uri = False
def process(self, instance):

View file

@ -61,6 +61,8 @@ class IntegrateHeroVersion(
# Must happen after IntegrateNew
order = pyblish.api.IntegratorOrder + 0.1
settings_category = "core"
optional = True
active = True

View file

@ -24,6 +24,8 @@ class IntegrateProductGroup(pyblish.api.InstancePlugin):
order = pyblish.api.IntegratorOrder - 0.1
label = "Product Group"
settings_category = "core"
# Attributes set by settings
product_grouping_profiles = None

View file

@ -22,6 +22,8 @@ class PreIntegrateThumbnails(pyblish.api.InstancePlugin):
label = "Override Integrate Thumbnail Representations"
order = pyblish.api.IntegratorOrder - 0.1
settings_category = "core"
integrate_profiles = []
def process(self, instance):

View file

@ -31,6 +31,7 @@ class ValidateOutdatedContainers(
label = "Validate Outdated Containers"
order = pyblish.api.ValidatorOrder
settings_category = "core"
optional = True
actions = [ShowInventory]

View file

@ -14,6 +14,8 @@ class ValidateIntent(pyblish.api.ContextPlugin):
order = pyblish.api.ValidatorOrder
label = "Validate Intent"
settings_category = "core"
enabled = False
# Can be modified by settings

View file

@ -17,6 +17,7 @@ class ValidateVersion(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin):
order = pyblish.api.ValidatorOrder
label = "Validate Version"
settings_category = "core"
optional = False
active = True