continue refactoring
This commit is contained in:
		
							parent
							
								
									fc405797d9
								
							
						
					
					
						commit
						575bbade7b
					
				| @ -1032,7 +1032,7 @@ class ACTIONLIB_OT_store_anim_pose(Operator): | |||||||
|             modified=time.time_ns() |             modified=time.time_ns() | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         lib.adapter.write_asset_description(asset_description, asset_path) |         lib.adapter.write_description_file(asset_description, asset_path) | ||||||
| 
 | 
 | ||||||
|         # Restore action and cleanup |         # Restore action and cleanup | ||||||
|         ob.animation_data.action = current_action |         ob.animation_data.action = current_action | ||||||
|  | |||||||
| @ -1,8 +1,9 @@ | |||||||
| 
 | 
 | ||||||
| from asset_library.common.functions import (read_catalog, write_catalog, norm_asset_datas, get_catalog_path) | from asset_library.common.functions import (read_catalog, write_catalog, norm_asset_datas) | ||||||
| from asset_library.common.bl_utils import get_addon_prefs, load_datablocks | from asset_library.common.bl_utils import get_addon_prefs, load_datablocks | ||||||
| from asset_library.common.file_utils import read_file, write_file | from asset_library.common.file_utils import read_file, write_file | ||||||
| from asset_library.common.template import Template | from asset_library.common.template import Template | ||||||
|  | from asset_library.constants import (PREVIEW_ASSETS_SCRIPT, MODULE_DIR) | ||||||
| 
 | 
 | ||||||
| from asset_library import (action, collection, file) | from asset_library import (action, collection, file) | ||||||
| 
 | 
 | ||||||
| @ -18,6 +19,7 @@ import json | |||||||
| import uuid | import uuid | ||||||
| import time | import time | ||||||
| from functools import partial | from functools import partial | ||||||
|  | import subprocess | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class AssetLibraryAdapter(PropertyGroup): | class AssetLibraryAdapter(PropertyGroup): | ||||||
| @ -26,7 +28,7 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|     name = "Base Adapter" |     name = "Base Adapter" | ||||||
|     #library = None |     #library = None | ||||||
| 
 | 
 | ||||||
|     bundle_directory : StringProperty() |     #bundle_directory : StringProperty() | ||||||
|      |      | ||||||
|     @property |     @property | ||||||
|     def library(self): |     def library(self): | ||||||
| @ -37,29 +39,9 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             if lib.conform.adapter == self: |             if lib.conform.adapter == self: | ||||||
|                 return lib |                 return lib | ||||||
| 
 | 
 | ||||||
|     @property |     #@property | ||||||
|     def library_path(self): |     #def library_path(self): | ||||||
|         return self.library.library_path |     #    return self.library.library_path | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def image_template(self): |  | ||||||
|         return Template(self.library.image_template) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def video_template(self): |  | ||||||
|         return Template(self.library.video_template) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def asset_description_template(self): |  | ||||||
|         return Template(self.library.asset_description_template) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def data_type(self): |  | ||||||
|         return self.library.data_type |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def data_types(self): |  | ||||||
|         return self.library.data_types |  | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def is_conform(self): |     def is_conform(self): | ||||||
| @ -70,6 +52,13 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             if lib.conform.adapter == self: |             if lib.conform.adapter == self: | ||||||
|                 return True  |                 return True  | ||||||
| 
 | 
 | ||||||
|  |     @property | ||||||
|  |     def target_directory(self): | ||||||
|  |         if self.is_conform: | ||||||
|  |             return self.library.conform.directory | ||||||
|  | 
 | ||||||
|  |         return self.library.bundle_dir | ||||||
|  |      | ||||||
|     @property |     @property | ||||||
|     def blend_depth(self): |     def blend_depth(self): | ||||||
|         if self.is_conform: |         if self.is_conform: | ||||||
| @ -78,21 +67,55 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|         return self.library.blend_depth |         return self.library.blend_depth | ||||||
|      |      | ||||||
|     @property |     @property | ||||||
|     def externalize_data(self): |     def template_image(self): | ||||||
|         return self.library.externalize_data |         return Template(self.library.conform.template_image) | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def catalog_path(self): |     def template_video(self): | ||||||
|         return self.library.catalog_path |         return Template(self.library.conform.template_video) | ||||||
| 
 | 
 | ||||||
|     def get_catalog_path(self, filepath): |     @property | ||||||
|         return get_catalog_path(filepath) |     def template_description(self): | ||||||
|  |         return Template(self.library.conform.template_description) | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def data_type(self): | ||||||
|  |         return self.library.data_type | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def data_types(self): | ||||||
|  |         return self.library.data_types | ||||||
|  | 
 | ||||||
|  |     #@property | ||||||
|  |     #def externalize_data(self): | ||||||
|  |     #    return self.library.externalize_data | ||||||
|  | 
 | ||||||
|  |     #@property | ||||||
|  |     #def catalog_path(self): | ||||||
|  |     #    return self.library.catalog_path | ||||||
|  | 
 | ||||||
|  |     def get_catalog_path(self, directory=None): | ||||||
|  |         directory = directory or self.target_directory | ||||||
|  |         return Path(directory, 'blender_assets.cats.txt') | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def cache_file(self): |     def cache_file(self): | ||||||
|         return Path(self.library_path) / f"blender_assets.{self.library.id}.json" |         return Path(self.target_directory) / f"blender_assets.{self.library.id}.json" | ||||||
|         #return get_asset_datas_file(self.library_path) |         #return get_asset_datas_file(self.library_path) | ||||||
| 
 | 
 | ||||||
|  |     @property | ||||||
|  |     def diff_file(self): | ||||||
|  |         return Path(bpy.app.tempdir, 'diff.json') | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def preview_blend(self): | ||||||
|  |         return MODULE_DIR / self.data_type.lower() / "preview.blend" | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def preview_assets_file(self): | ||||||
|  |         return Path(bpy.app.tempdir, "preview_assets_file.json") | ||||||
|  | 
 | ||||||
|     @property |     @property | ||||||
|     def addon_prefs(self): |     def addon_prefs(self): | ||||||
|         return get_addon_prefs() |         return get_addon_prefs() | ||||||
| @ -116,6 +139,12 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|     def norm_file_name(self, name): |     def norm_file_name(self, name): | ||||||
|         return name.replace(' ', '_') |         return name.replace(' ', '_') | ||||||
| 
 | 
 | ||||||
|  |     def read_file(self, file): | ||||||
|  |         return read_file(file) | ||||||
|  | 
 | ||||||
|  |     def write_file(self, file, data): | ||||||
|  |         return write_file(file, data) | ||||||
|  | 
 | ||||||
|     def copy_file(self, source, destination): |     def copy_file(self, source, destination): | ||||||
|         src = Path(source) |         src = Path(source) | ||||||
|         dst = Path(destination) |         dst = Path(destination) | ||||||
| @ -185,6 +214,31 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
| 
 | 
 | ||||||
|         return asset_path |         return asset_path | ||||||
| 
 | 
 | ||||||
|  |     def get_template_path(self, template, name, asset_path, catalog): | ||||||
|  |          | ||||||
|  |         if template.startswith('.'): #the template is relative | ||||||
|  |             template = Path(asset_path, template).as_posix() | ||||||
|  | 
 | ||||||
