Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSybren A. Stüvel <sybren@stuvel.eu>2021-07-02 14:34:43 +0300
committerSybren A. Stüvel <sybren@stuvel.eu>2021-07-02 14:34:43 +0300
commitfb377f2a92c7b99cc6b2882621d8cae5a56302df (patch)
tree59bc7aea5895dd6c79072b769fd08c1b47c20a3b
parent5af0466627e0e5fb799a737796c149c8e1ee56ed (diff)
parentc84f83153900009f1c7743e3b21792ab1a730257 (diff)
Merge remote-tracking branch 'origin/master' into asset-browser-poselib
-rw-r--r--blenderkit/__init__.py29
-rw-r--r--blenderkit/bg_blender.py7
-rw-r--r--blenderkit/categories.py26
-rw-r--r--blenderkit/download.py43
-rw-r--r--blenderkit/paths.py2
-rw-r--r--blenderkit/rerequests.py14
-rw-r--r--blenderkit/search.py79
-rw-r--r--blenderkit/tasks_queue.py4
-rw-r--r--blenderkit/thumbnails/intro.jpgbin0 -> 66605 bytes
-rw-r--r--blenderkit/ui.py27
-rw-r--r--blenderkit/ui_panels.py78
-rw-r--r--blenderkit/upload.py1
-rw-r--r--blenderkit/utils.py16
13 files changed, 250 insertions, 76 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py
index e8043626..c58e5d99 100644
--- a/blenderkit/__init__.py
+++ b/blenderkit/__init__.py
@@ -155,10 +155,10 @@ def scene_load(context):
@bpy.app.handlers.persistent
def check_timers_timer():
''' checks if all timers are registered regularly. Prevents possible bugs from stopping the addon.'''
- if not bpy.app.timers.is_registered(search.timer_update):
- bpy.app.timers.register(search.timer_update)
- if not bpy.app.timers.is_registered(download.timer_update):
- bpy.app.timers.register(download.timer_update)
+ if not bpy.app.timers.is_registered(search.search_timer):
+ bpy.app.timers.register(search.search_timer)
+ if not bpy.app.timers.is_registered(download.download_timer):
+ bpy.app.timers.register(download.download_timer)
if not (bpy.app.timers.is_registered(tasks_queue.queue_worker)):
bpy.app.timers.register(tasks_queue.queue_worker)
if not bpy.app.timers.is_registered(bg_blender.bg_update):
@@ -1542,7 +1542,7 @@ class BlenderKitSceneSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
)
switch_after_append: BoolProperty(
name='Switch to scene after download',
- default=False
+ default=True
)
@@ -1714,6 +1714,13 @@ class BlenderKitAddonPreferences(AddonPreferences):
update=utils.save_prefs
)
+ # single_timer: BoolProperty(
+ # name="Use timers",
+ # description="Use timers for BlenderKit. Usefull for debugging since timers seem to be unstable",
+ # default=True,
+ # update=utils.save_prefs
+ # )
+
experimental_features: BoolProperty(
name="Enable experimental features",
description="Enable all experimental features of BlenderKit. Use at your own risk.",
@@ -1773,6 +1780,15 @@ class BlenderKitAddonPreferences(AddonPreferences):
layout.prop(self, "categories_fix")
+# # @bpy.app.handlers.persistent
+# def blenderkit_timer():
+#
+#
+# if not user_preferences.use_timers:
+# search.search_timer()
+# download.download_timer()
+# tasks_queue.queue_worker()
+# bg_blender.bg_update()
# registration
classes = (
@@ -1800,6 +1816,7 @@ classes = (
)
+
def register():
for cls in classes:
bpy.utils.register_class(cls)
@@ -1874,6 +1891,8 @@ def register():
if a.type == 'PREFERENCES':
tasks_queue.add_task((bpy.ops.wm.blenderkit_welcome, ('INVOKE_DEFAULT',)), fake_context=True,
fake_context_area='PREFERENCES')
+ #save preferences after manually enabling the addon
+ tasks_queue.add_task((bpy.ops.wm.save_userpref, ()), fake_context=False,)
def unregister():
diff --git a/blenderkit/bg_blender.py b/blenderkit/bg_blender.py
index 01c62538..c4294b30 100644
--- a/blenderkit/bg_blender.py
+++ b/blenderkit/bg_blender.py
@@ -108,11 +108,14 @@ def bg_update():
'''monitoring of background process'''
text = ''
#utils.p('timer search')
+ # utils.p('start bg_blender timer bg_update')
s = bpy.context.scene
global bg_processes
if len(bg_processes) == 0:
+ # utils.p('end bg_blender timer bg_update')
+
return 2
#cleanup dead processes first
remove_processes = []
@@ -156,7 +159,11 @@ def bg_update():
# if len(bg_processes) == 0:
# bpy.app.timers.unregister(bg_update)
if len(bg_processes) > 0:
+ # utils.p('end bg_blender timer bg_update')
+
return .3
+ # utils.p('end bg_blender timer bg_update')
+
return 1.
diff --git a/blenderkit/categories.py b/blenderkit/categories.py
index f91fe512..3a0d2624 100644
--- a/blenderkit/categories.py
+++ b/blenderkit/categories.py
@@ -81,11 +81,35 @@ def get_category_path(categories, category):
slug = ch['slug']
while parents.get(slug):
slug = parents.get(slug)
-
category_path.insert(0, slug)
return category_path
check_categories.append(ch)
+ return category_path
+
+def get_category_name_path(categories, category):
+ '''finds the category in all possible subcategories and returns the path to it'''
+ category_path = []
+ check_categories = categories[:]
+ parents = {}
+ utils.pprint(categories)
+ while len(check_categories) > 0:
+ ccheck = check_categories.pop()
+ # print(ccheck['name'])
+ if not ccheck.get('children'):
+ continue
+ for ch in ccheck['children']:
+ # print(ch['name'])
+ parents[ch['slug']] = ccheck['slug']
+
+ if ch['slug'] == category:
+ category_path = [ch['slug']]
+ slug = ch['slug']
+ while parents.get(slug):
+ slug = parents.get(slug)
+ category_path.insert(0, slug)
+ return category_path
+ check_categories.append(ch)
def get_category(categories, cat_path=()):
for category in cat_path:
diff --git a/blenderkit/download.py b/blenderkit/download.py
index 7cffff44..f0c101a1 100644
--- a/blenderkit/download.py
+++ b/blenderkit/download.py
@@ -17,7 +17,7 @@
# ##### END GPL LICENSE BLOCK #####
-from blenderkit import paths, append_link, utils, ui, colors, tasks_queue, rerequests, resolutions
+from blenderkit import paths, append_link, utils, ui, colors, tasks_queue, rerequests, resolutions, ui_panels
import threading
import time
@@ -62,7 +62,7 @@ def check_missing():
for l in missing:
asset_data = l['asset_data']
- downloaded = check_existing(asset_data, resolution=asset_data['resolution'])
+ downloaded = check_existing(asset_data, resolution=asset_data.get('resolution'))
if downloaded:
try:
l.reload()
@@ -315,11 +315,11 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None,
sprops = s.blenderkit_scene
scene = append_link.append_scene(file_names[0], link=sprops.append_link == 'LINK', fake_user=False)
- print('scene appended')
+ # print('scene appended')
if scene is not None:
props = scene.blenderkit
asset_main = scene
- print(sprops.switch_after_append)
+ # print(sprops.switch_after_append)
if sprops.switch_after_append:
bpy.context.window_manager.windows[0].scene = scene
@@ -563,7 +563,7 @@ def replace_resolution_appended(file_paths, asset_data, resolution):
# @bpy.app.handlers.persistent
-def timer_update():
+def download_timer():
# TODO might get moved to handle all blenderkit stuff, not to slow down.
'''
check for running and finished downloads.
@@ -571,10 +571,14 @@ def timer_update():
Finished downloads are processed and linked/appended to scene.
'''
global download_threads
+ # utils.p('start download timer')
+
# bk_logger.debug('timer download')
if len(download_threads) == 0:
- return 2.0
+ # utils.p('end download timer')
+
+ return 2
s = bpy.context.scene
for threaddata in download_threads:
t = threaddata[0]
@@ -589,13 +593,14 @@ def timer_update():
if sr is not None:
for r in sr:
if asset_data['id'] == r['id']:
- r['downloaded'] = tcom.progress
-
+ r['downloaded'] = 0.5#tcom.progress
if not t.is_alive():
if tcom.error:
sprops = utils.get_search_props()
sprops.report = tcom.report
download_threads.remove(threaddata)
+ # utils.p('end download timer')
+
return
file_paths = paths.get_download_filepaths(asset_data, tcom.passargs['resolution'])
@@ -661,6 +666,8 @@ def timer_update():
sres['downloaded'] = 100
bk_logger.debug('finished download thread')
+ # utils.p('end download timer')
+
return .5
@@ -753,6 +760,7 @@ class Downloader(threading.Thread):
# def main_download_thread(asset_data, tcom, scene_id, api_key):
def run(self):
'''try to download file from blenderkit'''
+ # utils.p('start downloader thread')
asset_data = self.asset_data
tcom = self.tcom
scene_id = self.scene_id
@@ -832,6 +840,8 @@ class Downloader(threading.Thread):
tcom.report = f'Unpacking files'
self.asset_data['resolution'] = self.resolution
resolutions.send_to_bg(self.asset_data, file_name, command='unpack')
+ # utils.p('end downloader thread')
+
class ThreadCom: # object passed to threads to read background process stdout info
@@ -1226,7 +1236,7 @@ def show_enum_values(obj, prop_name):
class BlenderkitDownloadOperator(bpy.types.Operator):
"""Download and link asset to scene. Only link if asset already available locally"""
bl_idname = "scene.blenderkit_download"
- bl_label = "BlenderKit Asset Download"
+ bl_label = "Download"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
# asset_type: EnumProperty(
@@ -1258,6 +1268,8 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
invoke_resolution: BoolProperty(name='Replace resolution popup',
description='pop up to ask which resolution to download', default=False)
+ invoke_scene_settings: BoolProperty(name='Scene import settings popup',
+ description='pop up scene import settings', default=False)
resolution: EnumProperty(
items=available_resolutions_callback,
@@ -1376,7 +1388,10 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
def draw(self, context):
layout = self.layout
- layout.prop(self, 'resolution', expand=True, icon_only=False)
+ if self.invoke_resolution:
+ layout.prop(self, 'resolution', expand=True, icon_only=False)
+ if self.invoke_scene_settings:
+ ui_panels.draw_scene_import_settings(self, context)
def invoke(self, context, event):
# if self.close_window:
@@ -1399,6 +1414,8 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
self.resolution = 'ORIGINAL'
return wm.invoke_props_dialog(self)
+ if self.invoke_scene_settings:
+ return wm.invoke_props_dialog(self)
# if self.close_window:
# time.sleep(0.1)
# context.area.tag_redraw()
@@ -1416,7 +1433,7 @@ def register_download():
bpy.app.handlers.save_pre.append(scene_save)
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
if user_preferences.use_timers:
- bpy.app.timers.register(timer_update)
+ bpy.app.timers.register(download_timer)
def unregister_download():
@@ -1424,5 +1441,5 @@ def unregister_download():
bpy.utils.unregister_class(BlenderkitKillDownloadOperator)
bpy.app.handlers.load_post.remove(scene_load)
bpy.app.handlers.save_pre.remove(scene_save)
- if bpy.app.timers.is_registered(timer_update):
- bpy.app.timers.unregister(timer_update)
+ if bpy.app.timers.is_registered(download_timer):
+ bpy.app.timers.unregister(download_timer)
diff --git a/blenderkit/paths.py b/blenderkit/paths.py
index 0ca55271..57511108 100644
--- a/blenderkit/paths.py
+++ b/blenderkit/paths.py
@@ -27,7 +27,7 @@ BLENDERKIT_API = "/api/v1/"
BLENDERKIT_REPORT_URL = "usage_report/"
BLENDERKIT_USER_ASSETS = "/my-assets"
BLENDERKIT_PLANS = "/plans/pricing/"
-BLENDERKIT_MANUAL = "https://youtu.be/1hVgcQhIAo8"
+BLENDERKIT_MANUAL = "https://youtu.be/pSay3yaBWV0"
BLENDERKIT_MODEL_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/upload/"
BLENDERKIT_MATERIAL_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-material/"
BLENDERKIT_BRUSH_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-brush/"
diff --git a/blenderkit/rerequests.py b/blenderkit/rerequests.py
index 6a2659c2..f9c51559 100644
--- a/blenderkit/rerequests.py
+++ b/blenderkit/rerequests.py
@@ -22,10 +22,11 @@ from blenderkit import ui, utils, paths, tasks_queue, bkit_oauth
import requests
import bpy
import logging
+
bk_logger = logging.getLogger('rerequests')
-def rerequest(method, url, **kwargs):
+def rerequest(method, url, recursion=0, **kwargs):
# first get any additional args from kwargs
immediate = False
if kwargs.get('immediate'):
@@ -34,10 +35,11 @@ def rerequest(method, url, **kwargs):
# first normal attempt
try:
response = requests.request(method, url, **kwargs)
- except:
- return rerequest(method, url, **kwargs)
+ except Exception as e:
+ print(e)
+ return None
- bk_logger.debug(url+ str( kwargs))
+ bk_logger.debug(url + str(kwargs))
bk_logger.debug(response.status_code)
if response.status_code == 401:
@@ -53,7 +55,7 @@ def rerequest(method, url, **kwargs):
if user_preferences.api_key != '':
if user_preferences.enable_oauth and user_preferences.api_key_refresh != '':
tasks_queue.add_task((ui.add_report, (
- 'refreshing token. If this fails, please login in BlenderKit Login panel.', 10)))
+ 'refreshing token. If this fails, please login in BlenderKit Login panel.', 10)))
refresh_url = paths.get_bkit_url()
auth_token, refresh_token, oauth_response = bkit_oauth.refresh_token(
user_preferences.api_key_refresh, refresh_url)
@@ -80,7 +82,7 @@ def rerequest(method, url, **kwargs):
tasks_queue.add_task((ui.add_report, (
'Refreshing token failed.Please login manually.', 10)))
# tasks_queue.add_task((bkit_oauth.write_tokens, ('', '', '')))
- tasks_queue.add_task((bpy.ops.wm.blenderkit_login,( 'INVOKE_DEFAULT',)),fake_context = True)
+ tasks_queue.add_task((bpy.ops.wm.blenderkit_login, ('INVOKE_DEFAULT',)), fake_context=True)
return response
diff --git a/blenderkit/search.py b/blenderkit/search.py
index 534f4a09..dbe25d61 100644
--- a/blenderkit/search.py
+++ b/blenderkit/search.py
@@ -48,6 +48,7 @@ import copy
import json
import math
import unicodedata
+import urllib
import queue
import logging
@@ -80,7 +81,7 @@ reports_queue = queue.Queue()
rtips = ['Click or drag model or material in scene to link/append ',
"Please rate responsively and plentifully. This helps us distribute rewards to the authors.",
"Click on brushes to link them into scene.",
- "All materials and brushes are free.",
+ "All materials are free.",
"Storage for public assets is unlimited.",
"Locked models are available if you subscribe to Full plan.",
"Login to upload your own models, materials or brushes.",
@@ -246,7 +247,7 @@ def parse_result(r):
durl, tname, small_tname = '', '', ''
if r['assetType'] == 'hdr':
- tname = paths.extract_filename_from_url(r['thumbnailMiddleUrlNonsquared'])
+ tname = paths.extract_filename_from_url(r['thumbnailLargeUrlNonsquared'])
else:
tname = paths.extract_filename_from_url(r['thumbnailMiddleUrl'])
small_tname = paths.extract_filename_from_url(r['thumbnailSmallUrl'])
@@ -349,10 +350,10 @@ def parse_result(r):
# @bpy.app.handlers.persistent
-def timer_update():
+def search_timer():
# this makes a first search after opening blender. showing latest assets.
# utils.p('timer search')
-
+ # utils.p('start search timer')
global first_time
preferences = bpy.context.preferences.addons['blenderkit'].preferences
if first_time and not bpy.app.background: # first time
@@ -367,6 +368,8 @@ def timer_update():
utils.get_largest_area()
ui.update_ui_size(ui.active_area_pointer, ui.active_region_pointer)
ui.add_report(text='BlenderKit Tip: ' + random.choice(rtips), timeout=12, color=colors.GREEN)
+ # utils.p('end search timer')
+
return 3.0
# if preferences.first_run:
@@ -377,10 +380,14 @@ def timer_update():
global search_threads
if len(search_threads) == 0:
+ # utils.p('end search timer')
+
return 1.0
# don't do anything while dragging - this could switch asset during drag, and make results list length different,
# causing a lot of throuble.
if bpy.context.scene.blenderkitUI.dragging:
+ # utils.p('end search timer')
+
return 0.5
for thread in search_threads:
# TODO this doesn't check all processes when one gets removed,
@@ -415,6 +422,8 @@ def timer_update():
while not reports_queue.empty():
props.report = str(reports_queue.get())
+ # utils.p('end search timer')
+
return .2
rdata = thread[0].result
@@ -422,7 +431,10 @@ def timer_update():
ok, error = check_errors(rdata)
if ok:
- bpy.ops.object.run_assetbar_fix_context()
+ ui_props = bpy.context.scene.blenderkitUI
+
+ if not ui_props.assetbar_on:
+ bpy.ops.object.run_assetbar_fix_context()
@@ -432,14 +444,14 @@ def timer_update():
result_field.append(asset_data)
# Get ratings from BlenderKit server
- if utils.profile_is_validator():
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- api_key = user_preferences.api_key
- headers = utils.get_headers(api_key)
- for r in rdata['results']:
- if ratings_utils.get_rating_local(asset_data['id']) is None:
- thread = threading.Thread(target=ratings_utils.get_rating, args=([r['id'], headers]), daemon=True)
- thread.start()
+ # if utils.profile_is_validator():
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ api_key = user_preferences.api_key
+ headers = utils.get_headers(api_key)
+ for r in rdata['results']:
+ if ratings_utils.get_rating_local(asset_data['id']) is None:
+ rating_thread = threading.Thread(target=ratings_utils.get_rating, args=([r['id'], headers]), daemon=True)
+ rating_thread.start()
wm[search_name] = result_field
wm['search results'] = result_field
@@ -447,7 +459,6 @@ def timer_update():
wm['search results orig'] = wm[search_name + ' orig']
load_previews()
- ui_props = bpy.context.scene.blenderkitUI
if len(result_field) < ui_props.scrolloffset or not (thread[0].params.get('get_next')):
# jump back
ui_props.scrolloffset = 0
@@ -457,7 +468,7 @@ def timer_update():
if len(wm['search results']) == 0:
tasks_queue.add_task((ui.add_report, ('No matching results found.',)))
# undo push
- bpy.ops.wm.undo_push_context(message='Get BlenderKit search')
+ # bpy.ops.wm.undo_push_context(message='Get BlenderKit search')
else:
bk_logger.error(error)
@@ -466,6 +477,7 @@ def timer_update():
# print('finished search thread')
mt('preview loading finished')
+ # utils.p('end search timer')
return .3
@@ -642,6 +654,7 @@ class ThumbDownloader(threading.Thread):
def run(self):
# print('thumb downloader', self.url)
+ # utils.p('start thumbdownloader thread')
r = None
try:
r = requests.get(self.url, stream=False)
@@ -655,6 +668,8 @@ class ThumbDownloader(threading.Thread):
# with open(path, 'wb') as f:
# for chunk in r.iter_content(1048576*4):
# f.write(chunk)
+ # utils.p('end thumbdownloader thread')
+
def write_gravatar(a_id, gravatar_path):
@@ -800,7 +815,8 @@ def query_to_url(query={}, params={}):
order.append('-score,_score')
else:
order.append('_score')
- requeststring += '+order:' + ','.join(order)
+ if requeststring.find('+order:')==-1:
+ requeststring += '+order:' + ','.join(order)
requeststring += '&addon_version=%s' % params['addon_version']
if params.get('scene_uuid') is not None:
@@ -843,6 +859,8 @@ class Searcher(threading.Thread):
params = self.params
t = time.time()
+ # utils.p('start search thread')
+
mt('search thread started')
# tempdir = paths.get_temp_dir('%s_search' % query['asset_type'])
# json_filepath = os.path.join(tempdir, '%s_searchresult.json' % query['asset_type'])
@@ -856,6 +874,8 @@ class Searcher(threading.Thread):
except requests.exceptions.RequestException as e:
bk_logger.error(e)
reports_queue.put(str(e))
+ # utils.p('end search thread')
+
return
mt('search response is back ')
@@ -875,10 +895,14 @@ class Searcher(threading.Thread):
# it means it's a server error that has a clear message.
# That's why it gets processed in the update timer, where it can be passed in messages to user.
self.result = rdata
+ # utils.p('end search thread')
+
return
# print('number of results: ', len(rdata.get('results', [])))
if self.stopped():
utils.p('stopping search : ' + str(query))
+ # utils.p('end search thread')
+
return
mt('search finished')
@@ -896,7 +920,7 @@ class Searcher(threading.Thread):
thumb_small_filepaths.append(imgpath)
if d["assetType"] == 'hdr':
- larege_thumb_url = d['thumbnailMiddleUrlNonsquared']
+ larege_thumb_url = d['thumbnailLargeUrlNonsquared']
else:
larege_thumb_url = d['thumbnailMiddleUrl']
@@ -945,10 +969,12 @@ class Searcher(threading.Thread):
for k in thumb_full_download_threads.keys():
if k not in thumb_full_filepaths:
killthreads_full.append(k) # do actual killing here?
- # TODO do the killing/ stopping here! remember threads might have finished inbetween!
+ # TODO do the killing/ stopping here. remember threads might have finished inbetween.
if self.stopped():
utils.p('stopping search : ' + str(query))
+ # utils.p('end search thread')
+
return
# this loop handles downloading of small thumbnails
@@ -973,6 +999,8 @@ class Searcher(threading.Thread):
i += 1
if self.stopped():
utils.p('stopping search : ' + str(query))
+ # utils.p('end search thread')
+
return
idx = 0
while len(thumb_sml_download_threads) > 0:
@@ -984,6 +1012,8 @@ class Searcher(threading.Thread):
i += 1
if self.stopped():
+ # utils.p('end search thread')
+
utils.p('stopping search : ' + str(query))
return
@@ -995,6 +1025,7 @@ class Searcher(threading.Thread):
# daemon=True)
thread.start()
thumb_full_download_threads[imgpath] = thread
+ # utils.p('end search thread')
mt('thumbnails finished')
@@ -1002,7 +1033,9 @@ def build_query_common(query, props):
'''add shared parameters to query'''
query_common = {}
if props.search_keywords != '':
- query_common["query"] = props.search_keywords
+ # keywords = urllib.parse.urlencode(props.search_keywords)
+ keywords = props.search_keywords.replace('&','%26')
+ query_common["query"] = keywords
if props.search_verification_status != 'ALL' and utils.profile_is_validator():
query_common['verification_status'] = props.search_verification_status.lower()
@@ -1215,7 +1248,7 @@ def get_search_simple(parameters, filepath=None, page_size=100, max_results=1000
requeststring += '&page_size=' + str(page_size)
bk_logger.debug(requeststring)
response = rerequests.get(requeststring, headers=headers) # , params = rparameters)
- # print(r.json())
+ # print(response.json())
search_results = response.json()
results = []
@@ -1504,7 +1537,7 @@ def register_search():
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
if user_preferences.use_timers:
- bpy.app.timers.register(timer_update)
+ bpy.app.timers.register(search_timer)
categories.load_categories()
@@ -1515,5 +1548,5 @@ def unregister_search():
for c in classes:
bpy.utils.unregister_class(c)
- if bpy.app.timers.is_registered(timer_update):
- bpy.app.timers.unregister(timer_update)
+ if bpy.app.timers.is_registered(search_timer):
+ bpy.app.timers.unregister(search_timer)
diff --git a/blenderkit/tasks_queue.py b/blenderkit/tasks_queue.py
index f52cfd63..0d991878 100644
--- a/blenderkit/tasks_queue.py
+++ b/blenderkit/tasks_queue.py
@@ -58,6 +58,8 @@ def add_task(task, wait = 0, only_last = False, fake_context = False, fake_conte
def queue_worker():
+ # utils.p('start queue worker timer')
+
#bk_logger.debug('timer queue worker')
time_step = 2.0
q = get_queue()
@@ -110,6 +112,8 @@ def queue_worker():
# print('queue while 2')
for task in back_to_queue:
q.put(task)
+ # utils.p('end queue worker timer')
+
return 2.0
diff --git a/blenderkit/thumbnails/intro.jpg b/blenderkit/thumbnails/intro.jpg
new file mode 100644
index 00000000..52ce56e3
--- /dev/null
+++ b/blenderkit/thumbnails/intro.jpg
Binary files differ
diff --git a/blenderkit/ui.py b/blenderkit/ui.py
index f6438d85..68c19cf0 100644
--- a/blenderkit/ui.py
+++ b/blenderkit/ui.py
@@ -371,13 +371,17 @@ def draw_tooltip_with_author(asset_data, x, y):
img = get_large_thumbnail_image(asset_data)
gimg = None
- atip = ''
+ author_text = ''
+
if bpy.context.window_manager.get('bkit authors') is not None:
a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id'])
if a is not None and a != '':
if a.get('gravatarImg') is not None:
gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash'])
+ if len(a['firstName'])>0 or len(a['lastName'])>0:
+ author_text = f"by {a['firstName']} {a['lastName']}"
+
aname = asset_data['displayName']
aname = aname[0].upper() + aname[1:]
if len(aname) > 36:
@@ -388,12 +392,9 @@ def draw_tooltip_with_author(asset_data, x, y):
rcount = 0
quality = '-'
if rc:
- rcount = min(rc['quality'], rc['workingHours'])
+ rcount = min(rc.get('quality',0), rc.get('workingHours',0))
if rcount > show_rating_threshold:
quality = round(asset_data['ratingsAverage'].get('quality'))
- author_text = ''
- if len(a['firstName'])>0 or len(a['lastName'])>0:
- author_text = f"by {a['firstName']} {a['lastName']}"
draw_tooltip(x, y, name=aname, author=author_text, quality=quality, img=img,
gravatar=gimg)
@@ -482,12 +483,14 @@ def draw_callback_2d_progress(self, context):
loc = view3d_utils.location_3d_to_region_2d(bpy.context.region, bpy.context.space_data.region_3d,
d['location'])
+ # print('drawing downloader')
if loc is not None:
if asset_data['assetType'] == 'model':
# models now draw with star trek mode, no need to draw percent for the image.
draw_downloader(loc[0], loc[1], percent=tcom.progress, img=img, text=tcom.report)
else:
draw_downloader(loc[0], loc[1], percent=tcom.progress, img=img, text=tcom.report)
+ # utils.p('end drawing downlaoders downloader')
else:
draw_progress(x, y - index * 30, text='downloading %s' % asset_data['name'],
percent=tcom.progress)
@@ -1191,8 +1194,8 @@ class AssetBarOperator(bpy.types.Operator):
# timers testing - seems timers might be causing crashes. testing it this way now.
if not user_preferences.use_timers:
- search.timer_update()
- download.timer_update()
+ search.search_timer()
+ download.download_timer()
tasks_queue.queue_worker()
bg_blender.bg_update()
@@ -1450,7 +1453,7 @@ class AssetBarOperator(bpy.types.Operator):
if not asset_data.get('canDownload'):
message = "Let's support asset creators and Open source."
link_text = 'Unlock the asset.'
- url = paths.get_bkit_url() + '/get-blenderkit/' + asset_data['id'] + '/?from_addon'
+ url = paths.get_bkit_url() + '/get-blenderkit/' + asset_data['id'] + '/?from_addon=True'
bpy.ops.wm.blenderkit_url_dialog('INVOKE_REGION_WIN', url=url, message=message,
link_text=link_text)
return {'RUNNING_MODAL'}
@@ -1625,6 +1628,14 @@ class AssetBarOperator(bpy.types.Operator):
invoke_resolution=True,
max_resolution=asset_data.get('max_resolution', 0)
)
+ elif ui_props.asset_type == 'SCENE':
+ bpy.ops.scene.blenderkit_download('INVOKE_DEFAULT',
+ asset_index=asset_search_index,
+ # replace_resolution=True,
+ invoke_resolution=False,
+ invoke_scene_settings=True,
+ max_resolution=asset_data.get('max_resolution', 0)
+ )
else:
bpy.ops.scene.blenderkit_download( # asset_type=ui_props.asset_type,
asset_index=asset_search_index,
diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py
index b92e985d..fe91658c 100644
--- a/blenderkit/ui_panels.py
+++ b/blenderkit/ui_panels.py
@@ -36,6 +36,7 @@ from bpy.props import (
import bpy
import os
+import random
import logging
bk_logger = logging.getLogger('blenderkit')
@@ -887,6 +888,15 @@ class VIEW3D_PT_blenderkit_categories(Panel):
def draw(self, context):
draw_panel_categories(self, context)
+def draw_scene_import_settings(self, context):
+ s = context.scene
+ props = s.blenderkit_scene
+ layout = self.layout
+ layout.prop(props, 'switch_after_append')
+ # layout.label(text='Import method:')
+ row = layout.row()
+ row.prop(props, 'append_link', expand=True, icon_only=False)
+
class VIEW3D_PT_blenderkit_import_settings(Panel):
bl_category = "BlenderKit"
@@ -931,11 +941,8 @@ class VIEW3D_PT_blenderkit_import_settings(Panel):
row.prop(props, 'append_method', expand=True, icon_only=False)
if ui_props.asset_type == 'SCENE':
- props = s.blenderkit_scene
- layout.prop(props, 'switch_after_append')
- layout.label(text='Import method:')
- row = layout.row()
- row.prop(props, 'append_link', expand=True, icon_only=False)
+ draw_scene_import_settings(self,context)
+
if ui_props.asset_type == 'HDR':
props = s.blenderkit_HDR
@@ -1113,13 +1120,19 @@ class BlenderKitWelcomeOperator(bpy.types.Operator):
if self.step == 0:
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- message = "BlenderKit connects from Blender to an online, " \
- "community built shared library of models, " \
- "materials, and brushes. " \
- "Use addon preferences to set up where files will be saved in the Global directory setting."
+ # message = "BlenderKit connects from Blender to an online, " \
+ # "community built shared library of models, " \
+ # "materials, and brushes. " \
+ # "Use addon preferences to set up where files will be saved in the Global directory setting."
+ #
+ # utils.label_multiline(layout, text=message, width=300)
+
+ layout.template_icon(icon_value=self.img.preview.icon_id, scale=18)
+
+ # utils.label_multiline(layout, text="\n Let's start by searching for some cool materials?", width=300)
+ op = layout.operator("wm.url_open", text='Watch Video Tutorial', icon='QUESTION')
+ op.url = paths.BLENDERKIT_MANUAL
- utils.label_multiline(layout, text=message, width=300)
- utils.label_multiline(layout, text="\n Let's start by searching for some cool materials?", width=300)
else:
message = "Operator Tutorial called with invalid step"
@@ -1131,14 +1144,36 @@ class BlenderKitWelcomeOperator(bpy.types.Operator):
# bpy.context.window_manager.windows[0].screen.areas[5].spaces[0].show_region_ui = False
print('running search no')
ui_props = bpy.context.scene.blenderkitUI
- ui_props.asset_type = 'MATERIAL'
- bpy.context.scene.blenderkit_mat.search_keywords = 'ice'
+ random_searches = [
+ ('MATERIAL','ice'),
+ ('MODEL','car'),
+ ('MODEL','vase'),
+ ('MODEL','grass'),
+ ('MODEL','plant'),
+ ('MODEL','man'),
+ ('MATERIAL','metal'),
+ ('MATERIAL','wood'),
+ ('MATERIAL','floor'),
+ ('MATERIAL','bricks'),
+ ]
+ random_search = random.choice(random_searches)
+ ui_props.asset_type = random_search[0]
+
+ bpy.context.scene.blenderkit_mat.search_keywords = ''#random_search[1]
+ bpy.context.scene.blenderkit_mat.search_keywords = '+is_free:true+score_gte:1000+order:-created'#random_search[1]
# search.search()
return {'FINISHED'}
def invoke(self, context, event):
wm = bpy.context.window_manager
- return wm.invoke_props_dialog(self)
+ img = utils.get_thumbnail('intro.jpg')
+ utils.img_to_preview(img, copy_original = True)
+ self.img = img
+ w, a, r = utils.get_largest_area(area_type='VIEW_3D')
+ if a is not None:
+ a.spaces.active.show_region_ui = True
+
+ return wm.invoke_props_dialog(self, width = 500)
def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
@@ -1468,6 +1503,7 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
box.scale_y = 0.4
box.label(text='Properties')
box.separator()
+
if self.asset_data.get('license') == 'cc_zero':
t = 'CC Zero '
icon = pcoll['cc0']
@@ -1778,9 +1814,19 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
# top draggabe bar with name of the asset
top_row = layout.row()
top_drag_bar = top_row.box()
+ bcats = bpy.context.window_manager['bkit_categories']
+
+ cat_path = categories.get_category_path(bcats,
+ self.asset_data['category'])[1:]
+ for i,c in enumerate(cat_path):
+ cat_path[i] = c.capitalize()
+ cat_path = ' > '.join(cat_path)
+ # box.label(text=cat_path)
+
aname = asset_data['displayName']
aname = aname[0].upper() + aname[1:]
- top_drag_bar.label(text=aname)
+
+ top_drag_bar.label(text=f'{cat_path} > {aname}')
# left side
row = layout.row(align=True)
@@ -1811,6 +1857,8 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
sr = bpy.context.window_manager['search results']
asset_data = sr[ui_props.active_index]
self.img = ui.get_large_thumbnail_image(asset_data)
+ utils.img_to_preview(self.img, copy_original = True)
+
self.asset_type = asset_data['assetType']
self.asset_id = asset_data['id']
# self.tex = utils.get_hidden_texture(self.img)
diff --git a/blenderkit/upload.py b/blenderkit/upload.py
index b1d20f94..367f2cbd 100644
--- a/blenderkit/upload.py
+++ b/blenderkit/upload.py
@@ -731,7 +731,6 @@ class FastMetadata(bpy.types.Operator):
active_asset = utils.get_active_asset_by_type(asset_type = self.asset_type)
asset_data = active_asset.get('asset_data')
- print('can edit asset?', can_edit_asset(asset_data=asset_data))
if not can_edit_asset(asset_data=asset_data):
return {'CANCELLED'}
self.asset_id = asset_data['id']
diff --git a/blenderkit/utils.py b/blenderkit/utils.py
index bae1244d..3d1f3eae 100644
--- a/blenderkit/utils.py
+++ b/blenderkit/utils.py
@@ -337,9 +337,14 @@ def get_hidden_texture(name, force_reload=False):
return t
-def img_to_preview(img):
- img.preview.image_size = (img.size[0], img.size[1])
- img.preview.image_pixels_float = img.pixels[:]
+def img_to_preview(img, copy_original = False):
+ if bpy.app.version[0]>=3:
+ img.preview_ensure()
+ if not copy_original:
+ return;
+ if img.preview.image_size != img.size:
+ img.preview.image_size = (img.size[0], img.size[1])
+ img.preview.image_pixels_float = img.pixels[:]
# img.preview.icon_size = (img.size[0], img.size[1])
# img.preview.icon_pixels_float = img.pixels[:]
@@ -852,11 +857,14 @@ def get_fake_context(context, area_type='VIEW_3D'):
# print(w,a,r)
return C_dict
+# def is_url(text):
+
def label_multiline(layout, text='', icon='NONE', width=-1):
''' draw a ui label, but try to split it in multiple lines.'''
if text.strip() == '':
return
+ text = text.replace('\r\n','\n')
lines = text.split('\n')
if width > 0:
threshold = int(width / 5.5)
@@ -865,6 +873,8 @@ def label_multiline(layout, text='', icon='NONE', width=-1):
maxlines = 8
li = 0
for l in lines:
+ # if is_url(l):
+
while len(l) > threshold:
i = l.rfind(' ', 0, threshold)
if i < 1: