2
$\begingroup$

Similar to Python : Get selected objects in outliner

How can one access the assets that are currently selected in the asset browser editor using the python API ?

I assume it should be available on a per-editor basis since, contrary to the outliner where selection state is shared between all editors, different asset browser editors can have different asset selection states :

enter image description here

$\endgroup$
8
  • $\begingroup$ i cannot even find the "right" area type 😱 TypeError: bpy_struct: item.attr = val: enum "ASSET_BROWSER" not found in ('EMPTY', 'VIEW_3D', 'IMAGE_EDITOR', 'NODE_EDITOR', 'SEQUENCE_EDITOR', 'CLIP_EDITOR', 'DOPESHEET_EDITOR', 'GRAPH_EDITOR', 'NLA_EDITOR', 'TEXT_EDITOR', 'CONSOLE', 'INFO', 'TOPBAR', 'STATUSBAR', 'OUTLINER', 'PROPERTIES', 'FILE_BROWSER', 'SPREADSHEET', 'PREFERENCES') $\endgroup$
    – Chris
    Commented Jan 11, 2022 at 16:38
  • $\begingroup$ have a look at startup/bl_operators/assets.py. It looks like you need something like active_asset = SpaceAssetInfo.get_active_asset(context) There only seems to be the concept of active and not selected? $\endgroup$ Commented Jan 11, 2022 at 16:50
  • $\begingroup$ @Chris Yeah it's not .type it's .ui_type... was fooled by it too ! $\endgroup$
    – Gorgious
    Commented Jan 11, 2022 at 18:53
  • 1
    $\begingroup$ The quote from the docs: "Avoid using this, it will be replaced..." made my day :D $\endgroup$
    – brockmann
    Commented Feb 3, 2022 at 11:36
  • 1
    $\begingroup$ @brockmann Fast forward in 5 years when this quote is still there in the docs... xD $\endgroup$
    – Gorgious
    Commented Feb 3, 2022 at 13:00

2 Answers 2

5
$\begingroup$

Blender 4.0+

Blender 4.0 introduces bpy.types.AssetRepresentation, bpy.context.selected_assets, bpy.context.asset we can use to our advantage.

import bpy


class PrintSelectedAssets(bpy.types.Operator):
    bl_idname = "asset.print_selected_assets"
    bl_label = "Print Selected Assets"

    @classmethod
    def poll(cls, context):
        return context.selected_assets

    def execute(self, context):
        for asset_representation in context.selected_assets:
            print(f"{asset_representation.full_path=}")
            print(f"{asset_representation.full_library_path=}")
            print(f"{asset_representation.id_type=}")
            print(f"{asset_representation.name=}")
            # This will be None if the asset is not located in current file :
            print(f"{asset_representation.local_id=}")
        print(context.asset)  # Active asset

        return {"FINISHED"}


def display_button(self, context):
    self.layout.operator(PrintSelectedAssets.bl_idname)


def register():
    bpy.utils.register_class(PrintSelectedAssets)
    bpy.types.ASSETBROWSER_MT_editor_menus.append(display_button)


def unregister():
    bpy.types.ASSETBROWSER_MT_editor_menus.remove(display_button)
    bpy.utils.unregister_class(PrintSelectedAssets)


if __name__ == "__main__":
    register()

Blender 3.6

I found the answer while researching another answer.

It's actually an attribute of File context which unless I'm mistaken does require the piece of code to be executed inside the context of the asset browser.

Here's the slightly altered script that adds a button in the Asset Browser header that, when clicked, outputs some information about the selected assets in the console :

import bpy
from pathlib import Path


class PrintSelectedAssets(bpy.types.Operator):
    bl_idname = "asset.print_selected_assets"
    bl_label = "Print Selected Assets"

    @classmethod
    def poll(cls, context):
        return context.selected_asset_files

    def execute(self, context):
        current_library_name = context.area.spaces.active.params.asset_library_ref
        if current_library_name != "LOCAL":  # NOT Current file
            library_path = Path(context.preferences.filepaths.asset_libraries.get(current_library_name).path)

        for asset_file in context.selected_asset_files:
            if current_library_name == "LOCAL":
                print(f"{asset_file.local_id.name} is selected in the asset browser. (Local File)")
            else:
                asset_fullpath = library_path / asset_file.relative_path
                print(f"{asset_fullpath} is selected in the asset browser.")
                print(f"It is located in a user library named '{current_library_name}'")
            
        return {"FINISHED"}