|  |         params = { | ||||||
|  |             'name': name, | ||||||
|  |             'asset_path': Path(asset_path), | ||||||
|  |             'catalog': catalog, | ||||||
|  |             'catalog_name': catalog.replace('/', '_'), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return self.format_path(template, **params) | ||||||
|  | 
 | ||||||
|  |     def get_description_path(self, name, asset_path, catalog) -> Path: | ||||||
|  |         """"Get the path of the json or yaml describing all assets data in one file""" | ||||||
|  |         return self.get_template_path(self.library.conform.template_description, name, asset_path, catalog) | ||||||
|  | 
 | ||||||
|  |     def get_image_path(self, name, asset_path, catalog) -> Path: | ||||||
|  |         return self.get_template_path(self.library.conform.template_image, name, asset_path, catalog) | ||||||
|  | 
 | ||||||
|  |     def get_video_path(self, name, asset_path, catalog) -> Path: | ||||||
|  |         return self.get_template_path(self.library.conform.template_video, name, asset_path, catalog) | ||||||
|  | 
 | ||||||
|  |     ''' | ||||||
|     def get_path(self, type, name, asset_path, template=None) -> Path: |     def get_path(self, type, name, asset_path, template=None) -> Path: | ||||||
|         if not template: |         if not template: | ||||||
|             template = getattr(self, f'{type}_template') |             template = getattr(self, f'{type}_template') | ||||||
| @ -193,27 +247,40 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             template = Template(template) |             template = Template(template) | ||||||
| 
 | 
 | ||||||
|         filepath = Path(asset_path) |         filepath = Path(asset_path) | ||||||
|         return (filepath / template.format(name=name, path=Path(asset_path))).resolve() | 
 | ||||||
|  |         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): |     #def get_image_path(self, name, asset_path): | ||||||
|     #    filepath = Path(asset_path) |     #    filepath = Path(asset_path) | ||||||
|     #    image_name = self._get_file_name(name, asset_path) |     #    image_name = self._get_file_name(name, asset_path) | ||||||
|     #    return (filepath / self.image_template.format(name=image_name)).resolve() |     #    return (filepath / self.template_image.format(name=image_name)).resolve() | ||||||
|  | 
 | ||||||
|      |      | ||||||
|     def get_cache_image_path(self, name, catalog) -> Path: |     def get_cache_image_path(self, name, catalog) -> Path: | ||||||
|         """"Get the the cache path of a image for asset without an externalized image""" |         """"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')) |         return Path(self.library_path, '.previews', f"{catalog.replace('/', '_')}_{name}").with_suffix(('.png')) | ||||||
| 
 | 
 | ||||||
|     def get_cache_image(self, name, catalog): |     def get_cache_image(self, name, catalog): | ||||||
|         cache_image_path = self.get_cache_image_path(name, catalog) |         cache_image_path = self.get_cache_image_path(name, catalog) | ||||||
|         if cache_image_path.exists(): |         if cache_image_path.exists(): | ||||||
|             return cache_image_path |             return cache_image_path | ||||||
|  |     ''' | ||||||
| 
 | 
 | ||||||
|     #def get_video_path(self, name, asset_path): |     #def get_video_path(self, name, asset_path): | ||||||
|     #    filepath = Path(asset_path) |     #    filepath = Path(asset_path) | ||||||
|     #    video_name = self._get_file_name(name, asset_path) |     #    video_name = self._get_file_name(name, asset_path) | ||||||
|     #    return (filepath / self.video_template.format(name=video_name)).resolve() |     #    return (filepath / self.template_video.format(name=video_name)).resolve() | ||||||
| 
 |     ''' | ||||||
|     def get_image(self, name, asset_path): |     def get_image(self, name, asset_path): | ||||||
|         image_path = self.get_path('image', name, asset_path) |         image_path = self.get_path('image', name, asset_path) | ||||||
|         if image_path.exists(): |         if image_path.exists(): | ||||||
| @ -223,21 +290,19 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|         video_path = self.get_path('video', name, asset_path) |         video_path = self.get_path('video', name, asset_path) | ||||||
|         if video_path.exists(): |         if video_path.exists(): | ||||||
|             return video_path |             return video_path | ||||||
|  |             ''' | ||||||
| 
 | 
 | ||||||
|     def get_asset_description_path(self, asset_path) -> Path: |  | ||||||
|         """"Get the path of the json or yaml describing all assets data in onle file""" |  | ||||||
|         filepath = Path(asset_path) |  | ||||||
|         return (filepath / self.asset_description_template.format(name=filepath.stem)).resolve() |  | ||||||
| 
 | 
 | ||||||
|     def read_asset_description(self, asset_path) -> dict: | 
 | ||||||
|  |     def read_asset_description_file(self, asset_path) -> dict: | ||||||
|         """Read the description file of the asset""" |         """Read the description file of the asset""" | ||||||
| 
 | 
 | ||||||
|         asset_description_path = self.get_asset_description_path(asset_path) |         description_path = self.get_description_path(asset_path) | ||||||
|         return read_file(asset_description_path) |         return self.read_file(description_path) | ||||||
| 
 | 
 | ||||||
|     def write_asset_description(self, asset_data, asset_path) -> None: |     def write_description_file(self, asset_data, asset_path) -> None: | ||||||
|         asset_description_path = self.get_asset_description_path(asset_path) |         description_path = self.get_description_path(asset_path) | ||||||
|         return write_file(asset_description_path, asset_data) |         return write_file(description_path, asset_data) | ||||||
| 
 | 
 | ||||||
|     def write_asset(self, asset, asset_path): |     def write_asset(self, asset, asset_path): | ||||||
|         bpy.data.libraries.write( |         bpy.data.libraries.write( | ||||||
| @ -248,26 +313,47 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             compress=True |             compress=True | ||||||
|         ) |         ) | ||||||
|      |      | ||||||
|  |     def read_catalog(self, directory=None): | ||||||
|  |         """Read the catalog file of the library target directory or of the specified directory""" | ||||||
|  |         catalog_path = self.get_catalog_path(directory) | ||||||
| 
 | 
 | ||||||
|     def read_catalog(self, filepath=None): |         cat_data = {} | ||||||
|         """Read the catalog file of the library bundle path or of the specified filepath""" |  | ||||||
| 
 | 
 | ||||||
|         catalog_path = self.catalog_path |         for line in catalog_path.read_text(encoding="utf-8").split('\n'): | ||||||
|         if filepath: |             if line.startswith(('VERSION', '#')) or not line: | ||||||
|             catalog_path = self.get_catalog_path(filepath) |                 continue | ||||||
|         return read_catalog(catalog_path) |  | ||||||
| 
 | 
 | ||||||
|     def write_catalog(self, catalog_data, filepath=None): |             cat_id, cat_path, cat_name = line.split(':') | ||||||
|         """Write the catalog file in the library bundle path or of the specified filepath""" |             cat_data[cat_path] = {'id':cat_id, 'name':cat_name} | ||||||
|          |          | ||||||
|         catalog_path = self.catalog_path |         return cat_data | ||||||
|         if filepath: |  | ||||||
|             catalog_path = self.get_catalog_path(filepath) |  | ||||||
| 
 | 
 | ||||||
|         return write_catalog(catalog_path, catalog_data) |     def write_catalog(self, catalog_data, directory=None): | ||||||
|  |         """Write the catalog file in the library target directory or of the specified directory""" | ||||||
|  |          | ||||||
|  |         catalog_path = self.get_catalog_path(directory) | ||||||
|  | 
 | ||||||
|  |         lines = ['VERSION 1', ''] | ||||||
|  | 
 | ||||||
|  |         # Add missing parents catalog | ||||||
|  |         norm_data = {} | ||||||
|  |         for cat_path, cat_data in catalog_data.items(): | ||||||
|  |             norm_data[cat_path] = cat_data | ||||||
|  |             for p in Path(cat_path).parents[:-1]: | ||||||
|  |                 if p in data or p in norm_data: | ||||||
|  |                     continue | ||||||
|  |                  | ||||||
|  |                 norm_data[p.as_posix()] = {'id': str(uuid.uuid4()), 'name': '-'.join(p.parts)} | ||||||
|  | 
 | ||||||
|  |         for cat_path, cat_data in sorted(norm_data.items()): | ||||||
|  |             cat_name = cat_data['name'].replace('/', '-') | ||||||
|  |             lines.append(f"{cat_data['id']}:{cat_path}:{cat_name}") | ||||||
|  |          | ||||||
|  |         print(f'Catalog writen at: {catalog_path}') | ||||||
|  |         catalog_path.write_text('\n'.join(lines), encoding="utf-8") | ||||||
| 
 | 
 | ||||||
|     def read_cache(self): |     def read_cache(self): | ||||||
|         return read_file(self.cache_file) |         return self.read_file(self.cache_file) | ||||||
| 
 | 
 | ||||||
|     def norm_asset_datas(self, asset_file_datas): |     def norm_asset_datas(self, asset_file_datas): | ||||||
|         ''' Return a new flat list of asset data |         ''' Return a new flat list of asset data | ||||||
| @ -326,8 +412,148 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
| 
 | 
 | ||||||
|         return catalog_parts[:self.blend_depth] |         return catalog_parts[:self.blend_depth] | ||||||
| 
 | 
 | ||||||
|  |     #def transfert_preview(self, ) | ||||||
|  | 
 | ||||||
|  |     ''' | ||||||
|  |     def generate_previews(self, assets, callback): | ||||||
|  |         def _generate_previews(assets, callback, src_assets=None): | ||||||
|  |             if src_assets: | ||||||
|  |                 src_assets = [] | ||||||
|  | 
 | ||||||
|  |             if bpy.app.is_job_running('RENDER_PREVIEW'): | ||||||
|  |                 print("Waiting for render...") | ||||||
|  |                 return 0.2  # waiting time | ||||||
|  |              | ||||||
|  |             while assets:  # generate next preview | ||||||
|  |                 asset = assets.pop()                 | ||||||
|  |                 #print(f"Creating preview for world {world.name}...") | ||||||
|  |                  | ||||||
|  |                 asset_path = asset.asset_data['filepath'] | ||||||
|  |                 src_asset = self.load_datablocks(asset_path, names=asset.name, link=False, type=self.data_types) | ||||||
|  |                 if not src_asset: | ||||||
|  |                     #print(f'No asset named {asset.name} in {asset_path]}') | ||||||
|  |                     return | ||||||
|  | 
 | ||||||
|  |                 src_assets.append(src_asset) | ||||||
|  |                 # # set image in the preview object's material | ||||||
|  |                 # obj = bpy.context.active_object | ||||||
|  |                 # image = world.node_tree.nodes['Environment Texture'].image | ||||||
|  |                 # obj.material_slots[0].material.node_tree.nodes['Image Texture'].image = image | ||||||
|  |                 if self.data_type == 'COLLECTION': | ||||||
|  |                     asset.children.link(src_asset) | ||||||
|  | 
 | ||||||
|  |                 # start preview render | ||||||
|  |                 with bpy.context.temp_override(id=asset): | ||||||
|  |                     bpy.ops.ed.lib_id_generate_preview() | ||||||
|  |                 return 0.2 | ||||||
|  |              | ||||||
|  |             for asset in src_asset: | ||||||
|  |                 asset.user_clear() | ||||||
|  |             bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) | ||||||
|  | 
 | ||||||
|  |             callback() | ||||||
|  |             return None | ||||||
|  | 
 | ||||||
|  |     assets = assets.copy() | ||||||
|  |      | ||||||
|  |     # create preview images | ||||||
|  |     bpy.app.timers.register( | ||||||
|  |         functools.partial( | ||||||
|  |             _generate_previews,  | ||||||
|  |             assets,  | ||||||
|  |             callback | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  |     ''' | ||||||
|  |     def generate_preview(self, asset_description): | ||||||
|  |         """Only generate preview when conforming a library""" | ||||||
|  | 
 | ||||||
|  |         #print('generate_preview', filepath, asset_names, data_type) | ||||||
|  | 
 | ||||||
|  |         scn = bpy.context.scene | ||||||
|  |         #Creating the preview for collection, object or material | ||||||
|  |         camera = scn.camera | ||||||
|  |         vl = bpy.context.view_layer | ||||||
|  | 
 | ||||||
|  |         data_type = self.data_type #asset_description['data_type'] | ||||||
|  |         asset_path = asset_description['filepath'] | ||||||
|  |         asset_data_names = {} | ||||||
|  |         for asset_data in asset_description['assets']: | ||||||
|  | 
 | ||||||
|  |             name = asset_data['name'] | ||||||
|  |             catalog = asset_data['catalog'] | ||||||
|  | 
 | ||||||
|  |             image_path = self.get_image_path(name, asset_path, catalog) | ||||||
|  |             if image_path.exists(): | ||||||
|  |                 continue | ||||||
|  |              | ||||||
|  |             #Store in a dict all asset_data that does not have preview | ||||||
|  |             asset_data_names[name] = dict(asset_data, image_path=image_path) | ||||||
|  |          | ||||||
|  |         if not asset_data_names: | ||||||
|  |             # No preview to generate | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  |         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 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.object.delete(use_global=False) | ||||||
|  | 
 | ||||||
|  |                 #scn.collection.children.unlink(asset) | ||||||
|  | 
 | ||||||
|  |                 bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) | ||||||
|  | 
 | ||||||
