166 lines
6.3 KiB
Python
166 lines
6.3 KiB
Python
|
|
"""
|
|
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
|
|
|