def display_button(self, context):
    self.layout.operator(PrintSelectedAssets.bl_idname)


def register():
    bpy.utils.register_class(PrintSelectedAssets)
    bpy.types.ASSETBROWSER_MT_editor_menus.append(display_button)


def unregister():
    bpy.types.ASSETBROWSER_MT_editor_menus.remove(display_button)
    bpy.utils.unregister_class(PrintSelectedAssets)


if __name__ == "__main__":
    register()
$\endgroup$
2
  • $\begingroup$ context should be the context of the asset browser? context.selected_assets won't work out of that context I think $\endgroup$
    – Noob Cat
    Commented Mar 10 at 12:14
  • 1
    $\begingroup$ @NoobCat well, yes, because you can have multiple asset browsers open at the same time with different selection states $\endgroup$
    – Gorgious
    Commented Mar 11 at 9:35
3
$\begingroup$

How to get it from the window area

>>> bpy.context.screen.areas[3].spaces.active.params.filename
'geometry_nodes\\procedural_hair_node_assets.blend\\NodeTree\\Braid Hair Curves'

enter image description here

If the asset browser area on the window has been identified, it is useful to learn the information from the console.

In the example, it is "bpy.context.screen.areas[3]".

but the number will vary depending on the environment.

The area can be identified

by https://github.com/Pullusb/devTools

which is an add-on that provides a convenient button on the console.

enter image description here

Acquire information via operator

We already have the code for the answer, but some of the context data accesses have "mechanisms that can only be accessed via the operator".

For example, the following access is only accessible on the operator and not in the area

https://docs.blender.org/api/current/bpy.types.FileSelectEntry.html

Therefore, it is necessary to set up an access button in the area from which to obtain the divestment. Of course, if you place this button anywhere other than on the asset browser, it will not work.

import bpy
from pathlib import Path

# breakpoint = bpy.types.BP_PT_bp.bp
class PrintSelectedAssets(bpy.types.Operator):
    bl_idname = "asset.print_selected_assets"
    bl_label = "Print Selected Assets"

    @classmethod
    def poll(cls, context):
        return context.selected_asset_files

    def execute(self, context):
        for asset in context.selected_asset_files:
            asset_re_path=asset.relative_path
            print("### asset path :",asset_re_path)
            
        return {"FINISHED"}


def display_button(self, context):
    self.layout.operator(PrintSelectedAssets.bl_idname)


def register():
    bpy.utils.register_class(PrintSelectedAssets)
    bpy.types.ASSETBROWSER_MT_editor_menus.append(display_button)


def unregister():
    bpy.utils.unregister_class(PrintSelectedAssets)
    bpy.types.ASSETBROWSER_MT_editor_menus.remove(display_button)


if __name__ == "__main__":
    register()

enter image description here

enter image description here


For blender4.0

There seems to have been a change in the API. The following are the changes

From selected_asset_files

To selected_assets

https://docs.blender.org/api/current/bpy.context.html#bpy.context.selected_assets

https://docs.blender.org/api/current/bpy.types.AssetRepresentation.html#bpy.types.AssetRepresentation

import bpy
from pathlib import Path

class PrintSelectedAssets(bpy.types.Operator):
    bl_idname = "asset.print_selected_assets"
    bl_label = "Print Selected Assets"


    @classmethod
    def poll(cls, context):
        
        
        return context.selected_assets

    def execute(self, context):
        for asset in context.selected_assets:

        
            asset_path=asset.full_path
            
            print("### asset :",asset_path)
            
        return {"FINISHED"}


def display_button(self, context):
    self.layout.operator(PrintSelectedAssets.bl_idname)


def register():
    bpy.utils.register_class(PrintSelectedAssets)
    bpy.types.ASSETBROWSER_MT_editor_menus.append(display_button)


def unregister():
    for f in bpy.types.ASSETBROWSER_MT_editor_menus._dyn_ui_initialize():
        if f.__name__ == display_button.__name__:
            bpy.types.ASSETBROWSER_MT_editor_menus.remove(f)
            return
        

if __name__ == "__main__":
    unregister()
    register()
$\endgroup$
2
  • $\begingroup$ It works, but how to get all selected assets? It return only one (the last)... $\endgroup$
    – Bicukow
    Commented Dec 27, 2023 at 13:44
  • 1
    $\begingroup$ @Bicukow I have made an addition to my answer. Please check it. $\endgroup$
    – mml
    Commented Dec 28, 2023 at 22:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .