270 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| """
 | |
| Plugin for making an asset library of all  blender file found in a folder
 | |
| """
 | |
| 
 | |
| import re
 | |
| from pathlib import Path
 | |
| from itertools import groupby
 | |
| import uuid
 | |
| import os
 | |
| import shutil
 | |
| import json
 | |
| import urllib3
 | |
| import traceback
 | |
| import time
 | |
| 
 | |
| import bpy
 | |
| from bpy.props import (StringProperty, IntProperty, BoolProperty)
 | |
| 
 | |
| from asset_library.plugins.library_plugin import LibraryPlugin
 | |
| from asset_library.core.template import Template
 | |
| from asset_library.core.file_utils import install_module
 | |
| 
 | |
| 
 | |
| class Kitsu(LibraryPlugin):
 | |
| 
 | |
|     name = "Kitsu"
 | |
|     template_name : StringProperty()
 | |
|     template_file : StringProperty()
 | |
|     source_directory : StringProperty(subtype='DIR_PATH')
 | |
|     #blend_depth: IntProperty(default=1)
 | |
|     source_template_image : StringProperty()
 | |
|     target_template_image : StringProperty()
 | |
| 
 | |
|     url: StringProperty()
 | |
|     login: StringProperty()
 | |
|     password: StringProperty(subtype='PASSWORD')
 | |
|     project_name: StringProperty()
 | |
|     
 | |
|     def connect(self, url=None, login=None, password=None):
 | |
|         '''Connect to kitsu api using provided url, login and password'''
 | |
| 
 | |
|         gazu = install_module('gazu')
 | |
|         urllib3.disable_warnings()
 | |
| 
 | |
|         if not self.url:
 | |
|             print(f'Kitsu Url: {self.url} is empty')
 | |
|             return
 | |
| 
 | |
|         url = self.url
 | |
|         if not url.endswith('/api'):
 | |
|             url += '/api'
 | |
| 
 | |
|         print(f'Info: Setting Host for kitsu {url}')
 | |
|         gazu.client.set_host(url)
 | |
| 
 | |
|         if not gazu.client.host_is_up():
 | |
|             print('Error: Kitsu Host is down')
 | |
| 
 | |
|         try:
 | |
|             print(f'Info: Log in to kitsu as {self.login}')
 | |
|             res = gazu.log_in(self.login, self.password)
 | |
|             print(f'Info: Sucessfully login to Kitsu as {res["user"]["full_name"]}')
 | |
|             return res['user']
 | |
|         except Exception as e:
 | |
|             print(f'Error: {traceback.format_exc()}')
 | |
| 
 | |
|     def get_asset_path(self, name, catalog, directory=None):
 | |
|         directory = directory or self.source_directory
 | |
|         return Path(directory, self.get_asset_relative_path(name, catalog))
 | |
| 
 | |
|     def get_asset_info(self, data, asset_path):
 | |
|         
 | |
|         modified = time.time_ns()
 | |
|         catalog = data['entity_type_name'].title()
 | |
|         asset_path = self.prop_rel_path(asset_path, 'source_directory')
 | |
|         #asset_name = self.norm_file_name(data['name'])
 | |
| 
 | |
|         asset_info = dict(
 | |
|             filepath=asset_path,
 | |
|             modified=modified,
 | |
|             library_id=self.library.id,
 | |
|             assets=[dict(
 | |
|                 catalog=catalog,
 | |
|                 metadata=data.get('data', {}),
 | |
|                 description=data['description'],
 | |
|                 tags=[],
 | |
|                 type=self.data_type,
 | |
|                 #image=self.library.template_image,
 | |
|                 #video=self.library.template_video,
 | |
|                 name=data['name'])
 | |
|             ]
 | |
|         )
 | |
|         
 | |
|         return asset_info
 | |
| 
 | |
|     # def bundle(self, cache_diff=None):
 | |
|     #     """Group all asset in one or multiple blends for the asset browser"""
 | |
| 
 | |
|     #     return super().bundle(cache_diff=cache_diff)
 | |
| 
 | |
|     def set_asset_preview(self, asset, asset_data):
 | |
|         '''Load an externalize image as preview for an asset using the source template'''
 | |
| 
 | |
|         asset_path = self.format_path(Path(asset_data['filepath']).as_posix())
 | |
| 
 | |
|         image_path = self.find_path(self.target_template_image, asset_data, filepath=asset_path)
 | |
| 
 | |
|         if image_path:
 | |
|             with bpy.context.temp_override(id=asset):
 | |
|                 bpy.ops.ed.lib_id_load_custom_preview(
 | |
|                     filepath=str(image_path)
 | |
|                 )
 | |
|         else:
 | |
|             print(f'No image found for {self.target_template_image} on {asset.name}')
 | |
|         
 | |
|         if asset.preview:
 | |
|             return asset.preview
 | |
| 
 | |
| 
 | |
|     def generate_previews(self, cache=None):
 | |
|         
 | |
|         print('Generate previews...')
 | |
| 
 | |
|         if cache in (None, ''):
 | |
|             cache = self.fetch()
 | |
|         elif isinstance(cache, (Path, str)):
 | |
|             cache = self.read_cache(cache)
 | |
| 
 | |
|         #TODO Support all multiple data_type
 | |
|         for asset_info in cache:
 | |
| 
 | |
