From b63453d38f1e11a92ed94be26d3d07cb97875bb8 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 20 Sep 2019 09:56:33 +0200 Subject: [PATCH 01/13] mapping provided and required attributes in plugins --- .../plugins/global/publish/collect_anatomy.py | 20 +++++ .../plugins/global/publish/collect_comment.py | 7 ++ .../plugins/global/publish/collect_context.py | 15 ++++ .../global/publish/collect_context_label.py | 7 ++ .../publish/collect_current_shell_file.py | 8 ++ .../global/publish/collect_deadline_user.py | 9 +- .../global/publish/collect_filesequences.py | 10 +++ .../global/publish/collect_machine_name.py | 8 ++ .../publish/collect_output_repre_config.py | 10 ++- .../plugins/global/publish/collect_presets.py | 9 ++ .../global/publish/collect_project_data.py | 9 +- .../global/publish/collect_templates.py | 88 +++++++++++++++++-- .../publish/integrate_assumed_destination.py | 9 +- 13 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 pype/plugins/global/publish/collect_anatomy.py diff --git a/pype/plugins/global/publish/collect_anatomy.py b/pype/plugins/global/publish/collect_anatomy.py new file mode 100644 index 0000000000..b053a3a0d1 --- /dev/null +++ b/pype/plugins/global/publish/collect_anatomy.py @@ -0,0 +1,20 @@ +""" +Requires: + None +Provides: + context -> anatomy (pypeapp.Anatomy) +""" + +from pypeapp import Anatomy +import pyblish.api + + +class CollectTemplates(pyblish.api.ContextPlugin): + """Collect Anatomy into Context""" + + order = pyblish.api.CollectorOrder + label = "Collect Templates" + + def process(self, context): + context.data['anatomy'] = Anatomy() + self.log.info("Anatomy templates collected...") diff --git a/pype/plugins/global/publish/collect_comment.py b/pype/plugins/global/publish/collect_comment.py index 5bbd1da2a1..22970665a1 100644 --- a/pype/plugins/global/publish/collect_comment.py +++ b/pype/plugins/global/publish/collect_comment.py @@ -1,3 +1,10 @@ +""" +Requires: + None +Provides: + context -> comment (str) +""" + import pyblish.api diff --git a/pype/plugins/global/publish/collect_context.py b/pype/plugins/global/publish/collect_context.py index 31ab95259c..b718f18fa8 100644 --- a/pype/plugins/global/publish/collect_context.py +++ b/pype/plugins/global/publish/collect_context.py @@ -1,3 +1,18 @@ +""" +Requires: + environment -> SAPUBLISH_INPATH + environment -> SAPUBLISH_OUTPATH + +Provides: + context -> returnJsonPath (str) + context -> project + context -> asset + instance -> destination_list (list) + instance -> representations (list) + instance -> source (list) + instance -> representations +""" + import os import pyblish.api from avalon import io diff --git a/pype/plugins/global/publish/collect_context_label.py b/pype/plugins/global/publish/collect_context_label.py index ec8e0f7cdc..9c07d7de5b 100644 --- a/pype/plugins/global/publish/collect_context_label.py +++ b/pype/plugins/global/publish/collect_context_label.py @@ -1,3 +1,10 @@ +""" +Requires: + context -> currentFile (str) +Provides: + context -> label (str) +""" + import os import pyblish.api diff --git a/pype/plugins/global/publish/collect_current_shell_file.py b/pype/plugins/global/publish/collect_current_shell_file.py index a467459bc8..961cad86a1 100644 --- a/pype/plugins/global/publish/collect_current_shell_file.py +++ b/pype/plugins/global/publish/collect_current_shell_file.py @@ -1,3 +1,11 @@ +""" +Requires: + None + +Provides: + context -> currentFile (str) +""" + import os import pyblish.api diff --git a/pype/plugins/global/publish/collect_deadline_user.py b/pype/plugins/global/publish/collect_deadline_user.py index 624e455251..125f9d0d26 100644 --- a/pype/plugins/global/publish/collect_deadline_user.py +++ b/pype/plugins/global/publish/collect_deadline_user.py @@ -1,3 +1,11 @@ +""" +Requires: + environment -> DEADLINE_PATH + +Provides: + context -> deadlineUser (str) +""" + import os import subprocess @@ -54,4 +62,3 @@ class CollectDeadlineUser(pyblish.api.ContextPlugin): self.log.info("Found Deadline user: {}".format(user)) context.data['deadlineUser'] = user - diff --git a/pype/plugins/global/publish/collect_filesequences.py b/pype/plugins/global/publish/collect_filesequences.py index 33531549cb..73f3a459c8 100644 --- a/pype/plugins/global/publish/collect_filesequences.py +++ b/pype/plugins/global/publish/collect_filesequences.py @@ -1,3 +1,13 @@ +""" +Requires: + environment -> PYPE_PUBLISH_PATHS + context -> workspaceDir + +Provides: + context -> user (str) + instance -> new instance +""" + import os import re import copy diff --git a/pype/plugins/global/publish/collect_machine_name.py b/pype/plugins/global/publish/collect_machine_name.py index 02360cff04..72ef68f8ed 100644 --- a/pype/plugins/global/publish/collect_machine_name.py +++ b/pype/plugins/global/publish/collect_machine_name.py @@ -1,3 +1,11 @@ +""" +Requires: + none + +Provides: + context -> machine (str) +""" + import pyblish.api diff --git a/pype/plugins/global/publish/collect_output_repre_config.py b/pype/plugins/global/publish/collect_output_repre_config.py index 5595e29cab..f02199e778 100644 --- a/pype/plugins/global/publish/collect_output_repre_config.py +++ b/pype/plugins/global/publish/collect_output_repre_config.py @@ -1,5 +1,11 @@ -import os -import json +""" +Requires: + config_data -> ftrack.output_representation + +Provides: + context -> output_repre_config (str) +""" + import pyblish.api from pypeapp import config diff --git a/pype/plugins/global/publish/collect_presets.py b/pype/plugins/global/publish/collect_presets.py index 7e0d3e2f4b..abf85a6f01 100644 --- a/pype/plugins/global/publish/collect_presets.py +++ b/pype/plugins/global/publish/collect_presets.py @@ -1,3 +1,12 @@ +""" +Requires: + config_data -> colorspace.default + config_data -> dataflow.default + +Provides: + context -> presets +""" + from pyblish import api from pypeapp import config diff --git a/pype/plugins/global/publish/collect_project_data.py b/pype/plugins/global/publish/collect_project_data.py index de51ad880c..acdbc2c41f 100644 --- a/pype/plugins/global/publish/collect_project_data.py +++ b/pype/plugins/global/publish/collect_project_data.py @@ -1,8 +1,15 @@ +""" +Requires: + None + +Provides: + context -> projectData +""" + import pyblish.api import pype.api as pype - class CollectProjectData(pyblish.api.ContextPlugin): """Collecting project data from avalon db""" diff --git a/pype/plugins/global/publish/collect_templates.py b/pype/plugins/global/publish/collect_templates.py index fe48e97c03..8113f1d763 100644 --- a/pype/plugins/global/publish/collect_templates.py +++ b/pype/plugins/global/publish/collect_templates.py @@ -1,16 +1,86 @@ +""" +Requires: + session -> AVALON_PROJECT + context -> anatomy (pypeapp.Anatomy) + instance -> subset + instance -> asset + instance -> family -import pype.api as pype -from pypeapp import Anatomy +Provides: + instance -> template + instance -> assumedTemplateData + instance -> assumedDestination +""" +import os + +from avalon import io, api import pyblish.api -class CollectTemplates(pyblish.api.ContextPlugin): - """Inject the current working file into context""" +class CollectTemplates(pyblish.api.InstancePlugin): + """Fill templates with data needed for publish""" - order = pyblish.api.CollectorOrder - label = "Collect Templates" + order = pyblish.api.CollectorOrder + 0.1 + label = "Collect and fill Templates" - def process(self, context): - context.data['anatomy'] = Anatomy() - self.log.info("Anatomy templates collected...") + def process(self, instance): + # get all the stuff from the database + subset_name = instance.data["subset"] + asset_name = instance.data["asset"] + project_name = api.Session["AVALON_PROJECT"] + + project = io.find_one({"type": "project", + "name": project_name}, + projection={"config": True, "data": True}) + + template = project["config"]["template"]["publish"] + anatomy = instance.context.data['anatomy'] + + asset = io.find_one({"type": "asset", + "name": asset_name, + "parent": project["_id"]}) + + assert asset, ("No asset found by the name '{}' " + "in project '{}'".format(asset_name, project_name)) + silo = asset['silo'] + + subset = io.find_one({"type": "subset", + "name": subset_name, + "parent": asset["_id"]}) + + # assume there is no version yet, we start at `1` + version = None + version_number = 1 + if subset is not None: + version = io.find_one({"type": "version", + "parent": subset["_id"]}, + sort=[("name", -1)]) + + # if there is a subset there ought to be version + if version is not None: + version_number += int(version["name"]) + + hierarchy = asset['data']['parents'] + if hierarchy: + # hierarchy = os.path.sep.join(hierarchy) + hierarchy = os.path.join(*hierarchy) + + template_data = {"root": api.Session["AVALON_PROJECTS"], + "project": {"name": project_name, + "code": project['data']['code']}, + "silo": silo, + "family": instance.data['family'], + "asset": asset_name, + "subset": subset_name, + "version": version_number, + "hierarchy": hierarchy, + "representation": "TEMP"} + + instance.data["template"] = template + instance.data["assumedTemplateData"] = template_data + + # We take the parent folder of representation 'filepath' + instance.data["assumedDestination"] = os.path.dirname( + (anatomy.format(template_data)).publish.path + ) diff --git a/pype/plugins/global/publish/integrate_assumed_destination.py b/pype/plugins/global/publish/integrate_assumed_destination.py index 6999ce6ab8..3bbd4cf33b 100644 --- a/pype/plugins/global/publish/integrate_assumed_destination.py +++ b/pype/plugins/global/publish/integrate_assumed_destination.py @@ -30,7 +30,8 @@ class IntegrateAssumedDestination(pyblish.api.InstancePlugin): "resources") # Clean the path - mock_destination = os.path.abspath(os.path.normpath(mock_destination)).replace("\\", "/") + mock_destination = os.path.abspath( + os.path.normpath(mock_destination)).replace("\\", "/") # Define resource destination and transfers resources = instance.data.get("resources", list()) @@ -38,7 +39,8 @@ class IntegrateAssumedDestination(pyblish.api.InstancePlugin): for resource in resources: # Add destination to the resource - source_filename = os.path.basename(resource["source"]).replace("\\", "/") + source_filename = os.path.basename( + resource["source"]).replace("\\", "/") destination = os.path.join(mock_destination, source_filename) # Force forward slashes to fix issue with software unable @@ -53,7 +55,8 @@ class IntegrateAssumedDestination(pyblish.api.InstancePlugin): files = resource['files'] for fsrc in files: fname = os.path.basename(fsrc) - fdest = os.path.join(mock_destination, fname).replace("\\", "/") + fdest = os.path.join( + mock_destination, fname).replace("\\", "/") transfers.append([fsrc, fdest]) instance.data["resources"] = resources From 603b0fd3fdaad96ec27e4fc7446856e26ddf2e90 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 23 Sep 2019 11:08:52 +0200 Subject: [PATCH 02/13] fixed variable name --- pype/plugins/global/publish/submit_publish_job.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pype/plugins/global/publish/submit_publish_job.py b/pype/plugins/global/publish/submit_publish_job.py index 8d352b8872..b812fb16e6 100644 --- a/pype/plugins/global/publish/submit_publish_job.py +++ b/pype/plugins/global/publish/submit_publish_job.py @@ -1,7 +1,6 @@ import os import json import re -from pprint import pprint import logging from avalon import api, io @@ -147,7 +146,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): "PYPE_ROOT" ] - def _submit_deadline_post_job(self, instance, job): """ Deadline specific code separated from :meth:`process` for sake of @@ -192,7 +190,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): # Transfer the environment from the original job to this dependent # job so they use the same environment - environment = job["Props"].get("Env", {}) i = 0 for index, key in enumerate(environment): @@ -295,7 +292,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): # Optional metadata (for debugging) "metadata": { "instance": data, - "job": job, + "job": render_job, "session": api.Session.copy() } } From b7c827f35d4b8d223ed62838bb15d60abfdb8b48 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:13:51 +0200 Subject: [PATCH 03/13] family widget also stores and collect key of family in presets so can be trackable on pyblish --- pype/standalonepublish/widgets/__init__.py | 1 + pype/standalonepublish/widgets/widget_family.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pype/standalonepublish/widgets/__init__.py b/pype/standalonepublish/widgets/__init__.py index 4c6a0e85a5..c6e0dd9a47 100644 --- a/pype/standalonepublish/widgets/__init__.py +++ b/pype/standalonepublish/widgets/__init__.py @@ -6,6 +6,7 @@ HelpRole = QtCore.Qt.UserRole + 2 FamilyRole = QtCore.Qt.UserRole + 3 ExistsRole = QtCore.Qt.UserRole + 4 PluginRole = QtCore.Qt.UserRole + 5 +PluginKeyRole = QtCore.Qt.UserRole + 6 from ..resources import get_resource from .button_from_svgs import SvgResizable, SvgButton diff --git a/pype/standalonepublish/widgets/widget_family.py b/pype/standalonepublish/widgets/widget_family.py index 63776b1df3..26eb8077d9 100644 --- a/pype/standalonepublish/widgets/widget_family.py +++ b/pype/standalonepublish/widgets/widget_family.py @@ -5,7 +5,7 @@ import json from collections import namedtuple from . import QtWidgets, QtCore -from . import HelpRole, FamilyRole, ExistsRole, PluginRole +from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole from . import FamilyDescriptionWidget from pypeapp import config @@ -116,8 +116,10 @@ class FamilyWidget(QtWidgets.QWidget): def collect_data(self): plugin = self.list_families.currentItem().data(PluginRole) + key = self.list_families.currentItem().data(PluginKeyRole) family = plugin.family.rsplit(".", 1)[-1] data = { + 'family_preset_key': key, 'family': family, 'subset': self.input_result.text(), 'version': self.version_spinbox.value() @@ -318,7 +320,7 @@ class FamilyWidget(QtWidgets.QWidget): has_families = False presets = config.get_presets().get('standalone_publish', {}) - for creator in presets.get('families', {}).values(): + for key, creator in presets.get('families', {}).items(): creator = namedtuple("Creator", creator.keys())(*creator.values()) label = creator.label or creator.family @@ -327,6 +329,7 @@ class FamilyWidget(QtWidgets.QWidget): item.setData(HelpRole, creator.help or "") item.setData(FamilyRole, creator.family) item.setData(PluginRole, creator) + item.setData(PluginKeyRole, key) item.setData(ExistsRole, False) self.list_families.addItem(item) From 71ad16e650e8df39fe50bfb63a6792084e34e7bb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:14:50 +0200 Subject: [PATCH 04/13] drop frame uses full path to ffprobe set in FFMPEG_PATH env --- pype/standalonepublish/widgets/widget_drop_frame.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pype/standalonepublish/widgets/widget_drop_frame.py b/pype/standalonepublish/widgets/widget_drop_frame.py index e60db892db..a5a686bae1 100644 --- a/pype/standalonepublish/widgets/widget_drop_frame.py +++ b/pype/standalonepublish/widgets/widget_drop_frame.py @@ -220,15 +220,21 @@ class DropDataFrame(QtWidgets.QFrame): self._process_data(data) def load_data_with_probe(self, filepath): + ffprobe_path = os.getenv("FFMPEG_PATH", "") + if ffprobe_path: + ffprobe_path += '/ffprobe' + else: + ffprobe_path = 'ffprobe' + args = [ - 'ffprobe', + ffprobe_path, '-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams', filepath ] ffprobe_p = subprocess.Popen( - args, + ' '.join(args), stdout=subprocess.PIPE, shell=True ) From c9b8bcc60247dbd4471c6e0280543158703f14de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:15:14 +0200 Subject: [PATCH 05/13] host of application is set to standalonepublisher instead of shell --- pype/standalonepublish/publish.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/standalonepublish/publish.py b/pype/standalonepublish/publish.py index 13b505666c..f199aaf84e 100644 --- a/pype/standalonepublish/publish.py +++ b/pype/standalonepublish/publish.py @@ -103,7 +103,7 @@ def avalon_api_publish(data, gui=True): "-pp", os.pathsep.join(pyblish.api.registered_paths()) ] - os.environ["PYBLISH_HOSTS"] = "shell" + os.environ["PYBLISH_HOSTS"] = "standalonepublisher" os.environ["SAPUBLISH_INPATH"] = json_data_path if gui: @@ -139,7 +139,7 @@ def cli_publish(data, gui=True): if gui: args += ["gui"] - os.environ["PYBLISH_HOSTS"] = "shell" + os.environ["PYBLISH_HOSTS"] = "standalonepublisher" os.environ["SAPUBLISH_INPATH"] = json_data_path os.environ["SAPUBLISH_OUTPATH"] = return_data_path From 6f889eec9e332ba42ed7ea01df5e385e1e4164af Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:15:54 +0200 Subject: [PATCH 06/13] added conversion to int in case frameStart contain string --- pype/plugins/global/publish/integrate_new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index 6c89e22a83..a3efd10b2e 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -307,7 +307,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): if repre.get("frameStart"): frame_start_padding = len(str( repre.get("frameEnd"))) - index_frame_start = repre.get("frameStart") + index_frame_start = int(repre.get("frameStart")) dst_padding_exp = src_padding_exp for i in src_collection.indexes: From e3ac16427256cb59a87eb86eb939246d7f245e70 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:17:30 +0200 Subject: [PATCH 07/13] collect scene version is skipped in standalone publisher --- pype/plugins/global/publish/collect_scene_version.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/plugins/global/publish/collect_scene_version.py b/pype/plugins/global/publish/collect_scene_version.py index 12075e2417..3fac823b5c 100644 --- a/pype/plugins/global/publish/collect_scene_version.py +++ b/pype/plugins/global/publish/collect_scene_version.py @@ -13,6 +13,8 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): label = 'Collect Version' def process(self, context): + if "standalonepublisher" in context.data.get("host"): + return filename = os.path.basename(context.data.get('currentFile')) From 4bd116b096bd529dd3c09945ce9870fd42e38863 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:18:16 +0200 Subject: [PATCH 08/13] collect presets order is lowered so they are collected much earlier (before collect_context plugin) --- pype/plugins/global/publish/collect_presets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/collect_presets.py b/pype/plugins/global/publish/collect_presets.py index 7e0d3e2f4b..4d483ec79b 100644 --- a/pype/plugins/global/publish/collect_presets.py +++ b/pype/plugins/global/publish/collect_presets.py @@ -5,7 +5,7 @@ from pypeapp import config class CollectPresets(api.ContextPlugin): """Collect Presets.""" - order = api.CollectorOrder + order = api.CollectorOrder - 0.491 label = "Collect Presets" def process(self, context): From 3e00bb57e848f0e3074c4d4ff07444f9dd843fc9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:18:51 +0200 Subject: [PATCH 09/13] added standalonepublisher to hosts of collect output repre config --- pype/plugins/global/publish/collect_output_repre_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/collect_output_repre_config.py b/pype/plugins/global/publish/collect_output_repre_config.py index 5595e29cab..248599f749 100644 --- a/pype/plugins/global/publish/collect_output_repre_config.py +++ b/pype/plugins/global/publish/collect_output_repre_config.py @@ -9,7 +9,7 @@ class CollectOutputRepreConfig(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder label = "Collect Config for representation" - hosts = ["shell"] + hosts = ["shell", "standalonepublisher"] def process(self, context): config_data = config.get_presets()["ftrack"]["output_representation"] From ff0009f8147cbbe4c90bb0b346d8586fcb38be0c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:21:17 +0200 Subject: [PATCH 10/13] anatomy template is not set if family don't have set anatom_template key --- .../plugins/global/publish/collect_context.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/collect_context.py b/pype/plugins/global/publish/collect_context.py index 31ab95259c..61c3bcf4d8 100644 --- a/pype/plugins/global/publish/collect_context.py +++ b/pype/plugins/global/publish/collect_context.py @@ -31,9 +31,25 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin): in_data = json.load(f) asset_name = in_data['asset'] + family_preset_key = in_data.get('family_preset_key', '') family = in_data['family'] subset = in_data['subset'] + # Load presets + presets = context.data.get("presets") + if not presets: + from pypeapp import config + presets = config.get_presets() + + # Get from presets anatomy key that will be used for getting template + # - default integrate new is used if not set + anatomy_key = presets.get( + "standalone_publish", {}).get( + "families", {}).get( + family_preset_key, {}).get( + "anatomy_template" + ) + project = io.find_one({'type': 'project'}) asset = io.find_one({ 'type': 'asset', @@ -63,7 +79,9 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin): component['destination'] = component['files'] component['stagingDir'] = component['stagingDir'] - component['anatomy_template'] = 'render' + # Do not set anatomy_template if not specified + if anatomy_key: + component['anatomy_template'] = anatomy_key if isinstance(component['files'], list): collections, remainder = clique.assemble(component['files']) self.log.debug("collecting sequence: {}".format(collections)) From 195f9640bd87c44929db23c542497527333d2f23 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Oct 2019 13:22:37 +0200 Subject: [PATCH 11/13] added extractor for thumbnails in standalone publisher should create thumbnail from any image or video input --- .../global/publish/extract_thumbnail_sa.py | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 pype/plugins/global/publish/extract_thumbnail_sa.py diff --git a/pype/plugins/global/publish/extract_thumbnail_sa.py b/pype/plugins/global/publish/extract_thumbnail_sa.py new file mode 100644 index 0000000000..7e31e3c701 --- /dev/null +++ b/pype/plugins/global/publish/extract_thumbnail_sa.py @@ -0,0 +1,126 @@ +import os +import tempfile +import subprocess +import pyblish.api +import pype.api + + +class ExtractThumbnail(pyblish.api.InstancePlugin): + """Extract jpeg thumbnail from component input from standalone publisher + + Uses jpeg file from component if possible (when single or multiple jpegs + are loaded to component selected as thumbnail) otherwise extracts from + input file/s single jpeg to temp. + """ + + label = "Extract Thumbnail" + hosts = ["standalonepublisher"] + order = pyblish.api.ExtractorOrder + + def process(self, instance): + repres = instance.data.get('representations') + if not repres: + return + + thumbnail_repre = None + for repre in repres: + if repre.get("thumbnail"): + thumbnail_repre = repre + break + + if not thumbnail_repre: + return + + files = thumbnail_repre.get("files") + if not files: + return + + if isinstance(files, list): + files_len = len(files) + file = str(files[0]) + else: + files_len = 1 + file = files + + is_jpeg = False + if file.endswith(".jpeg") or file.endswith(".jpg"): + is_jpeg = True + + if is_jpeg and files_len == 1: + # skip if already is single jpeg file + return + + elif is_jpeg: + # use first frame as thumbnail if is sequence of jpegs + full_thumbnail_path = file + self.log.info( + "For thumbnail is used file: {}".format(full_thumbnail_path) + ) + + else: + # Convert to jpeg if not yet + full_input_path = os.path.join(thumbnail_repre["stagingDir"], file) + self.log.info("input {}".format(full_input_path)) + + full_thumbnail_path = tempfile.mkstemp(suffix=".jpg")[1] + self.log.info("output {}".format(full_thumbnail_path)) + + config_data = instance.context.data.get("output_repre_config", {}) + + proj_name = os.environ.get("AVALON_PROJECT", "__default__") + profile = config_data.get( + proj_name, + config_data.get("__default__", {}) + ) + + ffmpeg_path = os.getenv("FFMPEG_PATH", "") + if ffmpeg_path: + ffmpeg_path += "/ffmpeg" + else: + ffmpeg_path = "ffmpeg" + + jpeg_items = [] + jpeg_items.append(ffmpeg_path) + # override file if already exists + jpeg_items.append("-y") + # add input filters from peresets + if profile: + jpeg_items.extend(profile.get('input', [])) + # input file + jpeg_items.append("-i {}".format(full_input_path)) + # extract only single file + jpeg_items.append("-vframes 1") + # output file + jpeg_items.append(full_thumbnail_path) + + subprocess_jpeg = " ".join(jpeg_items) + + # run subprocess + self.log.debug("Executing: {}".format(subprocess_jpeg)) + subprocess.Popen( + subprocess_jpeg, + stdout=subprocess.PIPE, + shell=True + ) + + # remove thumbnail key from origin repre + thumbnail_repre.pop("thumbnail") + + filename = os.path.basename(full_thumbnail_path) + staging_dir = os.path.dirname(full_thumbnail_path) + + # create new thumbnail representation + representation = { + 'name': 'jpg', + 'ext': 'jpg', + 'files': filename, + "stagingDir": staging_dir, + "thumbnail": True, + "tags": [] + } + + # add Delete tag when temp file was rendered + if not is_jpeg: + representation["tags"].append("delete") + + instance.data["representations"].append(representation) From 97673d503ccdd70e5b991ebbbf144a5c836aa80e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 7 Oct 2019 12:32:35 +0200 Subject: [PATCH 12/13] fix(standalonepublish): getting `frameStart` and `frameEnd` from representaions --- pype/plugins/global/publish/collect_context.py | 2 ++ pype/plugins/global/publish/extract_thumbnail_sa.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pype/plugins/global/publish/collect_context.py b/pype/plugins/global/publish/collect_context.py index 61c3bcf4d8..f538509a9b 100644 --- a/pype/plugins/global/publish/collect_context.py +++ b/pype/plugins/global/publish/collect_context.py @@ -66,6 +66,8 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin): "label": subset, "name": subset, "family": family, + "frameStart": in_data.get("representations", [None])[0].get("frameStart", None), + "frameEnd": in_data.get("representations", [None])[0].get("frameEnd", None), "families": [family, 'ftrack'], }) self.log.info("collected instance: {}".format(instance.data)) diff --git a/pype/plugins/global/publish/extract_thumbnail_sa.py b/pype/plugins/global/publish/extract_thumbnail_sa.py index 7e31e3c701..f42985b560 100644 --- a/pype/plugins/global/publish/extract_thumbnail_sa.py +++ b/pype/plugins/global/publish/extract_thumbnail_sa.py @@ -119,8 +119,8 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): "tags": [] } - # add Delete tag when temp file was rendered - if not is_jpeg: - representation["tags"].append("delete") + # # add Delete tag when temp file was rendered + # if not is_jpeg: + # representation["tags"].append("delete") instance.data["representations"].append(representation) From 0c64aeb84ff3a5ace706f1a472f015ef67c19cdf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 7 Oct 2019 13:29:20 +0200 Subject: [PATCH 13/13] fix(global): little cleanup - was used old label `template` were `anatomy` should be - it was getting filled templates as object not as dictionary --- pype/plugins/global/publish/collect_anatomy.py | 4 ++-- pype/plugins/global/publish/collect_templates.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/plugins/global/publish/collect_anatomy.py b/pype/plugins/global/publish/collect_anatomy.py index b053a3a0d1..9412209850 100644 --- a/pype/plugins/global/publish/collect_anatomy.py +++ b/pype/plugins/global/publish/collect_anatomy.py @@ -9,11 +9,11 @@ from pypeapp import Anatomy import pyblish.api -class CollectTemplates(pyblish.api.ContextPlugin): +class CollectAnatomy(pyblish.api.ContextPlugin): """Collect Anatomy into Context""" order = pyblish.api.CollectorOrder - label = "Collect Templates" + label = "Collect Anatomy" def process(self, context): context.data['anatomy'] = Anatomy() diff --git a/pype/plugins/global/publish/collect_templates.py b/pype/plugins/global/publish/collect_templates.py index 8113f1d763..b3aecca21a 100644 --- a/pype/plugins/global/publish/collect_templates.py +++ b/pype/plugins/global/publish/collect_templates.py @@ -82,5 +82,5 @@ class CollectTemplates(pyblish.api.InstancePlugin): # We take the parent folder of representation 'filepath' instance.data["assumedDestination"] = os.path.dirname( - (anatomy.format(template_data)).publish.path + (anatomy.format(template_data))["publish"]["path"] )