2025-12-01

This commit is contained in:
2026-03-17 14:58:51 -06:00
parent 183e865f8b
commit 4b82b57113
6846 changed files with 954887 additions and 162606 deletions
@@ -8,21 +8,21 @@ The original method is then called from the new method, with the same arguments,
import json
import os
import time
import logging
from . import icons
import bpy
import bl_pkg.bl_extension_ui as exui
from . import icons
from bl_ui.space_userpref import (
USERPREF_PT_addons,
USERPREF_PT_extensions,
USERPREF_MT_extensions_active_repo,
)
from bpy.props import EnumProperty
from bpy.props import StringProperty, IntProperty
from bpy.props import IntProperty, StringProperty
from bpy.types import Operator
import time
EXTENSIONS_API_URL = "https://www.blenderkit.com/api/v1/extensions/"
bk_logger = logging.getLogger(__name__)
# --- New Modal Operator ---
class BK_OT_buy_extension_and_watch(Operator):
@@ -59,7 +59,7 @@ class BK_OT_buy_extension_and_watch(Operator):
# Open the URL
try:
bpy.ops.wm.url_open(url=self.url)
print(f"BlenderKit: Opening buy URL: {self.url}")
bk_logger.info("Opening buy URL: %s.", self.url)
except Exception as e:
self.report({"ERROR"}, f"Could not open URL: {e}")
# Don't cancel, maybe the user still wants the refresh?
@@ -75,10 +75,11 @@ class BK_OT_buy_extension_and_watch(Operator):
self._last_refresh_time = (
self._start_time
) # Initialize to avoid immediate refresh
print(
f"BlenderKit: Started watching repository index {self.repo_index} for updates."
bk_logger.info(
"Started watching repository index %s for updates.", self.repo_index
)
context.area.tag_redraw() # Update UI to show operator is running if needed
if context and context.area:
context.area.tag_redraw() # Update UI to show operator is running if needed
return {"RUNNING_MODAL"}
def modal(self, context, event):
@@ -87,19 +88,19 @@ class BK_OT_buy_extension_and_watch(Operator):
# --- Exit Conditions ---
# 1. User closed Preferences or changed area
if context.area is None or context.area.type != "PREFERENCES":
print("BlenderKit: Preferences window closed or changed, stopping watcher.")
bk_logger.info("Preferences window closed or changed, stopping watcher.")
self.cancel(context)
return {"CANCELLED"}
# 2. Timeout
if current_time - self._start_time > self._max_duration:
print("BlenderKit: Watcher timed out, stopping.")
bk_logger.info("Watcher timed out, stopping.")
self.cancel(context)
return {"CANCELLED"}
# 3. User cancellation
if event.type in {"RIGHTMOUSE", "ESC"}:
print("BlenderKit: Watcher cancelled by user.")
bk_logger.info("Watcher cancelled by user.")
self.cancel(context)
return {"CANCELLED"}
@@ -107,24 +108,25 @@ class BK_OT_buy_extension_and_watch(Operator):
if event.type == "TIMER":
# Check if refresh interval has passed
if current_time - self._last_refresh_time >= self._refresh_interval:
print(
f"BlenderKit: Refresh interval reached, attempting sync for repo index {self.repo_index}..."
bk_logger.info(
"Refresh interval reached, attempting sync for repo index %s...",
self.repo_index,
)
try:
# Check if repo still exists at that index
if self.repo_index < len(context.preferences.extensions.repos):
bpy.ops.extensions.repo_sync(repo_index=self.repo_index)
print(
f"BlenderKit: repo_sync called for index {self.repo_index}."
bk_logger.info(
"repo_sync called for index %s.", self.repo_index
)
else:
print(
f"BlenderKit: Repository index {self.repo_index} no longer valid."
bk_logger.info(
"Repository index %s no longer valid.", self.repo_index
)
# Optionally cancel here if repo is gone
except Exception as e:
except:
# This might fail if another operation is in progress
print(f"BlenderKit: extensions.repo_sync failed: {e}")
bk_logger.exception("extensions.repo_sync failed.")
finally:
self._last_refresh_time = (
current_time # Reset timer regardless of success
@@ -137,13 +139,32 @@ class BK_OT_buy_extension_and_watch(Operator):
wm = context.window_manager
wm.event_timer_remove(self._timer)
self._timer = None
print("BlenderKit: Watcher timer removed.")
context.area.tag_redraw() # Update UI
bk_logger.info("Watcher timer removed.")
if context and context.area:
context.area.tag_redraw() # Update UI
# --- End New Modal Operator ---
def redraw_preferences_once():
"""Tag the redraw on the Blender preferences.
Meant to be registered as a timer, runs just once.
"""
for window in bpy.context.window_manager.windows:
screen = window.screen
if not screen:
continue
for area in screen.areas:
if area.type != "PREFERENCES":
continue
for region in area.regions:
if region.type in {"UI", "WINDOW"}:
region.tag_redraw()
return None
def extension_draw_item_blenderkit(
layout,
*,
@@ -166,14 +187,17 @@ def extension_draw_item_blenderkit(
cache_reloaded = ensure_repo_cache()
if cache_reloaded:
# If cache was just reloaded, tag UI for redraw
layout.tag_redraw()
print("BlenderKit: Cache reloaded, tagging layout for redraw.")
# as UILayout doesn't have tag_redraw we call a custom function
if bpy.app.timers.is_registered(redraw_preferences_once):
bpy.app.timers.unregister(redraw_preferences_once)
bpy.app.timers.register(redraw_preferences_once, first_interval=0.01)
bk_logger.info("Cache reloaded, tagging preferences for redraw.")
# check if the cache is already in the window manager
if "blenderkit_extensions_repo_cache" not in bpy.context.window_manager:
# Log if cache is missing after trying to ensure it
print(
"BlenderKit: Extension cache not available in window_manager after ensure_repo_cache call."
bk_logger.info(
"Extension cache not available in window_manager after ensure_repo_cache call."
)
# Optionally draw a minimal representation or return early to avoid errors
# For now, just return to avoid potential errors accessing bk_ext_cache
@@ -330,6 +354,7 @@ def extension_draw_item_blenderkit(
if show:
import os
from bpy.app.translations import pgettext_iface as iface_
col = layout.column()
@@ -432,7 +457,6 @@ def extension_draw_item_override(
extensions_warnings, # `dict[str, list[str]]`
show_developer_ui=False, # `bool`
):
print("BlenderKit Debug: ENTERING extension_draw_item_override")
# filter by verification state, only for blenderkit repository
if repo_item.remote_url == EXTENSIONS_API_URL:
extension_draw_item_blenderkit(
@@ -513,7 +537,7 @@ def clear_repo_cache():
def ensure_repo_cache():
"""
r"""
Reads the .json file blender stores in \extensions\www_blenderkit_com\.blender_ext
and parses it to a dict from json, we can use it then for drawing purposes and have the extra data BlenderKit api provides.
Checks the modification time of the cache file and reloads it if necessary.
@@ -528,10 +552,10 @@ def ensure_repo_cache():
# If repo doesn't exist, clear cache if it exists in window manager
if cache_key in wm:
del wm[cache_key]
print(f"BlenderKit: Cleared stale extension cache for missing repository.")
bk_logger.info("Cleared stale extension cache for missing repository.")
if mtime_key in wm:
del wm[mtime_key]
print(f"BlenderKit Debug: Repository not found, exiting check.")
bk_logger.debug("Repository not found, exiting check.")
return False # No repo, nothing loaded
# get the path to the cache file which is in repository directory under /.blender_ext/index.json
@@ -544,13 +568,11 @@ def ensure_repo_cache():
if os.path.exists(cache_file):
current_mtime = os.path.getmtime(cache_file)
except OSError as e: # Handle potential race condition or permission issue
print(
f"BlenderKit: Warning - Could not get modification time for {cache_file}: {e}"
)
bk_logger.exception("Could not get modification time for %s.", cache_file)
# Clear cache if we can't verify its freshness? Safer approach.
if cache_key in wm:
del wm[cache_key]
print(f"BlenderKit: Cleared extension cache due to mtime access error.")
bk_logger.info("Cleared extension cache due to mtime access error.")
if mtime_key in wm:
del wm[mtime_key]
return False # Error, nothing loaded
@@ -604,7 +626,7 @@ def ensure_repo_cache():
): # Ensure pkg is a dict and 'id' key exists
new_cache[pkg["id"][:32]] = pkg
else:
print(f"BlenderKit: Skipping invalid package entry in cache: {pkg}")
bk_logger.info("Skipping invalid package entry in cache: %s.", pkg)
wm[cache_key] = new_cache
wm[mtime_key] = current_mtime # Update mtime only on successful load
@@ -612,21 +634,21 @@ def ensure_repo_cache():
reloaded_flag = True # Mark that we reloaded successfully
except json.JSONDecodeError:
print(
f"BlenderKit: Error decoding JSON from {cache_file}. Cache not loaded/updated."
bk_logger.warning(
"Error decoding JSON from %s. Cache not loaded/updated.", cache_file
)
# Clear potentially corrupt cache? Or leave old one? Clearing is safer.
if cache_key in wm:
del wm[cache_key]
print("BlenderKit: Cleared cache due to JSON error.")
bk_logger.info("Cleared cache due to JSON error.")
if mtime_key in wm:
del wm[mtime_key]
except Exception as e:
print(f"BlenderKit: Error reading or processing cache file {cache_file}: {e}")
except Exception:
bk_logger.exception("Error reading or processing cache file %s.", cache_file)
# Clear potentially corrupt cache?
if cache_key in wm:
del wm[cache_key]
print("BlenderKit: Cleared cache due to file processing error.")
bk_logger.info("Cleared cache due to file processing error.")
if mtime_key in wm:
del wm[mtime_key]