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:
-rw-r--r--blenderkit/__init__.py28
-rw-r--r--blenderkit/categories.py2
-rw-r--r--blenderkit/download.py2
-rw-r--r--blenderkit/oauth.py176
-rw-r--r--blenderkit/paths.py23
-rw-r--r--blenderkit/ratings.py4
-rw-r--r--blenderkit/search.py8
-rw-r--r--blenderkit/tasks_queue.py20
-rw-r--r--blenderkit/ui_panels.py18
-rw-r--r--blenderkit/upload.py4
-rw-r--r--blenderkit/upload_bg.py6
-rw-r--r--blenderkit/utils.py13
12 files changed, 270 insertions, 34 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py
index 0bafa699..6a8b1886 100644
--- a/blenderkit/__init__.py
+++ b/blenderkit/__init__.py
@@ -41,9 +41,11 @@ if "bpy" in locals():
importlib.reload(bg_blender)
importlib.reload(paths)
importlib.reload(utils)
+ importlib.reload(oauth)
+ importlib.reload(tasks_queue)
else:
from blenderkit import asset_inspector, search, download, upload, ratings, autothumb, ui, bg_blender, paths, utils, \
- overrides, ui_panels, categories
+ overrides, ui_panels, categories, oauth, tasks_queue
import os
import math
@@ -71,7 +73,6 @@ from bpy.types import (
PropertyGroup,
)
-
# logging.basicConfig(filename = 'blenderkit.log', level = logging.INFO,
# format = ' %(asctime)s:%(filename)s:%(funcName)s:%(lineno)d:%(message)s')
@@ -1208,9 +1209,8 @@ class BlenderKitAddonPreferences(AddonPreferences):
# this must match the addon name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __name__
- from os.path import expanduser
- home = expanduser("~")
- default_global_dict = home + os.sep + 'blenderkit_data'
+
+ default_global_dict = paths.default_global_dict()
api_key: StringProperty(
name="BlenderKit API Key",
@@ -1220,6 +1220,20 @@ class BlenderKitAddonPreferences(AddonPreferences):
update=utils.save_prefs
)
+ api_key_refresh: StringProperty(
+ name="BlenderKit refresh API Key",
+ description="API key used to refresh the token regularly.",
+ default="",
+ subtype="PASSWORD",
+ update=utils.save_prefs
+ )
+
+ login_attempt: BoolProperty(
+ name="Login/Signup attempt",
+ description="When this is on, BlenderKit is trying to connect and login.",
+ default=False
+ )
+
global_dir: StringProperty(
name="Global Files Directory",
description="Global storage for your assets, will use subdirectories for the contents",
@@ -1389,6 +1403,8 @@ def register():
bpy.app.handlers.load_post.append(scene_load)
utils.load_prefs()
overrides.register_overrides()
+ oauth.register()
+ tasks_queue.register()
def unregister():
@@ -1403,6 +1419,8 @@ def unregister():
ui_panels.unregister_ui_panels()
bg_blender.unregister()
overrides.unregister_overrides()
+ oauth.unregister()
+ tasks_queue.unregister()
del bpy.types.Scene.blenderkit_models
del bpy.types.Scene.blenderkit_scene
diff --git a/blenderkit/categories.py b/blenderkit/categories.py
index 3c50f2c7..e2dfed3d 100644
--- a/blenderkit/categories.py
+++ b/blenderkit/categories.py
@@ -60,7 +60,7 @@ def copy_categories():
def fetch_categories(API_key):
BLENDERKIT_API_MAIN = "https://www.blenderkit.com/api/v1/"
- url = paths.get_bkit_url() + 'categories/'
+ url = paths.get_api_url() + 'categories/'
headers = utils.get_headers(API_key)
diff --git a/blenderkit/download.py b/blenderkit/download.py
index 175a9771..bffb2e8a 100644
--- a/blenderkit/download.py
+++ b/blenderkit/download.py
@@ -174,7 +174,7 @@ def report_usages():
api_key = user_preferences.api_key
sid = get_scene_id()
headers = utils.get_headers(api_key)
- url = paths.get_bkit_url() + paths.BLENDERKIT_REPORT_URL
+ url = paths.get_api_url() + paths.BLENDERKIT_REPORT_URL
assets = {}
asset_obs = []
diff --git a/blenderkit/oauth.py b/blenderkit/oauth.py
new file mode 100644
index 00000000..78c8dfb3
--- /dev/null
+++ b/blenderkit/oauth.py
@@ -0,0 +1,176 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+import json
+import webbrowser
+from http.server import BaseHTTPRequestHandler, HTTPServer
+from urllib.parse import parse_qs, urlparse
+
+import requests
+import threading
+from blenderkit import tasks_queue, utils, paths
+
+CLIENT_ID = "IdFRwa3SGA8eMpzhRVFMg5Ts8sPK93xBjif93x0F"
+PORTS = [62485, 1234]
+
+
+class SimpleOAuthAuthenticator(object):
+ def __init__(self, server_url, client_id, ports):
+ self.server_url = server_url
+ self.client_id = client_id
+ self.ports = ports
+
+ def _get_tokens(self, authorization_code=None, refresh_token=None, grant_type="authorization_code"):
+ data = {
+ "grant_type": grant_type,
+ "state": "random_state_string",
+ "client_id": self.client_id,
+ "scopes": "read write",
+ }
+ if authorization_code:
+ data['code'] = authorization_code
+ if refresh_token:
+ data['refresh_token'] = refresh_token
+
+ response = requests.post(
+ '%s/o/token/' % self.server_url,
+ data=data
+ )
+ if response.status_code != 200:
+ return None, None
+ refresh_token = json.loads(response.content)['refresh_token']
+ access_token = json.loads(response.content)['access_token']
+ return access_token, refresh_token
+
+ def get_new_token(self):
+ class HTTPServerHandler(BaseHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+ if 'code' in self.path:
+ self.auth_code = self.path.split('=')[1]
+ # Display to the user that they no longer need the browser window
+ self.wfile.write(bytes('<html><h1>You may now close this window.</h1></html>', 'utf-8'))
+ qs = parse_qs(urlparse(self.path).query)
+ self.server.authorization_code = qs['code'][0]
+
+ for port in self.ports:
+ try:
+ httpServer = HTTPServer(('localhost', port), HTTPServerHandler)
+ except OSError:
+ continue
+ break
+ webbrowser.open_new(
+ "%s/o/authorize?client_id=%s&state=random_state_string&response_type=code&"
+ "redirect_uri=http://localhost:%s/consumer/exchange/" % (self.server_url, self.client_id, port),
+ )
+
+ httpServer.handle_request()
+ authorization_code = httpServer.authorization_code
+ return self._get_tokens(authorization_code=authorization_code)
+
+ def get_refreshed_token(self, refresh_token):
+ return self._get_tokens(refresh_token=refresh_token, grant_type="refresh_token")
+
+
+def login_thread():
+ thread = threading.Thread(target=login, args=([]), daemon=True)
+ thread.start()
+
+
+def login():
+ authenticator = SimpleOAuthAuthenticator(server_url=paths.get_bkit_url(), client_id=CLIENT_ID, ports=PORTS)
+ auth_token, refresh_token = authenticator.get_new_token()
+ print('tokens retrieved')
+ tasks_queue.tasks_queue.put('blenderkit.oauth.write_tokens("%s", "%s")' % (auth_token, refresh_token))
+
+
+def refresh_token_thread():
+ preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ if len(preferences.api_key_refresh) > 0:
+ thread = threading.Thread(target=refresh_token, args=([preferences.api_key_refresh]), daemon=True)
+ thread.start()
+
+
+def refresh_token(api_key_refresh):
+ authenticator = SimpleOAuthAuthenticator(server_url=paths.get_bkit_url(), client_id=CLIENT_ID, ports=PORTS)
+ auth_token, refresh_token = authenticator.get_refreshed_token(api_key_refresh)
+ tasks_queue.tasks_queue.put('blenderkit.oauth.write_tokens("%s", "%s")' % (auth_token, refresh_token))
+
+
+def write_tokens(auth_token, refresh_token):
+ print('writing tokens?')
+ preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ preferences.api_key = auth_token
+ preferences.api_key_refresh = refresh_token
+ preferences.login_attempt = False
+ props = utils.get_search_props()
+ props.report = 'Login success!'
+
+
+class RegisterLoginOnline(bpy.types.Operator):
+ """Bring linked object hierarchy to scene and make it editable."""
+
+ bl_idname = "wm.blenderkit_login"
+ bl_label = "BlenderKit login or signup"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return True
+
+ def execute(self, context):
+ preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ preferences.login_attempt = True
+ login_thread()
+ return {'FINISHED'}
+
+
+class CancelLoginOnline(bpy.types.Operator):
+ """Cancel login attempt."""
+
+ bl_idname = "wm.blenderkit_login_cancel"
+ bl_label = "BlenderKit login cancel"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return True
+
+ def execute(self, context):
+ preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ preferences.login_attempt = False
+ return {'FINISHED'}
+
+classess = (
+ RegisterLoginOnline,
+ CancelLoginOnline,
+)
+
+
+def register():
+ for c in classess:
+ bpy.utils.register_class(c)
+
+
+def unregister():
+ for c in classess:
+ bpy.utils.unregister_class(c)
diff --git a/blenderkit/paths.py b/blenderkit/paths.py
index 71479c7e..1595ad78 100644
--- a/blenderkit/paths.py
+++ b/blenderkit/paths.py
@@ -18,9 +18,10 @@
import bpy, os, sys
-BLENDERKIT_API_LOCAL = "http://localhost:8001/api/v1/"
-BLENDERKIT_API_MAIN = "https://www.blenderkit.com/api/v1/"
-BLENDERKIT_API_DEVEL = "https://devel.blenderkit.com/api/v1/"
+BLENDERKIT_LOCAL = "http://localhost:8001"
+BLENDERKIT_MAIN = "https://www.blenderkit.com"
+BLENDERKIT_DEVEL = "https://devel.blenderkit.com"
+BLENDERKIT_API = "/api/v1/"
BLENDERKIT_REPORT_URL = "usage_report/"
BLENDERKIT_USER_ASSETS = "https://www.blenderkit.com/my-assets"
BLENDERKIT_PLANS = "https://www.blenderkit.com/plans/pricing/"
@@ -38,14 +39,24 @@ def get_bkit_url():
d = bpy.app.debug_value
# d = 2
if d == 1:
- url = BLENDERKIT_API_LOCAL
+ url = BLENDERKIT_LOCAL
elif d == 2:
- url = BLENDERKIT_API_DEVEL
+ url = BLENDERKIT_DEVEL
else:
- url = BLENDERKIT_API_MAIN
+ url = BLENDERKIT_MAIN
return url
+def get_api_url():
+ return get_bkit_url() + BLENDERKIT_API
+
+
+def default_global_dict():
+ from os.path import expanduser
+ home = expanduser("~")
+ return home + os.sep + 'blenderkit_data'
+
+
def get_categories_filepath():
tempdir = get_temp_dir()
return os.path.join(tempdir, 'categories.json')
diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py
index 122e89cb..8220b188 100644
--- a/blenderkit/ratings.py
+++ b/blenderkit/ratings.py
@@ -90,7 +90,7 @@ def upload_rating(asset):
bkit_ratings = asset.bkit_ratings
# print('rating asset', asset_data['name'], asset_data['asset_base_id'])
- url = paths.get_bkit_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
+ url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
ratings = [
]
@@ -103,7 +103,7 @@ def upload_rating(asset):
thread = threading.Thread(target=uplaod_rating_thread, args=(url, ratings, headers))
thread.start()
- url = paths.get_bkit_url() + 'assets/' + asset['asset_data']['id'] + '/review'
+ url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/review'
reviews = {
'reviewText': bkit_ratings.rating_compliments,
diff --git a/blenderkit/search.py b/blenderkit/search.py
index e47b3ad1..39a770ee 100644
--- a/blenderkit/search.py
+++ b/blenderkit/search.py
@@ -24,8 +24,9 @@ if "bpy" in locals():
imp.reload(categories)
imp.reload(ui)
imp.reload(version_checker)
+ imp.reload(oauth)
else:
- from blenderkit import paths, utils, categories, ui, version_checker
+ from blenderkit import paths, utils, categories, ui, oauth, version_checker
import blenderkit
from bpy.app.handlers import persistent
@@ -79,7 +80,7 @@ def scene_load(context):
wm = bpy.context.window_manager
fetch_server_data()
# following doesn't necessarilly happen if version isn't checked yet or similar, first run.
- wm['bkit_update'] = version_checker.compare_versions(blenderkit)
+ # wm['bkit_update'] = version_checker.compare_versions(blenderkit)
utils.load_categories()
@@ -89,6 +90,7 @@ def fetch_server_data():
url = paths.BLENDERKIT_ADDON_URL
api_key = user_preferences.api_key
# version_checker.check_version_thread(url, api_key, blenderkit)
+ oauth.refresh_token_thread()
categories.fetch_categories_thread(api_key)
@@ -534,7 +536,7 @@ class Searcher(threading.Thread):
params['get_next'] = False
if not params['get_next']:
# build a new request
- url = paths.get_bkit_url() + 'search/'
+ url = paths.get_api_url() + 'search/'
nquery = {
# 'tags': query['keywords'],
diff --git a/blenderkit/tasks_queue.py b/blenderkit/tasks_queue.py
new file mode 100644
index 00000000..08ac90bf
--- /dev/null
+++ b/blenderkit/tasks_queue.py
@@ -0,0 +1,20 @@
+import bpy
+
+import queue
+
+import blenderkit
+
+tasks_queue = queue.Queue()
+
+def every_2_seconds():
+ while not tasks_queue.empty():
+ print('as a task: ')
+ fstring = tasks_queue.get()
+ eval(fstring)
+ return 2.0
+
+def register():
+ bpy.app.timers.register(every_2_seconds)
+
+def unregister():
+ bpy.app.timers.unregister(every_2_seconds) \ No newline at end of file
diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py
index 2f94ba13..1047eb98 100644
--- a/blenderkit/ui_panels.py
+++ b/blenderkit/ui_panels.py
@@ -523,13 +523,17 @@ class VIEW3D_PT_blenderkit_unified(Panel):
row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
w = context.region.width
-
- if len(user_preferences.api_key) < 35 and user_preferences.asset_counter >25:
- op = layout.operator("wm.url_open", text="Register online",
- icon='QUESTION')
- op.url = paths.BLENDERKIT_SIGNUP_URL
- layout.label(text='Paste your API Key:')
- layout.prop(user_preferences, 'api_key', text='')
+ if user_preferences.login_attempt:
+ layout.label(text = 'Login through browser')
+ layout.label(text = 'in progress.')
+ layout.operator("wm.blenderkit_login_cancel", text = "Cancel", icon = 'CANCEL')
+ return
+
+ if len(user_preferences.api_key) < 20 and user_preferences.asset_counter >-10:
+ layout.operator("wm.blenderkit_login", text="Login/ Sign up",
+ icon='URL')
+ # layout.label(text='Paste your API Key:')
+ # layout.prop(user_preferences, 'api_key', text='')
layout.separator()
elif bpy.data.filepath == '':
diff --git a/blenderkit/upload.py b/blenderkit/upload.py
index be00430c..6a512e4a 100644
--- a/blenderkit/upload.py
+++ b/blenderkit/upload.py
@@ -465,7 +465,7 @@ def mark_for_validation(self, context, asset_type):
"verificationStatus": "ready"
}
- url = paths.get_bkit_url() + 'assets/'
+ url = paths.get_api_url() + 'assets/'
headers = utils.get_headers(user_preferences.api_key)
@@ -559,7 +559,7 @@ def start_upload(self, context, asset_type, as_new, metadata_only):
return {'CANCELLED'}
# first upload metadata to server, so it can be saved inside the current file
- url = paths.get_bkit_url() + 'assets/'
+ url = paths.get_api_url() + 'assets/'
headers = utils.get_headers(upload_data['token'])
diff --git a/blenderkit/upload_bg.py b/blenderkit/upload_bg.py
index 538f9784..1fa6f6fb 100644
--- a/blenderkit/upload_bg.py
+++ b/blenderkit/upload_bg.py
@@ -76,7 +76,7 @@ def upload_files(filepath, upload_data, files):
'fileIndex': f['index'],
'originalFilename': os.path.basename(f['file_path'])
}
- upload_create_url = paths.get_bkit_url() + 'uploads/'
+ upload_create_url = paths.get_api_url() + 'uploads/'
upload = requests.post(upload_create_url, json=upload_info, headers=headers, verify=True)
upload = upload.json()
@@ -108,7 +108,7 @@ def upload_files(filepath, upload_data, files):
time.sleep(1)
# confirm single file upload to bkit server
- upload_done_url = paths.get_bkit_url() + 'uploads_s3/' + upload['id'] + '/upload-file/'
+ upload_done_url = paths.get_api_url() + 'uploads_s3/' + upload['id'] + '/upload-file/'
upload_response = requests.post(upload_done_url, headers=headers, verify=True)
bg_blender.progress('finished uploading')
@@ -187,7 +187,7 @@ if __name__ == "__main__":
"verificationStatus": "uploaded"
}
- url = paths.get_bkit_url() + 'assets/'
+ url = paths.get_api_url() + 'assets/'
headers = utils.get_headers(upload_data['token'])
diff --git a/blenderkit/utils.py b/blenderkit/utils.py
index fd6c7d83..cebc2eaf 100644
--- a/blenderkit/utils.py
+++ b/blenderkit/utils.py
@@ -171,17 +171,22 @@ def load_prefs():
if os.path.exists(fpath):
with open(fpath, 'r') as s:
prefs = json.load(s)
- user_preferences.api_key = prefs['API_key']
- user_preferences.global_dir = prefs['global_dir']
+ user_preferences.api_key = prefs.get('API_key','')
+ user_preferences.global_dir = prefs.get('global_dir', paths.default_global_dict())
+
+ user_preferences.api_key_refresh = prefs.get('API_key_refresh','')
def save_prefs(self, context):
# print(type(context),type(bpy.context))
if not bpy.app.background and hasattr(bpy.context, 'view_layer'):
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
if user_preferences.api_key != '':
- if len(user_preferences.api_key)>35:
+ #we test the api key for lenght, so not a random accidentaly typed sequence gets saved.
+ if len(user_preferences.api_key)>25:
+
prefs = {
'API_key': user_preferences.api_key,
+ 'API_key_refresh': user_preferences.api_key_refresh,
'global_dir': user_preferences.global_dir,
}
# user_preferences.api_key = user_preferences.api_key.strip()
@@ -194,7 +199,7 @@ def save_prefs(self, context):
# reset the api key in case the user writes some nonsense, e.g. a search string instead of the Key
user_preferences.api_key = ''
props = get_search_props()
- props.report = 'Please paste a correct API Key.'
+ props.report = 'Login failed. Please paste a correct API Key.'
def load_categories():
categories.copy_categories()