def dup(self):
        current_scene = S.obs_scene_from_source(
            S.obs_frontend_get_current_scene())
        scene_item = S.obs_scene_find_source(current_scene, self.source_name)
        info = S.obs_transform_info()
        crop = S.obs_sceneitem_crop()
        S.obs_sceneitem_get_info(scene_item, info)
        S.obs_sceneitem_get_crop(scene_item, crop)
        duplicate = S.obs_sceneitem_get_source(scene_item)
        duplicated = S.obs_source_duplicate(duplicate,
                                            "duplicate" + self.source_name,
                                            False)

        scenes = S.obs_frontend_get_scenes()
        for scene in scenes:
            name = S.obs_source_get_name(scene)
            if name == self.scene_name:
                scene = S.obs_scene_from_source(scene)
                scene_item2 = S.obs_scene_add(scene, duplicated)
                S.obs_sceneitem_set_info(scene_item2, info)
                S.obs_sceneitem_set_crop(scene_item2, crop)
                S.obs_scene_release(scene)

        S.obs_source_release(duplicated)
        S.source_list_release(scenes)
        S.obs_scene_release(current_scene)
Example #2
0
def getTransformationList(sceneitems):
    transformations = []
    for sceneitem in sceneitems:
        pos = obs.vec2()
        obs.obs_sceneitem_get_pos(sceneitem, pos)
        rot = obs.obs_sceneitem_get_rot(sceneitem)
        scale = obs.vec2()
        obs.obs_sceneitem_get_scale(sceneitem, scale)
        alignment = obs.obs_sceneitem_get_alignment(sceneitem)
        bounds = obs.vec2()
        obs.obs_sceneitem_get_bounds(sceneitem, bounds)
        boundsType = obs.obs_sceneitem_get_bounds_type(sceneitem)
        boundsAlignment = obs.obs_sceneitem_get_bounds_alignment(sceneitem)
        crop = obs.obs_sceneitem_crop()
        obs.obs_sceneitem_get_crop(sceneitem, crop)
        transformations.append({
            "pos": [pos.x, pos.y],
            "rot":
            rot,
            "scale": [scale.x, scale.y],
            "alignment":
            alignment,
            "bounds": [bounds.x, bounds.y],
            "boundsType":
            boundsType,
            "boundsAlignment":
            boundsAlignment,
            "crop": [crop.left, crop.right, crop.top, crop.bottom]
        })
        obs.obs_sceneitem_release(sceneitem)
    return transformations
Example #3
0
def dumpSceneData():
    scene = obs.obs_frontend_get_current_scene()
    sceneObject = obs.obs_scene_from_source(scene)
    items = obs.obs_scene_enum_items(sceneObject)
    itemArray = []
    for item in items:
        sceneItem = obs.obs_sceneitem_get_source(item)
        name = obs.obs_source_get_name(sceneItem)
        if "tweentool:" not in name:
            pos = obs.vec2()
            obs.obs_sceneitem_get_pos(item, pos)
            rot = obs.obs_sceneitem_get_rot(item)
            scale = obs.vec2()
            obs.obs_sceneitem_get_scale(item, scale)
            alignment = obs.obs_sceneitem_get_alignment(item)
            bounds = obs.vec2()
            obs.obs_sceneitem_get_bounds(item, bounds)
            boundsType = obs.obs_sceneitem_get_bounds_type(item)
            boundsAlignment = obs.obs_sceneitem_get_bounds_alignment(item)
            crop = obs.obs_sceneitem_crop()
            obs.obs_sceneitem_get_crop(item, crop)
            itemArray.append({
                "name":
                name,
                "pos": [pos.x, pos.y],
                "rot":
                rot,
                "scale": [scale.x, scale.y],
                "alignment":
                alignment,
                "bounds": [bounds.x, bounds.y],
                "boundsType":
                boundsType,
                "boundsAlignment":
                boundsAlignment,
                "crop": [crop.left, crop.right, crop.top, crop.bottom]
            })
    return itemArray