|             if asset_info.get('type', self.data_type) == 'FILE':
 | |
|                 self.generate_blend_preview(asset_info)
 | |
|             else:
 | |
|                 self.generate_asset_preview(asset_info)
 | |
| 
 | |
|     def generate_asset_preview(self, asset_info):
 | |
| 
 | |
|         data_type = self.data_type
 | |
|         scn = bpy.context.scene
 | |
|         vl = bpy.context.view_layer
 | |
| 
 | |
|         asset_path = self.format_path(asset_info['filepath'])
 | |
| 
 | |
|         lens = 85
 | |
| 
 | |
|         if not asset_path.exists():
 | |
|             print(f'Blend file {asset_path} not exit')
 | |
|             return
 | |
| 
 | |
| 
 | |
|         asset_data_names = {}
 | |
| 
 | |
|         # First check wich assets need a preview
 | |
|         for asset_data in asset_info['assets']:
 | |
|             name = asset_data['name']
 | |
|             image_path = self.format_path(self.target_template_image, asset_data, filepath=asset_path)
 | |
| 
 | |
|             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:
 | |
|             print(f'All previews already existing for {asset_path}')
 | |
|             return
 | |
| 
 | |
|         #asset_names = [a['name'] for a in asset_info['assets']]
 | |
|         asset_names = list(asset_data_names.keys())
 | |
|         assets = self.load_datablocks(asset_path, names=asset_names, link=True, type=data_type)
 | |
| 
 | |
|         print(asset_names)
 | |
|         print(assets)
 | |
| 
 | |
|         for asset in assets:
 | |
|             if not asset:
 | |
|                 continue
 | |
|             
 | |
|             print(f'Generate Preview for asset {asset.name}')
 | |
| 
 | |
|             asset_data = asset_data_names[asset.name]
 | |
|             
 | |
|             #print(self.target_template_image, asset_path)
 | |
|             image_path = self.format_path(self.target_template_image, asset_data, filepath=asset_path)
 | |
|             
 | |
|             # Force redo preview
 | |
|             # if asset.preview:
 | |
|             #     print(f'Writing asset preview to {image_path}')
 | |
|             #     self.write_preview(asset.preview, image_path)
 | |
|             #     continue
 | |
| 
 | |
|             if data_type == 'COLLECTION':
 | |
| 
 | |
|                 bpy.ops.object.collection_instance_add(name=asset.name)
 | |
|                 
 | |
|                 scn.camera.data.lens = lens
 | |
|                 bpy.ops.view3d.camera_to_view_selected()
 | |
|                 scn.camera.data.lens -= 5
 | |
| 
 | |
|                 instance = vl.objects.active
 | |
| 
 | |
|                 #scn.collection.children.link(asset)
 | |
|                 
 | |
|                 scn.render.filepath = str(image_path)
 | |
|                 scn.render.image_settings.file_format = self.format_from_ext(image_path.suffix)
 | |
|                 scn.render.image_settings.color_mode = 'RGBA'
 | |
|                 scn.render.image_settings.quality = 90
 | |
| 
 | |
| 
 | |
|                 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.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
 | |
| 
 | |
|     def fetch(self):
 | |
|         """Gather in a list all assets found in the folder"""
 | |
| 
 | |
|         print(f'Fetch Assets for {self.library.name}')
 | |
| 
 | |
|         gazu = install_module('gazu')
 | |
|         self.connect()
 | |
| 
 | |
|         template_file = Template(self.template_file)
 | |
|         template_name = Template(self.template_name)
 | |
| 
 | |
|         project = gazu.client.fetch_first('projects', {'name': self.project_name})
 | |
|         entity_types = gazu.client.fetch_all('entity-types')
 | |
|         entity_types_ids = {e['id']: e['name'] for e in entity_types}
 | |
| 
 | |
|         cache = self.read_cache()
 | |
| 
 | |
|         for asset_data in gazu.asset.all_assets_for_project(project):
 | |
|             asset_data['entity_type_name'] = entity_types_ids[asset_data.pop('entity_type_id')]
 | |
|             asset_name = asset_data['name']
 | |
| 
 | |
|             asset_field_data = dict(asset_name=asset_name, type=asset_data['entity_type_name'], source_directory=self.source_directory)
 | |
| 
 | |
|             try:
 | |
|                 asset_field_data.update(template_name.parse(asset_name))
 | |
|             except Exception:
 | |
|                 print(f'Warning: Could not parse {asset_name} with template {template_name}')
 | |
| 
 | |
|             asset_path = template_file.find(asset_field_data)
 | |
|             if not asset_path:
 | |
|                 print(f'Warning: Could not find file for {template_file.format(asset_field_data)}')
 | |
|                 continue
 | |
| 
 | |
| 
 | |
|             asset_path = self.prop_rel_path(asset_path, 'source_directory')
 | |
|             asset_cache_data = dict(
 | |
|                 catalog=asset_data['entity_type_name'].title(),
 | |
|                 metadata=asset_data.get('data', {}),
 | |
|                 description=asset_data['description'],
 | |
|                 tags=[],
 | |
|                 type=self.data_type,
 | |
|                 name=asset_data['name']
 | |
|             )
 | |
|             
 | |
|             cache.add_asset_cache(asset_cache_data, filepath=asset_path)
 | |
|             
 | |
| 
 | |
|         return cache
 |