diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py new file mode 100644 index 0000000000..e3086fb638 --- /dev/null +++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py @@ -0,0 +1,53 @@ +import re + +import pyblish.api +import openpype.api +from openpype import lib + + +class ValidateFrameRange(pyblish.api.InstancePlugin): + """Validating frame range of rendered files against state in DB.""" + + label = "Validate Frame Range" + hosts = ["standalonepublisher"] + families = ["render"] + order = openpype.api.ValidateContentsOrder + + optional = True + # published data might be sequence (.mov, .mp4) in that counting files + # doesnt make sense + check_extensions = ["exr", "dpx", "jpg", "jpeg", "png", "tiff", "tga", + "gif", "svg"] + skip_timelines_check = [] # skip for specific task names (regex) + + def process(self, instance): + if any(re.search(pattern, instance.data["task"]) + for pattern in self.skip_timelines_check): + self.log.info("Skipping for {} task".format(instance.data["task"])) + + asset_data = lib.get_asset(instance.data["asset"])["data"] + frame_start = asset_data["frameStart"] + frame_end = asset_data["frameEnd"] + handle_start = asset_data["handleStart"] + handle_end = asset_data["handleEnd"] + duration = (frame_end - frame_start + 1) + handle_start + handle_end + + repre = instance.data.get("representations", [None]) + if not repre: + self.log.info("No representations, skipping.") + return + + ext = repre[0]['ext'].replace(".", '') + + if not ext or ext.lower() not in self.check_extensions: + self.log.warning("Cannot check for extension {}".format(ext)) + return + + frames = len(instance.data.get("representations", [None])[0]["files"]) + + err_msg = "Frame duration from DB:'{}' ". format(int(duration)) +\ + " doesn't match number of files:'{}'".format(frames) +\ + " Please change frame range for Asset or limit no. of files" + assert frames == duration, err_msg + + self.log.debug("Valid ranges {} - {}".format(int(duration), frames)) diff --git a/openpype/settings/defaults/project_settings/standalonepublisher.json b/openpype/settings/defaults/project_settings/standalonepublisher.json index 9d40d2ded6..979f5285d3 100644 --- a/openpype/settings/defaults/project_settings/standalonepublisher.json +++ b/openpype/settings/defaults/project_settings/standalonepublisher.json @@ -100,6 +100,22 @@ ], "help": "Script exported from matchmoving application" }, + "create_render": { + "name": "render", + "label": "Render", + "family": "render", + "icon": "image", + "defaults": ["Animation", "Lighting", "Lookdev", "Compositing"], + "help": "Rendered images or video files" + }, + "create_mov_batch": { + "name": "mov_batch", + "label": "Batch Mov", + "family": "render_mov_batch", + "icon": "image", + "defaults": ["Main"], + "help": "Process multiple Mov files and publish them for layout and comp." + }, "__dynamic_keys_labels__": { "create_workfile": "Workfile", "create_model": "Model", @@ -109,10 +125,32 @@ "create_camera": "Camera", "create_editorial": "Editorial", "create_image": "Image", - "create_matchmove": "Matchmove" + "create_matchmove": "Matchmove", + "create_render": "Render", + "create_mov_batch": "Batch Mov" } }, "publish": { + "ValidateSceneSettings": { + "enabled": true, + "optional": true, + "active": true, + "check_extensions": [ + "exr", + "dpx", + "jpg", + "jpeg", + "png", + "tiff", + "tga", + "gif", + "svg" + ], + "families": [ + "render" + ], + "skip_timelines_check": [] + }, "ExtractThumbnailSP": { "ffmpeg_args": { "input": [ diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json index 28755ad268..0ef7612805 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json @@ -56,6 +56,52 @@ "key": "publish", "label": "Publish plugins", "children": [ + { + "type": "dict", + "collapsible": true, + "key": "ValidateSceneSettings", + "label": "Validate Scene Settings", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "label", + "label": "Validate if frame range in DB matches number of published files" + }, + { + "type": "list", + "key": "check_extensions", + "object_type": "text", + "label": "Check Frame Range for Extensions" + }, + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "type": "list", + "key": "skip_timelines_check", + "object_type": "text", + "label": "Skip Frame Range check for Tasks" + } + ] + }, { "type": "dict", "collapsible": true,