Example #4
0
 def _obs_sceneitem_set_crop(self, scene_name, source_name, crop_sizes):
     with self._sceneitem_by_name(scene_name, source_name) as si:
         crop = _obs.obs_sceneitem_crop()
         crop.left, crop.right, crop.top, crop.bottom = crop_sizes
         _obs.obs_sceneitem_set_crop(si, crop)
Example #5
0
 def _obs_sceneitem_get_crop(self, scene_name, source_name):
     with self._sceneitem_by_name(scene_name, source_name) as si:
         crop = _obs.obs_sceneitem_crop()
         _obs.obs_sceneitem_get_crop(si, crop)
         return crop.left, crop.right, crop.top, crop.bottom
Example #6
0
def sad_threaded(props, prop):
    # 1. Make it grayscale
    cam_source = obs.obs_get_source_by_name("Shitty Webcam")
    grayscale_filter = obs.obs_source_get_filter_by_name(cam_source, "Gray")

    data = obs.obs_data_create()
    obs.obs_data_set_double(data, "clut_amount", 1.0)
    obs.obs_source_update(grayscale_filter, data)

    # 2. Save initial props
    current_scene_source = obs.obs_frontend_get_current_scene()
    obs.obs_frontend_set_current_preview_scene(current_scene_source)
    current_scene = obs.obs_scene_from_source(current_scene_source)
    cam_sceneitem = obs.obs_scene_find_source(current_scene, "Shitty Webcam")

    initial_scale = obs.vec2()
    obs.obs_sceneitem_get_scale(cam_sceneitem, initial_scale)

    initial_pos = obs.vec2()
    obs.obs_sceneitem_get_pos(cam_sceneitem, initial_pos)

    initial_box_transform = obs.matrix4()
    obs.obs_sceneitem_get_box_transform(cam_sceneitem, initial_box_transform)

    initial_crop = obs.obs_sceneitem_crop()
    obs.obs_sceneitem_get_crop(cam_sceneitem, initial_crop)
    # matrix4.x.x -> x size
    # matrix4.y.y -> y size
    # matrix4.t.x -> x position
    # matrix4.t.y -> y position
    # for prop in ["x", "y", "z", "t"]:
    #   print(f"Matrix property {prop}")
    #   vec = getattr(initial_box_transform, prop)
    #   print(dir(vec))
    #   for vec_prop in ["m", "w", "x", "y", "z"]:
    #     print(f"Vec Property {vec_prop}: {getattr(vec, vec_prop)}")
    size_x = initial_box_transform.x.x
    size_y = initial_box_transform.y.y

    initial_draw_transform = obs.matrix4()
    obs.obs_sceneitem_get_draw_transform(cam_sceneitem, initial_draw_transform)
    print(dir(initial_draw_transform))

    # 3. Mute desktop audio, play sound of silence
    desktop_audio = obs.obs_get_output_source(4)
    obs.obs_source_set_muted(desktop_audio, True)

    song = obs.obs_source_create("ffmpeg_source", "Sound of Silence", None,
                                 None)
    song_settings = obs.obs_data_create()
    obs.obs_data_set_string(
        song_settings, "local_file",
        "C:\\Users\\avikn\\Downloads\\sound_of_silence.mp3")
    obs.obs_source_update(song, song_settings)
    obs.obs_data_release(song_settings)
    song_item = obs.obs_scene_add(current_scene, song)

    # 4. Scale up / reposition the camera.
    # It's gross but it works don't touch it.
    dynamic_scale = obs.vec2()
    obs.vec2_copy(dynamic_scale, initial_scale)

    increment = obs.vec2()
    increment.x = 0.0015
    increment.y = 0.0015

    crop = (initial_crop.top, initial_crop.right, initial_crop.bottom,
            initial_crop.left)
    size_x, size_y = get_size(cam_sceneitem)
    dynamic_crop = obs.obs_sceneitem_crop()

    bounds = obs.vec2()
    bounds.x = size_x
    bounds.y = size_y
    obs.obs_sceneitem_set_bounds(cam_sceneitem, bounds)

    for _ in range(240):
        obs.obs_sceneitem_set_bounds_type(cam_sceneitem, 0)
        obs.vec2_add(dynamic_scale, dynamic_scale, increment)
        obs.obs_sceneitem_set_scale(cam_sceneitem, dynamic_scale)
        nsize_x, nsize_y = get_size(cam_sceneitem)
        x_delta = nsize_x - size_x + (dynamic_crop.right * 2)
        y_delta = nsize_y - size_y + (dynamic_crop.top * 2)

        dynamic_crop.top = int(y_delta / 2)
        dynamic_crop.right = int(x_delta / 2)
        dynamic_crop.bottom = int(y_delta / 2)
        dynamic_crop.left = int(x_delta / 2)

        obs.obs_sceneitem_set_crop(cam_sceneitem, dynamic_crop)

        obs.obs_sceneitem_set_bounds_type(cam_sceneitem, 1)
        obs.obs_frontend_preview_program_trigger_transition()
        time.sleep(0.1)

    # 5. Cleanup
    obs.obs_source_set_muted(desktop_audio, False)

    obs.obs_sceneitem_set_scale(cam_sceneitem, initial_scale)
    obs.obs_sceneitem_set_crop(cam_sceneitem, initial_crop)
    obs.obs_data_set_double(data, "clut_amount", 0.0)
    obs.obs_source_update(grayscale_filter, data)
    obs.obs_sceneitem_remove(song_item)
    obs.obs_source_release(song)
    time.sleep(0.1)
    obs.obs_frontend_preview_program_trigger_transition()
Example #7
0
 def _crop(self):
     crop = obs.obs_sceneitem_crop()
     obs.obs_sceneitem_get_crop(self.sceneitem, crop)
     return crop
def changeSourceToMousePosition():
    #Get current scene
    currentScene = currentSceneName()
    if currentScene is None:
        return
    #Get scene item
    src = obs.obs_get_source_by_name(currentScene)
    if src is None:
        return
    scene = obs.obs_scene_from_source(src)
    if scene is None:
        return
    obs.obs_source_release(src)
    for sourceName in [sourceName1, sourceName2]:
        sceneItem = obs.obs_scene_find_source(scene, sourceName)
        if sceneItem is None:
            break

        #Variables
        global currentLeft
        global currentTop
        global currentRight
        global currentBottom
        global wantedLeft
        global wantedTop
        global wantedRight
        global wantedBottom

        #Following mouse
        if followingMouse:
            global currentCamera
            mousePos = queryMousePosition()
            wantedCamera = mousePos
            xSizeNow = xMaxSize - currentRight - currentLeft
            ySizeNow = yMaxSize - currentBottom - currentTop
            scaleRateFixer = ((xMaxSize + yMaxSize) / (xSizeNow + ySizeNow))
            xDiff = (wantedCamera.x -
                     currentCamera[0]) * followRate / 100 * scaleRateFixer
            yDiff = (wantedCamera.y -
                     currentCamera[1]) * followRate / 100 * scaleRateFixer
            #Check if already reached wanted camera
            if abs(currentCamera[0] + xDiff -
                   wantedCamera.x) > abs(currentCamera[0] - wantedCamera.x):
                xDiff = wantedCamera.x - currentCamera[0]
            if abs(currentCamera[1] + yDiff -
                   wantedCamera.y) > abs(currentCamera[1] - wantedCamera.y):
                yDiff = wantedCamera.y - currentCamera[1]
            #Move camera
            currentCamera[0] += xDiff
            currentCamera[1] += yDiff
            #Move crop
            wantedLeft += xDiff
            wantedRight -= xDiff
            wantedTop += yDiff
            wantedBottom -= yDiff

        #When rectangle is outside
        fixedWantedLeft = wantedLeft
        fixedWantedTop = wantedTop
        fixedWantedRight = wantedRight
        fixedWantedBottom = wantedBottom
        if fixedWantedLeft < 0:
            fixedWantedRight += fixedWantedLeft
            fixedWantedLeft = 0
        elif fixedWantedRight < 0:
            fixedWantedLeft += fixedWantedRight
            fixedWantedRight = 0
        if fixedWantedTop < 0:
            fixedWantedBottom += fixedWantedTop
            fixedWantedTop = 0
        elif fixedWantedBottom < 0:
            fixedWantedTop += fixedWantedBottom
            fixedWantedBottom = 0

        #If zoom is off
        if not wantsZoom:
            fixedWantedLeft = 0
            fixedWantedTop = 0
            fixedWantedRight = 0
            fixedWantedBottom = 0

        #Move crop
        currentLeft += (fixedWantedLeft - currentLeft) * zoomRate / 100
        currentTop += (fixedWantedTop - currentTop) * zoomRate / 100
        currentRight += (fixedWantedRight - currentRight) * zoomRate / 100
        currentBottom += (fixedWantedBottom - currentBottom) * zoomRate / 100

        #Set to OBS
        cropZone = obs.obs_sceneitem_crop()
        cropZone.left = int(round(currentLeft))
        cropZone.top = int(round(currentTop))
        cropZone.right = int(round(currentRight))
        cropZone.bottom = int(round(currentBottom))
        obs.obs_sceneitem_set_crop(sceneItem, cropZone)
