From bd6717fe20d889919ad6d7e67050cbae5b6d8ca0 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 18 Aug 2020 15:56:09 +0200 Subject: [PATCH 1/7] fix shell popping up with ffmpeg --- pype/plugins/global/publish/extract_burnin.py | 4 +- pype/plugins/global/publish/extract_jpeg.py | 2 +- pype/plugins/global/publish/extract_review.py | 10 +- .../global/publish/extract_review_slate.py | 4 +- .../publish/extract_review.py | 199 ------------------ .../publish/extract_thumbnail.py | 122 ----------- 6 files changed, 13 insertions(+), 328 deletions(-) delete mode 100644 pype/plugins/standalonepublisher/publish/extract_review.py delete mode 100644 pype/plugins/standalonepublisher/publish/extract_thumbnail.py diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index e1508b9131..dedfd98979 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -224,7 +224,7 @@ class ExtractBurnin(pype.api.Extractor): self.log.debug("Executing: {}".format(args)) # Run burnin script - output = pype.api.subprocess(args) + output = pype.api.subprocess(args, shell=True) self.log.debug("Output: {}".format(output)) for filepath in temp_data["full_input_paths"]: @@ -964,7 +964,7 @@ class ExtractBurnin(pype.api.Extractor): args = [executable, scriptpath, json_data] self.log.debug("Executing: {}".format(args)) - output = pype.api.subprocess(args) + output = pype.api.subprocess(args, shell=True) self.log.debug("Output: {}".format(output)) repre_update = { diff --git a/pype/plugins/global/publish/extract_jpeg.py b/pype/plugins/global/publish/extract_jpeg.py index 9b775f8b6f..97af9a3751 100644 --- a/pype/plugins/global/publish/extract_jpeg.py +++ b/pype/plugins/global/publish/extract_jpeg.py @@ -83,7 +83,7 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin): # run subprocess self.log.debug("{}".format(subprocess_jpeg)) - pype.api.subprocess(subprocess_jpeg) + pype.api.subprocess(subprocess_jpeg, shell=True) if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index e1a0d7043a..ac8766f5a7 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -175,7 +175,7 @@ class ExtractReview(pyblish.api.InstancePlugin): # run subprocess self.log.debug("Executing: {}".format(subprcs_cmd)) - output = pype.api.subprocess(subprcs_cmd) + output = pype.api.subprocess(subprcs_cmd, shell=True) self.log.debug("Output: {}".format(output)) output_name = output_def["filename_suffix"] @@ -342,6 +342,12 @@ class ExtractReview(pyblish.api.InstancePlugin): "-i \"{}\"".format(temp_data["full_input_path"]) ) + if temp_data["output_is_sequence"]: + # Set start frame + ffmpeg_input_args.append( + "-start_number {}".format(temp_data["output_frame_start"]) + ) + # Add audio arguments if there are any. Skipped when output are images. if not temp_data["output_ext_is_image"]: audio_in_args, audio_filters, audio_out_args = self.audio_args( @@ -1482,7 +1488,7 @@ class ExtractReview(pyblish.api.InstancePlugin): # run subprocess self.log.debug("Executing: {}".format(subprcs_cmd)) - output = pype.api.subprocess(subprcs_cmd) + output = pype.api.subprocess(subprcs_cmd, shell=True) self.log.debug("Output: {}".format(output)) # create representation data diff --git a/pype/plugins/global/publish/extract_review_slate.py b/pype/plugins/global/publish/extract_review_slate.py index f2ea6c0875..2e1fc25ae5 100644 --- a/pype/plugins/global/publish/extract_review_slate.py +++ b/pype/plugins/global/publish/extract_review_slate.py @@ -186,7 +186,7 @@ class ExtractReviewSlate(pype.api.Extractor): # run slate generation subprocess self.log.debug("Slate Executing: {}".format(slate_subprcs_cmd)) - slate_output = pype.api.subprocess(slate_subprcs_cmd) + slate_output = pype.api.subprocess(slate_subprcs_cmd, shell=True) self.log.debug("Slate Output: {}".format(slate_output)) # create ffmpeg concat text file path @@ -221,7 +221,7 @@ class ExtractReviewSlate(pype.api.Extractor): # ffmpeg concat subprocess self.log.debug("Executing concat: {}".format(concat_subprcs_cmd)) - concat_output = pype.api.subprocess(concat_subprcs_cmd) + concat_output = pype.api.subprocess(concat_subprcs_cmd, shell=True) self.log.debug("Output concat: {}".format(concat_output)) self.log.debug("__ repre[tags]: {}".format(repre["tags"])) diff --git a/pype/plugins/standalonepublisher/publish/extract_review.py b/pype/plugins/standalonepublisher/publish/extract_review.py deleted file mode 100644 index 0f845afcb1..0000000000 --- a/pype/plugins/standalonepublisher/publish/extract_review.py +++ /dev/null @@ -1,199 +0,0 @@ -import os -import tempfile - -import pyblish.api -import clique -import pype.api -import pype.lib - - -class ExtractReviewSP(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 SP" - order = pyblish.api.ExtractorOrder + 0.02 - families = ["review"] - hosts = ["standalonepublisher"] - - def process(self, instance): - # adding plugin attributes from presets - presets = instance.context.data["presets"] - try: - publish_presets = presets["plugins"]["standalonepublisher"]["publish"] - 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] - - # prepare output file - repr_file = filename + "_{0}.{1}".format(name, ext) - out_stagigng_dir = tempfile.mkdtemp(prefix="extract_review_") - full_output_path = os.path.join(out_stagigng_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", [])) - - if isinstance(repre["files"], list): - # set length of video by len of inserted files - video_len = len(repre["files"]) - else: - video_len = repre["frameEnd"] - repre["frameStart"] + 1 - output_args.append( - "-frames {}".format(video_len) - ) - - # 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 = pype.lib.get_ffmpeg_tool_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, - "stagingDir": out_stagigng_dir, - "tags": new_tags, - "outputName": name, - "frameStartFtrack": 1, - "frameEndFtrack": video_len - }) - # cleanup thumbnail from new repre - if repre_new.get("thumbnail"): - repre_new.pop("thumbnail") - if "thumbnail" in repre_new["tags"]: - repre_new["tags"].remove("thumbnail") - - # adding representation - self.log.debug("Adding: {}".format(repre_new)) - # cleanup repre from preview - if "preview" in repre: - repre.pop("preview") - if "preview" in repre["tags"]: - repre["tags"].remove("preview") - 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) diff --git a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py deleted file mode 100644 index cddc9c3a82..0000000000 --- a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py +++ /dev/null @@ -1,122 +0,0 @@ -import os -import tempfile -import subprocess -import pyblish.api -import pype.api -import pype.lib - - -class ExtractThumbnailSP(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 SP" - hosts = ["standalonepublisher"] - order = pyblish.api.ExtractorOrder - - # Presetable attribute - ffmpeg_args = None - - 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)) - - ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") - - ffmpeg_args = self.ffmpeg_args or {} - - jpeg_items = [] - jpeg_items.append(ffmpeg_path) - # override file if already exists - jpeg_items.append("-y") - # add input filters from peresets - jpeg_items.extend(ffmpeg_args.get("input") or []) - # input file - jpeg_items.append("-i {}".format(full_input_path)) - # extract only single file - jpeg_items.append("-vframes 1") - - jpeg_items.extend(ffmpeg_args.get("output") or []) - - # 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 b3f279c3ba57061b037777000bb341603807f015 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 20 Aug 2020 14:59:26 +0200 Subject: [PATCH 2/7] return extract thumbnail to SP --- .../publish/extract_thumbnail.py | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 pype/plugins/standalonepublisher/publish/extract_thumbnail.py diff --git a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py new file mode 100644 index 0000000000..cddc9c3a82 --- /dev/null +++ b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py @@ -0,0 +1,122 @@ +import os +import tempfile +import subprocess +import pyblish.api +import pype.api +import pype.lib + + +class ExtractThumbnailSP(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 SP" + hosts = ["standalonepublisher"] + order = pyblish.api.ExtractorOrder + + # Presetable attribute + ffmpeg_args = None + + 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)) + + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") + + ffmpeg_args = self.ffmpeg_args or {} + + jpeg_items = [] + jpeg_items.append(ffmpeg_path) + # override file if already exists + jpeg_items.append("-y") + # add input filters from peresets + jpeg_items.extend(ffmpeg_args.get("input") or []) + # input file + jpeg_items.append("-i {}".format(full_input_path)) + # extract only single file + jpeg_items.append("-vframes 1") + + jpeg_items.extend(ffmpeg_args.get("output") or []) + + # 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 6516e8536162a6d9aa9f662293be9568914015be Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 20 Aug 2020 14:59:46 +0200 Subject: [PATCH 3/7] remove add_representation --- .../publish/extract_shot_data.py | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/pype/plugins/standalonepublisher/publish/extract_shot_data.py b/pype/plugins/standalonepublisher/publish/extract_shot_data.py index 6cbc2c7882..c39247d6d6 100644 --- a/pype/plugins/standalonepublisher/publish/extract_shot_data.py +++ b/pype/plugins/standalonepublisher/publish/extract_shot_data.py @@ -13,7 +13,6 @@ class ExtractShotData(pype.api.Extractor): families = ["review", "audio"] # presets - add_representation = None # ".jpeg" def process(self, instance): representation = instance.data.get("representations") @@ -68,7 +67,7 @@ class ExtractShotData(pype.api.Extractor): self.log.info(f"Processing: {args}") ffmpeg_args = " ".join(args) - output = pype.api.subprocess(ffmpeg_args) + output = pype.api.subprocess(ffmpeg_args, shell=True) self.log.info(output) repr = { @@ -90,34 +89,4 @@ class ExtractShotData(pype.api.Extractor): instance.data["representations"].append(repr) - if self.add_representation: - # Generate jpegs. - clip_img_sequence = os.path.join( - staging_dir, instance.data["name"] + ".%04d.jpeg" - ) - args = [ - ffmpeg_path, "-i", - f"\"{clip_trimed_path}\"", - f"\"{clip_img_sequence}\"" - ] - self.log.info(f"Processing: {args}") - output = pype.lib._subprocess(args) - self.log.info(output) - - # collect jpeg sequence if editorial data for publish - # are image sequence - collection = clique.Collection( - head=instance.data["name"] + ".", tail='.jpeg', padding=4 - ) - for f in os.listdir(staging_dir): - if collection.match(f): - collection.add(f) - - instance.data["representations"].append({ - "name": "jpeg", - "ext": "jpeg", - "files": list(collection), - "stagingDir": staging_dir - }) - self.log.debug(f"Instance data: {pformat(instance.data)}") From f5cb0b04891f367ccdf7bc07270259b4ac22ec2a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 20 Aug 2020 15:00:07 +0200 Subject: [PATCH 4/7] fix padding with start frame 0 --- pype/plugins/global/publish/integrate_new.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index 4510fc2d04..28a52e4353 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -351,7 +351,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): index_frame_start = None - if repre.get("frameStart"): + if repre.get("frameStart") is not None: frame_start_padding = int( anatomy.templates["render"].get( "frame_padding", @@ -378,7 +378,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): dst_padding = src_padding_exp % i - if index_frame_start: + if index_frame_start is not None: dst_padding_exp = "%0{}d".format(frame_start_padding) dst_padding = dst_padding_exp % index_frame_start index_frame_start += 1 From 9876bfa4cf0d6270f74f2fa16bfb5206b2910c0b Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 20 Aug 2020 15:00:29 +0200 Subject: [PATCH 5/7] add option to remove outputName from template data --- pype/plugins/global/publish/extract_review.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index ac8766f5a7..2807376d54 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -193,6 +193,8 @@ class ExtractReview(pyblish.api.InstancePlugin): # Force to pop these key if are in new repre new_repre.pop("preview", None) new_repre.pop("thumbnail", None) + if "clean_name" in new_repre.get("tags", []): + new_repre.pop("outputName") # adding representation self.log.debug( @@ -1528,6 +1530,8 @@ class ExtractReview(pyblish.api.InstancePlugin): for repre in representations_new: if "delete" in repre.get("tags", []): representations_new.remove(repre) + if "clean_name" in repre.get("tags", []): + repre_new.pop("outputName") instance.data.update({ "reviewToWidth": self.to_width, From f41bf542e8adddf372d142a3c97f912cb060cc70 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 20 Aug 2020 15:59:16 +0200 Subject: [PATCH 6/7] simplify default --- .../standalonepublisher/publish/collect_clip_instances.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/plugins/standalonepublisher/publish/collect_clip_instances.py b/pype/plugins/standalonepublisher/publish/collect_clip_instances.py index 3d9773d0b2..a7af8df143 100644 --- a/pype/plugins/standalonepublisher/publish/collect_clip_instances.py +++ b/pype/plugins/standalonepublisher/publish/collect_clip_instances.py @@ -18,15 +18,15 @@ class CollectClipInstances(pyblish.api.InstancePlugin): "referenceMain": { "family": "review", "families": ["review", "ftrack"], - "ftrackFamily": "review", + # "ftrackFamily": "review", "extension": ".mp4" }, "audioMain": { "family": "audio", "families": ["ftrack"], - "ftrackFamily": "audio", + # "ftrackFamily": "audio", "extension": ".wav", - "version": 1 + # "version": 1 }, "shotMain": { "family": "shot", From 016f529a90ef5ece370a1e6f1636805cc06c4876 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 20 Aug 2020 15:59:33 +0200 Subject: [PATCH 7/7] add reference family to ftrack --- pype/plugins/ftrack/publish/integrate_ftrack_instances.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py index f5d7689678..9ef82cbc4b 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py @@ -30,7 +30,8 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): 'audio': 'audio', 'workfile': 'scene', 'animation': 'cache', - 'image': 'img' + 'image': 'img', + 'reference': 'reference' } def process(self, instance):