Skip to content

Commit

Permalink
Merge pull request #122 from sketchfab/bug/updates-to-blender4
Browse files Browse the repository at this point in the history
Updates plugin to Blender 4, and minor fixes
  • Loading branch information
loicEpicGames authored Dec 13, 2023
2 parents 5a0769c + ea511b4 commit 85c1294
Show file tree
Hide file tree
Showing 51 changed files with 56 additions and 4,692 deletions.
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
addons/.idea/
addons/io_scene_gltf2/.idea/
addons/io_sketchfab_plugin/io/*
releases/*
.idea/
releases/*
__pycache__/
**.pyc
sketchfab/.cache
4 changes: 0 additions & 4 deletions .gitmodules

This file was deleted.

17 changes: 0 additions & 17 deletions .project

This file was deleted.

8 changes: 0 additions & 8 deletions .pydevproject

This file was deleted.

6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ After installing the addon, two optional settings are available:

<p align="center"><img style="max-width:100%" src="https://user-images.githubusercontent.com/52042414/158475442-3e6c90c3-983d-4d91-8f58-f8c3d20216dc.jpg"></p>

**Note to Blender 2.79 OSX/Linux users:** The addon uses an embedded version of the SSL library. Do not hesitate to [report an issue](#report-an-issue) if you encounter any issue related to SSL.

<br>

## Login

After installation, the addon is available in the 3D view in the tab 'Sketchfab' in the Properties panel (shortcut **N**) for Blender 2.80 and after, and in the Tools panel (shortcut **T**) for Blender 2.79.
After installation, the addon is available in the 3D view in the tab 'Sketchfab' in the Properties panel (shortcut **N**) for Blender 2.80+.

Login (mandatory to import or export models) can be achieved through using the email and password associated to your Sketchfab account, or by using your API token, available in the settings of your [Sketchfab account](https://sketchfab.com/settings/password):

Expand Down Expand Up @@ -113,7 +111,7 @@ There is no "quick fix" for those kinds of behaviours, which are actively being

Here is a list of known issues on import, as well as some possible fixes.

Please note that the materials are being converted from Sketchfab to Cycles in Blender 2.79, and Eevee in Blender 2.80. If a material looks wrong, using the **Node editor** could therefore help you fixing possible issues.
Please note that the materials are being converted from Sketchfab to Eevee in Blender 2.80+. If a material looks wrong, using the **Node editor** could therefore help you fixing possible issues.

#### Mesh not parented to armature

Expand Down
114 changes: 46 additions & 68 deletions addons/io_sketchfab_plugin/__init__.py → __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,50 +34,13 @@
IntProperty,
PointerProperty)

from .io import *
from .io.imp.gltf2_io_gltf import *
from .blender.imp.gltf2_blender_gltf import *
from .blender.blender_version import Version


# Blender 2.79 has been shipped with openssl version 0.9.8 which uses a TLS protocol
# that is now blocked for security reasons on websites (github.com for example)
# In order to allow communication with github.com and other websites, the code will intend
# to use the updated openssl version distributed with the addon.
# Note: Blender 2.8 will have a more recent openssl version. This fix is only for 2.79 and olders
if bpy.app.version < (2, 80, 0) and not bpy.app.build_platform == b'Windows':
try:
sslib_path = None
if bpy.app.build_platform == b'Darwin':
sslib_path = os.path.join(os.path.dirname(__file__), 'dependencies/_ssl.cpython-35m-darwin.so')
elif bpy.app.build_platform == b'Linux':
sslib_path = os.path.join(os.path.dirname(__file__), '/io_sketchfab_plugin/_ssl.cpython-35m-x86_64-linux-gnu.so')

import importlib.util
spec = importlib.util.spec_from_file_location("_ssl", sslib_path)
new_ssl = importlib.util.module_from_spec(spec)
spec.loader.exec_module(new_ssl)


from importlib import reload
import ssl
reload(ssl)
from requests.packages.urllib3.util import ssl_
reload(ssl_)
print('SSL python module has been successfully overriden by Sketchfab addon')
print('It might fix other addons having the same refused TLS protocol issue')
except Exception as e:
print(e)
print("Failed to override SSL lib. The plugin will not be able to check for updates")


bl_info = {
'name': 'Sketchfab Plugin',
'description': 'Browse and download free Sketchfab downloadable models',
'author': 'Sketchfab',
'license': 'APACHE2',
'deps': '',
'version': (1, 5, 0),
'version': (1, 6, 0),
"blender": (2, 80, 0),
'location': 'View3D > Tools > Sketchfab',
'warning': '',
Expand Down Expand Up @@ -105,8 +68,8 @@ class Config:
SKETCHFAB_REPORT_URL = 'https://help.sketchfab.com/hc/en-us/requests/new?type=exporters&subject=Blender+Plugin'

SKETCHFAB_URL = 'https://sketchfab.com'
DUMMY_CLIENTID = 'hGC7unF4BHyEB0s7Orz5E1mBd3LluEG0ILBiZvF9'
SKETCHFAB_OAUTH = SKETCHFAB_URL + '/oauth2/token/?grant_type=password&client_id=' + DUMMY_CLIENTID
CLIENTID = 'hGC7unF4BHyEB0s7Orz5E1mBd3LluEG0ILBiZvF9'
SKETCHFAB_OAUTH = SKETCHFAB_URL + '/oauth2/token/'
SKETCHFAB_API = 'https://api.sketchfab.com'
SKETCHFAB_SEARCH = SKETCHFAB_API + '/v3/search'
SKETCHFAB_MODEL = SKETCHFAB_API + '/v3/models'
Expand Down Expand Up @@ -244,12 +207,6 @@ def get_thumbnail_url(thumbnails_json):
return min_thumbnail
return best_thumbnail

def make_model_name(gltf_data):
if 'title' in gltf_data.asset.extras:
return gltf_data.asset.extras['title']

return 'GLTFModel'

def setup_plugin():
if not os.path.exists(Config.SKETCHFAB_THUMB_DIR):
os.makedirs(Config.SKETCHFAB_THUMB_DIR)
Expand Down Expand Up @@ -432,6 +389,7 @@ def __init__(self):
self.next_results_url = None
self.prev_results_url = None
self.user_orgs = []
self.user_has_orgs = False
self.active_org = None
self.use_org_profile = False

Expand Down Expand Up @@ -473,6 +431,7 @@ def logout(self):
#pprops.search_domain = "DEFAULT"

self.user_orgs = []
self.user_has_orgs = False
self.active_org = None
self.use_org_profile = False
props.use_org_profile = False
Expand All @@ -495,7 +454,7 @@ def parse_user_info(self, r, *args, **kargs):
self.username = user_data['username']
self.display_name = user_data['displayName']
self.plan_type = user_data['account']
requests.get(Config.SKETCHFAB_ME + "/orgs", headers=self.headers, hooks={'response': self.parse_orgs_info})
requests.get(Config.SKETCHFAB_ME + "/orgs", headers=self.headers, hooks={'response': self.on_user_orgs_check})
else:
print('\nInvalid access or API token\nYou can get your API token here:\nhttps://sketchfab.com/settings/password\n')
set_login_status('ERROR', 'Failed to authenticate')
Expand All @@ -504,6 +463,14 @@ def parse_user_info(self, r, *args, **kargs):
self.api_token = ''
self.headers = {}

def request_user_orgs(self):
if not self.active_org:
requests.get(Config.SKETCHFAB_ME + "/orgs", headers=self.headers, hooks={'response': self.parse_orgs_info})
pass

def on_user_orgs_check(self, r, *args, **kargs):
self.user_has_orgs = bool((r.status_code == 200) and len(r.json().get("results", [])))

def parse_orgs_info(self, r, *args, **kargs):
"""
Get and store information about user's orgs, and its orgs projects
Expand Down Expand Up @@ -564,6 +531,7 @@ def parse_projects_info(r, *args, **kargs):
# Set the first org as active
if len(self.user_orgs):
self.active_org = self.user_orgs[0]
self.user_has_orgs = True

# Iterate on all orgs (not just the 24 first)
if orgs_data["next"] is not None:
Expand Down Expand Up @@ -716,9 +684,11 @@ def handle_download(self, r, *args, **kwargs):
skfb_model.download_url = gltf['url']
skfb_model.time_url_requested = time.time()
skfb_model.url_expires = gltf['expires']
self.get_archive(gltf['url'])
self.get_archive(gltf['url'], skfb_model.title)
else:
ShowMessage("ERROR", "Cannot retrieve information for this model", "")

def get_archive(self, url):
def get_archive(self, url, title):
if url is None:
print('Url is None')
return
Expand Down Expand Up @@ -755,7 +725,7 @@ def get_archive(self, url):
gltf_path, gltf_zip = unzip_archive(archive_path)
if gltf_path:
try:
import_model(gltf_path, uid)
import_model(gltf_path, uid, title)
except Exception as e:
import traceback
print(traceback.format_exc())
Expand Down Expand Up @@ -826,6 +796,8 @@ def update_tr(self, context):

def get_user_orgs(self, context):
api = get_sketchfab_props().skfb_api
if not api.user_has_orgs:
api.request_user_orgs()
return [(org["uid"], org["displayName"], "") for org in api.user_orgs]

def get_org_projects(self, context):
Expand All @@ -837,7 +809,7 @@ def get_available_search_domains(self, context):

search_domains = [domain for domain in Config.SKETCHFAB_SEARCH_DOMAIN]

if len(api.user_orgs) and api.use_org_profile:
if api.user_has_orgs and api.use_org_profile:
search_domains = [
("ACTIVE_ORG", "Active Organization", api.active_org["displayName"], 0)
]
Expand All @@ -856,6 +828,12 @@ def refresh_orgs(self, context):
api = props.skfb_api

api.use_org_profile = pprops.use_org_profile

if api.user_has_orgs and not api.active_org :
bpy.context.window.cursor_set("WAIT")
api.request_user_orgs()
bpy.context.window.cursor_set("DEFAULT")

orgs = [org for org in api.user_orgs if org["uid"] == pprops.active_org]
api.active_org = orgs[0] if len(orgs) else None

Expand All @@ -875,7 +853,7 @@ def refresh_orgs(self, context):

def get_sorting_options(self, context):
api = get_sketchfab_props().skfb_api
if len(api.user_orgs) and api.use_org_profile:
if api.user_has_orgs and api.use_org_profile:
return (
('RELEVANCE', "Relevance", ""),
('RECENT', "Recent", "")
Expand Down Expand Up @@ -1183,8 +1161,8 @@ def async_func(*args, **kwargs):
return async_func


def import_model(gltf_path, uid):
bpy.ops.wm.import_modal('INVOKE_DEFAULT', gltf_path=gltf_path, uid=uid)
def import_model(gltf_path, uid, title):
bpy.ops.wm.import_modal('INVOKE_DEFAULT', gltf_path=gltf_path, uid=uid, title=title)


def build_search_request(query, pbr, animated, staffpick, face_count, category, sort_by):
Expand Down Expand Up @@ -1378,8 +1356,13 @@ def invoke(self, context, event):
context.window_manager.modal_handler_add(self)
login_props = get_sketchfab_login_props()
if(login_props.use_mail):
url = '{}&username={}&password={}'.format(Config.SKETCHFAB_OAUTH, urllib.parse.quote_plus(login_props.email), urllib.parse.quote_plus(login_props.password))
requests.post(url, hooks={'response': self.handle_mail_login})
data = {
'grant_type': 'password',
'client_id': Config.CLIENTID,
'username': login_props.email,
'password': login_props.password,
}
requests.post(Config.SKETCHFAB_OAUTH, data=data, hooks={'response': self.handle_mail_login})
else:
self.handle_token_login(login_props.api_token)
except Exception as e:
Expand All @@ -1397,33 +1380,28 @@ class ImportModalOperator(bpy.types.Operator):

gltf_path : StringProperty()
uid : StringProperty()
title: StringProperty()

def execute(self, context):
print('IMPORT')
return {'FINISHED'}

def modal(self, context, event):
if bpy.context.scene.render.engine not in ["CYCLES", "BLENDER_EEVEE"]:
bpy.context.scene.render.engine = Version.ENGINE
gltf_importer = glTFImporter(self.gltf_path)
gltf_importer.read()

bpy.context.scene.render.engine = "BLENDER_EEVEE"
try:
old_objects = [o.name for o in bpy.data.objects] # Get the current objects inorder to find the new node hierarchy
BlenderGlTF.create(gltf_importer)
bpy.ops.import_scene.gltf(filepath=self.gltf_path)
set_import_status('')
Utils.clean_downloaded_model_dir(self.uid)
root_name = Utils.make_model_name(gltf_importer.data)
Utils.clean_node_hierarchy([o for o in bpy.data.objects if o.name not in old_objects], root_name)
Utils.clean_node_hierarchy([o for o in bpy.data.objects if o.name not in old_objects], self.title)
return {'FINISHED'}
except Exception:
import traceback
print(traceback.format_exc())
set_import_status('')
return {'FINISHED'}

return {'RUNNING_MODAL'}

def invoke(self, context, event):
context.window_manager.modal_handler_add(self)
set_import_status('Importing...')
Expand Down Expand Up @@ -1524,7 +1502,7 @@ def draw(self, context):

self.layout.enabled = get_plugin_enabled() and api.is_user_logged()

if not api.user_orgs:
if not api.user_has_orgs:
self.layout.label(text="You are not part of an organization", icon='INFO')
self.layout.operator("wm.url_open", text='Learn about Sketchfab for Teams').url = "https://sketchfab.com/features/teams"
else:
Expand Down Expand Up @@ -2134,7 +2112,7 @@ def upload(filepath, filename):
else:

# Org or not
if len(api.user_orgs) and api.use_org_profile:
if api.user_has_orgs and api.use_org_profile:
uploadUrl = "%s/%s/models" % (Config.SKETCHFAB_ORGS, api.active_org["uid"])
_data["orgProject"] = props.active_project
else:
Expand Down Expand Up @@ -2395,7 +2373,7 @@ def check_plugin_version(request, *args, **kwargs):

def register():
sketchfab_icon = bpy.utils.previews.new()
icons_dir = os.path.join(os.path.dirname(__file__), "resources")
icons_dir = os.path.dirname(__file__)
sketchfab_icon.load("skfb", os.path.join(icons_dir, "logo.png"), 'IMAGE')
sketchfab_icon.load("0", os.path.join(icons_dir, "placeholder.png"), 'IMAGE')

Expand Down
10 changes: 0 additions & 10 deletions addons/io_sketchfab_plugin/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions addons/io_sketchfab_plugin/blender/README.md

This file was deleted.

Loading

0 comments on commit 85c1294

Please sign in to comment.