From 060aa80c9b650a7b3629007ebbc9aceb3d636534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cchristopheseux=E2=80=9D?= <“seuxchristophe@hotmail.fr”> Date: Tue, 3 Jan 2023 13:53:01 +0100 Subject: [PATCH] start renaming adapter -> library_type --- action/operators.py | 28 ++-- adapters/adapter.py | 240 ++++++++-------------------- adapters/scan_folder.py | 342 +++------------------------------------- operators.py | 77 +++++---- 4 files changed, 147 insertions(+), 540 deletions(-) diff --git a/action/operators.py b/action/operators.py index 76d9e39..6dcb6ce 100644 --- a/action/operators.py +++ b/action/operators.py @@ -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) diff --git a/adapters/adapter.py b/adapters/adapter.py index f2665ae..4f43f34 100644 --- a/adapters/adapter.py +++ b/adapters/adapter.py @@ -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() - ''' \ No newline at end of file + \ No newline at end of file diff --git a/adapters/scan_folder.py b/adapters/scan_folder.py index 01541ce..2bc5ec4 100644 --- a/adapters/scan_folder.py +++ b/adapters/scan_folder.py @@ -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)) \ No newline at end of file diff --git a/operators.py b/operators.py index 52bca99..768582d 100644 --- a/operators.py +++ b/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')