|  |     def generate_previews(self): | ||||||
|  |         cache = self.fetch() | ||||||
|  | 
 | ||||||
|  |         #cache_diff.sort(key=lambda x :x['filepath']) | ||||||
|  |         #blend_groups = groupby(cache_diff, key=lambda x :x['filepath']) | ||||||
|  | 
 | ||||||
|  |         #TODO Support all multiple data_type | ||||||
|  |         for asset_description in cache: | ||||||
|  |             self.generate_preview(asset_description) | ||||||
|  | 
 | ||||||
|  |             # filepath = asset_description['filepath'] | ||||||
|  | 
 | ||||||
|  |             # asset_datas = asset_description["assets"] | ||||||
|  | 
 | ||||||
|  |             # asset_datas.sort(key=lambda x :x.get('type', self.data_type)) | ||||||
|  |             # data_type_groups = groupby(asset_datas, key=lambda x :x.get('type', self.data_type)) | ||||||
|  | 
 | ||||||
|  |             # for data_type, same_type_asset_datas in data_type_groups: | ||||||
|  |                  | ||||||
|  |             #     asset_names = [a['name'] for a in same_type_asset_datas] | ||||||
|  |             #     self.generate_preview(filepath, asset_names, data_type) | ||||||
|  |      | ||||||
|     def set_asset_preview(self, asset, asset_data): |     def set_asset_preview(self, asset, asset_data): | ||||||
|         """Load an externalize image as preview for an asset""" |         '''Load an externalize image as preview for an asset''' | ||||||
| 
 | 
 | ||||||
|         image_path = Path(asset_data['image']) |         image_path = Path(asset_data['image']) | ||||||
|         if not image_path.is_absolute(): |         if not image_path.is_absolute(): | ||||||
| @ -339,10 +565,11 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|                 bpy.ops.ed.lib_id_load_custom_preview( |                 bpy.ops.ed.lib_id_load_custom_preview( | ||||||
|                     filepath=str(image_path) |                     filepath=str(image_path) | ||||||
|                 ) |                 ) | ||||||
|             return |  | ||||||
|          |          | ||||||
|         if asset.preview: |         if asset.preview: | ||||||
|             return |             return asset.preview | ||||||
|  |              | ||||||
|  |         return | ||||||
| 
 | 
 | ||||||
|         #Creating the preview for collection, object or material |         #Creating the preview for collection, object or material | ||||||
|         src_asset = self.load_datablocks(asset_data['filepath'], names=asset_data['name'], link=False, type=self.data_types) |         src_asset = self.load_datablocks(asset_data['filepath'], names=asset_data['name'], link=False, type=self.data_types) | ||||||
| @ -350,23 +577,40 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             print(f'No asset named {asset_data["name"]} in {asset_data["filepath"]}') |             print(f'No asset named {asset_data["name"]} in {asset_data["filepath"]}') | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         bpy.ops.ed.lib_id_generate_preview({"id": src_asset}) |         if not self.data_type == 'COLLECTION': | ||||||
|         #time.sleep(0.01) |             print(f'Generate preview of type {self.data_type} not supported yet') | ||||||
|  |             return | ||||||
| 
 | 
 | ||||||
|         #Transfering pixels between previews |         # asset.children.link(src_asset) | ||||||
|         w, h = src_asset.preview.image_size |         # bpy.ops.ed.lib_id_generate_preview({"id": asset}) | ||||||
|         pixels = [0] * (w*h*4) |  | ||||||
|         src_asset.preview.image_pixels_float.foreach_get(pixels) |  | ||||||
| 
 | 
 | ||||||
|         asset.preview_ensure() |         # while bpy.app.is_job_running("RENDER_PREVIEW"): | ||||||
|         asset.preview.image_size = src_asset.preview.image_size |         #     print(bpy.app.is_job_running("RENDER_PREVIEW")) | ||||||
|         asset.preview.image_pixels_float.foreach_set(pixels) |         #     time.sleep(0.2) | ||||||
|  | 
 | ||||||