Example #9
0
def script_tick(seconds):  # OBS script interface.
    global discord_source

    source_name = obs.obs_data_get_string(settings, 'discord_source')
    if source_name != obs.obs_source_get_name(discord_source):
        obs.obs_source_release(
            discord_source)  # Doesn’t error even if discord_source == None.
        discord_source = obs.obs_get_source_by_name(source_name)

    if not client:
        return

    # NOTE: These are 0 when the source isn’t visible at all in the current scene. Not that it matters, but I was just weirded out by it until I got it.
    source_width = obs.obs_source_get_width(discord_source)
    source_height = obs.obs_source_get_height(discord_source)

    margin_top = MARGIN_TOP
    if not obs.obs_data_get_bool(settings, 'full_screen'):
        margin_top = margin_top + TITLE_BAR

    # Get Discord call layout distribution and caller size.
    people = [x for x in client.video]  # Mutability and shiz.
    nonvideo = obs.obs_data_get_bool(settings, 'show_nonvideo_participants')
    if nonvideo:
        people += client.audio
    count = len(people)
    if count == 1 and (not client.audio or not client.video and nonvideo):
        count = 2  # Discord adds a call to action that occupies the same space as a second caller.
    rows = None
    cols = None
    width = 0
    height = None
    offsetx = 0
    offsety = 0
    offset_last = None
    if source_width and source_height:
        totalw = source_width - MARGIN_SIDES * 2
        totalh = source_height - margin_top - MARGIN_BTM
        if totalw > 0 and totalh > 0:
            wide = None
            # Discord packs the callers in as many columns as possible, unless their videos appear bigger with fewer columns.
            for c in reversed(range(1, count + 1)):
                r = math.ceil(count / c)
                w = (totalw - CALLER_SPACING * (c - 1)) / c
                h = (totalh - CALLER_SPACING * (r - 1)) / r
                wi = w / h > CALLER_ASPECT
                if wi:
                    w = h * CALLER_ASPECT
                if w > width:
                    rows = r
                    cols = c
                    width = w
                    height = h
                    wide = wi
            if rows:
                # If the window is wider or taller than the callers fit in, Discord will center them as a whole.
                inner_width = (width * cols + CALLER_SPACING * (cols - 1))
                if wide:  # Wider than needed, therefore center horizontally.
                    offsetx = (totalw - inner_width) / 2
                else:  # Taller than needed, therefore center vertically.
                    height = width / CALLER_ASPECT  # We compared using widths only before, so height needs to be adjusted.
                    offsety = (totalh - (height * rows + CALLER_SPACING *
                                         (rows - 1))) / 2

                # If last row contains fewer callers than columns, Discord will center it.
                offset_last = count % cols
                if offset_last > 0:
                    offset_last = (inner_width -
                                   (width * offset_last + CALLER_SPACING *
                                    (offset_last - 1))) / 2

    # Apply necessary changes to relevant scene items.
    scene_sources = obs.obs_frontend_get_scenes()
    for scene_src in scene_sources:
        scene = obs.obs_scene_from_source(scene_src)  # Shouldn’t be released.
        items = obs.obs_scene_enum_items(scene)
        i = 0
        next_vis = None
        for item in reversed(items):
            _next_vis = None
            if obs.obs_sceneitem_get_source(
                    item) == discord_source:  # Shouldn’t be released.
                uid = int(
                    obs.obs_data_get_string(settings, f'participant{i}') or -1)
                visible = True
                try:
                    index = people.index(uid)
                except (IndexError, ValueError):
                    visible = False
                i += 1
                obs.obs_sceneitem_set_visible(item, visible)
                if visible and rows:
                    crop = obs.obs_sceneitem_crop()
                    obs.obs_sceneitem_get_crop(item, crop)
                    scale = obs.vec2()
                    obs.obs_sceneitem_get_scale(item, scale)
                    bounds = obs.vec2()
                    obs.obs_sceneitem_get_bounds(item, bounds)

                    # If item was set to not use a bounding box policy, calculate it from its other transform properties.
                    if obs.obs_sceneitem_get_bounds_type(
                            item) == obs.OBS_BOUNDS_NONE:
                        obs.vec2_set(
                            bounds,
                            scale.x * (source_width - crop.right - crop.left),
                            scale.y * (source_height - crop.bottom - crop.top))
                        obs.obs_sceneitem_set_bounds(item, bounds)

                    obs.obs_sceneitem_set_bounds_type(
                        item, obs.OBS_BOUNDS_SCALE_OUTER)
                    obs.obs_sceneitem_set_bounds_alignment(
                        item, 0
                    )  # obs.OBS_ALIGN_CENTER doesn’t seem to be implemented.

                    # Get top left corner of this caller.
                    r = math.ceil((index + 1) / cols)
                    c = index % cols + 1
                    x = MARGIN_SIDES + offsetx + (width +
                                                  CALLER_SPACING) * (c - 1)
                    if r == rows:
                        x = x + offset_last
                    y = margin_top + offsety + (height + CALLER_SPACING) * (r -
                                                                            1)

                    # Make sure the crop doesn’t overflow the item bounds.
                    aspect = bounds.x / bounds.y
                    clipx = 0
                    clipy = 0
                    if aspect > CALLER_ASPECT:
                        clipy = (height - width / aspect) / 2
                    else:
                        clipx = (width - height * aspect) / 2

                    crop.left = math.ceil(x + CALLER_BORDER + clipx)
                    crop.top = math.ceil(y + CALLER_BORDER + clipy)
                    crop.right = source_width - int(x + width - CALLER_BORDER -
                                                    clipx)
                    crop.bottom = source_height - int(y + height -
                                                      CALLER_BORDER - clipy)
                    obs.obs_sceneitem_set_crop(item, crop)

                    sx = abs(scale.x)
                    if uid == int(
                            obs.obs_data_get_string(settings, 'myself')
                            or -1) and uid in client.video:
                        sx = -sx
                    sy = scale.y
                    obs.vec2_set(scale, sx, sy)
                    obs.obs_sceneitem_set_scale(item, scale)
                if not nonvideo and obs.obs_data_get_bool(
                        settings, 'item_right_below'):
                    _next_vis = uid in client.audio
            elif next_vis is not None:
                obs.obs_sceneitem_set_visible(item, next_vis)
            next_vis = _next_vis
        obs.sceneitem_list_release(items)
    obs.source_list_release(scene_sources)
