Skip to content

lib

get_background_layers(file_url)

Pulls file name from background json file, enrich with folder url for AE to be able import files.

Order is important, follows order in json.

Parameters:

Name Type Description Default
file_url str

abs url of background json

required

Returns:

Type Description
list

of abs paths to images

Source code in client/ayon_aftereffects/api/lib.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def get_background_layers(file_url):
    """
        Pulls file name from background json file, enrich with folder url for
        AE to be able import files.

        Order is important, follows order in json.

        Args:
            file_url (str): abs url of background json

        Returns:
            (list): of abs paths to images
    """
    with open(file_url) as json_file:
        data = json.load(json_file)

    layers = list()
    bg_folder = os.path.dirname(file_url)
    for child in data['children']:
        if child.get("filename"):
            layers.append(os.path.join(bg_folder, child.get("filename")).
                          replace("\\", "/"))
        else:
            for layer in child['children']:
                if layer.get("filename"):
                    layers.append(os.path.join(bg_folder,
                                               layer.get("filename")).
                                  replace("\\", "/"))
    return layers

get_entity_attributes(entity)

Get attributes of folder or task entity.

Returns:

Name Type Description
dict dict[str, Union[float, int]]

Scene data.

Source code in client/ayon_aftereffects/api/lib.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def get_entity_attributes(entity: dict) -> dict[str, Union[float, int]]:
    """Get attributes of folder or task entity.

    Returns:
        dict: Scene data.

    """
    attrib: dict = entity["attrib"]
    fps = attrib.get("fps", 0)
    frame_start = attrib.get("frameStart", 0)
    frame_end = attrib.get("frameEnd", 0)
    handle_start = attrib.get("handleStart", 0)
    handle_end = attrib.get("handleEnd", 0)
    resolution_width = attrib.get("resolutionWidth", 0)
    resolution_height = attrib.get("resolutionHeight", 0)
    duration = (frame_end - frame_start + 1) + handle_start + handle_end

    return {
        "fps": fps,
        "frameStart": frame_start,
        "frameEnd": frame_end,
        "handleStart": handle_start,
        "handleEnd": handle_end,
        "resolutionWidth": resolution_width,
        "resolutionHeight": resolution_height,
        "duration": duration
    }

get_unique_item_name(items, name)

Creates unique name for 'item'.

Gets all item names (compositions|containers) and if 'name' is present in them, increases suffix by 1 (eg. creates unique item name - for Loader)

Parameters:

Name Type Description Default
items list

of strings, names only

required
name string

checked value

required

Returns:

Type Description
string

name_00X (without version)

Source code in client/ayon_aftereffects/api/lib.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def get_unique_item_name(items, name):
    """Creates unique name for 'item'.

    Gets all item names (compositions|containers) and if 'name' is
    present in them, increases suffix by 1 (eg. creates unique item name
      - for Loader)

    Args:
        items (list): of strings, names only
        name (string):  checked value

    Returns:
        (string): name_00X (without version)
    """
    names = {}
    index_regex = re.compile(r"_\d{3}$")
    for item in items:
        item_name = index_regex.sub("", item)
        names.setdefault(item_name, 0)
        names[item_name] += 1
    occurrences = names.get(name, 0)

    return "{}_{:0>3d}".format(name, occurrences + 1)

maintained_selection()

Maintain selection during context.

Source code in client/ayon_aftereffects/api/lib.py
48
49
50
51
52
53
54
55
@contextlib.contextmanager
def maintained_selection():
    """Maintain selection during context."""
    selection = get_stub().get_selected_items(True, False, False)
    try:
        yield selection
    finally:
        pass

publish_in_test(log, close_plugin_name=None)

Loops through all plugins, logs to console. Used for tests.

Parameters:

Name Type Description Default
close_plugin_name Optional[str]

Name of plugin with responsibility to close application.

None
Source code in client/ayon_aftereffects/api/lib.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
def publish_in_test(log, close_plugin_name=None):
    """Loops through all plugins, logs to console. Used for tests.

    Args:
        log (Logger)
        close_plugin_name (Optional[str]): Name of plugin with responsibility
            to close application.
    """

    # Error exit as soon as any error occurs.
    error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}"
    close_plugin = find_close_plugin(close_plugin_name, log)

    for result in pyblish.util.publish_iter():
        for record in result["records"]:
            # Why do we log again? pyblish logger is logging to stdout...
            log.info("{}: {}".format(result["plugin"].label, record.msg))

        if not result["error"]:
            continue

        # QUESTION We don't break on error?
        error_message = error_format.format(**result)
        log.error(error_message)
        if close_plugin:  # close host app explicitly after error
            context = pyblish.api.Context()
            try:
                close_plugin().process(context)
            except Exception as exp:
                log.error(exp)

raise_window_to_front(window)

Raise a Qt window to the foreground. On Windows, activateWindow() is silently ignored when the calling process does not own the foreground (e.g. when triggered via the CEP panel). AttachThreadInput temporarily borrows the foreground thread's input state so SetForegroundWindow succeeds even on the first call, before Python has ever received focus. Args: window (QtWidgets.QWidget): Window to bring to the front.

Source code in client/ayon_aftereffects/api/lib.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def raise_window_to_front(window):
    """Raise a Qt window to the foreground.
    On Windows, activateWindow() is silently ignored when the calling
    process does not own the foreground (e.g. when triggered via the
    CEP panel). AttachThreadInput temporarily borrows the foreground
    thread's input state so SetForegroundWindow succeeds even on the
    first call, before Python has ever received focus.
    Args:
        window (QtWidgets.QWidget): Window to bring to the front.
    """
    window.show()
    window.raise_()
    window.activateWindow()
    if sys.platform == "win32":
        import ctypes
        user32 = ctypes.windll.user32
        hwnd = int(window.winId())
        foreground_hwnd = user32.GetForegroundWindow()
        foreground_tid = user32.GetWindowThreadProcessId(
            foreground_hwnd, None
        )
        current_tid = ctypes.windll.kernel32.GetCurrentThreadId()
        if foreground_tid and foreground_tid != current_tid:
            user32.AttachThreadInput(current_tid, foreground_tid, True)
            user32.SetForegroundWindow(hwnd)
            user32.AttachThreadInput(current_tid, foreground_tid, False)
        else:
            user32.SetForegroundWindow(hwnd)

set_settings(frames, resolution, comp_ids=None, print_msg=True, entity=None)

Sets number of frames and resolution to selected comps.

Parameters:

Name Type Description Default
frames bool

True if set frame info

required
resolution bool

True if set resolution

required
comp_ids list[int]

specific composition ids, if empty it tries to look for currently selected

None
print_msg bool

True throw JS alert with msg

True
entity Optional[dict]

Entity to use attributes from to define the frame range, fps and resolution from. If not provided, current task entity is used.

None
Source code in client/ayon_aftereffects/api/lib.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
def set_settings(
        frames, resolution, comp_ids=None, print_msg=True, entity=None):
    """Sets number of frames and resolution to selected comps.

    Args:
        frames (bool): True if set frame info
        resolution (bool): True if set resolution
        comp_ids (list[int]): specific composition ids, if empty
            it tries to look for currently selected
        print_msg (bool): True throw JS alert with msg
        entity (Optional[dict]): Entity to use attributes from to define the
            frame range, fps and resolution from. If not provided, current
            task entity is used.
    """
    frame_start = frames_duration = fps = width = height = None

    if entity is None:
        entity = get_current_task_entity()
    settings = get_entity_attributes(entity)

    msg = ''
    if frames:
        frame_start = settings["frameStart"] - settings["handleStart"]
        frames_duration = settings["duration"]
        fps = settings["fps"]
        msg += f"frame start:{frame_start}, duration:{frames_duration}, "\
               f"fps:{fps}"
    if resolution:
        width = settings["resolutionWidth"]
        height = settings["resolutionHeight"]
        msg += f"width:{width} and height:{height}"

    stub = get_stub()
    if not comp_ids:
        comps = stub.get_selected_items(True, False, False)
        comp_ids = [comp.id for comp in comps]
    if not comp_ids:
        stub.print_msg("Select at least one composition to apply settings.")
        return

    for comp_id in comp_ids:
        msg = f"Setting for comp {comp_id} " + msg
        log.debug(msg)
        stub.set_comp_properties(comp_id, frame_start, frames_duration,
                                 fps, width, height)
        if print_msg:
            stub.print_msg(msg)