|  |         # getattr(bpy.data, self.data_types).remove(src_asset) | ||||||
|  |         # return asset.preview | ||||||
|  |         #src_asset.user_clear() | ||||||
|  |         #return src_asset | ||||||
|  | 
 | ||||||
|  |         #asset.children.unlink(src_asset) | ||||||
|  |         #getattr(bpy.data, self.data_types).remove(src_asset) | ||||||
|  |         # time.sleep(1) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         # #Transfering pixels between previews | ||||||
|  |         # w, h = src_asset.preview.image_size | ||||||
|  |         # pixels = [0] * (w*h*4) | ||||||
|  |         # src_asset.preview.image_pixels_float.foreach_get(pixels) | ||||||
|  | 
 | ||||||
|  |         # asset.preview_ensure() | ||||||
|  |         # asset.preview.image_size = src_asset.preview.image_size | ||||||
|  |         # asset.preview.image_pixels_float.foreach_set(pixels) | ||||||
| 
 | 
 | ||||||
|         #print('pixels transfered') |         #print('pixels transfered') | ||||||
| 
 | 
 | ||||||
|         bpy.app.timers.register(partial(getattr(bpy.data, self.data_types).remove, src_asset), first_interval=1) |         #bpy.app.timers.register(partial(getattr(bpy.data, self.data_types).remove, src_asset), first_interval=1) | ||||||
|      |      | ||||||
|         #getattr(bpy.data, self.data_types).remove(src_asset) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def set_asset_catalog(self, asset, asset_data, catalog_data): |     def set_asset_catalog(self, asset, asset_data, catalog_data): | ||||||
| @ -405,6 +649,10 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|                     continue |                     continue | ||||||
|                 asset.asset_data.tags.new(tag, skip_if_exists=True) |                 asset.asset_data.tags.new(tag, skip_if_exists=True) | ||||||
| 
 | 
 | ||||||
|  |     def set_asset_description(self, asset, asset_data): | ||||||
|  |         """Set asset description base on provided data""" | ||||||
|  |         asset.asset_data.description = asset_data.get('description', '') | ||||||
|  | 
 | ||||||
|     def bundle(self, cache_diff=None): |     def bundle(self, cache_diff=None): | ||||||
|         """Group all new assets in one or multiple blends for the asset browser""" |         """Group all new assets in one or multiple blends for the asset browser""" | ||||||
| 
 | 
 | ||||||
| @ -412,7 +660,9 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             print(f'{self.data_type} is not supported yet') |             print(f'{self.data_type} is not supported yet') | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         lib_path = self.library_path |         target_dir = self.target_directory | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|         catalog_data = self.read_catalog() #TODO remove unused catalog |         catalog_data = self.read_catalog() #TODO remove unused catalog | ||||||
| 
 | 
 | ||||||
|         write_cache = False |         write_cache = False | ||||||
| @ -423,11 +673,18 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             # Only write complete cache at the end |             # Only write complete cache at the end | ||||||
|             write_cache = True |             write_cache = True | ||||||
| 
 | 
 | ||||||
|  |             self.generate_previews() | ||||||
|  | 
 | ||||||
|         elif isinstance(cache_diff, (Path, str)): |         elif isinstance(cache_diff, (Path, str)): | ||||||
|             cache_diff = json.loads(Path(cache_diff).read_text(encoding='utf-8')) |             cache_diff = json.loads(Path(cache_diff).read_text(encoding='utf-8')) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |          | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|         if self.blend_depth == 0: |         if self.blend_depth == 0: | ||||||
|             groups = [(cache_diff)] |             raise Exception('Blender depth must be 1 at min') | ||||||
|  |             #groups = [(cache_diff)] | ||||||
|         else: |         else: | ||||||
|             cache_diff.sort(key=self.group_key) |             cache_diff.sort(key=self.group_key) | ||||||
|             groups = groupby(cache_diff, key=self.group_key) |             groups = groupby(cache_diff, key=self.group_key) | ||||||
| @ -440,9 +697,10 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         i = 0 |         i = 0 | ||||||
|  |         #assets_to_preview = [] | ||||||
|         for sub_path, asset_datas in groups: |         for sub_path, asset_datas in groups: | ||||||
|             blend_name = sub_path[-1].replace(' ', '_').lower() |             blend_name = sub_path[-1].replace(' ', '_').lower() | ||||||
|             blend_path = Path(lib_path, *sub_path, blend_name).with_suffix('.blend') |             blend_path = Path(target_dir, *sub_path, blend_name).with_suffix('.blend') | ||||||
| 
 | 
 | ||||||
|             if blend_path.exists(): |             if blend_path.exists(): | ||||||
|                 print(f'Opening existing bundle blend: {blend_path}') |                 print(f'Opening existing bundle blend: {blend_path}') | ||||||
| @ -471,9 +729,10 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|                 elif operation == 'ADD' or not asset: |                 elif operation == 'ADD' or not asset: | ||||||
|                     if asset: |                     if asset: | ||||||
|                         #raise Exception(f"Asset {asset_data['name']} Already in Blend") |                         #raise Exception(f"Asset {asset_data['name']} Already in Blend") | ||||||
|  |                         print(f"Asset {asset_data['name']} Already in Blend") | ||||||
|                         getattr(bpy.data, self.data_types).remove(asset) |                         getattr(bpy.data, self.data_types).remove(asset) | ||||||
| 
 | 
 | ||||||
|                     #print(f"INFO: Add new asset: {asset_data['name']}") |                     print(f"INFO: Add new asset: {asset_data['name']}") | ||||||
|                     asset = getattr(bpy.data, self.data_types).new(name=asset_data['name']) |                     asset = getattr(bpy.data, self.data_types).new(name=asset_data['name']) | ||||||
|                 else: |                 else: | ||||||
|                     print(f'operation {operation} not supported should be in (ADD, REMOVE, MODIFIED)') |                     print(f'operation {operation} not supported should be in (ADD, REMOVE, MODIFIED)') | ||||||
| @ -482,25 +741,35 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|                 asset.asset_mark() |                 asset.asset_mark() | ||||||
| 
 | 
 | ||||||
|                 self.set_asset_preview(asset, asset_data) |                 self.set_asset_preview(asset, asset_data) | ||||||
|  | 
 | ||||||
|  |                 #if not asset_preview: | ||||||
|  |                 #    assets_to_preview.append((asset_data['filepath'], asset_data['name'], asset_data['data_type'])) | ||||||
|                 #if self.externalize_data: |                 #if self.externalize_data: | ||||||
|                 #    self.write_preview(preview, filepath) |                 #    self.write_preview(preview, filepath) | ||||||
| 
 | 
 | ||||||
|                 self.set_asset_catalog(asset, asset_data, catalog_data) |                 self.set_asset_catalog(asset, asset_data, catalog_data) | ||||||
|                 self.set_asset_metadata(asset, asset_data) |                 self.set_asset_metadata(asset, asset_data) | ||||||
|                 self.set_asset_tags(asset, asset_data) |                 self.set_asset_tags(asset, asset_data) | ||||||
|                 asset.asset_data.description = asset_data.get('description', '') |                 self.set_asset_description(asset, asset_data) | ||||||
|  |                  | ||||||
| 
 | 
 | ||||||
|                 i += 1 |                 i += 1 | ||||||
| 
 | 
 | ||||||
|  |             #self.write_asset_preview_file() | ||||||
|  | 
 | ||||||
|  |              | ||||||
|  | 
 | ||||||
|             print(f'Saving Blend to {blend_path}') |             print(f'Saving Blend to {blend_path}') | ||||||
| 
 | 
 | ||||||
|             blend_path.parent.mkdir(exist_ok=True, parents=True) |             #blend_path.parent.mkdir(exist_ok=True, parents=True) | ||||||
|             bpy.ops.wm.save_as_mainfile(filepath=str(blend_path), compress=True) | 
 | ||||||
|  |             #bpy.ops.wm.save_as_mainfile(filepath=str(blend_path), compress=True) | ||||||
|          |          | ||||||
|         #if write_cache: |         #if write_cache: | ||||||
|         #    self.write_cache(cache) |         #    self.write_cache(cache) | ||||||
| 
 | 
 | ||||||
