Example #1
0
    def process(self, instance):
        errored_plugins = get_errored_plugins_from_data(instance.context)
        if errored_plugins:
            raise RuntimeError(
                "Skipping incrementing current file because publishing failed."
            )

        scene_path = version_up(instance.context.data["currentFile"])
        aftereffects.stub().saveAs(scene_path, True)

        self.log.info("Incremented workfile to: {}".format(scene_path))
Example #2
0
def launch(*subprocess_args):
    """Starts the websocket server that will be hosted
       in the Photoshop extension.
    """
    from avalon import api, aftereffects

    api.install(aftereffects)
    sys.excepthook = safe_excepthook

    # Launch aftereffects and the websocket server.
    process = subprocess.Popen(subprocess_args, stdout=subprocess.PIPE)

    websocket_server = WebServerTool()
    # Add Websocket route
    websocket_server.add_route("*", "/ws/", WebSocketAsync)
    # Add after effects route to websocket handler
    route_name = 'AfterEffects'
    print("Adding {} route".format(route_name))
    WebSocketAsync.add_route(route_name, AfterEffectsRoute)
    websocket_server.start_server()

    while True:
        if process.poll() is not None:
            print("AfterEffects process is not alive. Exiting")
            websocket_server.stop()
            sys.exit(1)
        try:
            _stub = aftereffects.stub()
            if _stub:
                break
        except Exception:
            time.sleep(0.5)

    if os.environ.get("AVALON_AFTEREFFECTS_WORKFILES_ON_LAUNCH", True):
        if os.getenv("WORKFILES_SAVE_AS"):
            workfiles.show(save=False)
        else:
            workfiles.show()

    # AE could be closed immediately, withou workfile selection
    try:
        if aftereffects.stub():
            api.emit("application.launched")

        self.callback_queue = queue.Queue()
        while True:
            main_thread_listen(process, websocket_server)

    except ConnectionNotEstablishedYet:
        pass
    finally:
        # Wait on Photoshop to close before closing the websocket server
        process.wait()
        websocket_server.stop()
Example #3
0
 def process(self, instance):
     stub = aftereffects.stub()
     self.log.debug("instance::{}".format(instance.data))
     item = instance.data
     comp_name = item["comp_name"].replace(stub.PUBLISH_ICON, '')
     stub.rename_item(item["comp_id"], comp_name)
     instance.data["comp_name"] = comp_name
Example #4
0
    def process(self):
        stub = aftereffects.stub()  # only after After Effects is up
        if (self.options or {}).get("useSelection"):
            items = stub.get_selected_items(comps=True,
                                            folders=False,
                                            footages=False)
        if len(items) > 1:
            self._show_msg("Please select only single composition at time.")
            return False

        if not items:
            self._show_msg("Nothing to create. Select composition " +
                           "if 'useSelection' or create at least " +
                           "one composition.")
            return False

        existing_subsets = [instance['subset'].lower()
                            for instance in aftereffects.list_instances()]

        item = items.pop()
        if self.name.lower() in existing_subsets:
            txt = "Instance with name \"{}\" already exists.".format(self.name)
            self._show_msg(txt)
            return False

        self.data["members"] = [item.id]
        self.data["uuid"] = item.id  # for SubsetManager
        stub.imprint(item, self.data)
        stub.set_label_color(item.id, 14)  # Cyan options 0 - 16
        stub.rename_item(item.id, stub.PUBLISH_ICON + self.data["subset"])
Example #5
0
 def process(self, context):
     for instance in context:
         if instance.data["family"] == 'render.farm':
             comp_id = instance.data["comp_id"]
             if not comp_id:
                 self.log.debug("No comp_id filled in instance")
                 return
             context.data["audioFile"] = os.path.normpath(
                 aftereffects.stub().get_audio_url(comp_id)
             ).replace("\\", "/")
Example #6
0
    def is_host_connected():
        """Returns True if connected, False if app is not running at all."""
        if ConsoleTrayApp.process.poll() is not None:
            return False
        try:
            _stub = aftereffects.stub()

            if _stub:
                return True
        except Exception:
            pass

        return None
Example #7
0
    def get_expected_files(self, render_instance):
        """
            Returns list of rendered files that should be created by
            Deadline. These are not published directly, they are source
            for later 'submit_publish_job'.

        Args:
            render_instance (RenderInstance): to pull anatomy and parts used
                in url

        Returns:
            (list) of absolut urls to rendered file
        """
        start = render_instance.frameStart
        end = render_instance.frameEnd

        # pull file name from Render Queue Output module
        render_q = aftereffects.stub().get_render_info()
        if not render_q:
            raise ValueError("No file extension set in Render Queue")
        _, ext = os.path.splitext(os.path.basename(render_q.file_name))

        base_dir = self._get_output_dir(render_instance)
        expected_files = []
        if "#" not in render_q.file_name:  # single frame (mov)W
            path = os.path.join(base_dir, "{}_{}_{}.{}".format(
                render_instance.asset,
                render_instance.subset,
                "v{:03d}".format(render_instance.version),
                ext.replace('.', '')
            ))
            expected_files.append(path)
        else:
            for frame in range(start, end + 1):
                path = os.path.join(base_dir, "{}_{}_{}.{}.{}".format(
                    render_instance.asset,
                    render_instance.subset,
                    "v{:03d}".format(render_instance.version),
                    str(frame).zfill(self.padding_width),
                    ext.replace('.', '')
                ))
                expected_files.append(path)
        return expected_files
 def process(self, instance):
     aftereffects.stub().save()
 def process(self, context):
     context.data["currentFile"] = os.path.normpath(
         aftereffects.stub().get_active_document_full_name()).replace(
             "\\", "/")
Example #10
0
 def process(self, instance):
     stub = aftereffects.stub()
     item = instance.data
     # comp name contains highlight icon
     stub.rename_item(item["comp_id"], item["comp_name"])
Example #11
0
import re

from avalon import api, aftereffects

from pype.lib import get_background_layers, get_unique_layer_name

stub = aftereffects.stub()


