feat: add 1.0.0 version for blender 4.4.3
This commit is contained in:
177
__init__.py
Normal file
177
__init__.py
Normal file
@@ -0,0 +1,177 @@
|
||||
import bpy
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
def get_external_datablocks():
|
||||
"""Return a list of external data-blocks"""
|
||||
out = []
|
||||
for attr in dir(bpy.data):
|
||||
collections = getattr(bpy.data, attr)
|
||||
if isinstance(collections, type(bpy.data.objects)):
|
||||
for data_block in collections:
|
||||
if (isinstance(data_block, bpy.types.Image) or isinstance(data_block, bpy.types.MovieClip)) and hasattr(data_block, "filepath"):
|
||||
if hasattr(data_block, "packed_file"):
|
||||
print(f"[{'P' if data_block.packed_file is not None else ' '}] [{data_block.__class__}] {data_block.source}: {data_block.filepath}")
|
||||
else:
|
||||
print(f" [{data_block.__class__}] {data_block.source}: {data_block.filepath}")
|
||||
out.append(data_block)
|
||||
|
||||
return out
|
||||
|
||||
def collect_data(data_block, dirpath, sequence_in_subfolder=True):
|
||||
"""Copy data into a given folder. Only work for 'MOVIE' and 'SEQUENCE' data-blocks"""
|
||||
if data_block.source == "MOVIE":
|
||||
source_path = os.path.normpath(bpy.path.abspath(data_block.filepath))
|
||||
dest_path = os.path.join(dirpath, os.path.basename(source_path))
|
||||
print(f"Copying FROM '{source_path}' TO '{dest_path}'")
|
||||
shutil.copyfile(source_path, dest_path)
|
||||
|
||||
elif data_block.source == "SEQUENCE":
|
||||
source_dirpath = os.path.dirname(os.path.normpath(bpy.path.abspath(data_block.filepath)))
|
||||
if sequence_in_subfolder:
|
||||
dest_dirpath = os.path.join(dirpath, os.path.basename(source_dirpath))
|
||||
else:
|
||||
dest_dirpath = dirpath
|
||||
if not os.path.isdir(dest_dirpath):
|
||||
os.mkdir(dest_dirpath)
|
||||
print(f"Copying FROM '{source_dirpath}' TO '{dest_dirpath}'")
|
||||
for filename in os.listdir(source_dirpath):
|
||||
if os.path.splitext(filename)[1] != ".db":
|
||||
shutil.copyfile(os.path.join(source_dirpath, filename), os.path.join(dest_dirpath, filename))
|
||||
|
||||
def get_source_datablocks(datablocks, source):
|
||||
"""Return the list data-blocks which are of specific sources"""
|
||||
out = []
|
||||
for data_block in datablocks:
|
||||
if data_block.source == source:
|
||||
out.append(data_block)
|
||||
return out
|
||||
|
||||
def main():
|
||||
external_datablocks = get_external_datablocks()
|
||||
print(f"{len(external_datablocks)} external data-blocks")
|
||||
|
||||
bl_dirpath = os.path.dirname(bpy.data.filepath)
|
||||
bl_filename = os.path.splitext(os.path.basename(bpy.data.filepath))[0]
|
||||
if len(external_datablocks) > 0:
|
||||
# Create a subfolder per blend file
|
||||
external_data_dirpath = os.path.join(bl_dirpath, f"{bl_filename}-external_data")
|
||||
if not os.path.isdir(external_data_dirpath):
|
||||
os.mkdir(external_data_dirpath)
|
||||
|
||||
for data_block in external_datablocks:
|
||||
collect_data(data_block, external_data_dirpath)
|
||||
|
||||
|
||||
class WM_OT_ConsolidateProject(bpy.types.Operator):
|
||||
"""Open the consolidation dialog box"""
|
||||
bl_label = "Consolidate Project"
|
||||
bl_idname = "wm.consolidate_project"
|
||||
|
||||
my_purge_unused_data: bpy.props.BoolProperty(name="Purge Unused Data", default=True)
|
||||
my_pack_ressources: bpy.props.BoolProperty(name="Pack External Ressources", default=True)
|
||||
my_collect_movies: bpy.props.BoolProperty(name="Collect Movies", default=True)
|
||||
my_collect_sequences: bpy.props.BoolProperty(name="Collect Image Sequences", default=True)
|
||||
my_sequences_in_subfolders: bpy.props.BoolProperty(name="Save Image Sequences in Sub-Folders", default=False)
|
||||
|
||||
my_external_datablocks = []
|
||||
my_external_movies = []
|
||||
my_external_sequences = []
|
||||
|
||||
my_dirpath = None
|
||||
my_filename = None
|
||||
my_external_data_dirpath = None
|
||||
|
||||
def execute(self, context):
|
||||
if self.my_purge_unused_data:
|
||||
bpy.ops.outliner.orphans_purge()
|
||||
if self.my_pack_ressources:
|
||||
bpy.ops.file.pack_all()
|
||||
if self.my_collect_movies:
|
||||
for data_block in self.my_external_movies:
|
||||
collect_data(data_block, self.my_external_data_dirpath)
|
||||
if self.my_collect_sequences:
|
||||
for data_block in self.my_external_sequences:
|
||||
collect_data(data_block, self.my_external_data_dirpath, self.my_sequences_in_subfolders)
|
||||
self.report({'INFO'}, "Consolidation complete")
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.my_external_datablocks = get_external_datablocks()
|
||||
self.my_external_movies = get_source_datablocks(self.my_external_datablocks, source='MOVIE')
|
||||
self.my_external_sequences = get_source_datablocks(self.my_external_datablocks, source='SEQUENCE')
|
||||
|
||||
self.my_dirpath = os.path.dirname(bpy.data.filepath)
|
||||
self.my_filename = os.path.splitext(os.path.basename(bpy.data.filepath))[0]
|
||||
self.my_external_data_dirpath = os.path.join(self.my_dirpath, f"{self.my_filename}-external_data")
|
||||
|
||||
if not os.path.isdir(self.my_external_data_dirpath):
|
||||
os.mkdir(self.my_external_data_dirpath)
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Cleaning and Packing Ressources", icon="PACKAGE")
|
||||
row = col.row()
|
||||
row.prop(self, "my_purge_unused_data")
|
||||
row = col.row()
|
||||
row.prop(self, "my_pack_ressources")
|
||||
|
||||
layout.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Collect movies and image sequences", icon="FILE_MOVIE")
|
||||
|
||||
row = col.row()
|
||||
row.prop(self, "my_collect_movies")
|
||||
row = col.row()
|
||||
row.prop(self, "my_collect_sequences")
|
||||
row = col.row()
|
||||
row.prop(self, "my_sequences_in_subfolders", icon="NEWFOLDER")
|
||||
row.enabled = self.my_collect_sequences
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="External data-blocks")
|
||||
for data_block in self.my_external_datablocks:
|
||||
row = box.row()
|
||||
display_data_block(data_block, row)
|
||||
|
||||
|
||||
def display_data_block(data_block, layout):
|
||||
split = layout.split(factor=.9)
|
||||
if data_block.source in ["SEQUENCE", "MOVIE"]:
|
||||
split.label(text=f"{data_block.name}", icon="FILE_MOVIE")
|
||||
#split.label(text="", icon="WARNING_LARGE")
|
||||
else:
|
||||
split.label(text=f"{data_block.name}", icon="FILE_IMAGE")
|
||||
if hasattr(data_block, "packed_file"):
|
||||
if data_block.packed_file is not None:
|
||||
split.label(text=f"", icon="PACKAGE")
|
||||
else:
|
||||
split.label(text=f"", icon="UGLYPACKAGE")
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(WM_OT_ConsolidateProject.bl_idname, text="ETNCL - Consolidate", icon="PACKAGE")
|
||||
self.layout.separator()
|
||||
|
||||
blender_classes = [
|
||||
WM_OT_ConsolidateProject
|
||||
]
|
||||
|
||||
def register():
|
||||
for cls in blender_classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_external_data.prepend(menu_func_import)
|
||||
|
||||
def unregister():
|
||||
for cls in blender_classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_external_data.remove(menu_func_import)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
Reference in New Issue
Block a user