|         #self.write_catalog(catalog_data) |         self.write_catalog(catalog_data) | ||||||
|  | 
 | ||||||
|          |          | ||||||
|         bpy.ops.wm.quit_blender() |         bpy.ops.wm.quit_blender() | ||||||
|      |      | ||||||
| @ -566,4 +835,11 @@ class AssetLibraryAdapter(PropertyGroup): | |||||||
|             layout.prop(self, k, text=bpy.path.display_name(k)) |             layout.prop(self, k, text=bpy.path.display_name(k)) | ||||||
|      |      | ||||||
|     def format_path(self, template, **kargs): |     def format_path(self, template, **kargs): | ||||||
|         return Template(template).format(self.to_dict(), **kargs).resolve() | 
 | ||||||
|  |         params = dict(self.to_dict(),  | ||||||
|  |             bundle_dir=Path(self.library.bundle_directory), | ||||||
|  |             conform_dir=Path(self.library.conform.directory), | ||||||
|  |             **kargs | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         return Template(template).format(params).resolve() | ||||||
| @ -82,8 +82,8 @@ class KitsuLibrary(AssetLibraryAdapter): | |||||||
|                 description=data['description'], |                 description=data['description'], | ||||||
|                 tags=[], |                 tags=[], | ||||||
|                 type=self.data_type, |                 type=self.data_type, | ||||||
|                 image=str(self.image_template.format(name=asset_name)), |                 image=str(self.template_image.format(name=asset_name)), | ||||||
|                 video=str(self.video_template.format(name=asset_name)), |                 video=str(self.template_video.format(name=asset_name)), | ||||||
|                 name=data['name']) |                 name=data['name']) | ||||||
|             ] |             ] | ||||||
|         ) |         ) | ||||||
| @ -98,17 +98,12 @@ class KitsuLibrary(AssetLibraryAdapter): | |||||||
|     def get_preview(self, asset_data): |     def get_preview(self, asset_data): | ||||||
| 
 | 
 | ||||||
|         name = asset_data['name'] |         name = asset_data['name'] | ||||||
|         preview = (f / image_template.format(name=name)).resolve() |         preview = (f / template_image.format(name=name)).resolve() | ||||||
|         if not preview.exists(): |         if not preview.exists(): | ||||||
|             preview_blend_file(f, preview) |             preview_blend_file(f, preview) | ||||||
|          |          | ||||||
|         return preview |         return preview | ||||||
| 
 | 
 | ||||||
|     def conform(self, directory, templates): |  | ||||||
|         """Split each assets per blend and externalize preview""" |  | ||||||
| 
 |  | ||||||
|         print(f'Conforming {self.library.name} to {directory}') |  | ||||||
| 
 |  | ||||||
|          |          | ||||||
|     def fetch(self): |     def fetch(self): | ||||||
|         """Gather in a list all assets found in the folder""" |         """Gather in a list all assets found in the folder""" | ||||||
|  | |||||||
| @ -55,8 +55,8 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|             metadata=dict(asset.asset_data), |             metadata=dict(asset.asset_data), | ||||||
|             tags=asset.asset_data.tags.keys(), |             tags=asset.asset_data.tags.keys(), | ||||||
|             type=self.data_type, |             type=self.data_type, | ||||||
|             image=str(self.image_template.format(name=asset_name)), |             image=str(self.template_image.format(name=asset_name)), | ||||||
|             video=str(self.video_template.format(name=asset_name)), |             video=str(self.template_video.format(name=asset_name)), | ||||||
|             name=asset.name) |             name=asset.name) | ||||||
|         ) |         ) | ||||||
|          |          | ||||||
| @ -178,7 +178,7 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|                 asset.asset_mark() |                 asset.asset_mark() | ||||||
| 
 | 
 | ||||||
|                 # Load external preview if exists |                 # Load external preview if exists | ||||||
|                 #image_template = Template(asset_data['preview']) |                 #template_image = Template(asset_data['preview']) | ||||||
|                 image_path = Path(asset_data['image']) |                 image_path = Path(asset_data['image']) | ||||||
|                 if not image_path.is_absolute(): |                 if not image_path.is_absolute(): | ||||||
|                     image_path = Path(asset_data['filepath'], image_path) |                     image_path = Path(asset_data['filepath'], image_path) | ||||||
| @ -242,7 +242,7 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|     def get_preview(self, asset_data): |     def get_preview(self, asset_data): | ||||||
| 
 | 
 | ||||||
|         name = asset_data['name'] |         name = asset_data['name'] | ||||||
|         preview = (f / image_template.format(name=name)).resolve() |         preview = (f / template_image.format(name=name)).resolve() | ||||||
|         if not preview.exists(): |         if not preview.exists(): | ||||||
|             preview_blend_file(f, preview) |             preview_blend_file(f, preview) | ||||||
|          |          | ||||||
| @ -264,8 +264,8 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|         catalog_ids = {v['id']: {'path': k, 'name': v['name']} for k,v in catalog_data.items()} |         catalog_ids = {v['id']: {'path': k, 'name': v['name']} for k,v in catalog_data.items()} | ||||||
|         directory = Path(directory).resolve() |         directory = Path(directory).resolve() | ||||||
| 
 | 
 | ||||||
|         image_template = templates.get('image') or self.image_template |         template_image = templates.get('image') or self.template_image | ||||||
|         video_template = templates.get('video') or self.video_template |         template_video = templates.get('video') or self.template_video | ||||||
| 
 | 
 | ||||||
|         # Get list of all modifications |         # Get list of all modifications | ||||||
|         for blend_file in self._find_blend_files(): |         for blend_file in self._find_blend_files(): | ||||||
| @ -295,12 +295,12 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|                 asset_path = self.get_asset_path(name=asset.name, catalog=catalog_path, directory=directory) |                 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) |                 asset_description = self.get_asset_description(asset, catalog=catalog_path, modified=modified) | ||||||
| 
 | 
 | ||||||
|                 self.write_asset_description(asset_description, asset_path) |                 self.write_description_file(asset_description, asset_path) | ||||||
|                 #Write blend file containing only one asset |                 #Write blend file containing only one asset | ||||||
|                 self.write_asset(asset=asset, asset_path=asset_path) |                 self.write_asset(asset=asset, asset_path=asset_path) | ||||||
| 
 | 
 | ||||||
|                 # Copy image if source image found else write the asset preview |                 # 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=image_template) |                 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) |                 dst_image_path = self.get_path('image', name=asset.name, asset_path=asset_path) | ||||||
| 
 | 
 | ||||||
|                 if src_image_path.exists(): |                 if src_image_path.exists(): | ||||||
| @ -309,7 +309,7 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|                     self.write_preview(asset.preview, dst_image_path) |                     self.write_preview(asset.preview, dst_image_path) | ||||||
| 
 | 
 | ||||||
|                 # Copy video if source video found |                 # Copy video if source video found | ||||||
|                 src_video_path = self.get_path('video', name=asset.name, asset_path=blend_file, template=video_template) |                 src_video_path = self.get_path('video', name=asset.name, asset_path=blend_file, template=template_video) | ||||||
| 
 | 
 | ||||||
|                 #print('src_video_path', src_video_path) |                 #print('src_video_path', src_video_path) | ||||||
|                 if src_video_path.exists(): |                 if src_video_path.exists(): | ||||||
| @ -364,7 +364,7 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|             if not field_data: |             if not field_data: | ||||||
|                 raise Exception() |                 raise Exception() | ||||||
| 
 | 
 | ||||||
|             #asset_data = (blend_file / prefs.asset_description_template.format(name=name)).resolve() |             #asset_data = (blend_file / prefs.template_description.format(name=name)).resolve() | ||||||
| 
 | 
 | ||||||
|             catalogs = [v for k,v in sorted(field_data.items()) if k.isdigit()] |             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] | ||||||
| @ -387,7 +387,7 @@ class ScanFolderLibrary(AssetLibraryAdapter): | |||||||
|                 continue |                 continue | ||||||
| 
 | 
 | ||||||
