mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
Merge pull request #1480 from ynput/feature/YN-0079_fix_frames_on_deadline
Feature: Fix frames on Deadline
This commit is contained in:
commit
e5838c035c
4 changed files with 111 additions and 96 deletions
|
|
@ -1,11 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""AYON plugin tools."""
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
import collections
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
CAPITALIZE_REGEX = re.compile(r"[a-zA-Z0-9]")
|
||||
|
||||
|
|
|
|||
|
|
@ -249,7 +249,8 @@ def create_skeleton_instance(
|
|||
# map inputVersions `ObjectId` -> `str` so json supports it
|
||||
"inputVersions": list(map(str, data.get("inputVersions", []))),
|
||||
"colorspace": data.get("colorspace"),
|
||||
"hasExplicitFrames": data.get("hasExplicitFrames")
|
||||
"hasExplicitFrames": data.get("hasExplicitFrames", False),
|
||||
"reuseLastVersion": data.get("reuseLastVersion", False),
|
||||
}
|
||||
|
||||
if data.get("renderlayer"):
|
||||
|
|
|
|||
|
|
@ -7,13 +7,20 @@ import copy
|
|||
import warnings
|
||||
import hashlib
|
||||
import xml.etree.ElementTree
|
||||
from typing import TYPE_CHECKING, Optional, Union, List
|
||||
from typing import TYPE_CHECKING, Optional, Union, List, Any
|
||||
import clique
|
||||
import speedcopy
|
||||
import logging
|
||||
|
||||
import ayon_api
|
||||
import pyblish.util
|
||||
import pyblish.plugin
|
||||
import pyblish.api
|
||||
|
||||
from ayon_api import (
|
||||
get_server_api_connection,
|
||||
get_representations,
|
||||
get_last_version_by_product_name
|
||||
)
|
||||
from ayon_core.lib import (
|
||||
import_filepath,
|
||||
Logger,
|
||||
|
|
@ -34,6 +41,8 @@ if TYPE_CHECKING:
|
|||
|
||||
TRAIT_INSTANCE_KEY: str = "representations_with_traits"
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_template_name_profiles(
|
||||
project_name, project_settings=None, logger=None
|
||||
|
|
@ -1030,7 +1039,7 @@ def main_cli_publish(
|
|||
# NOTE: ayon-python-api does not have public api function to find
|
||||
# out if is used service user. So we need to have try > except
|
||||
# block.
|
||||
con = ayon_api.get_server_api_connection()
|
||||
con = get_server_api_connection()
|
||||
try:
|
||||
con.set_default_service_username(username)
|
||||
except ValueError:
|
||||
|
|
@ -1143,3 +1152,90 @@ def get_trait_representations(
|
|||
|
||||
"""
|
||||
return instance.data.get(TRAIT_INSTANCE_KEY, [])
|
||||
|
||||
|
||||
def fill_sequence_gaps_with_previous_version(
|
||||
collection: str,
|
||||
staging_dir: str,
|
||||
instance: pyblish.plugin.Instance,
|
||||
current_repre_name: str,
|
||||
start_frame: int,
|
||||
end_frame: int
|
||||
) -> tuple[Optional[dict[str, Any]], Optional[dict[int, str]]]:
|
||||
"""Tries to replace missing frames from ones from last version"""
|
||||
used_version_entity, repre_file_paths = _get_last_version_files(
|
||||
instance, current_repre_name
|
||||
)
|
||||
if repre_file_paths is None:
|
||||
# issues in getting last version files
|
||||
return (None, None)
|
||||
|
||||
prev_collection = clique.assemble(
|
||||
repre_file_paths,
|
||||
patterns=[clique.PATTERNS["frames"]],
|
||||
minimum_items=1
|
||||
)[0][0]
|
||||
prev_col_format = prev_collection.format("{head}{padding}{tail}")
|
||||
|
||||
added_files = {}
|
||||
anatomy = instance.context.data["anatomy"]
|
||||
col_format = collection.format("{head}{padding}{tail}")
|
||||
for frame in range(start_frame, end_frame + 1):
|
||||
if frame in collection.indexes:
|
||||
continue
|
||||
hole_fpath = os.path.join(staging_dir, col_format % frame)
|
||||
|
||||
previous_version_path = prev_col_format % frame
|
||||
previous_version_path = anatomy.fill_root(previous_version_path)
|
||||
if not os.path.exists(previous_version_path):
|
||||
log.warning(
|
||||
"Missing frame should be replaced from "
|
||||
f"'{previous_version_path}' but that doesn't exist. "
|
||||
)
|
||||
return (None, None)
|
||||
|
||||
log.warning(
|
||||
f"Replacing missing '{hole_fpath}' with "
|
||||
f"'{previous_version_path}'"
|
||||
)
|
||||
speedcopy.copyfile(previous_version_path, hole_fpath)
|
||||
added_files[frame] = hole_fpath
|
||||
|
||||
return (used_version_entity, added_files)
|
||||
|
||||
|
||||
def _get_last_version_files(
|
||||
instance: pyblish.plugin.Instance,
|
||||
current_repre_name: str,
|
||||
) -> tuple[Optional[dict[str, Any]], Optional[list[str]]]:
|
||||
product_name = instance.data["productName"]
|
||||
project_name = instance.data["projectEntity"]["name"]
|
||||
folder_entity = instance.data["folderEntity"]
|
||||
|
||||
version_entity = get_last_version_by_product_name(
|
||||
project_name,
|
||||
product_name,
|
||||
folder_entity["id"],
|
||||
fields={"id", "attrib"}
|
||||
)
|
||||
|
||||
if not version_entity:
|
||||
return None, None
|
||||
|
||||
matching_repres = get_representations(
|
||||
project_name,
|
||||
version_ids=[version_entity["id"]],
|
||||
representation_names=[current_repre_name],
|
||||
fields={"files"}
|
||||
)
|
||||
|
||||
matching_repre = next(matching_repres, None)
|
||||
if not matching_repre:
|
||||
return None, None
|
||||
|
||||
repre_file_paths = [
|
||||
file_info["path"]
|
||||
for file_info in matching_repre["files"]
|
||||
]
|
||||
|
||||
return (version_entity, repre_file_paths)
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ import clique
|
|||
import speedcopy
|
||||
import pyblish.api
|
||||
|
||||
from ayon_api import get_last_version_by_product_name, get_representations
|
||||
|
||||
from ayon_core.lib import (
|
||||
get_ffmpeg_tool_args,
|
||||
filter_profiles,
|
||||
path_to_subprocess_arg,
|
||||
run_subprocess,
|
||||
)
|
||||
from ayon_core.pipeline.publish.lib import (
|
||||
fill_sequence_gaps_with_previous_version
|
||||
)
|
||||
from ayon_core.lib.transcoding import (
|
||||
IMAGE_EXTENSIONS,
|
||||
get_ffprobe_streams,
|
||||
|
|
@ -508,10 +509,10 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
resolution_width=temp_data.resolution_width,
|
||||
resolution_height=temp_data.resolution_height,
|
||||
extension=temp_data.input_ext,
|
||||
temp_data=temp_data
|
||||
temp_data=temp_data,
|
||||
)
|
||||
elif fill_missing_frames == "previous_version":
|
||||
new_frame_files = self.fill_sequence_gaps_with_previous(
|
||||
fill_output = fill_sequence_gaps_with_previous_version(
|
||||
collection=collection,
|
||||
staging_dir=new_repre["stagingDir"],
|
||||
instance=instance,
|
||||
|
|
@ -519,8 +520,13 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
start_frame=temp_data.frame_start,
|
||||
end_frame=temp_data.frame_end,
|
||||
)
|
||||
_, new_frame_files = fill_output
|
||||
# fallback to original workflow
|
||||
if new_frame_files is None:
|
||||
self.log.warning(
|
||||
"Falling back to filling from currently "
|
||||
"last rendered."
|
||||
)
|
||||
new_frame_files = (
|
||||
self.fill_sequence_gaps_from_existing(
|
||||
collection=collection,
|
||||
|
|
@ -1050,92 +1056,6 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
return all_args
|
||||
|
||||
def fill_sequence_gaps_with_previous(
|
||||
self,
|
||||
collection: str,
|
||||
staging_dir: str,
|
||||
instance: pyblish.plugin.Instance,
|
||||
current_repre_name: str,
|
||||
start_frame: int,
|
||||
end_frame: int
|
||||
) -> Optional[dict[int, str]]:
|
||||
"""Tries to replace missing frames from ones from last version"""
|
||||
repre_file_paths = self._get_last_version_files(
|
||||
instance, current_repre_name)
|
||||
if repre_file_paths is None:
|
||||
# issues in getting last version files, falling back
|
||||
return None
|
||||
|
||||
prev_collection = clique.assemble(
|
||||
repre_file_paths,
|
||||
patterns=[clique.PATTERNS["frames"]],
|
||||
minimum_items=1
|
||||
)[0][0]
|
||||
prev_col_format = prev_collection.format("{head}{padding}{tail}")
|
||||
|
||||
added_files = {}
|
||||
anatomy = instance.context.data["anatomy"]
|
||||
col_format = collection.format("{head}{padding}{tail}")
|
||||
for frame in range(start_frame, end_frame + 1):
|
||||
if frame in collection.indexes:
|
||||
continue
|
||||
hole_fpath = os.path.join(staging_dir, col_format % frame)
|
||||
|
||||
previous_version_path = prev_col_format % frame
|
||||
previous_version_path = anatomy.fill_root(previous_version_path)
|
||||
if not os.path.exists(previous_version_path):
|
||||
self.log.warning(
|
||||
"Missing frame should be replaced from "
|
||||
f"'{previous_version_path}' but that doesn't exist. "
|
||||
"Falling back to filling from currently last rendered."
|
||||
)
|
||||
return None
|
||||
|
||||
self.log.warning(
|
||||
f"Replacing missing '{hole_fpath}' with "
|
||||
f"'{previous_version_path}'"
|
||||
)
|
||||
speedcopy.copyfile(previous_version_path, hole_fpath)
|
||||
added_files[frame] = hole_fpath
|
||||
|
||||
return added_files
|
||||
|
||||
def _get_last_version_files(
|
||||
self,
|
||||
instance: pyblish.plugin.Instance,
|
||||
current_repre_name: str,
|
||||
):
|
||||
product_name = instance.data["productName"]
|
||||
project_name = instance.data["projectEntity"]["name"]
|
||||
folder_entity = instance.data["folderEntity"]
|
||||
|
||||
version_entity = get_last_version_by_product_name(
|
||||
project_name,
|
||||
product_name,
|
||||
folder_entity["id"],
|
||||
fields={"id"}
|
||||
)
|
||||
if not version_entity:
|
||||
return None
|
||||
|
||||
matching_repres = get_representations(
|
||||
project_name,
|
||||
version_ids=[version_entity["id"]],
|
||||
representation_names=[current_repre_name],
|
||||
fields={"files"}
|
||||
)
|
||||
|
||||
if not matching_repres:
|
||||
return None
|
||||
matching_repre = list(matching_repres)[0]
|
||||
|
||||
repre_file_paths = [
|
||||
file_info["path"]
|
||||
for file_info in matching_repre["files"]
|
||||
]
|
||||
|
||||
return repre_file_paths
|
||||
|
||||
def fill_sequence_gaps_with_blanks(
|
||||
self,
|
||||
collection: str,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue