Add selected data-block(s) in Outliner to the library on current blend file
Here is the script to achieve this:
- Make sure you have a library Path
Make sure the current blend file is saved
Run Script in Text Editor
import bpy
from pathlib import Path
from os.path import join as os_path_join
from bpy.props import *
from bpy.types import Operator, Panel
from bpy.utils import register_class, unregister_class
from collections import defaultdict
from bpy.app.handlers import persistent
id_type_to_blend_data = {
"Action": "actions",
"Armature": "armatures",
"Brush": "brushes",
"CacheFile": "cache_files",
"Camera": "cameras",
"Curve": "curves",
"VectorFont": "fonts",
"GreasePencil": "grease_pencils",
"Collection": "collections",
"Image": "images",
"Key": "shape_keys",
"PointLight": "lights",
"FreestyleLineStyle": "linestyles",
"Lattice": "lattices",
"Material": "materials",
"Mesh": "meshes",
"MovieClip": "movieclips",
"GeometryNodeTree": "node_groups",
"CompositorNodeTree": "node_groups",
"ShaderNodeTree": "node_groups",
"TextureNodeTree": "node_groups",
"Object": "objects",
"PaintCurve": "paint_curves",
"Palette": "palettes",
"ParticleSettings": "particles",
"LightProbe": "lightprobes",
"Scene": "scenes",
"Speaker": "speakers",
"Text": "texts",
"ImageTexture": "textures",
"WindowManager": "window_managers",
"World": "worlds",
"WorkSpace": "workspaces",
}
id_type_to_inner = {
"Action": "Action",
"Armature": "Armature",
"Brush": "Brush",
"CacheFile": "CacheFile",
"Camera": "Camera",
"Curve": "Curve",
"VectorFont": "Font",
"GreasePencil": "GPencil",
"Collection": "Collection",
"Image": "Image",
"PointLight": "Light",
"FreestyleLineStyle": "FreestyleLineStyle",
"Lattice": "Lattice",
"Material": "Material",
"Mesh": "Mesh",
"MovieClip": "MovieClip",
"GeometryNodeTree": "NodeTree",
"CompositorNodeTree": "NodeTree",
"ShaderNodeTree": "NodeTree",
"TextureNodeTree": "NodeTree",
"Object": "Object",
"PaintCurve": "PaintCurve",
"Palette": "Palette",
"ParticleSettings": "ParticleSettings",
"LightProbe": "LightProbe",
"Scene": "Scene",
"Speaker": "Speaker",
"Text": "Text",
"ImageTexture": "Texture",
"World": "World",
"WorkSpace": "WorkSpace",
}
def get_outliner_area_region():
try:
success = False
for area in bpy.context.screen.areas:
if area.type == "OUTLINER":
success = True
break
if not success: return None, None
success = False
for region in area.regions:
if region.type == "WINDOW":
success = True
break
if not success: return None, None
return area, region
except:
return None, None
def get_enum_items(self, context):
try:
lib_ind = bpy.context.preferences.filepaths.asset_libraries
except:
get_enum_items.path_items = []
get_enum_items.path_items = [(str(r), p.path, "") for r, p in enumerate(lib_ind)]
return get_enum_items.path_items
get_enum_items.path_items = []
class NPanel(Panel):
bl_label = "Library Tool"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Library Tool"
bl_idname = "LIB_PT_TOOL"
def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(context.scene, "lib_ind")
col.prop(context.scene, "lib_blend")
col.operator(AddLib.bl_idname)
class AddLib(Operator):
bl_idname = "view3d.add_lib"
bl_label = "Lib Add from Outliner"
bl_description = "Add Library from Outliner selected data-blocks"
bl_options = {'REGISTER', 'UNDO'}
def error_end(self, s):
self.report({'WARNING'}, s)
return {'CANCELLED'}
def invoke(self, context, event):
global current_path
current_path = bpy.data.filepath
if not current_path: return self.error_end("Need Save current blend file first, cancelled")
try:
lib_paths = bpy.context.preferences.filepaths.asset_libraries
except:
return self.error_end("Library Paths not find, cancelled")
if not lib_paths: return self.error_end("No Library Paths, cancelled")
try:
tar_ind = int(context.scene.lib_ind)
tar_path = Path(lib_paths[tar_ind].path)
except:
return self.error_end("Target Path not find, cancelled")
success = False
for blend in tar_path.glob("**/*.blend"):
if not blend.is_file(): continue
if blend.stem == context.scene.lib_blend:
success = True
break
if not success: return self.error_end("Could not find the library blend file, please add an empty blend file to the library directory first.")
area, region = get_outliner_area_region()
if area and region:
with bpy.context.temp_override(area=area, region=region):
ids = [(e.name, type(e).__name__) for e in bpy.context.selected_ids if hasattr(e, "asset_mark") and type(e).__name__ in id_type_to_inner]
else:
return self.error_end("Outliner not find, cancelled")
if not ids: return self.error_end("No Markable Selected data-blocks in Outliner, cancelled")
global ddict, lib_blend
lib_blend = blend
ddict = defaultdict(list)
for name, ty in ids:
ddict[ty].append(name)
print("load file")
bpy.app.handlers.load_post.append(load_post)
bpy.ops.wm.open_mainfile(filepath=str(blend))
print("end")
return {'FINISHED'}
@persistent
def load_post(dummy):
print("load_post")
old_names = {}
for ty, names in ddict.items():
old_names[ty] = {e.name for e in getattr(bpy.data, id_type_to_blend_data[ty])}
inner = id_type_to_inner[ty]
for name in names:
print(name)
bpy.ops.wm.append(
filepath=os_path_join(current_path, inner, name),
directory=os_path_join(current_path, inner),
filename=name)
blend_data = bpy.data
for ty in ddict:
names = old_names[ty]
for obj in getattr(blend_data, id_type_to_blend_data[ty]):
if obj.name not in names:
obj.asset_mark()
bpy.ops.wm.save_as_mainfile(filepath=str(lib_blend))
bpy.app.handlers.load_post.remove(load_post)
bpy.ops.wm.open_mainfile(filepath=current_path)
reg_cls = (
NPanel,
AddLib,
)
def register():
for cls in reg_cls:
register_class(cls)
bpy.types.Scene.lib_ind = EnumProperty(name="Library Paths", items=get_enum_items)
bpy.types.Scene.lib_blend = StringProperty(name="Library Blend file", default="_lib_")
def unregister():
for cls in reg_cls:
unregister_class(cls)
if __name__ == "__main__":
register()
- Choose a path in Library Tool category in 3D Viewport N-panel
- Add an empty blend file to this directory and rename to
_lib_
- Open 1 Outliner and go to blend file category
- Selct material(s)
- Press the Button in N-panel
It will open the _lib_.blend
and append the selected data-block(s), mark the assets, save, and open the current blend file again.