Example #10
0
def script_tick(tick):
    global globSettings
    global animationInfo
    global animationRunning
    global app
    global currentScene

    if animationRunning:
        animationInfo["animTime"] += tick
        animationInfo["animTime"] = min(animationInfo["animTime"],
                                        animationInfo["stopTime"])
        scaleFactor = easeInOutQuad(
            animationInfo["animTime"] / animationInfo["stopTime"], 0, 1, 1)

        animScene = animationInfo["animScene"]
        initial = animationInfo["initial"]
        destination = animationInfo["destination"]

        result = []
        sceneObject = obs.obs_scene_from_source(animScene)
        if obs.obs_source_get_name(
                animScene) in obs.obs_frontend_get_scene_names():
            items = obs.obs_scene_enum_items(sceneObject)
            for i in range(len(initial)):
                pos = obs.vec2()
                pos.x = scaleFactor * (destination[i]["pos"][0] - initial[i]
                                       ["pos"][0]) + initial[i]["pos"][0]
                pos.y = scaleFactor * (destination[i]["pos"][1] - initial[i]
                                       ["pos"][1]) + initial[i]["pos"][1]
                rot = scaleFactor * (destination[i]["rot"] -
                                     initial[i]["rot"]) + initial[i]["rot"]
                scale = obs.vec2()
                scale.x = scaleFactor * (
                    destination[i]["scale"][0] -
                    initial[i]["scale"][0]) + initial[i]["scale"][0]
                scale.y = scaleFactor * (
                    destination[i]["scale"][1] -
                    initial[i]["scale"][1]) + initial[i]["scale"][1]
                alignment = destination[i]["alignment"]
                bounds = obs.vec2()
                bounds.x = scaleFactor * (
                    destination[i]["bounds"][0] -
                    initial[i]["bounds"][0]) + initial[i]["bounds"][0]
                bounds.y = scaleFactor * (
                    destination[i]["bounds"][1] -
                    initial[i]["bounds"][1]) + initial[i]["bounds"][1]
                boundsType = destination[i]["boundsType"]
                boundsAlignment = destination[i]["boundsAlignment"]
                crop = obs.obs_sceneitem_crop()
                crop.left = math.floor(
                    scaleFactor *
                    (destination[i]["crop"][0] - initial[i]["crop"][0]) +
                    initial[i]["crop"][0])
                crop.right = math.floor(
                    scaleFactor *
                    (destination[i]["crop"][1] - initial[i]["crop"][1]) +
                    initial[i]["crop"][1])
                crop.top = math.floor(
                    scaleFactor *
                    (destination[i]["crop"][2] - initial[i]["crop"][2]) +
                    initial[i]["crop"][2])
                crop.bottom = math.floor(
                    scaleFactor *
                    (destination[i]["crop"][3] - initial[i]["crop"][3]) +
                    initial[i]["crop"][3])
                obs.obs_sceneitem_set_pos(items[i], pos)
                obs.obs_sceneitem_set_rot(items[i], rot)
                obs.obs_sceneitem_set_scale(items[i], scale)
                obs.obs_sceneitem_set_alignment(items[i], alignment)
                obs.obs_sceneitem_set_bounds(items[i], bounds)
                obs.obs_sceneitem_set_bounds_type(items[i], boundsType)
                obs.obs_sceneitem_set_bounds_alignment(items[i],
                                                       boundsAlignment)
                obs.obs_sceneitem_set_crop(items[i], crop)
            obs.sceneitem_list_release(items)

        #obs.obs_scene_release(sceneObject)

        if animationInfo["animTime"] == animationInfo["stopTime"]:
            obs.obs_source_release(animScene)
            animationInfo["animScene"] = None
            animationRunning = False
