""" Plugin for making an asset library of all blender file found in a folder """ from asset_library.plugins.scan_folder import ScanFolder from asset_library.core.bl_utils import load_datablocks from asset_library.core.template import Template import bpy from bpy.props import (StringProperty, IntProperty, BoolProperty) import re from pathlib import Path from itertools import groupby import uuid import os import shutil import json import time from pprint import pprint class Conform(ScanFolder): name = "Conform" source_directory : StringProperty(subtype='DIR_PATH') target_template_file : StringProperty() target_template_info : StringProperty() target_template_image : StringProperty() target_template_video : StringProperty() def draw_prefs(self, layout): layout.prop(self, "source_directory", text="Source : Directory") col = layout.column(align=True) col.prop(self, "source_template_file", icon='COPY_ID', text='Template file') col.prop(self, "source_template_image", icon='COPY_ID', text='Template image') col.prop(self, "source_template_video", icon='COPY_ID', text='Template video') col.prop(self, "source_template_info", icon='COPY_ID', text='Template info') col = layout.column(align=True) col.prop(self, "target_template_file", icon='COPY_ID', text='Target : Template file') col.prop(self, "target_template_image", icon='COPY_ID', text='Template image') col.prop(self, "target_template_video", icon='COPY_ID', text='Template video') col.prop(self, "target_template_info", icon='COPY_ID', text='Template info') def get_asset_bundle_path(self, asset_data): """Template file are relative""" src_directory = Path(self.source_directory).resolve() src_template_file = Template(self.source_template_file) asset_path = Path(asset_data['filepath']).as_posix() asset_path = self.format_path(asset_path) rel_path = asset_path.relative_to(src_directory).as_posix() field_data = src_template_file.parse(rel_path) #field_data = {f"catalog_{k}": v for k, v in field_data.items()} # Change the int in the template by string to allow format #target_template_file = re.sub(r'{(\d+)}', r'{cat\1}', self.target_template_file) format_data = self.format_asset_data(asset_data) #format_data['asset_name'] = format_data['asset_name'].lower().replace(' ', '_') path = Template(self.target_template_file).format(format_data, **field_data).with_suffix('.blend') path = Path(self.bundle_directory, path).resolve() return path def set_asset_preview(self, asset, asset_data): '''Load an externalize image as preview for an asset using the target template''' image_template = self.target_template_image if not image_template: return asset_path = self.get_asset_bundle_path(asset_data) image_path = self.find_path(image_template, asset_data, filepath=asset_path) if image_path: with bpy.context.temp_override(id=asset): bpy.ops.ed.lib_id_load_custom_preview( filepath=str(image_path) ) else: print(f'No image found for {image_template} on {asset.name}') if asset.preview: return asset.preview def generate_previews(self, cache_diff): print('Generate previews...') # if cache in (None, ''): # cache = self.fetch() # elif isinstance(cache, (Path, str)): # cache = self.read_cache(cache) if isinstance(cache, (Path, str)): cache_diff = LibraryCacheDiff(cache_diff) #TODO Support all multiple data_type for asset_info in cache: if asset_info.get('type', self.data_type) == 'FILE': self.generate_blend_preview(asset_info) else: self.generate_asset_preview(asset_info) def generate_asset_preview(self, asset_info): """Only generate preview when conforming a library""" #print('\ngenerate_preview', asset_info['filepath']) scn = bpy.context.scene vl = bpy.context.view_layer #Creating the preview for collection, object or material #camera = scn.camera data_type = self.data_type #asset_info['data_type'] asset_path = self.format_path(asset_info['filepath']) # Check if a source video exists and if so copying it in the new directory if self.source_template_video and self.target_template_video: for asset_data in asset_info['assets']: asset_data = dict(asset_data, filepath=asset_path) dst_asset_path = self.get_asset_bundle_path(asset_data) dst_video_path = self.format_path(self.target_template_video, asset_data, filepath=dst_asset_path) if dst_video_path.exists(): print(f'The dest video {dst_video_path} already exist') continue src_video_path = self.find_path(self.source_template_video, asset_data) if src_video_path: print(f'Copy video from {src_video_path} to {dst_video_path}') self.copy_file(src_video_path, dst_video_path) # Check if asset as a preview image or need it to be generated asset_data_names = {} if self.target_template_image: for asset_data in asset_info['assets']: asset_data = dict(asset_data, filepath=asset_path) name = asset_data['name'] dst_asset_path = self.get_asset_bundle_path(asset_data) dst_image_path = self.format_path(self.target_template_image, asset_data, filepath=dst_asset_path) if dst_image_path.exists(): print(f'The dest image {dst_image_path} already exist') continue # Check if a source image exists and if so copying it in the new directory if self.source_template_image: src_image_path = self.find_path(self.source_template_image, asset_data) if src_image_path: if src_image_path.suffix == dst_image_path.suffix: self.copy_file(src_image_path, dst_image_path) else: print(src_image_path) self.save_image(src_image_path, dst_image_path, remove=True) continue #Store in a dict all asset_data that does not have preview asset_data_names[name] = dict(asset_data, image_path=dst_image_path) if not asset_data_names:# No preview to generate return print('Making Preview for', list(asset_data_names.keys())) asset_names = list(asset_data_names.keys()) assets = self.load_datablocks(asset_path, names=asset_names, link=True, type=data_type) for asset in assets: if not asset: continue asset_data = asset_data_names[asset.name] image_path = asset_data['image_path'] if asset.preview: print(f'Writing asset preview to {image_path}') self.write_preview(asset.preview, image_path) continue if data_type == 'COLLECTION': bpy.ops.object.collection_instance_add(name=asset.name) bpy.ops.view3d.camera_to_view_selected() instance = vl.objects.active #scn.collection.children.link(asset) scn.render.filepath = str(image_path) print(f'Render asset {asset.name} to {image_path}') bpy.ops.render.render(write_still=True) #instance.user_clear() asset.user_clear() bpy.data.objects.remove(instance) bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)