From d387dca0272c9be2a80beb52ac8272cabb10f426 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 26 Jan 2024 10:44:13 +0000 Subject: [PATCH 01/12] Use duration from streams as its more precise --- openpype/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 10eb261482..37f7ea7737 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -445,7 +445,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # Set video input attributes max_int = str(2147483647) video_data = get_ffprobe_data(video_file_path, logger=self.log) - duration = float(video_data["format"]["duration"]) + duration = float(video_data["streams"][0]["duration"]) cmd_args = [ "-y", From e6818f94f5fead64b6ff8767462064fef8e10a41 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 29 Jan 2024 09:17:07 +0000 Subject: [PATCH 02/12] Illicit suggestion --- openpype/plugins/publish/extract_thumbnail.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 37f7ea7737..8a1e9fd12d 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -445,7 +445,11 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # Set video input attributes max_int = str(2147483647) video_data = get_ffprobe_data(video_file_path, logger=self.log) - duration = float(video_data["streams"][0]["duration"]) + duration = max( + float(stream.get("duration", 0)) + for stream in video_data["streams"] + if stream.get("codec_type") == "video" + ) cmd_args = [ "-y", From 3f8830e27d9c7f4002985ebcf05f7fe395fc3e17 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Mon, 29 Jan 2024 10:13:18 +0000 Subject: [PATCH 03/12] Update openpype/plugins/publish/extract_thumbnail.py --- openpype/plugins/publish/extract_thumbnail.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 8a1e9fd12d..2e272b061b 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -445,6 +445,10 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # Set video input attributes max_int = str(2147483647) video_data = get_ffprobe_data(video_file_path, logger=self.log) + # Use duration of the individual streams since it is returned with + # higher decimal precision than 'format.duration'. We need this + # more precise value for calculating the correct amount of frames + # for higher FPS ranges or decimal ranges, e.g. 29.97 FPS duration = max( float(stream.get("duration", 0)) for stream in video_data["streams"] From 3807172faed3addc22790c6831065d7424e08035 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Mon, 29 Jan 2024 10:13:40 +0000 Subject: [PATCH 04/12] Update openpype/plugins/publish/extract_thumbnail.py --- openpype/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 2e272b061b..cbeada6bac 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -448,7 +448,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # Use duration of the individual streams since it is returned with # higher decimal precision than 'format.duration'. We need this # more precise value for calculating the correct amount of frames - # for higher FPS ranges or decimal ranges, e.g. 29.97 FPS + # for higher FPS ranges or decimal ranges, e.g. 29.97 FPS duration = max( float(stream.get("duration", 0)) for stream in video_data["streams"] From 0aea2ae39f4f947716c7ef69f49bda5dd13ad5c1 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 08:11:11 +0000 Subject: [PATCH 05/12] Add submodule --- client/ayon_core/hosts/unreal/integration | 1 + 1 file changed, 1 insertion(+) create mode 160000 client/ayon_core/hosts/unreal/integration diff --git a/client/ayon_core/hosts/unreal/integration b/client/ayon_core/hosts/unreal/integration new file mode 160000 index 0000000000..6d2793170e --- /dev/null +++ b/client/ayon_core/hosts/unreal/integration @@ -0,0 +1 @@ +Subproject commit 6d2793170ed57187842f683a943593973abcc337 From 344e244a993a3082b8836afdb87f5883e63ff0e8 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 26 Feb 2024 18:04:40 +0800 Subject: [PATCH 06/12] validate no animation for model family in Max --- .../plugins/publish/validate_no_animation.py | 67 +++++++++++++++++++ .../max/server/settings/publishers.py | 9 +++ server_addon/max/server/version.py | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py new file mode 100644 index 0000000000..9f859a1b28 --- /dev/null +++ b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +import pyblish.api +from pymxs import runtime as rt +from ayon_core.pipeline import ( + PublishValidationError, + OptionalPyblishPluginMixin +) +from ayon_core.hosts.max.api.action import SelectInvalidAction + + +class ValidateNoAnimation(pyblish.api.InstancePlugin, + OptionalPyblishPluginMixin): + """Validates No Animation + + Ensure no keyframes on nodes in the Instance + """ + + order = pyblish.api.ValidatorOrder + families = ["model"] + hosts = ["max"] + optional = True + label = "Validate No Animation" + actions = [SelectInvalidAction] + + def process(self, instance): + if not self.is_active(instance.data): + return + invalid = self.get_invalid(instance) + if invalid: + bullet_point_invalid_statement = "\n".join( + "- {}: {}".format(obj, message) + for obj, message in invalid + ) + raise PublishValidationError( + "Keyframes found on:\n\n{0}".format( + bullet_point_invalid_statement) + , + title="Keyframes on model" + ) + + @staticmethod + def get_invalid(instance): + invalid = [] + selected_objects = instance.data["members"] + for sel in selected_objects: + sel_pos_ctl = rt.getPropertyController( + sel.controller, 'Position') + ctl_count = (sel_pos_ctl.keys).count + if len(ctl_count) > 0: + invalid.append( + (sel), f"Object Position(s) has {ctl_count} keyframe(s)") + sel_rot_ctl = rt.getPropertyController( + sel.controller, "Rotation" + ) + ctl_count = (sel_rot_ctl.keys).count + if len(ctl_count) > 0: + invalid.append( + (sel), f"Object Rotation(s) has {ctl_count} keyframe(s)") + sel_scale_ctl = rt.getPropertyController( + sel.controller, "Scale" + ) + ctl_count = (sel_scale_ctl.keys).count + if len(ctl_count) > 0: + invalid.append( + (sel), f"Object Rotation(s) has {ctl_count} keyframe(s)") + + return invalid diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index 5e28c1b467..8f9f1009f4 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -82,6 +82,10 @@ class PublishersModel(BaseSettingsModel): "the system automatically skips checking it" ) ) + ValidateNoAnimation: BasicValidateModel = SettingsField( + default_factory=BasicValidateModel, + title="Validate No Animation" + ) ValidateLoadedPlugin: ValidateLoadedPluginModel = SettingsField( default_factory=ValidateLoadedPluginModel, title="Validate Loaded Plugin" @@ -134,6 +138,11 @@ DEFAULT_PUBLISH_SETTINGS = { "optional": True, "family_plugins_mapping": [] }, + "ValidateNoAnimation": { + "enabled": True, + "optional": True, + "active": False, + }, "ExtractModelObj": { "enabled": True, "optional": True, diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py index 1276d0254f..0a8da88258 100644 --- a/server_addon/max/server/version.py +++ b/server_addon/max/server/version.py @@ -1 +1 @@ -__version__ = "0.1.5" +__version__ = "0.1.6" From 999563ea521a877fd9074c52cec00d8ccb21bf77 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 26 Feb 2024 18:31:39 +0800 Subject: [PATCH 07/12] tweak comment and some syntax error --- .../max/plugins/publish/validate_no_animation.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py index 9f859a1b28..4f57933085 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py @@ -46,22 +46,22 @@ class ValidateNoAnimation(pyblish.api.InstancePlugin, sel_pos_ctl = rt.getPropertyController( sel.controller, 'Position') ctl_count = (sel_pos_ctl.keys).count - if len(ctl_count) > 0: + if ctl_count > 0: invalid.append( - (sel), f"Object Position(s) has {ctl_count} keyframe(s)") + ( (sel), f"Object Position(s) has {ctl_count} keyframe(s)")) sel_rot_ctl = rt.getPropertyController( sel.controller, "Rotation" ) ctl_count = (sel_rot_ctl.keys).count - if len(ctl_count) > 0: + if ctl_count > 0: invalid.append( - (sel), f"Object Rotation(s) has {ctl_count} keyframe(s)") + ((sel), f"Object Rotation(s) has {ctl_count} keyframe(s)")) sel_scale_ctl = rt.getPropertyController( sel.controller, "Scale" ) ctl_count = (sel_scale_ctl.keys).count - if len(ctl_count) > 0: + if ctl_count > 0: invalid.append( - (sel), f"Object Rotation(s) has {ctl_count} keyframe(s)") + ((sel), f"Object Scale(s) has {ctl_count} keyframe(s)")) return invalid From ef654cd7d8d1cbe3aea4238328aced4082bd9d4a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 26 Feb 2024 20:05:09 +0800 Subject: [PATCH 08/12] use sel.isAnimated instead of doing check on controller --- .../plugins/publish/validate_no_animation.py | 41 ++++++------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py index 4f57933085..0b7a296cd9 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py @@ -27,41 +27,24 @@ class ValidateNoAnimation(pyblish.api.InstancePlugin, return invalid = self.get_invalid(instance) if invalid: - bullet_point_invalid_statement = "\n".join( - "- {}: {}".format(obj, message) - for obj, message in invalid - ) raise PublishValidationError( - "Keyframes found on:\n\n{0}".format( - bullet_point_invalid_statement) + "Keyframes found on:\n\n{0}".format(invalid) , title="Keyframes on model" ) @staticmethod def get_invalid(instance): - invalid = [] - selected_objects = instance.data["members"] - for sel in selected_objects: - sel_pos_ctl = rt.getPropertyController( - sel.controller, 'Position') - ctl_count = (sel_pos_ctl.keys).count - if ctl_count > 0: - invalid.append( - ( (sel), f"Object Position(s) has {ctl_count} keyframe(s)")) - sel_rot_ctl = rt.getPropertyController( - sel.controller, "Rotation" - ) - ctl_count = (sel_rot_ctl.keys).count - if ctl_count > 0: - invalid.append( - ((sel), f"Object Rotation(s) has {ctl_count} keyframe(s)")) - sel_scale_ctl = rt.getPropertyController( - sel.controller, "Scale" - ) - ctl_count = (sel_scale_ctl.keys).count - if ctl_count > 0: - invalid.append( - ((sel), f"Object Scale(s) has {ctl_count} keyframe(s)")) + """Get invalid object(s) which have keyframe(s) + + + Args: + instance (pyblish.api.instance): Instance + + Returns: + list: list of invalid objects + """ + invalid = [invalid for invalid in instance.data["members"] + if invalid.isAnimated] return invalid From 2caf32c5b05f0153a8f1c25ad80cb08301d6d6e3 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 6 Mar 2024 23:08:40 +0800 Subject: [PATCH 09/12] supports the check on only one keyframe in timeline --- .../plugins/publish/validate_no_animation.py | 19 ++++++++++++++++++- server_addon/max/server/version.py | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py index 0b7a296cd9..4b2a18d606 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_no_animation.py @@ -8,6 +8,23 @@ from ayon_core.pipeline import ( from ayon_core.hosts.max.api.action import SelectInvalidAction +def get_invalid_keys(obj): + """function to check on whether there is keyframe in + + Args: + obj (str): object needed to check if there is a keyframe + + Returns: + bool: whether invalid object(s) exist + """ + for transform in ["Position", "Rotation", "Scale"]: + num_of_key = rt.NumKeys(rt.getPropertyController( + obj.controller, transform)) + if num_of_key > 0: + return True + return False + + class ValidateNoAnimation(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin): """Validates No Animation @@ -45,6 +62,6 @@ class ValidateNoAnimation(pyblish.api.InstancePlugin, list: list of invalid objects """ invalid = [invalid for invalid in instance.data["members"] - if invalid.isAnimated] + if invalid.isAnimated or get_invalid_keys(invalid)] return invalid diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py index 0a8da88258..f1380eede2 100644 --- a/server_addon/max/server/version.py +++ b/server_addon/max/server/version.py @@ -1 +1 @@ -__version__ = "0.1.6" +__version__ = "0.1.7" From fd8bf2cc67d03d9e7b80c903e1d6ccb40d6c0df0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 6 Mar 2024 16:29:12 +0100 Subject: [PATCH 10/12] Adjust clip start if slate is present Trim the clip's start time by 1 frame and update its duration accordingly when a "slate" is detected in the version data families. Also, corrected calculation for `frame_end_handle` to use `frame_end`. --- client/ayon_core/hosts/resolve/api/plugin.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/resolve/api/plugin.py b/client/ayon_core/hosts/resolve/api/plugin.py index 157b8de363..dfce3ea37a 100644 --- a/client/ayon_core/hosts/resolve/api/plugin.py +++ b/client/ayon_core/hosts/resolve/api/plugin.py @@ -410,6 +410,11 @@ class ClipLoader: source_out = int(_clip_property("End")) source_duration = int(_clip_property("Frames")) + # Trim clip start if slate is present + if "slate" in self.data["versionData"]["families"]: + source_in += 1 + source_duration = source_out - source_in + 1 + if not self.with_handles: # Load file without the handles of the source media # We remove the handles from the source in and source out @@ -435,7 +440,7 @@ class ClipLoader: handle_start = version_data.get("handleStart", 0) handle_end = version_data.get("handleEnd", 0) frame_start_handle = frame_start - handle_start - frame_end_handle = frame_start + handle_end + frame_end_handle = frame_end + handle_end database_frame_duration = int( frame_end_handle - frame_start_handle + 1 ) From b5873d47a8c8b9f4d812421bee0221f4ad7b7030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Wed, 6 Mar 2024 16:44:18 +0100 Subject: [PATCH 11/12] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 5a0ed1ae1d..e6badf936a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report description: File a bug report -title: '' +title: 'Your issue title here' labels: - 'type: bug' body: From 14db89cc359c2240727a24cc832e1733dbb67414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Wed, 6 Mar 2024 16:45:43 +0100 Subject: [PATCH 12/12] Update enhancement_request.yml --- .github/ISSUE_TEMPLATE/enhancement_request.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.yml b/.github/ISSUE_TEMPLATE/enhancement_request.yml index da4d0d9319..31b2eb2edd 100644 --- a/.github/ISSUE_TEMPLATE/enhancement_request.yml +++ b/.github/ISSUE_TEMPLATE/enhancement_request.yml @@ -1,6 +1,6 @@ name: Enhancement Request description: Create a report to help us enhance a particular feature -title: "" +title: "Your issue title here" labels: - "type: enhancement" body: @@ -49,4 +49,4 @@ body: label: "Additional context:" description: Add any other context or screenshots about the enhancement request here. validations: - required: false \ No newline at end of file + required: false