|             #First Check if there is a asset_data .json |             #First Check if there is a asset_data .json | ||||||
|             asset_description = self.read_asset_description(blend_file) |             asset_description = self.read_asset_description_file(blend_file) | ||||||
| 
 | 
 | ||||||
|             if not asset_description: |             if not asset_description: | ||||||
|                 # Scan the blend file for assets inside and write a custom asset description for info found |                 # Scan the blend file for assets inside and write a custom asset description for info found | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								collection/preview.blend
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								collection/preview.blend
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -332,6 +332,9 @@ def load_datablocks(src, names=None, type='objects', link=True, expr=None) -> li | |||||||
|     return_list = not isinstance(names, str) |     return_list = not isinstance(names, str) | ||||||
|     names = names or [] |     names = names or [] | ||||||
| 
 | 
 | ||||||
|  |     if type.isupper(): | ||||||
|  |         type = f'{type.lower()}s' | ||||||
|  | 
 | ||||||
|     if not isinstance(names, (list, tuple)): |     if not isinstance(names, (list, tuple)): | ||||||
|         names = [names] |         names = [names] | ||||||
|      |      | ||||||
|  | |||||||
| @ -13,6 +13,17 @@ import importlib | |||||||
| import sys | import sys | ||||||
| import shutil | import shutil | ||||||
| 
 | 
 | ||||||
|  | import contextlib | ||||||
|  | 
 | ||||||
|  | @contextlib.contextmanager | ||||||
|  | def cd(path): | ||||||
|  |     """Changes working directory and returns to previous on exit.""" | ||||||
|  |     prev_cwd = Path.cwd() | ||||||
|  |     os.chdir(path) | ||||||
|  |     try: | ||||||
|  |         yield | ||||||
|  |     finally: | ||||||
|  |         os.chdir(prev_cwd) | ||||||
| 
 | 
 | ||||||
| def install_module(module_name, package_name=None): | def install_module(module_name, package_name=None): | ||||||
|     '''Install a python module with pip or return it if already installed''' |     '''Install a python module with pip or return it if already installed''' | ||||||
|  | |||||||
| @ -181,6 +181,7 @@ def get_asset_source(replace_local=False): | |||||||
| 
 | 
 | ||||||
|     return source_path |     return source_path | ||||||
| 
 | 
 | ||||||
|  | ''' | ||||||
| def get_catalog_path(filepath=None): | def get_catalog_path(filepath=None): | ||||||
|     filepath = filepath or bpy.data.filepath |     filepath = filepath or bpy.data.filepath | ||||||
|     filepath = Path(filepath) |     filepath = Path(filepath) | ||||||
| @ -195,7 +196,7 @@ def get_catalog_path(filepath=None): | |||||||
|         catalog.touch(exist_ok=False) |         catalog.touch(exist_ok=False) | ||||||
| 
 | 
 | ||||||
|     return catalog |     return catalog | ||||||
| 
 | ''' | ||||||
| 
 | 
 | ||||||
| # def read_catalog(path, key='path'): | # def read_catalog(path, key='path'): | ||||||
| #     cat_data = {} | #     cat_data = {} | ||||||
| @ -219,7 +220,7 @@ def get_catalog_path(filepath=None): | |||||||
| #             cat_data[cat_name] = {'id':cat_id, 'path':cat_path} | #             cat_data[cat_name] = {'id':cat_id, 'path':cat_path} | ||||||
|      |      | ||||||
| #     return cat_data | #     return cat_data | ||||||
| 
 | """ | ||||||
| def read_catalog(path): | def read_catalog(path): | ||||||
|     cat_data = {} |     cat_data = {} | ||||||
| 
 | 
 | ||||||
| @ -299,6 +300,7 @@ def create_catalog_file(json_path : str|Path, keep_existing_category : bool = Tr | |||||||
|     print(f'Catalog saved at: {catalog_path}') |     print(f'Catalog saved at: {catalog_path}') | ||||||
| 
 | 
 | ||||||
|     return  |     return  | ||||||
|  | """ | ||||||
| 
 | 
 | ||||||
| def clear_env_libraries(): | def clear_env_libraries(): | ||||||
|     print('clear_env_libraries') |     print('clear_env_libraries') | ||||||
|  | |||||||
| @ -54,14 +54,12 @@ class Template: | |||||||
| 
 | 
 | ||||||
|     def format(self, data=None, **kargs): |     def format(self, data=None, **kargs): | ||||||
| 
 | 
 | ||||||
|         #print('format', self.template, data, kargs) |  | ||||||
| 
 |  | ||||||
|         data = {**(data or {}), **kargs} |         data = {**(data or {}), **kargs} | ||||||
| 
 | 
 | ||||||
|         try: |         try: | ||||||
|             path = self.template.format(**data) |             path = self.template.format(**data) | ||||||
|         except KeyError:  |         except KeyError as e: | ||||||
|             print(f'Cannot format {self.template} with {data}') |             print(f'Cannot format {self.template} with {data}, field {e} is missing') | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         path = os.path.expandvars(path) |         path = os.path.expandvars(path) | ||||||
|  | |||||||
| @ -14,3 +14,4 @@ MODULE_DIR = Path(__file__).parent | |||||||
| RESOURCES_DIR = MODULE_DIR / 'resources' | RESOURCES_DIR = MODULE_DIR / 'resources' | ||||||
| ADAPTER_DIR = MODULE_DIR / 'adapters' | ADAPTER_DIR = MODULE_DIR / 'adapters' | ||||||
| ADAPTERS = [] | ADAPTERS = [] | ||||||
|  | PREVIEW_ASSETS_SCRIPT = MODULE_DIR / 'common' / 'preview_assets.py' | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ command, write_catalog) | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @command | @command | ||||||
| def bundle_library(source_directory, bundle_directory, asset_description_template, thumbnail_template,  | def bundle_library(source_directory, bundle_directory, template_description, thumbnail_template,  | ||||||
|         template=None, data_file=None): |         template=None, data_file=None): | ||||||
| 
 | 
 | ||||||