Example #11
0
def script_tick(tick):
    if scriptSettings['anim']['animating']:
        scriptSettings['anim']['time'] += tick
        scriptSettings['anim']['time'] = min(scriptSettings['anim']['time'],
                                             scriptSettings['anim']['length'])
        initial = scriptSettings['anim']['src']
        destination = scriptSettings['anim']['dest']
        tScale = easeInOutQuad(
            scriptSettings['anim']['time'] / scriptSettings['anim']['length'],
            0, 1, 1)
        scene = obs.obs_frontend_get_current_scene()
        sceneObject = obs.obs_scene_from_source(scene)
        tweenItems = scriptSettings['anim']['tweener']['tweenItems']
        sceneItems = obs.obs_scene_enum_items(sceneObject)
        for sItem in sceneItems:
            sceneItem = obs.obs_sceneitem_get_source(sItem)
            sName = obs.obs_source_get_name(sceneItem)
            for tItem in tweenItems:
                if sName == tItem['name']:
                    pos = obs.vec2()
                    pos.x = tScale * (
                        destination[sName]["pos"][0] -
                        initial[sName]["pos"][0]) + initial[sName]["pos"][0]
                    pos.y = tScale * (
                        destination[sName]["pos"][1] -
                        initial[sName]["pos"][1]) + initial[sName]["pos"][1]
                    rot = tScale * (destination[sName]["rot"] - initial[sName]
                                    ["rot"]) + initial[sName]["rot"]
                    scale = obs.vec2()
                    scale.x = tScale * (destination[sName]["scale"][0] -
                                        initial[sName]["scale"][0]
                                        ) + initial[sName]["scale"][0]
                    scale.y = tScale * (destination[sName]["scale"][1] -
                                        initial[sName]["scale"][1]
                                        ) + initial[sName]["scale"][1]
                    alignment = destination[sName]["alignment"]
                    bounds = obs.vec2()
                    bounds.x = tScale * (destination[sName]["bounds"][0] -
                                         initial[sName]["bounds"][0]
                                         ) + initial[sName]["bounds"][0]
                    bounds.y = tScale * (destination[sName]["bounds"][1] -
                                         initial[sName]["bounds"][1]
                                         ) + initial[sName]["bounds"][1]
                    boundsType = destination[sName]["boundsType"]
                    boundsAlignment = destination[sName]["boundsAlignment"]
                    crop = obs.obs_sceneitem_crop()
                    crop.left = math.floor(tScale *
                                           (destination[sName]["crop"][0] -
                                            initial[sName]["crop"][0]) +
                                           initial[sName]["crop"][0])
                    crop.right = math.floor(tScale *
                                            (destination[sName]["crop"][1] -
                                             initial[sName]["crop"][1]) +
                                            initial[sName]["crop"][1])
                    crop.top = math.floor(tScale *
                                          (destination[sName]["crop"][2] -
                                           initial[sName]["crop"][2]) +
                                          initial[sName]["crop"][2])
                    crop.bottom = math.floor(tScale *
                                             (destination[sName]["crop"][3] -
                                              initial[sName]["crop"][3]) +
                                             initial[sName]["crop"][3])
                    obs.obs_sceneitem_set_pos(sItem, pos)
                    obs.obs_sceneitem_set_rot(sItem, rot)
                    obs.obs_sceneitem_set_scale(sItem, scale)
                    obs.obs_sceneitem_set_alignment(sItem, alignment)
                    obs.obs_sceneitem_set_bounds(sItem, bounds)
                    obs.obs_sceneitem_set_bounds_type(sItem, boundsType)
                    obs.obs_sceneitem_set_bounds_alignment(
                        sItem, boundsAlignment)
                    obs.obs_sceneitem_set_crop(sItem, crop)
        if scriptSettings['anim']['time'] >= scriptSettings['anim']['length']:
            scriptSettings['anim']['src'] = None
            scriptSettings['anim']['dest'] = None
            scriptSettings['anim']['time'] = math.inf
            scriptSettings['anim']['length'] = 10000
            scriptSettings['anim']['tweener'] = None
            scriptSettings['anim']['animating'] = False