8
$\begingroup$

Part of my addon's functionality is to replace local materials with their counterparts in linked libraries / assets.

In order to check if a material of the same name as a local material is available as an asset in the asset browser, I need some way to iterate through all assets of a given UserAssetLibrary and check for matches.

Unfortunately, I've not been able to find a method to get all assets contained in a UserAssetLibrary so far. After browsing the Data API it also doesn't seem like those are stored anywhere in the current BLEND file in the first place.

I suspect that since the asset browser seems to be a version of the file browser, I need to instead look into methods of getting a list of all files listed in the file browser. What I've found there has mostly been about finding the selcted file(s) though, not all files.

see:

Part of the function where this would be used below. Currently it only checks for linked files, but assets in the browser do not show up as materials in bpy.data.materials, and as such I cannot check for matches.

        for slot in obj.material_slots:
            if slot.material is not None and slot.material.library is None:
                old_material = slot.material
                new_material = None
                
                for mtl in bpy.data.materials:
                    # If an object is imported that has a material that already exists in the scene, it is numbered.
                    # Thus checking the substring of the name is necessary to catch all of them.
                    if mtl.library != None and ( mtl.name == old_material.name or mtl.name == old_material.name[:-4] ) and old_material.seut.overrideMatLib == False:
                        new_material = mtl
                        break                            

                if new_material != None:
                    slot.material = new_material
                    if old_material not in mtl_to_delete:
                        mtl_to_delete.append(old_material)
$\endgroup$

2 Answers 2

3
$\begingroup$

The asset libraries are stored in the preferences filepaths. Preferences are accessed with the current context.

An User Asset Library object holds the name of the library and the path to its root directory.

You can load the contents with bpy.data.libraries.load and the argument assets_only=True to filter only assets. Thanks to viktor for pointing it out.

import bpy
from pathlib import Path

prefs = bpy.context.preferences
filepaths = prefs.filepaths
asset_libraries = filepaths.asset_libraries

for asset_library in asset_libraries:
    library_name = asset_library.name
    library_path = Path(asset_library.path)
    blend_files = [fp for fp in library_path.glob("**/*.blend") if fp.is_file()]
    print(f"Checking the content of library '{library_name}' :")
    for blend_file in blend_files:
        with bpy.data.libraries.load(str(blend_file), assets_only=True) as (file_contents, _):
            # Note this will print out the names of the objects,
            # Not the actual objects
            print(file_contents.objects)
            print(file_contents.materials)
            print(file_contents.worlds)
            # etc.
$\endgroup$
2
$\begingroup$

When you are loading a library with bpy.data.libraries.load(str(blend_file)), you can use assets_only=True keyword in order to load only assets instead of all contents.

$\endgroup$
1
  • $\begingroup$ Ooh nice find, thanks for sharing ! I modified my answer to take it into account. Cheers $\endgroup$
    – Gorgious
    Commented Jul 20, 2022 at 13:15

You must log in to answer this question.

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