""" Plugin for making an asset library of all blender file found in a folder """ from asset_library.adapters.adapter import AssetLibraryAdapter from asset_library.common.bl_utils import load_datablocks from asset_library.common.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 class ScanFolderLibrary(AssetLibraryAdapter): name = "Scan Folder" source_directory : StringProperty(subtype='DIR_PATH') template_file : StringProperty() template_image : StringProperty() template_video : StringProperty() template_description : StringProperty() def get_asset_path(self, name, catalog, directory=None): directory = directory or self.source_directory catalog = self.norm_file_name(catalog) name = self.norm_file_name(name) return Path(directory, self.get_asset_relative_path(name, catalog)) def get_image_path(self, name, catalog, filepath): catalog = self.norm_file_name(catalog) name = self.norm_file_name(name) return self.format_path(self.template_image, dict(name=name, catalog=catalog, filepath=filepath)) def get_video_path(self, name, catalog, filepath): catalog = self.norm_file_name(catalog) name = self.norm_file_name(name) return self.format_path(self.template_video, dict(name=name, catalog=catalog, filepath=filepath)) def format_asset_description(self, asset_description, asset_path): asset_path = self.prop_rel_path(asset_path, 'source_directory') modified = asset_description.get('modified', time.time_ns()) if self.data_type == 'FILE': return dict( filepath=asset_path, author=asset_description.get('author'), modified=modified, catalog=asset_description['catalog'], tags=[], description=asset_description.get('description', ''), type=self.data_type, image=self.template_image, name=asset_description['name'] ) return dict( filepath=asset_path, modified=modified, library_id=self.library.id, assets=[dict( catalog=asset_data.get('catalog', asset_description['catalog']), author=asset_data.get('author'), metadata=asset_data.get('metadata', {}), description=asset_data.get('description', ''), tags=asset_data.get('tags', []), type=self.data_type, image=self.template_image, video=self.template_video, name=asset_data['name']) for asset_data in asset_description['assets'] ] ) def fetch(self): """Gather in a list all assets found in the folder""" print(f'Fetch Assets for {self.library.name}') source_directory = Path(self.source_directory) template_file = Template(self.template_file) catalog_data = self.read_catalog(directory=source_directory) catalog_ids = {v['id']: k for k, v in catalog_data.items()} cache = self.read_cache() or [] print(f'Search for blend using glob template: {template_file.glob_pattern}') print(f'Scanning Folder {source_directory}...') new_cache = [] for asset_path in template_file.glob(source_directory):#sorted(blend_files): source_rel_path = self.prop_rel_path(asset_path, 'source_directory') modified = asset_path.stat().st_mtime_ns # Check if the asset description as already been cached asset_description = next((a for a in cache if a['filepath'] == source_rel_path), None) if asset_description and asset_description['modified'] >= modified: print(asset_path, 'is skipped because not modified') new_cache.append(asset_description) continue rel_path = asset_path.relative_to(source_directory).as_posix() field_data = template_file.parse(rel_path) catalogs = [v for k,v in sorted(field_data.items()) if k.isdigit()] #catalogs = [c.replace('_', ' ').title() for c in catalogs] asset_name = field_data.get('asset_name', asset_path.stem) asset_description = { "name": asset_name, "catalog": '/'.join(catalogs), "assets": [], 'modified': modified } if self.data_type == 'FILE': asset_description = self.format_asset_description(asset_description, asset_path) new_cache.append(asset_description) continue # Now check if there is a asset description file asset_description_path = self.find_path(self.template_description, asset_description, filepath=asset_path) if asset_description_path: new_cache.append(self.read_file(asset_description_path)) continue # Scan the blend file for assets inside and write a custom asset description for info found print(f'Scanning blendfile {asset_path}...') assets = self.load_datablocks(asset_path, type=self.data_types, link=True, assets_only=True) print(f'Found {len(assets)} {self.data_types} inside') for asset in assets: #catalog_path = catalog_ids.get(asset.asset_data.catalog_id) #if not catalog_path: # print(f'No catalog found for asset {asset.name}') #catalog_path = asset_description['catalog']#asset_path.relative_to(self.source_directory).as_posix() # For now the catalog used is the one extract from the template file asset_description['assets'].append(self.get_asset_data(asset)) getattr(bpy.data, self.data_types).remove(asset) asset_description = self.format_asset_description(asset_description, asset_path) new_cache.append(asset_description) new_cache.sort(key=lambda x:x['filepath']) return new_cache