add standalone publish plugins to special folder

This commit is contained in:
iLLiCiTiT 2019-10-24 12:07:31 +02:00
parent 2a60c5ff9e
commit 290b2009db
4 changed files with 1 additions and 7 deletions

View file

@ -0,0 +1,117 @@
"""
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
import json
import logging
import clique
log = logging.getLogger("collector")
class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
"""
Collecting temp json data sent from a host context
and path for returning json data back to hostself.
"""
label = "Collect Context - SA Publish"
order = pyblish.api.CollectorOrder - 0.49
hosts = ["standalonepublisher"]
def process(self, context):
# get json paths from os and load them
io.install()
input_json_path = os.environ.get("SAPUBLISH_INPATH")
output_json_path = os.environ.get("SAPUBLISH_OUTPATH")
# context.data["stagingDir"] = os.path.dirname(input_json_path)
context.data["returnJsonPath"] = output_json_path
with open(input_json_path, "r") as f:
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',
'name': asset_name
})
context.data['project'] = project
context.data['asset'] = asset
instance = context.create_instance(subset)
instance.data.update({
"subset": subset,
"asset": asset_name,
"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))
self.log.info("parsing data: {}".format(in_data))
instance.data['destination_list'] = list()
instance.data['representations'] = list()
instance.data['source'] = 'standalone publisher'
for component in in_data['representations']:
component['destination'] = component['files']
component['stagingDir'] = component['stagingDir']
# 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))
instance.data["frameStart"] = int(component["frameStart"])
instance.data["frameEnd"] = int(component["frameEnd"])
instance.data['fps'] = int(component['fps'])
if component["preview"]:
instance.data["families"].append("review")
instance.data["repreProfiles"] = ["h264"]
component["tags"] = ["review", "delete"]
self.log.debug("Adding review family")
instance.data["representations"].append(component)
self.log.info(in_data)

View file

@ -0,0 +1,186 @@
import os
import pyblish.api
from pype.vendor import clique
import pype.api
class ExtractReviewSaP(pyblish.api.InstancePlugin):
"""Extracting Review mov file for Ftrack
Compulsory attribute of representation is tags list with "review",
otherwise the representation is ignored.
All new represetnations are created and encoded by ffmpeg following
presets found in `pype-config/presets/plugins/global/publish.json:ExtractReview:outputs`. To change the file extension
filter values use preset's attributes `ext_filter`
"""
label = "Extract Review SaP"
order = pyblish.api.ExtractorOrder + 0.02
families = ["review"]
hosts = ["standalonepublisher"]
def process(self, instance):
# adding plugin attributes from presets
presets = instance.context.data["presets"]
publish_presets = presets["plugins"]["global"]["publish"]
try:
plugin_attrs = publish_presets[self.__class__.__name__]
except KeyError:
raise KeyError("Preset for plugin \"{}\" are not set".format(
self.__class__.__name__
))
output_profiles = plugin_attrs.get("outputs", {})
fps = instance.data.get("fps")
start_frame = instance.data.get("frameStart")
self.log.debug("Families In: `{}`".format(instance.data["families"]))
# get specific profile if was defined
specific_profiles = instance.data.get("repreProfiles")
new_repres = []
# filter out mov and img sequences
for repre in instance.data["representations"]:
tags = repre.get("tags", [])
if "review" not in tags:
continue
staging_dir = repre["stagingDir"]
for name in specific_profiles:
profile = output_profiles.get(name)
if not profile:
self.log.warning(
"Profile \"{}\" was not found in presets".format(name)
)
continue
self.log.debug("Processing profile: {}".format(name))
ext = profile.get("ext", None)
if not ext:
ext = "mov"
self.log.debug((
"`ext` attribute not in output profile \"{}\"."
" Setting to default ext: `mov`"
).format(name))
if isinstance(repre["files"], list):
collections, remainder = clique.assemble(repre["files"])
full_input_path = os.path.join(
staging_dir,
collections[0].format("{head}{padding}{tail}")
)
filename = collections[0].format('{head}')
if filename.endswith("."):
filename = filename[:-1]
else:
full_input_path = os.path.join(staging_dir, repre["files"])
filename = repre["files"].split(".")[0]
repr_file = filename + "_{0}.{1}".format(name, ext)
full_output_path = os.path.join(staging_dir, repr_file)
self.log.info("input {}".format(full_input_path))
self.log.info("output {}".format(full_output_path))
repre_new = repre.copy()
new_tags = [x for x in tags if x != "delete"]
p_tags = profile.get("tags", [])
self.log.info("p_tags: `{}`".format(p_tags))
for _tag in p_tags:
if _tag not in new_tags:
new_tags.append(_tag)
self.log.info("new_tags: `{}`".format(new_tags))
input_args = []
# overrides output file
input_args.append("-y")
# preset's input data
input_args.extend(profile.get("input", []))
# necessary input data
# adds start arg only if image sequence
if isinstance(repre["files"], list):
input_args.extend([
"-start_number {}".format(start_frame),
"-framerate {}".format(fps)
])
input_args.append("-i {}".format(full_input_path))
output_args = []
# preset's output data
output_args.extend(profile.get("output", []))
# set length of video by len of inserted files
output_args.append("-frames {}".format(len(repre["files"])))
# letter_box
lb_string = (
"-filter:v "
"drawbox=0:0:iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black,"
"drawbox=0:ih-round((ih-(iw*(1/{0})))/2):iw:"
"round((ih-(iw*(1/{0})))/2):t=fill:c=black"
)
letter_box = profile.get("letter_box", None)
if letter_box:
output_args.append(lb_string.format(letter_box))
# output filename
output_args.append(full_output_path)
ffmpeg_path = os.getenv("FFMPEG_PATH", "")
if ffmpeg_path:
ffmpeg_path += "/ffmpeg"
else:
ffmpeg_path = "ffmpeg"
mov_args = [
ffmpeg_path,
" ".join(input_args),
" ".join(output_args)
]
subprcs_cmd = " ".join(mov_args)
# run subprocess
self.log.debug("Executing: {}".format(subprcs_cmd))
output = pype.api.subprocess(subprcs_cmd)
self.log.debug("Output: {}".format(output))
# create representation data
repre_new.update({
"name": name,
"ext": ext,
"files": repr_file,
"tags": new_tags,
"outputName": name
})
if repre_new.get("preview"):
repre_new.pop("preview")
if repre_new.get("thumbnail"):
repre_new.pop("thumbnail")
# adding representation
self.log.debug("Adding: {}".format(repre_new))
new_repres.append(repre_new)
for repre in instance.data["representations"]:
if "delete" in repre.get("tags", []):
instance.data["representations"].remove(repre)
for repre in new_repres:
self.log.debug("Adding repre: \"{}\"".format(
repre
))
instance.data["representations"].append(repre)

View file

@ -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)