class BackgroundLoader(api.Loader):
    """
        Load images from Background family
        Creates for each background separate folder with all imported images
        from background json AND automatically created composition with layers,
        each layer for separate image.

        For each load container is created and stored in project (.aep)
        metadata
    """
    families = ["background"]
    representations = ["json"]

    def load(self, context, name=None, namespace=None, data=None):
        items = stub.get_items(comps=True)
        existing_items = [layer.name for layer in items]

        comp_name = get_unique_layer_name(
            existing_items, "{}_{}".format(context["asset"]["name"], name))

        layers = get_background_layers(self.fname)
        comp = stub.import_background(None, stub.LOADED_ICON + comp_name,
Example #12
0
    def get_instances(self, context):
        instances = []

        current_file = context.data["currentFile"]
        version = context.data["version"]
        asset_entity = context.data["assetEntity"]
        project_entity = context.data["projectEntity"]

        compositions = aftereffects.stub().get_items(True)
        compositions_by_id = {item.id: item for item in compositions}
        for inst in aftereffects.stub().get_metadata():
            schema = inst.get('schema')
            # loaded asset container skip it
            if schema and 'container' in schema:
                continue

            if not inst["members"]:
                raise ValueError("Couldn't find id, unable to publish. " +
                                 "Please recreate instance.")
            item_id = inst["members"][0]
            work_area_info = aftereffects.stub().get_work_area(int(item_id))
            frameStart = work_area_info.workAreaStart

            frameEnd = round(work_area_info.workAreaStart +
                             float(work_area_info.workAreaDuration) *
                             float(work_area_info.frameRate)) - 1

            if inst["family"] == "render" and inst["active"]:
                instance = AERenderInstance(
                    family="render.farm",  # other way integrate would catch it
                    families=["render.farm"],
                    version=version,
                    time="",
                    source=current_file,
                    label="{} - farm".format(inst["subset"]),
                    subset=inst["subset"],
                    asset=context.data["assetEntity"]["name"],
                    attachTo=False,
                    setMembers='',
                    publish=True,
                    renderer='aerender',
                    name=inst["subset"],
                    resolutionWidth=asset_entity["data"].get(
                        "resolutionWidth",
                        project_entity["data"]["resolutionWidth"]),
                    resolutionHeight=asset_entity["data"].get(
                        "resolutionHeight",
                        project_entity["data"]["resolutionHeight"]),
                    pixelAspect=1,
                    tileRendering=False,
                    tilesX=0,
                    tilesY=0,
                    frameStart=frameStart,
                    frameEnd=frameEnd,
                    frameStep=1,
                    toBeRenderedOn='deadline'
                )

                comp = compositions_by_id.get(int(item_id))
                if not comp:
                    raise ValueError("There is no composition for item {}".
                                     format(item_id))
                instance.comp_name = comp.name
                instance.comp_id = item_id
                instance._anatomy = context.data["anatomy"]
                instance.anatomyData = context.data["anatomyData"]

                instance.outputDir = self._get_output_dir(instance)

                instances.append(instance)

        return instances
Example #13
0
class CollectAERender(abstract_collect_render.AbstractCollectRender):

    order = pyblish.api.CollectorOrder + 0.498
    label = "Collect After Effects Render Layers"
    hosts = ["aftereffects"]

    padding_width = 6
    rendered_extension = 'png'

    stub = aftereffects.stub()

    def get_instances(self, context):
        instances = []

        current_file = context.data["currentFile"]
        version = context.data["version"]
        asset_entity = context.data["assetEntity"]
        project_entity = context.data["projectEntity"]

        compositions = self.stub.get_items(True)
        compositions_by_id = {item.id: item for item in compositions}
        for inst in self.stub.get_metadata():
            schema = inst.get('schema')
            # loaded asset container skip it
            if schema and 'container' in schema:
                continue

            if not inst["members"]:
                raise ValueError("Couldn't find id, unable to publish. " +
                                 "Please recreate instance.")
            item_id = inst["members"][0]
            work_area_info = self.stub.get_work_area(int(item_id))

            if not work_area_info:
                self.log.warning("Orphaned instance, deleting metadata")
                self.stub.remove_instance(int(item_id))
                continue

            frameStart = work_area_info.workAreaStart

            frameEnd = round(work_area_info.workAreaStart +
                             float(work_area_info.workAreaDuration) *
                             float(work_area_info.frameRate)) - 1

            if inst["family"] == "render" and inst["active"]:
                instance = AERenderInstance(
                    family="render.farm",  # other way integrate would catch it
                    families=["render.farm"],
                    version=version,
                    time="",
                    source=current_file,
                    label="{} - farm".format(inst["subset"]),
                    subset=inst["subset"],
                    asset=context.data["assetEntity"]["name"],
                    attachTo=False,
                    setMembers='',
                    publish=True,
                    renderer='aerender',
                    name=inst["subset"],
                    resolutionWidth=asset_entity["data"].get(
                        "resolutionWidth",
                        project_entity["data"]["resolutionWidth"]),
                    resolutionHeight=asset_entity["data"].get(
                        "resolutionHeight",
                        project_entity["data"]["resolutionHeight"]),
                    pixelAspect=1,
                    tileRendering=False,
                    tilesX=0,
                    tilesY=0,
                    frameStart=frameStart,
                    frameEnd=frameEnd,
                    frameStep=1,
                    toBeRenderedOn='deadline')

                comp = compositions_by_id.get(int(item_id))
                if not comp:
                    raise ValueError(
                        "There is no composition for item {}".format(item_id))
                instance.comp_name = comp.name
                instance.comp_id = item_id
                instance._anatomy = context.data["anatomy"]
                instance.anatomyData = context.data["anatomyData"]

                instance.outputDir = self._get_output_dir(instance)

                instances.append(instance)

        self.log.debug("instances::{}".format(instances))
        return instances

    def get_expected_files(self, render_instance):
        """
            Returns list of rendered files that should be created by
            Deadline. These are not published directly, they are source
            for later 'submit_publish_job'.

        Args:
            render_instance (RenderInstance): to pull anatomy and parts used
                in url

        Returns:
            (list) of absolut urls to rendered file
        """
        start = render_instance.frameStart
        end = render_instance.frameEnd

        # pull file name from Render Queue Output module
        render_q = self.stub.get_render_info()
        if not render_q:
            raise ValueError("No file extension set in Render Queue")
        _, ext = os.path.splitext(os.path.basename(render_q.file_name))

        base_dir = self._get_output_dir(render_instance)
        expected_files = []
        if "#" not in render_q.file_name:  # single frame (mov)W
            path = os.path.join(
                base_dir,
                "{}_{}_{}.{}".format(render_instance.asset,
                                     render_instance.subset,
                                     "v{:03d}".format(render_instance.version),
                                     ext.replace('.', '')))
            expected_files.append(path)
        else:
            for frame in range(start, end + 1):
                path = os.path.join(
                    base_dir, "{}_{}_{}.{}.{}".format(
                        render_instance.asset, render_instance.subset,
                        "v{:03d}".format(render_instance.version),
                        str(frame).zfill(self.padding_width),
                        ext.replace('.', '')))
                expected_files.append(path)
        return expected_files

    def _get_output_dir(self, render_instance):
        """
            Returns dir path of rendered files, used in submit_publish_job
            for metadata.json location.
            Should be in separate folder inside of work area.

        Args:
            render_instance (RenderInstance):

        Returns:
            (str): absolute path to rendered files
        """
        # render to folder of workfile
        base_dir = os.path.dirname(render_instance.source)
        file_name, _ = os.path.splitext(
            os.path.basename(render_instance.source))
        base_dir = os.path.join(base_dir, 'renders', 'aftereffects', file_name)

        # for submit_publish_job
        return base_dir