start renaming adapter -> library_type
parent
e538c997a9
commit
060aa80c9b
|
@ -920,7 +920,7 @@ class ACTIONLIB_OT_store_anim_pose(Operator):
|
|||
)
|
||||
|
||||
## Define Tags
|
||||
tags = [t.strip() for t in self.tags.split(',')]
|
||||
tags = [t.strip() for t in self.tags.split(',') if t]
|
||||
tag_range = f'f{self.frame_start}'
|
||||
is_single_frame = True
|
||||
if self.action_type == 'ANIM':
|
||||
|
@ -1025,10 +1025,10 @@ class ACTIONLIB_OT_store_anim_pose(Operator):
|
|||
|
||||
self.action_to_asset(asset_action)
|
||||
|
||||
#lib.adapter.new_asset()
|
||||
|
||||
#Saving the preview
|
||||
|
||||
self.render_preview(img_path, video_path)
|
||||
|
||||
with context.temp_override(id=asset_action):
|
||||
bpy.ops.ed.lib_id_load_custom_preview(
|
||||
filepath=str(img_path)
|
||||
|
@ -1036,15 +1036,17 @@ class ACTIONLIB_OT_store_anim_pose(Operator):
|
|||
|
||||
lib.adapter.write_asset(asset=asset_action, asset_path=asset_path)
|
||||
|
||||
# asset_description = lib.adapter.get_asset_description(dict(
|
||||
# author=prefs.author,
|
||||
# assets=[dict(
|
||||
# name=asset_action.name,
|
||||
# description=self.description,
|
||||
# catalog=self.catalog,
|
||||
# tags=self.tags.split(',')
|
||||
# )]), asset_path
|
||||
# )
|
||||
|
||||
asset_data = lib.adapter.get_asset_data(asset_action)
|
||||
|
||||
diff = [dict(asset_data,
|
||||
image=str(img_path),
|
||||
filepath=str(asset_path),
|
||||
type='ACTION',
|
||||
library_id=lib.id,
|
||||
catalog=self.catalog,
|
||||
operation='ADD'
|
||||
)]
|
||||
# lib.adapter.write_description_file(asset_description, asset_path)
|
||||
|
||||
# Restore action and cleanup
|
||||
|
@ -1057,7 +1059,7 @@ class ACTIONLIB_OT_store_anim_pose(Operator):
|
|||
# TODO Write a proper method for this
|
||||
diff_path = Path(bpy.app.tempdir, 'diff.json')
|
||||
|
||||
diff = [dict(a, operation='ADD') for a in lib.adapter.norm_cache([asset_description])]
|
||||
#diff = [dict(a, operation='ADD') for a in [asset_description])]
|
||||
diff_path.write_text(json.dumps(diff, indent=4))
|
||||
|
||||
bpy.ops.assetlib.bundle(name=lib.name, diff=str(diff_path), blocking=True)
|
||||
|
|
|
@ -28,8 +28,6 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
#def __init__(self):
|
||||
name = "Base Adapter"
|
||||
#library = None
|
||||
|
||||
#bundle_directory : StringProperty()
|
||||
|
||||
@property
|
||||
def library(self):
|
||||
|
@ -42,22 +40,6 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
def bundle_directory(self):
|
||||
return self.library.library_path
|
||||
|
||||
# @property
|
||||
# def blend_depth(self):
|
||||
# return self.library.blend_depth
|
||||
|
||||
# @property
|
||||
# def template_image(self):
|
||||
# return Template(self.library.template_image)
|
||||
|
||||
# @property
|
||||
# def template_video(self):
|
||||
# return Template(self.library.template_video)
|
||||
|
||||
# @property
|
||||
# def template_description(self):
|
||||
# return Template(self.library.template_description)
|
||||
|
||||
@property
|
||||
def data_type(self):
|
||||
return self.library.data_type
|
||||
|
@ -73,12 +55,10 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
@property
|
||||
def cache_file(self):
|
||||
return Path(self.bundle_directory) / f"blender_assets.{self.library.id}.json"
|
||||
#return get_asset_datas_file(self.library_path)
|
||||
|
||||
@property
|
||||
def tmp_cache_file(self):
|
||||
return Path(bpy.app.tempdir) / f"blender_assets.{self.library.id}.json"
|
||||
#return get_asset_datas_file(self.library_path)
|
||||
|
||||
@property
|
||||
def diff_file(self):
|
||||
|
@ -151,19 +131,22 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
|
||||
return load_datablocks(src, names=names, type=type, link=link, expr=expr, assets_only=assets_only)
|
||||
|
||||
def get_asset_data(self, asset):
|
||||
"""Extract asset information on a datablock"""
|
||||
|
||||
return dict(
|
||||
name=asset.name,
|
||||
author=asset.asset_data.author,
|
||||
tags=list(asset.asset_data.tags.keys()),
|
||||
metadata=dict(asset.asset_data),
|
||||
description=asset.asset_data.description,
|
||||
)
|
||||
|
||||
def get_asset_relative_path(self, name, catalog):
|
||||
'''Get a relative path for the asset'''
|
||||
name = self.norm_file_name(name)
|
||||
return Path(catalog, name, name).with_suffix('.blend')
|
||||
|
||||
#def _get_file_name(self, name, filepath):
|
||||
# '''Ensure having a unique name per asset if in the same folder by prefixing with the blend_file name'''
|
||||
# file_name = name
|
||||
# if filepath.stem != name:
|
||||
# file_name = f'{file_name}_{name}'
|
||||
#
|
||||
# return file_name
|
||||
|
||||
def get_active_asset_library(self):
|
||||
asset_handle = bpy.context.asset_file_handle
|
||||
prefs = get_addon_prefs()
|
||||
|
@ -205,6 +188,12 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
def get_video_path(self, name, catalog, filepath):
|
||||
raise Exception('Need to be defined in the adapter')
|
||||
|
||||
def new_asset(self, asset, asset_data):
|
||||
raise Exception('Need to be defined in the adapter')
|
||||
|
||||
def remove_asset(self, asset, asset_data):
|
||||
raise Exception('Need to be defined in the adapter')
|
||||
|
||||
|
||||
def format_asset_data(self, data):
|
||||
"""Get a dict for use in template fields"""
|
||||
|
@ -215,7 +204,6 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
'catalog_name': data['catalog'].replace('/', '_'),
|
||||
}
|
||||
|
||||
|
||||
def format_path(self, template, data={}, **kargs):
|
||||
if not template:
|
||||
return None
|
||||
|
@ -242,92 +230,6 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
if paths:
|
||||
return Path(paths[0])
|
||||
|
||||
|
||||
|
||||
# def get_template_path(self, template, name, asset_path, catalog, **kargs):
|
||||
# if not template:
|
||||
# return None
|
||||
|
||||
# if template.startswith('.'): #the template is relative
|
||||
# template = Path(asset_path, template).as_posix()
|
||||
|
||||
# params = {
|
||||
# 'asset_name': name,
|
||||
# 'asset_path': Path(asset_path),
|
||||
# 'catalog': catalog,
|
||||
# 'catalog_name': catalog.replace('/', '_'),
|
||||
# }
|
||||
|
||||
# params.update(kargs)
|
||||
|
||||
# return self.format_path(template, **params)
|
||||
|
||||
# def get_description_path(self, name, asset_path, catalog, **kargs) -> Path:
|
||||
# """"Get the path of the json or yaml describing all assets data in one file"""
|
||||
# return self.get_template_path(self.library.template_description, name, asset_path, catalog)
|
||||
|
||||
# def get_image_path(self, name, asset_path, catalog, **kargs) -> Path:
|
||||
# return self.get_template_path(self.library.template_image, name, asset_path, catalog)
|
||||
|
||||
# def get_video_path(self, name, asset_path, catalog, **kargs) -> Path:
|
||||
# return self.get_template_path(self.library.template_video, name, asset_path, catalog)
|
||||
|
||||
'''
|
||||
def get_path(self, type, name, asset_path, template=None) -> Path:
|
||||
if not template:
|
||||
template = getattr(self, f'{type}_template')
|
||||
|
||||
if isinstance(template, str):
|
||||
template = Template(template)
|
||||
|
||||
filepath = Path(asset_path)
|
||||
|
||||
params = {
|
||||
'bundle_dir': self.library.bundle_directory,
|
||||
'conform_dir': self.library.conform.directory,
|
||||
'rel_path': '',
|
||||
'catalog':'',
|
||||
'catalog_name':'',
|
||||
'name': name
|
||||
}
|
||||
|
||||
return self.format_path(template, params)#(filepath / template.format(name=name, path=Path(asset_path))).resolve()
|
||||
|
||||
#def get_image_path(self, name, asset_path):
|
||||
# filepath = Path(asset_path)
|
||||
# image_name = self._get_file_name(name, asset_path)
|
||||
# return (filepath / self.template_image.format(name=image_name)).resolve()
|
||||
|
||||
|
||||
def get_cache_image_path(self, name, catalog) -> Path:
|
||||
""""Get the the cache path of a image for asset without an externalized image"""
|
||||
name = self.norm_file_name(name)
|
||||
return Path(self.library_path, '.previews', f"{catalog.replace('/', '_')}_{name}").with_suffix(('.png'))
|
||||
|
||||
def get_cache_image(self, name, catalog):
|
||||
cache_image_path = self.get_cache_image_path(name, catalog)
|
||||
if cache_image_path.exists():
|
||||
return cache_image_path
|
||||
'''
|
||||
|
||||
#def get_video_path(self, name, asset_path):
|
||||
# filepath = Path(asset_path)
|
||||
# video_name = self._get_file_name(name, asset_path)
|
||||
# return (filepath / self.template_video.format(name=video_name)).resolve()
|
||||
'''
|
||||
def get_image(self, name, asset_path):
|
||||
image_path = self.get_path('image', name, asset_path)
|
||||
if image_path.exists():
|
||||
return image_path
|
||||
|
||||
def get_video(self, name, asset_path):
|
||||
video_path = self.get_path('video', name, asset_path)
|
||||
if video_path.exists():
|
||||
return video_path
|
||||
'''
|
||||
|
||||
|
||||
|
||||
def read_asset_description_file(self, asset_path) -> dict:
|
||||
"""Read the description file of the asset"""
|
||||
|
||||
|
@ -339,6 +241,9 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
return write_file(description_path, asset_data)
|
||||
|
||||
def write_asset(self, asset, asset_path):
|
||||
|
||||
Path(asset_path).parent.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
bpy.data.libraries.write(
|
||||
str(asset_path),
|
||||
{asset},
|
||||
|
@ -434,17 +339,9 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
self.module_type.gui.draw_header(layout)
|
||||
|
||||
def draw_context_menu(self, layout):
|
||||
"""Draw the context menu of the Asset Browser Window"""
|
||||
#layout.separator()
|
||||
"""Draw the context menu of the Asset Browser Window"""
|
||||
self.module_type.gui.draw_context_menu(layout)
|
||||
|
||||
# def group_key(self, asset_data):
|
||||
# """Key used to group assets inside one blend"""
|
||||
|
||||
# catalog_parts = asset_data['catalog'].split('/') + [asset_data['name']]
|
||||
|
||||
# return catalog_parts[:self.library.blend_depth]
|
||||
|
||||
def generate_blend_preview(self, asset_description):
|
||||
asset_name = asset_description['name']
|
||||
catalog = asset_description['catalog']
|
||||
|
@ -492,46 +389,49 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
asset_path = self.format_path(asset_description['filepath'])
|
||||
|
||||
# Check if a source video exists and if so copying it in the new directory
|
||||
for asset_data in asset_description['assets']:
|
||||
dst_asset_path = self.get_asset_bundle_path(asset_data)
|
||||
dst_video_path = self.format_path(self.library.template_video, asset_data, filepath=dst_asset_path) #Template(src_video_path).find(asset_data, asset_path=dst_asset_path, **self.format_data)
|
||||
if self.library.template_video:
|
||||
for asset_data in asset_description['assets']:
|
||||
dst_asset_path = self.get_asset_bundle_path(asset_data)
|
||||
dst_video_path = self.format_path(self.library.template_video, asset_data, filepath=dst_asset_path) #Template(src_video_path).find(asset_data, asset_path=dst_asset_path, **self.format_data)
|
||||
|
||||
if dst_video_path.exists():
|
||||
print(f'The dest video {dst_video_path} already exist')
|
||||
continue
|
||||
if dst_video_path.exists():
|
||||
print(f'The dest video {dst_video_path} already exist')
|
||||
continue
|
||||
|
||||
src_video_template = asset_data.get('video')
|
||||
if not src_video_template:
|
||||
continue
|
||||
|
||||
src_video_path = self.find_path(src_video_template, asset_data, filepath=asset_path)#Template(src_video_path).find(asset_data, asset_path=dst_asset_path, **self.format_data)
|
||||
if src_video_path:
|
||||
self.copy_file(src_video_path, dst_video_path)
|
||||
print(f'Copy video from {src_video_path} to {dst_video_path}')
|
||||
src_video_template = asset_data.get('video')
|
||||
if not src_video_template:
|
||||
continue
|
||||
|
||||
src_video_path = self.find_path(src_video_template, asset_data, filepath=asset_path)#Template(src_video_path).find(asset_data, asset_path=dst_asset_path, **self.format_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 = {}
|
||||
for asset_data in asset_description['assets']:
|
||||
name = asset_data['name']
|
||||
dst_asset_path = self.get_asset_bundle_path(asset_data)
|
||||
|
||||
dst_image_path = self.format_path(self.library.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
|
||||
src_image_template = asset_data.get('image')
|
||||
if src_image_template:
|
||||
src_image_path = self.find_path(src_image_template, asset_data, filepath=asset_path)
|
||||
if self.library.template_image:
|
||||
for asset_data in asset_description['assets']:
|
||||
name = asset_data['name']
|
||||
dst_asset_path = self.get_asset_bundle_path(asset_data)
|
||||
|
||||
if src_image_path:
|
||||
self.copy_file(src_image_path, dst_image_path)
|
||||
#print(f'Copy image from {src_image_path} to {dst_image_path}')
|
||||
return
|
||||
dst_image_path = self.format_path(self.library.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
|
||||
src_image_template = asset_data.get('image')
|
||||
if src_image_template:
|
||||
src_image_path = self.find_path(src_image_template, asset_data, filepath=asset_path)
|
||||
|
||||
#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 src_image_path:
|
||||
self.copy_file(src_image_path, dst_image_path)
|
||||
#print(f'Copy image from {src_image_path} to {dst_image_path}')
|
||||
return
|
||||
|
||||
#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:
|
||||
|
@ -622,7 +522,7 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
image_path = self.find_path(image_template, asset_data, filepath=asset_path)
|
||||
|
||||
if image_path:
|
||||
print(f'Set asset preview for {image_path} for {asset}')
|
||||
#print(f'Set asset preview for {image_path} for {asset}')
|
||||
with bpy.context.temp_override(id=asset):
|
||||
bpy.ops.ed.lib_id_load_custom_preview(
|
||||
filepath=str(image_path)
|
||||
|
@ -656,13 +556,12 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
|
||||
def set_asset_tags(self, asset, asset_data):
|
||||
"""Create asset tags base on provided data"""
|
||||
tags = asset_data.get('tags', [])
|
||||
if tags:
|
||||
#Clear all tags first
|
||||
|
||||
if 'tags' in asset_data:
|
||||
for tag in asset.asset_data.tags[:]:
|
||||
asset.asset_data.tags.remove(tag)
|
||||
|
||||
for tag in tags:
|
||||
for tag in asset_data['tags']:
|
||||
if not tag:
|
||||
continue
|
||||
asset.asset_data.tags.new(tag, skip_if_exists=True)
|
||||
|
@ -670,9 +569,9 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
def set_asset_info(self, asset, asset_data):
|
||||
"""Set asset description base on provided data"""
|
||||
|
||||
#print(asset_data.get('description', ''))
|
||||
asset.asset_data.author = asset_data.get('author') or ''
|
||||
asset.asset_data.description = asset_data.get('description') or ''
|
||||
for key in ('author', 'description'):
|
||||
if key in asset_data:
|
||||
setattr(asset.asset_data, key, asset_data.get(key) or '')
|
||||
|
||||
def get_asset_bundle_path(self, asset_data):
|
||||
|
||||
|
@ -870,15 +769,4 @@ class AssetLibraryAdapter(PropertyGroup):
|
|||
annotations = self.__class__.__annotations__
|
||||
for k, v in annotations.items():
|
||||
layout.prop(self, k, text=bpy.path.display_name(k))
|
||||
|
||||
'''
|
||||
def format_path(self, template, **kargs):
|
||||
|
||||
params = dict(
|
||||
bundle_dir=Path(self.bundle_directory),
|
||||
**kargs,
|
||||
**self.to_dict(),
|
||||
)
|
||||
|
||||
return Template(template).format(params).resolve()
|
||||
'''
|
||||
|
|
@ -28,16 +28,7 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
template_image : StringProperty()
|
||||
template_video : StringProperty()
|
||||
template_description : StringProperty()
|
||||
#blend_depth : IntProperty()
|
||||
#externalize_preview : BoolProperty(default=True)
|
||||
|
||||
#def draw_header(self, layout):
|
||||
# '''Draw the header of the Asset Browser Window'''
|
||||
# layout.separator()
|
||||
# layout.operator("actionlib.store_anim_pose", text='Add Action', icon='FILE_NEW')
|
||||
|
||||
#def update(self):
|
||||
#
|
||||
def get_asset_path(self, name, catalog, directory=None):
|
||||
directory = directory or self.source_directory
|
||||
catalog = self.norm_file_name(catalog)
|
||||
|
@ -55,47 +46,22 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
name = self.norm_file_name(name)
|
||||
return self.format_path(self.template_video, dict(name=name, catalog=catalog, filepath=filepath))
|
||||
|
||||
'''
|
||||
def get_asset_description(self, asset, catalog, modified):
|
||||
|
||||
asset_path = self.get_asset_relative_path(name=asset.name, catalog=catalog)
|
||||
asset_name = self.norm_file_name(asset.name)
|
||||
|
||||
asset_description = dict(
|
||||
filepath='{source_directory}/' + asset_path.as_posix(),
|
||||
modified=modified,
|
||||
library_id=self.library.id,
|
||||
assets=[]
|
||||
)
|
||||
|
||||
asset_description['assets'].append(dict(
|
||||
catalog=catalog,
|
||||
metadata=dict(asset.asset_data),
|
||||
tags=asset.asset_data.tags.keys(),
|
||||
type=self.data_type,
|
||||
image=str(self.template_image.format(name=asset_name)),
|
||||
video=str(self.template_video.format(name=asset_name)),
|
||||
name=asset.name)
|
||||
)
|
||||
|
||||
return asset_description
|
||||
'''
|
||||
|
||||
def get_asset_description(self, data, asset_path):
|
||||
def format_asset_description(self, asset_description, asset_path):
|
||||
|
||||
asset_path = self.prop_rel_path(asset_path, 'source_directory')
|
||||
modified = data.get('modified', time.time_ns())
|
||||
modified = asset_description.get('modified', time.time_ns())
|
||||
|
||||
if self.data_type == 'FILE':
|
||||
return dict(
|
||||
filepath=asset_path,
|
||||
author=data.get('author'),
|
||||
author=asset_description.get('author'),
|
||||
modified=modified,
|
||||
catalog=data['catalog'],
|
||||
catalog=asset_description['catalog'],
|
||||
tags=[],
|
||||
description=asset_description.get('description', ''),
|
||||
type=self.data_type,
|
||||
image=self.template_image,
|
||||
name=data['name']
|
||||
name=asset_description['name']
|
||||
)
|
||||
|
||||
return dict(
|
||||
|
@ -103,267 +69,18 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
modified=modified,
|
||||
library_id=self.library.id,
|
||||
assets=[dict(
|
||||
catalog=asset_data['catalog'],
|
||||
author=data.get('author'),
|
||||
catalog=asset_data.get('catalog', asset_description['catalog']),
|
||||
author=asset_data.get('author'),
|
||||
metadata=asset_data.get('metadata', {}),
|
||||
description=asset_data.get('description'),
|
||||
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 data['assets']
|
||||
name=asset_data['name']) for asset_data in asset_description['assets']
|
||||
]
|
||||
)
|
||||
|
||||
def _find_blend_files(self):
|
||||
'''Get a sorted list of all blender files found matching the template'''
|
||||
template = Template(self.template)
|
||||
|
||||
print(f'Search for blend using glob template: {template.glob_pattern}')
|
||||
|
||||
source_directory = Path(os.path.expandvars(self.source_directory))
|
||||
print(f'Scanning Folder {source_directory}...')
|
||||
blend_files = list(source_directory.glob(template.glob_pattern))
|
||||
|
||||
blend_files.sort()
|
||||
|
||||
return blend_files
|
||||
|
||||
'''
|
||||
def _group_key(self, asset_data):
|
||||
"""Group assets inside one blend"""
|
||||
|
||||
catalog_parts = asset_data['catalog'].split('/') + [asset_data['name']]
|
||||
|
||||
return catalog_parts[:self.blend_depth]
|
||||
|
||||
def bundle(self, cache_diff=None):
|
||||
"""Group all asset in one or multiple blends for the asset browser"""
|
||||
|
||||
if self.data_type not in ('FILE', 'ACTION'):
|
||||
print(f'{self.data_type} is not supported yet')
|
||||
return
|
||||
|
||||
lib_path = self.library_path
|
||||
catalog_data = self.read_catalog() # TODO remove unused catalog
|
||||
|
||||
#asset_file_datas = self.fetch() # TODO replace to only change new assets
|
||||
|
||||
if not cache_diff:
|
||||
# Get list of all modifications
|
||||
cache, cache_diff = self.diff()
|
||||
self.write_cache(cache)
|
||||
|
||||
elif isinstance(cache_diff, (Path, str)):
|
||||
cache_diff = json.loads(Path(cache_diff).read_text(encoding='utf-8'))
|
||||
|
||||
if self.blend_depth == 0:
|
||||
groups = [(cache_diff)]
|
||||
else:
|
||||
cache_diff.sort(key=self._group_key)
|
||||
groups = groupby(cache_diff, key=self._group_key)
|
||||
|
||||
# #print(cache_diff)
|
||||
# print('\n')
|
||||
# for sub_path, asset_datas in groups:
|
||||
|
||||
# print('\n')
|
||||
# print(f'{sub_path=}')
|
||||
# print(f'asset_datas={list(asset_datas)}')
|
||||
|
||||
# raise Exception()
|
||||
|
||||
#progress = 0
|
||||
total_assets = len(cache_diff)
|
||||
print(f'total_assets={total_assets}')
|
||||
|
||||
if total_assets == 0:
|
||||
print('No assets found')
|
||||
return
|
||||
|
||||
i = 0
|
||||
for sub_path, asset_datas in groups:
|
||||
|
||||
# print('\n')
|
||||
# print(f'{sub_path=}')
|
||||
# print(f'asset_datas={list(asset_datas)}')
|
||||
|
||||
# print('\n')
|
||||
|
||||
blend_name = sub_path[-1].replace(' ', '_').lower()
|
||||
blend_path = Path(lib_path, *sub_path, blend_name).with_suffix('.blend')
|
||||
|
||||
if blend_path.exists():
|
||||
print(f'Opening existing bundle blend: {blend_path}')
|
||||
bpy.ops.wm.open_mainfile(filepath=str(blend_path))
|
||||
else:
|
||||
print(f'Create new bundle blend to: {blend_path}')
|
||||
bpy.ops.wm.read_homefile(use_empty=True)
|
||||
|
||||
for asset_data in asset_datas:
|
||||
if total_assets <= 100 or i % int(total_assets / 10) == 0:
|
||||
print(f'Progress: {int(i / total_assets * 100)+1}')
|
||||
|
||||
operation = asset_data.get('operation', 'ADD')
|
||||
asset = getattr(bpy.data, self.data_types).get(asset_data['name'])
|
||||
|
||||
if operation == 'REMOVE':
|
||||
if asset:
|
||||
getattr(bpy.data, self.data_types).remove(asset)
|
||||
else:
|
||||
print(f'ERROR : Remove Asset: {asset_data["name"]} not found in {blend_path}')
|
||||
continue
|
||||
|
||||
elif operation == 'MODIFY':
|
||||
if not asset:
|
||||
print(f'WARNING: Modifiy Asset: {asset_data["name"]} not found in {blend_path} it will be created')
|
||||
|
||||
elif operation == 'ADD' or not asset:
|
||||
if asset:
|
||||
#raise Exception(f"Asset {asset_data['name']} Already in Blend")
|
||||
getattr(bpy.data, self.data_types).remove(asset)
|
||||
|
||||
#print(f"INFO: Add new asset: {asset_data['name']}")
|
||||
asset = getattr(bpy.data, self.data_types).new(name=asset_data['name'])
|
||||
else:
|
||||
print(f'operation {operation} not supported should be in (ADD, REMOVE, MODIFIED)')
|
||||
continue
|
||||
|
||||
asset.asset_mark()
|
||||
|
||||
# Load external preview if exists
|
||||
#template_image = Template(asset_data['preview'])
|
||||
image_path = Path(asset_data['image'])
|
||||
if not image_path.is_absolute():
|
||||
image_path = Path(asset_data['filepath'], image_path)
|
||||
|
||||
image_path = self.format_path(image_path.as_posix())
|
||||
|
||||
if image_path and image_path.exists():
|
||||
with bpy.context.temp_override(id=asset):
|
||||
bpy.ops.ed.lib_id_load_custom_preview(
|
||||
filepath=str(image_path)
|
||||
)
|
||||
#else:
|
||||
# print(f'Preview {image_path} not found for asset {asset}')
|
||||
|
||||
asset.asset_data.description = asset_data.get('description', '')
|
||||
|
||||
catalog_name = asset_data['catalog']
|
||||
catalog = catalog_data.get(catalog_name)
|
||||
if not catalog:
|
||||
catalog = {'id': str(uuid.uuid4()), 'name': catalog_name}
|
||||
catalog_data[catalog_name] = catalog
|
||||
|
||||
asset.asset_data.catalog_id = catalog['id']
|
||||
|
||||
metadata = asset_data.get('metadata', {})
|
||||
|
||||
library_id = self.library.id
|
||||
if 'library_id' in asset_data:
|
||||
library_id = asset_data['library_id']
|
||||
|
||||
metadata['.library_id'] = library_id
|
||||
|
||||
#print(metadata)
|
||||
|
||||
metadata['filepath'] = asset_data['filepath']
|
||||
for k, v in metadata.items():
|
||||
asset.asset_data[k] = v
|
||||
|
||||
# Set tags if specified the asset_description
|
||||
tags = asset_data.get('tags', [])
|
||||
if tags:
|
||||
for tag in asset.asset_data.tags[:]:
|
||||
asset.asset_data.tags.remove(tag)
|
||||
|
||||
for tag in tags:
|
||||
if not tag:
|
||||
continue
|
||||
asset.asset_data.tags.new(tag, skip_if_exists=True)
|
||||
|
||||
i += 1
|
||||
|
||||
print(f'Saving Blend to {blend_path}')
|
||||
|
||||
blend_path.parent.mkdir(exist_ok=True, parents=True)
|
||||
bpy.ops.wm.save_as_mainfile(filepath=str(blend_path), compress=True)
|
||||
|
||||
self.write_catalog(catalog_data)
|
||||
|
||||
bpy.ops.wm.quit_blender()
|
||||
'''
|
||||
|
||||
'''
|
||||
def conform(self, directory, templates):
|
||||
"""Split each assets per blend and externalize preview"""
|
||||
|
||||
print(f'Conforming {self.library.name} to {directory}')
|
||||
|
||||
if self.data_type not in ('FILE', 'ACTION'):
|
||||
print(f'{self.data_type} is not supported yet')
|
||||
return
|
||||
|
||||
#lib_path = self.library_path
|
||||
source_directory = Path(os.path.expandvars(self.source_directory))
|
||||
catalog_data = self.read_catalog(filepath=source_directory)
|
||||
catalog_ids = {v['id']: {'path': k, 'name': v['name']} for k,v in catalog_data.items()}
|
||||
directory = Path(directory).resolve()
|
||||
|
||||
template_image = templates.get('image') or self.template_image
|
||||
template_video = templates.get('video') or self.template_video
|
||||
|
||||
# Get list of all modifications
|
||||
for blend_file in self._find_blend_files():
|
||||
|
||||
modified = blend_file.stat().st_mtime_ns
|
||||
|
||||
print(f'Scanning blendfile {blend_file}...')
|
||||
with bpy.data.libraries.load(str(blend_file), link=True, assets_only=True) as (data_from, data_to):
|
||||
asset_names = getattr(data_from, self.data_types)
|
||||
print(f'Found {len(asset_names)} {self.data_types} inside')
|
||||
|
||||
setattr(data_to, self.data_types, asset_names)
|
||||
|
||||
assets = getattr(data_to, self.data_types)
|
||||
#print('assets', assets)
|
||||
|
||||
for asset in assets:
|
||||
#TODO options for choose beetween asset catalog and filepath directory
|
||||
asset_catalog_data = catalog_ids.get(asset.asset_data.catalog_id)
|
||||
|
||||
if not asset_catalog_data:
|
||||
print(f'No catalog found for asset {asset.name}')
|
||||
asset_catalog_data = {"path": blend_file.parent.relative_to(source_directory).as_posix()}
|
||||
|
||||
catalog_path = asset_catalog_data['path']
|
||||
|
||||
asset_path = self.get_asset_path(name=asset.name, catalog=catalog_path, directory=directory)
|
||||
asset_description = self.get_asset_description(asset, catalog=catalog_path, modified=modified)
|
||||
|
||||
self.write_description_file(asset_description, asset_path)
|
||||
#Write blend file containing only one asset
|
||||
self.write_asset(asset=asset, asset_path=asset_path)
|
||||
|
||||
# Copy image if source image found else write the asset preview
|
||||
src_image_path = self.get_path('image', name=asset.name, asset_path=blend_file, template=template_image)
|
||||
dst_image_path = self.get_path('image', name=asset.name, asset_path=asset_path)
|
||||
|
||||
if src_image_path.exists():
|
||||
self.copy_file(src_image_path, dst_image_path)
|
||||
else:
|
||||
self.write_preview(asset.preview, dst_image_path)
|
||||
|
||||
# Copy video if source video found
|
||||
src_video_path = self.get_path('video', name=asset.name, asset_path=blend_file, template=template_video)
|
||||
|
||||
#print('src_video_path', src_video_path)
|
||||
if src_video_path.exists():
|
||||
dst_video_path = self.get_path('video', name=asset.name, asset_path=asset_path)
|
||||
self.copy_file(src_video_path, dst_video_path)
|
||||
|
||||
self.write_catalog(catalog_data, filepath=directory)
|
||||
'''
|
||||
def fetch(self):
|
||||
"""Gather in a list all assets found in the folder"""
|
||||
|
||||
|
@ -377,17 +94,8 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
cache = self.read_cache() or []
|
||||
|
||||
print(f'Search for blend using glob template: {template_file.glob_pattern}')
|
||||
|
||||
print(f'Scanning Folder {source_directory}...')
|
||||
#blend_files = list(source_directory.glob(template.glob_pattern))
|
||||
|
||||
# Remove delete blends for the list
|
||||
#blend_paths = [self.prop_rel_path(f, 'source_directory') for f in blend_files]
|
||||
#print('blend_paths', blend_paths)
|
||||
|
||||
|
||||
#cache = []
|
||||
#blend_paths = []
|
||||
new_cache = []
|
||||
|
||||
for asset_path in template_file.glob(source_directory):#sorted(blend_files):
|
||||
|
@ -407,11 +115,11 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
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]
|
||||
#catalogs = [c.replace('_', ' ').title() for c in catalogs]
|
||||
|
||||
asset_name = field_data.get('asset_name', asset_path.stem)
|
||||
|
||||
asset_datas = {
|
||||
asset_description = {
|
||||
"name": asset_name,
|
||||
"catalog": '/'.join(catalogs),
|
||||
"assets": [],
|
||||
|
@ -419,12 +127,12 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
}
|
||||
|
||||
if self.data_type == 'FILE':
|
||||
asset_description = self.get_asset_description(asset_datas, asset_path)
|
||||
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_datas, filepath=asset_path)
|
||||
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
|
||||
|
@ -439,33 +147,19 @@ class ScanFolderLibrary(AssetLibraryAdapter):
|
|||
|
||||
#if not catalog_path:
|
||||
# print(f'No catalog found for asset {asset.name}')
|
||||
catalog_path = asset_datas['catalog']#asset_path.relative_to(self.source_directory).as_posix()
|
||||
#catalog_path = asset_description['catalog']#asset_path.relative_to(self.source_directory).as_posix()
|
||||
|
||||
asset_datas['assets'] += [dict(
|
||||
catalog=catalog_path,
|
||||
tags=asset.asset_data.tags.keys(),
|
||||
metadata=dict(asset.asset_data),
|
||||
type=self.data_type,
|
||||
name=asset.name
|
||||
)]
|
||||
# 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.get_asset_description(asset_datas, asset_path)
|
||||
asset_description = self.format_asset_description(asset_description, asset_path)
|
||||
|
||||
new_cache.append(asset_description)
|
||||
|
||||
|
||||
#cache = [a for a in cache if a['filepath'] in blend_paths]
|
||||
|
||||
#for a in asset_data:
|
||||
# print(a)
|
||||
|
||||
#print(asset_data)
|
||||
new_cache.sort(key=lambda x:x['filepath'])
|
||||
|
||||
return new_cache
|
||||
|
||||
# Write json data file to store all asset found
|
||||
#print(f'Writing asset data file to, {asset_data_path}')
|
||||
#asset_data_path.write_text(json.dumps(asset_data, indent=4))
|
77
operators.py
77
operators.py
|
@ -84,6 +84,7 @@ class ASSETLIB_OT_edit_data(Operator):
|
|||
catalog: StringProperty(name='Catalog', update=asset_warning_callback, options={'TEXTEDIT_UPDATE'})
|
||||
name: StringProperty(name='Name', update=asset_warning_callback, options={'TEXTEDIT_UPDATE'})
|
||||
tags: StringProperty(name='Tags', description='Tags need to separate with a comma (,)')
|
||||
description: StringProperty(name='Description')
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -101,35 +102,50 @@ class ASSETLIB_OT_edit_data(Operator):
|
|||
new_name = lib.adapter.norm_file_name(self.name)
|
||||
new_asset_path = lib.adapter.get_asset_path(name=new_name, catalog=self.catalog)
|
||||
|
||||
#asset_data = lib.adapter.get_asset_data(self.asset)
|
||||
asset_data = dict(
|
||||
tags=[t.strip() for t in self.tags.split(',') if t],
|
||||
description=self.description,
|
||||
)
|
||||
|
||||
#lib.adapter.set_asset_catalog(asset, asset_data, catalog_data)
|
||||
self.asset.name = self.name
|
||||
lib.adapter.set_asset_tags(self.asset, asset_data)
|
||||
lib.adapter.set_asset_info(self.asset, asset_data)
|
||||
|
||||
self.old_asset_path.unlink()
|
||||
lib.adapter.write_asset(asset=self.asset, asset_path=new_asset_path)
|
||||
|
||||
if self.old_image_path.exists():
|
||||
new_img_path = lib.adapter.get_path('image', new_name, new_asset_path)
|
||||
new_img_path = lib.adapter.get_image_path(new_name, self.catalog, new_asset_path)
|
||||
self.old_image_path.rename(new_img_path)
|
||||
|
||||
if self.old_video_path.exists():
|
||||
new_video_path = lib.adapter.get_path('video', new_name, new_asset_path)
|
||||
new_video_path = lib.adapter.get_video_path(new_name, self.catalog, new_asset_path)
|
||||
self.old_video_path.rename(new_video_path)
|
||||
|
||||
if self.old_description_path.exists():
|
||||
self.old_description_path.unlink()
|
||||
#if self.old_description_path.exists():
|
||||
# self.old_description_path.unlink()
|
||||
|
||||
new_asset_description = lib.adapter.get_asset_description(
|
||||
asset=self.asset,
|
||||
catalog=self.catalog,
|
||||
modified=time.time_ns()
|
||||
)
|
||||
|
||||
lib.adapter.write_description_file(new_asset_description, new_asset_path)
|
||||
|
||||
if not list(self.old_asset_path.parent.iterdir()):
|
||||
try:
|
||||
self.old_asset_path.parent.rmdir()
|
||||
except Exception: #The folder is not empty
|
||||
pass
|
||||
|
||||
diff_path = Path(bpy.app.tempdir, 'diff.json')
|
||||
diff = [dict(name=self.old_asset_name, catalog=self.old_catalog, filepath=str(self.old_asset_path), operation='REMOVE')]
|
||||
|
||||
diff = [dict(self.old_asset_description, operation='REMOVE')]
|
||||
diff += [dict(lib.adapter.norm_asset_datas([new_asset_description])[0], operation='ADD')]
|
||||
asset_data = lib.adapter.get_asset_data(self.asset)
|
||||
diff += [dict(asset_data,
|
||||
image=str(new_img_path),
|
||||
filepath=str(new_asset_path),
|
||||
type=lib.data_type,
|
||||
library_id=lib.id,
|
||||
catalog=self.catalog,
|
||||
operation='ADD'
|
||||
)]
|
||||
|
||||
print(diff)
|
||||
|
||||
diff_path.write_text(json.dumps(diff, indent=4), encoding='utf-8')
|
||||
|
||||
|
@ -151,6 +167,7 @@ class ASSETLIB_OT_edit_data(Operator):
|
|||
layout.prop(self, "catalog", text="Catalog")
|
||||
layout.prop(self, "name", text="Name")
|
||||
layout.prop(self, 'tags')
|
||||
layout.prop(self, 'description')
|
||||
|
||||
#layout.prop()
|
||||
|
||||
|
@ -184,25 +201,31 @@ class ASSETLIB_OT_edit_data(Operator):
|
|||
|
||||
self.asset = load_datablocks(self.old_asset_path, self.old_asset_name, type=lib.data_types)
|
||||
|
||||
self.old_image_path = lib.adapter.get_path('image', self.old_asset_name, self.old_asset_path)
|
||||
self.old_video_path = lib.adapter.get_path('video', self.old_asset_name, self.old_asset_path)
|
||||
|
||||
self.old_description_path = lib.adapter.get_description_path(self.old_asset_path)
|
||||
|
||||
self.old_asset_description = lib.adapter.read_asset_description_file(self.old_asset_path)
|
||||
self.old_asset_description = lib.adapter.norm_asset_datas([self.old_asset_description])[0]
|
||||
|
||||
|
||||
if not self.asset:
|
||||
self.report({'ERROR'}, 'No asset found')
|
||||
|
||||
self.name = self.old_asset_name
|
||||
self.tags = ', '.join(self.asset.asset_data.tags.keys())
|
||||
self.description = asset_handle.asset_data.description
|
||||
|
||||
tags = [t.strip() for t in self.asset.asset_data.tags.keys() if t]
|
||||
self.tags = ', '.join(tags)
|
||||
#asset_path
|
||||
self.catalog = catalog_ids[asset_handle.asset_data.catalog_id]['path']
|
||||
self.old_catalog = catalog_ids[asset_handle.asset_data.catalog_id]['path']
|
||||
self.catalog = self.old_catalog
|
||||
|
||||
self.old_image_path = lib.adapter.get_image_path(name=self.name, catalog=self.catalog, filepath=self.old_asset_path)
|
||||
self.old_video_path = lib.adapter.get_video_path(name=self.name, catalog=self.catalog, filepath=self.old_asset_path)
|
||||
|
||||
#self.old_description_path = lib.adapter.get_description_path(self.old_asset_path)
|
||||
|
||||
#self.old_asset_description = lib.adapter.read_asset_description_file(self.old_asset_path)
|
||||
#self.old_asset_description = lib.adapter.norm_asset_datas([self.old_asset_description])[0]
|
||||
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self, width=450)
|
||||
|
||||
def cancel(self, context):
|
||||
print('Cancel Edit Data, removing the asset')
|
||||
|
|
Loading…
Reference in New Issue