Creating linked animation sequence in python

Hi @BadookaSlam I thought I did above. This is what I use daily. I’ll give you exactly what I use that also exports out fbx(s) as well from linked sequences automatically and removes the annoying game folder in the directory as well. Notice that it requires another module reference to do it properly and I called it “path_config”

import unreal
import importlib
import os
import shutil
ll = unreal.LevelSequenceEditorBlueprintLibrary
ues = unreal.EditorLevelLibrary()
level_editor_subsystem = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)
world = level_editor_subsystem.get_current_level()
world = ues.get_editor_world()
eas = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
msbp = unreal.MovieSceneBindingProxy
mst = unreal.MovieSceneTrack
s = unreal.SequencerTools
from unreal import LevelEditorSubsystem

task = unreal.AssetExportTask()
task.automated = 1
task.prompt = 0
task.write_empty_files = 1
task.use_file_archive = 0
task.replace_identical = 1

ait = unreal.AssetImportTask()
ait.automated = 1
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()

binding = ll.get_selected_bindings()[0]
eul = unreal.EditorUtilityLibrary()
d = eul.get_selected_asset_data()

asset_registry = unreal.AssetRegistryHelpers.get_asset_registry()

import path_config as pc
importlib.reload(pc)

main_path = pc.main_path + '/animations'
level_sequence = ll.get_focused_level_sequence()
bindings = ll.get_selected_bindings()

ase = unreal.AnimSequenceExporterFBX()

"""
SceneComponent
asset_user_data 
get_child_component
get_children_components
unreal.SkeletalMesh.skeleton 
"""



les = unreal.get_editor_subsystem(LevelEditorSubsystem)

def print_names(object):
    for i in object: print(i.get_display_name())
        
def export_anim(path="/Game/"):
    path = path.replace("/All/", "/")
    #s.export_anim_sequence()
    anim_factory = unreal.AnimSequenceFactory()
    level_sequence = ll.get_focused_level_sequence()
    bindings = ll.get_selected_bindings()
    exported_assets = []
    
    anim_seqs = []
    cur_assets = asset_registry.get_assets_by_path(path)
        
    for binding in bindings:
        parent = binding.get_parent()
        parent_name = parent.get_name().replace("(", "_").replace(")", "_")
        
        object_binding_id = level_sequence.get_binding_id(binding) #finally got the binding id
        skmc = ll.get_bound_objects(object_binding_id)[0]
        skm = skmc.skeletal_mesh
        name = skm.get_name()
        # name = '_'.join(name.split("_")[0:2])
        name = parent_name + "_" +  name
        name = name.replace(" ", "_")
        count = 0
        for asset in cur_assets:
            if(name in str(asset.asset_name)):
                count += 1
        if(count > 0):
            name += "_{0}".format(count)
            
        sk = skm.skeleton
        
        
        anim_factory.preview_skeletal_mesh = skm
        anim_factory.target_skeleton = sk
        anim_factory.set_editor_property("asset_import_task", ait)
        anim_factory.set_editor_property("edit_after_new", False)
         

        anim_seq_class = unreal.AnimSequence
        anim_sequence = asset_tools.create_asset(name, path, anim_seq_class, anim_factory)
        asset = asset_registry.get_asset_by_object_path(anim_sequence.get_path_name())
        # Anim Sequence Object.. asset? idk
        
        # anim_sequence = unreal.load_asset("/Game/Anim_test", anim_seq_class)
        
        export_option = unreal.AnimSeqExportOption() 
        export_option.export_transforms = True
        export_option.export_morph_targets = True
        export_option.export_attribute_curves = True
        export_option.export_material_curves = True
        export_option.record_in_world_space = True
        export_option.evaluate_all_skeletal_mesh_components = True 
        export_option.transact_recording = True
        
        s.export_anim_sequence(world, level_sequence, anim_sequence, export_option, binding, create_link=1)
        # link = s.link_anim_sequence(level_sequence, anim_sequence, export_option, binding)
        exported_assets.append(asset)
        anim_seqs.append(anim_sequence)
    export_fbxs(exported_assets=exported_assets, anim_seqs=anim_seqs)    
    # export fbx for all exported_assets
    return  

def export_fbxs(exported_assets, anim_seqs):
    fe = unreal.FbxExportOption()
    bt = unreal.MovieSceneBakeType.BAKE_TRANSFORMS
    bn = unreal.MovieSceneBakeType.NONE
    fe.ascii = 0
    fe.bake_actor_animation = bn
    fe.bake_camera_and_light_animation = bt
    fe.collision = 0
    fe.export_local_time = 1
    fe.export_morph_targets = 0
    fe.export_preview_mesh = 1
    fe.export_source_mesh = 0
    fe.force_front_x_axis = 0
    fe.level_of_detail = 0
    fe.map_skeletal_motion_to_root = 0
    fe.vertex_color = 0
    asset_tools.export_assets([x.package_name for x in exported_assets], main_path) # Works but makes stupid path, trying to avoid
    move_game_files(main_path)

    
def move_game_files(path):
    base_dir = path
    game_folder = os.path.join(base_dir, "Game")
        
    # Recursively find all .fbx files in the Game folder
    for root, dirs, files in os.walk(game_folder):

        for filename in files:
            if filename.lower().endswith(".fbx"):
                # Construct full source and destination paths
                source_path = os.path.join(root, filename)
                dest_path = os.path.join(base_dir, filename)
                
                # Move the file
                shutil.move(source_path, dest_path)
                print(f"Moved: {filename} from {root} to {base_dir}")

    print("All .fbx files have been moved to the animations folder.")
    shutil.rmtree(game_folder)
    print(f"Removed the folder: {game_folder}")
    

My path config module called path_config.py

import unreal
import os
ll = unreal.LevelSequenceEditorBlueprintLibrary

def change_shot_name(shot):
    if("pal" in shot.lower()):
        return shot.replace("Pal", "shot")
    elif("dock" in shot.lower()):
        return shot.replace("Dock_sh", "SQ")
    else:
        return shot
    
    
def get_output_dir(shot_name):
    path = main_path
    if(os.path.exists(path)==False):
        os.makedirs(path)
    versions = os.listdir(path)
    if(len(versions)==0):
        os.makedirs(os.path.join(path, "v0001"))
        path = os.path.join(path, "v0001")
        return path
    else:
        sorted_versions = [int(v.replace("v", "")) for v in versions]
        latest_version = max(sorted_versions)
        latest_version += 1
        path = os.path.join(path, "v{:04d}".format(latest_version))
    return path

main_path = "L:/ALL HOUDINI FILES/ASC_INSPIRATION/{main_project}/{project}/{shot}/"
lev = ll.get_focused_level_sequence()
shot = lev.get_name()
# shot = '_'.join(shot.split("_")[0:2])
shot = change_shot_name(shot)
main_project, project = unreal.Paths.get_project_file_path().split("/")[-2].split("_") #FinalBattle2
if(main_project.lower() == "exo"): main_project = "Exodus"
main_path = main_path.format(main_project=main_project, project=project, shot=shot)