|     field_pattern = r'{(\w+)}' |     field_pattern = r'{(\w+)}' | ||||||
| @ -38,7 +38,7 @@ def bundle_library(source_directory, bundle_directory, asset_description_templat | |||||||
| 
 | 
 | ||||||
|         name = field_data.get('name', f.stem) |         name = field_data.get('name', f.stem) | ||||||
|         thumbnail = (f / thumbnail_template.format(name=name)).resolve() |         thumbnail = (f / thumbnail_template.format(name=name)).resolve() | ||||||
|         asset_data = (f / asset_description_template.format(name=name)).resolve() |         asset_data = (f / template_description.format(name=name)).resolve() | ||||||
| 
 | 
 | ||||||
|         catalogs = sorted([v for k,v in sorted(field_data.items()) if k.isdigit()]) |         catalogs = sorted([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] | ||||||
| @ -163,7 +163,7 @@ if __name__ == '__main__' : | |||||||
|     bundle_library( |     bundle_library( | ||||||
|         source_directory=args.source_directory, |         source_directory=args.source_directory, | ||||||
|         bundle_directory=args.bundle_directory, |         bundle_directory=args.bundle_directory, | ||||||
|         asset_description_template=args.asset_description_template, |         template_description=args.template_description, | ||||||
|         thumbnail_template=args.thumbnail_template, |         thumbnail_template=args.thumbnail_template, | ||||||
|         template=args.template, |         template=args.template, | ||||||
|         data_file=args.data_file) |         data_file=args.data_file) | ||||||
|  | |||||||
							
								
								
									
										77
									
								
								operators.py
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								operators.py
									
									
									
									
									
								
							| @ -112,8 +112,8 @@ class ASSETLIB_OT_edit_data(Operator): | |||||||
|             new_video_path = lib.adapter.get_path('video', new_name, new_asset_path) |             new_video_path = lib.adapter.get_path('video', new_name, new_asset_path) | ||||||
|             self.old_video_path.rename(new_video_path) |             self.old_video_path.rename(new_video_path) | ||||||
| 
 | 
 | ||||||
|         if self.old_asset_description_path.exists(): |         if self.old_description_path.exists(): | ||||||
|             self.old_asset_description_path.unlink() |             self.old_description_path.unlink() | ||||||
| 
 | 
 | ||||||
|         new_asset_description = lib.adapter.get_asset_description( |         new_asset_description = lib.adapter.get_asset_description( | ||||||
|             asset=self.asset, |             asset=self.asset, | ||||||
| @ -121,7 +121,7 @@ class ASSETLIB_OT_edit_data(Operator): | |||||||
|             modified=time.time_ns() |             modified=time.time_ns() | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         lib.adapter.write_asset_description(new_asset_description, new_asset_path) |         lib.adapter.write_description_file(new_asset_description, new_asset_path) | ||||||
| 
 | 
 | ||||||
|         if not list(self.old_asset_path.parent.iterdir()): |         if not list(self.old_asset_path.parent.iterdir()): | ||||||
|             self.old_asset_path.parent.rmdir() |             self.old_asset_path.parent.rmdir() | ||||||
| @ -187,9 +187,9 @@ class ASSETLIB_OT_edit_data(Operator): | |||||||
|         self.old_image_path = lib.adapter.get_path('image', self.old_asset_name, self.old_asset_path) |         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_video_path = lib.adapter.get_path('video', self.old_asset_name, self.old_asset_path) | ||||||
| 
 | 
 | ||||||
|         self.old_asset_description_path = lib.adapter.get_asset_description_path(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(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] |         self.old_asset_description = lib.adapter.norm_asset_datas([self.old_asset_description])[0] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -408,8 +408,8 @@ class ASSETLIB_OT_conform_library(Operator): | |||||||
|     bl_description = "Split each assets per blend and externalize preview" |     bl_description = "Split each assets per blend and externalize preview" | ||||||
| 
 | 
 | ||||||
|     name : StringProperty() |     name : StringProperty() | ||||||
|     image_template : StringProperty() |     template_image : StringProperty() | ||||||
|     video_template : StringProperty() |     template_video : StringProperty() | ||||||
|     directory : StringProperty(subtype='DIR_PATH', name='Filepath') |     directory : StringProperty(subtype='DIR_PATH', name='Filepath') | ||||||
| 
 | 
 | ||||||
|     def execute(self, context: Context) -> Set[str]: |     def execute(self, context: Context) -> Set[str]: | ||||||
| @ -419,13 +419,13 @@ class ASSETLIB_OT_conform_library(Operator): | |||||||
|         #lib.adapter.conform(self.directory) |         #lib.adapter.conform(self.directory) | ||||||
| 
 | 
 | ||||||
|         templates = {} |         templates = {} | ||||||
|         if self.image_template: |         if self.template_image: | ||||||
|             templates['image'] = self.image_template |             templates['image'] = self.template_image | ||||||
|         if self.video_template: |         if self.template_video: | ||||||
|             templates['video'] = self.video_template |             templates['video'] = self.template_video | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         script_path = Path(gettempdir()) / 'bundle_library.py' |         script_path = Path(bpy.app.tempdir) / 'bundle_library.py' | ||||||
|         script_code = dedent(f""" |         script_code = dedent(f""" | ||||||
|             import bpy |             import bpy | ||||||
|             prefs = bpy.context.preferences.addons["asset_library"].preferences |             prefs = bpy.context.preferences.addons["asset_library"].preferences | ||||||
| @ -447,6 +447,58 @@ class ASSETLIB_OT_conform_library(Operator): | |||||||
|         return {'RUNNING_MODAL'} |         return {'RUNNING_MODAL'} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ASSETLIB_OT_generate_previews(Operator): | ||||||
|  |     bl_idname = "assetlib.generate_previews" | ||||||
|  |     bl_options = {"REGISTER", "UNDO"} | ||||||
|  |     bl_label = "Generate Previews" | ||||||
|  |     bl_description = "Generate and write the image for assets" | ||||||
|  | 
 | ||||||
|  |     diff : StringProperty() | ||||||
|  |     preview_blend : StringProperty() | ||||||
|  |     name : StringProperty() | ||||||
|  |     blocking : BoolProperty(default=True) | ||||||
|  | 
 | ||||||
|  |     def execute(self, context: Context) -> Set[str]: | ||||||
|  |         prefs = get_addon_prefs() | ||||||
|  |         lib = prefs.libraries.get(self.name) | ||||||
|  |         # self.write_file(self.diff_file, self.diff) | ||||||
|  | 
 | ||||||
|  |         # preview_assets = [(a.asset_data['filepath'], self.data_types, a.name) for a in assets] | ||||||
|  | 
 | ||||||
|  |         # self.preview_assets_file.write_text(json.dumps(preview_assets), encoding='utf-8') | ||||||
|  | 
 | ||||||
|  |         # cmd = [ | ||||||
|  |         #     bpy.app.binary_path, '-b', '--use-system-env', | ||||||
|  |         #     '--python', str(PREVIEW_ASSETS_SCRIPT), '--', | ||||||
|  |         #     '--preview-blend', str(self.preview_blend),  | ||||||
|  |         #     '--preview-assets-file', str(self.preview_assets_file) | ||||||
|  |         # ] | ||||||
|  |         # subprocess.call(cmd) | ||||||
|  |         preview_blend = self.preview_blend or lib.adapter.preview_blend | ||||||
|  |          | ||||||
|  |         script_path = Path(bpy.app.tempdir) / 'generate_previews.py' | ||||||
|  |         script_code = dedent(f""" | ||||||
|  |             import bpy | ||||||
|  |             prefs = bpy.context.preferences.addons["asset_library"].preferences | ||||||
|  |             lib = prefs.env_libraries.add() | ||||||
|  |             lib.set_dict({lib.to_dict()}) | ||||||
|  | 
 | ||||||
|  |             bpy.ops.wm.open_mainfile(filepath='{preview_blend}', load_ui=True) | ||||||
|  |             lib.conform.adapter.generate_previews() | ||||||
|  |             """) | ||||||
|  | 
 | ||||||
|  |         script_path.write_text(script_code) | ||||||
|  | 
 | ||||||
|  |         cmd = get_bl_cmd(script=str(script_path), background=True) | ||||||
|  | 
 | ||||||
|  |         if self.blocking: | ||||||
|  |             subprocess.call(cmd) | ||||||
|  |         else: | ||||||
|  |             subprocess.Popen(cmd) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         return {'FINISHED'} | ||||||
|  | 
 | ||||||
| class ASSETLIB_OT_play_preview(Operator): | class ASSETLIB_OT_play_preview(Operator): | ||||||
|     bl_idname = "assetlib.play_preview" |     bl_idname = "assetlib.play_preview" | ||||||
|     bl_options = {"REGISTER", "UNDO", "INTERNAL"} |     bl_options = {"REGISTER", "UNDO", "INTERNAL"} | ||||||
| @ -553,6 +605,7 @@ classes = ( | |||||||
|     ASSETLIB_OT_add_user_library, |     ASSETLIB_OT_add_user_library, | ||||||
|     ASSETLIB_OT_remove_user_library, |     ASSETLIB_OT_remove_user_library, | ||||||
|     ASSETLIB_OT_diff, |     ASSETLIB_OT_diff, | ||||||
|  |     ASSETLIB_OT_generate_previews, | ||||||
|     ASSETLIB_OT_bundle_library, |     ASSETLIB_OT_bundle_library, | ||||||
|     ASSETLIB_OT_clear_asset, |     ASSETLIB_OT_clear_asset, | ||||||
|     ASSETLIB_OT_edit_data, |     ASSETLIB_OT_edit_data, | ||||||
|  | |||||||
							
								
								
									
										69
									
								
								prefs.py
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								prefs.py
									
									
									
									
									
								
							| @ -12,7 +12,7 @@ from asset_library.constants import (DATA_TYPES, DATA_TYPE_ITEMS, | |||||||
| 
 | 
 | ||||||
| from asset_library.common.file_utils import import_module_from_path, norm_str | from asset_library.common.file_utils import import_module_from_path, norm_str | ||||||
| from asset_library.common.bl_utils import get_addon_prefs | from asset_library.common.bl_utils import get_addon_prefs | ||||||
| from asset_library.common.functions import get_catalog_path | #from asset_library.common.functions import get_catalog_path | ||||||
| 
 | 
 | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| import importlib | import importlib | ||||||
| @ -88,14 +88,16 @@ class ConformAssetLibrary(PropertyGroup): | |||||||
|     adapters : bpy.props.PointerProperty(type=AssetLibraryAdapters) |     adapters : bpy.props.PointerProperty(type=AssetLibraryAdapters) | ||||||
|     adapter_name : EnumProperty(items=get_adapter_items) |     adapter_name : EnumProperty(items=get_adapter_items) | ||||||
|     directory : StringProperty( |     directory : StringProperty( | ||||||
|         name="Destination Directory", |         name="Target Directory", | ||||||
|         subtype='DIR_PATH', |         subtype='DIR_PATH', | ||||||
|         default='' |         default='' | ||||||
|     ) |     ) | ||||||
|     image_template : StringProperty() |  | ||||||
|     video_template : StringProperty() |  | ||||||
| 
 | 
 | ||||||
|     externalize_data: BoolProperty(default=False, name='Externalize Data') |     template_image : StringProperty(default='', description='../{name}_image.png') | ||||||
|  |     template_video : StringProperty(default='', description='../{name}_video.mov') | ||||||
|  |     template_description : StringProperty(default='', description='../{name}_asset_description.json') | ||||||
|  |      | ||||||
|  |     #externalize_data: BoolProperty(default=False, name='Externalize Data') | ||||||
|     blend_depth: IntProperty(default=1, name='Blend Depth') |     blend_depth: IntProperty(default=1, name='Blend Depth') | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
| @ -228,23 +230,23 @@ class AssetLibrary(PropertyGroup): | |||||||
|         return self.name |         return self.name | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def image_template(self): |     def template_image(self): | ||||||
|         prefs = get_addon_prefs() |         prefs = get_addon_prefs() | ||||||
|         return prefs.image_template |         return prefs.template_image | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def video_template(self): |     def template_video(self): | ||||||
|         prefs = get_addon_prefs() |         prefs = get_addon_prefs() | ||||||
|         return prefs.video_template |         return prefs.template_video | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def asset_description_template(self): |     def template_description(self): | ||||||
|         prefs = get_addon_prefs() |         prefs = get_addon_prefs() | ||||||
|         return prefs.asset_description_template |         return prefs.template_description | ||||||
| 
 | 
 | ||||||
|     @property |     #@property | ||||||
|     def catalog_path(self): |     #def catalog_path(self): | ||||||
|         return get_catalog_path(self.library_path) |     #    return get_catalog_path(self.library_path) | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def options(self): |     def options(self): | ||||||
| @ -376,7 +378,7 @@ class AssetLibrary(PropertyGroup): | |||||||
|         if not self.use: |         if not self.use: | ||||||
|             if all(not l.use for l in self.merge_libraries): |             if all(not l.use for l in self.merge_libraries): | ||||||
|                 self.clear_library_path() |                 self.clear_library_path() | ||||||
|                 return |             return | ||||||
| 
 | 
 | ||||||
|         # Create the Asset Library Path |         # Create the Asset Library Path | ||||||
|         if not lib: |         if not lib: | ||||||
| @ -470,6 +472,10 @@ class AssetLibrary(PropertyGroup): | |||||||
|         op.name = self.name |         op.name = self.name | ||||||
|         op.conform = True |         op.conform = True | ||||||
| 
 | 
 | ||||||
|  |         op = subrow.operator('assetlib.generate_previews', text='', icon='SEQ_PREVIEW')#, icon='MOD_BUILD' | ||||||
|  |         op.name = self.name | ||||||
|  |         #op.conform = True | ||||||
|  | 
 | ||||||
|         op = subrow.operator('assetlib.bundle', text='', icon='MOD_BUILD')#, icon='MOD_BUILD' |         op = subrow.operator('assetlib.bundle', text='', icon='MOD_BUILD')#, icon='MOD_BUILD' | ||||||
|         op.name = self.name |         op.name = self.name | ||||||
|         op.directory = self.conform.directory |         op.directory = self.conform.directory | ||||||
| @ -479,17 +485,22 @@ class AssetLibrary(PropertyGroup): | |||||||
|         #subrow.separator(factor=3) |         #subrow.separator(factor=3) | ||||||
| 
 | 
 | ||||||
|         if self.expand_extra and self.conform.adapter: |         if self.expand_extra and self.conform.adapter: | ||||||
|  |             col.separator() | ||||||
|  |             self.conform.adapter.draw_prefs(col)     | ||||||
|  | 
 | ||||||
|  |             col.separator() | ||||||
|             col.separator() |             col.separator() | ||||||
|             #row = layout.row(align=True) |             #row = layout.row(align=True) | ||||||
|             #row.label(text='Conform Library') |             #row.label(text='Conform Library') | ||||||
|             col.prop(self.conform, "directory") |             col.prop(self.conform, "directory") | ||||||
|             col.prop(self.conform, "blend_depth") |             col.prop(self.conform, "blend_depth") | ||||||
|             col.prop(self.conform, "externalize_data") |             #col.prop(self.conform, "externalize_data") | ||||||
|             col.prop(self.conform, "image_template", text='Image Template') |             subcol = col.column(align=True) | ||||||
|             col.prop(self.conform, "video_template", text='Video Template') |             subcol.prop(self.conform, "template_description", text='Template Description', icon='COPY_ID') | ||||||
|  |             subcol.prop(self.conform, "template_image", text='Template Image', icon='COPY_ID') | ||||||
|  |             subcol.prop(self.conform, "template_video", text='Template Video', icon='COPY_ID') | ||||||
|  | 
 | ||||||
|                        |                        | ||||||
|             col.separator() |  | ||||||
|             self.conform.adapter.draw_prefs(col)               |  | ||||||
| 
 | 
 | ||||||
|         col.separator() |         col.separator() | ||||||
| 
 | 
 | ||||||
| @ -651,10 +662,10 @@ class AssetLibraryPrefs(AddonPreferences): | |||||||
|         update=update_all_library_path |         update=update_all_library_path | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     use_single_path : BoolProperty(default=True) |     #use_single_path : BoolProperty(default=True) | ||||||
|     asset_description_template : StringProperty(default='../{name}_asset_description.json') |     #template_description : StringProperty(default='../{name}_asset_description.json') | ||||||
|     image_template : StringProperty(default='../{name}_image.png') |     #template_image : StringProperty(default='../{name}_image.png') | ||||||
|     video_template : StringProperty(default='../{name}_video.mov') |     #template_video : StringProperty(default='../{name}_video.mov') | ||||||
| 
 | 
 | ||||||
|     config_directory : StringProperty( |     config_directory : StringProperty( | ||||||
|         name="Config Path", |         name="Config Path", | ||||||
| @ -745,16 +756,16 @@ class AssetLibraryPrefs(AddonPreferences): | |||||||
| 
 | 
 | ||||||
|             col.separator() |             col.separator() | ||||||
| 
 | 
 | ||||||
|             col.prop(self, 'asset_description_template', text='Asset Description Template', icon='COPY_ID') |             #col.prop(self, 'template_description', text='Asset Description Template', icon='COPY_ID') | ||||||
| 
 | 
 | ||||||
|             col.separator() |             #col.separator() | ||||||
| 
 | 
 | ||||||
|             col.prop(self, 'image_template', text='Image Template', icon='COPY_ID') |             #col.prop(self, 'template_image', text='Template Image', icon='COPY_ID') | ||||||
|             col.prop(self, 'image_player', text='Image Player') #icon='OUTLINER_OB_IMAGE' |             col.prop(self, 'image_player', text='Image Player') #icon='OUTLINER_OB_IMAGE' | ||||||
| 
 | 
 | ||||||
|             col.separator() |             #col.separator() | ||||||
| 
 | 
 | ||||||
|             col.prop(self, 'video_template', text='Video Template', icon='COPY_ID') |             #col.prop(self, 'template_video', text='Template Video', icon='COPY_ID') | ||||||
|             col.prop(self, 'video_player', text='Video Player') #icon='FILE_MOVIE' |             col.prop(self, 'video_player', text='Video Player') #icon='FILE_MOVIE' | ||||||
| 
 | 
 | ||||||
|             col.separator() |             col.separator() | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user