asset_library/plugins/conform.py

216 lines
8.1 KiB
Python
Raw Normal View History

2023-01-17 18:05:22 +01:00
"""
Plugin for making an asset library of all blender file found in a folder
"""
2024-07-04 11:53:58 +02:00
from asset_library.plugins.scan_folder import ScanFolder
from asset_library.core.bl_utils import load_datablocks
from asset_library.core.template import Template
2023-01-17 18:05:22 +01:00
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
2023-05-10 09:59:07 +02:00
def generate_previews(self, cache_diff):
2023-01-17 18:05:22 +01:00
print('Generate previews...')
2023-05-10 09:59:07 +02:00
# 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)
2023-01-17 18:05:22 +01:00
#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)