[Bf-extensions-cvs] [fa9b1187] master: io_online_sketchfab: moved to contrib: T63750
meta-androcto
noreply at git.blender.org
Fri May 24 04:24:42 CEST 2019
Commit: fa9b118763bb15d9c355251f93a58a0718edeacd
Author: meta-androcto
Date: Fri May 24 12:24:20 2019 +1000
Branches: master
https://developer.blender.org/rBACfa9b118763bb15d9c355251f93a58a0718edeacd
io_online_sketchfab: moved to contrib: T63750
===================================================================
A io_online_sketchfab/__init__.py
A io_online_sketchfab/pack_for_export.py
===================================================================
diff --git a/io_online_sketchfab/__init__.py b/io_online_sketchfab/__init__.py
new file mode 100644
index 00000000..5448d470
--- /dev/null
+++ b/io_online_sketchfab/__init__.py
@@ -0,0 +1,512 @@
+# ##### 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 #####
+
+bl_info = {
+ "name": "Sketchfab Exporter",
+ "author": "Bart Crouch",
+ "version": (1, 2, 3),
+ "blender": (2, 70, 0),
+ "location": "Tools > File I/O tab",
+ "description": "Upload your model to Sketchfab",
+ "warning": "",
+ "wiki_url": "",
+ "category": "Import-Export"
+}
+
+import bpy
+import os
+import tempfile
+import threading
+import subprocess
+
+from bpy.app.handlers import persistent
+from bpy.props import (
+ StringProperty,
+ EnumProperty,
+ BoolProperty,
+ PointerProperty,
+ )
+from bpy.types import (
+ Operator,
+ Panel,
+ AddonPreferences,
+ PropertyGroup,
+ )
+
+
+SKETCHFAB_API_URL = "https://api.sketchfab.com"
+SKETCHFAB_API_MODELS_URL = SKETCHFAB_API_URL + "/v1/models"
+SKETCHFAB_API_TOKEN_URL = SKETCHFAB_API_URL + "/v1/users/claim-token"
+SKETCHFAB_MODEL_URL = "https://sketchfab.com/show/"
+SKETCHFAB_EXPORT_FILENAME = "sketchfab-export.blend"
+
+_presets = os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets")
+SKETCHFAB_PRESET_FILENAME = os.path.join(_presets, "sketchfab.txt")
+SKETCHFAB_EXPORT_DATA_FILE = os.path.join(_presets, "sketchfab-export-data.json")
+del _presets
+
+
+# Singleton for storing global state
+class _SketchfabState:
+ __slots__ = (
+ "uploading",
+ "token_reload",
+ "size_label",
+ "model_url",
+
+ # store report args
+ "report_message",
+ "report_type",
+ )
+
+ def __init__(self):
+ self.uploading = False
+ self.token_reload = True
+ self.size_label = ""
+ self.model_url = ""
+
+ self.report_message = ""
+ self.report_type = ''
+
+
+sf_state = _SketchfabState()
+del _SketchfabState
+
+# if True, no contact is made with the webserver
+DEBUG_MODE = False
+
+
+# change a bytes int into a properly formatted string
+def format_size(size):
+ size /= 1024
+ size_suffix = "kB"
+ if size > 1024:
+ size /= 1024
+ size_suffix = "mB"
+ if size >= 100:
+ size = "%d" % int(size)
+ else:
+ size = "%.1f" % size
+ size += " " + size_suffix
+
+ return size
+
+
+# attempt to load token from presets
+ at persistent
+def load_token(dummy=False):
+ filepath = SKETCHFAB_PRESET_FILENAME
+ if not os.path.exists(filepath):
+ return
+
+ token = ""
+ try:
+ with open(filepath, 'r', encoding='utf-8') as f:
+ token = f.readline()
+ except:
+ import traceback
+ traceback.print_exc()
+
+ wm = bpy.context.window_manager
+ wm.sketchfab.token = token
+
+
+# save token to file
+def update_token(self, context):
+ token = context.window_manager.sketchfab.token
+ filepath = SKETCHFAB_PRESET_FILENAME
+
+ path = os.path.dirname(filepath)
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+ with open(filepath, 'w', encoding='utf-8') as f:
+ f.write(token)
+
+
+def upload_report(report_message, report_type):
+ sf_state.report_message = report_message
+ sf_state.report_type = report_type
+
+
+# upload the blend-file to sketchfab
+def upload(filepath, filename):
+ import requests
+
+ wm = bpy.context.window_manager
+ props = wm.sketchfab
+
+ title = props.title
+ if not title:
+ title = os.path.splitext(os.path.basename(bpy.data.filepath))[0]
+
+ data = {
+ "title": title,
+ "description": props.description,
+ "filename": filename,
+ "tags": props.tags,
+ "private": props.private,
+ "token": props.token,
+ "source": "blender-exporter",
+ }
+
+ if props.private and props.password != "":
+ data["password"] = props.password
+
+ files = {
+ "fileModel": open(filepath, 'rb'),
+ }
+
+ try:
+ r = requests.post(SKETCHFAB_API_MODELS_URL, data=data, files=files, verify=False)
+ except requests.exceptions.RequestException as e:
+ return upload_report("Upload failed. Error: %s" % str(e), 'WARNING')
+
+ result = r.json()
+ if r.status_code != requests.codes.ok:
+ return upload_report("Upload failed. Error: %s" % result["error"], 'WARNING')
+
+ sf_state.model_url = SKETCHFAB_MODEL_URL + result["result"]["id"]
+ return upload_report("Upload complete. Available on your sketchfab.com dashboard.", 'INFO')
+
+
+# operator to export model to sketchfab
+class ExportSketchfab(Operator):
+ """Upload your model to Sketchfab"""
+ bl_idname = "export.sketchfab"
+ bl_label = "Upload"
+
+ _timer = None
+ _thread = None
+
+ def modal(self, context, event):
+ if event.type == 'TIMER':
+ if not self._thread.is_alive():
+ wm = context.window_manager
+ props = wm.sketchfab
+ terminate(props.filepath)
+ if context.area:
+ context.area.tag_redraw()
+
+ # forward message from upload thread
+ if not sf_state.report_type:
+ sf_state.report_type = 'ERROR'
+ self.report({sf_state.report_type}, sf_state.report_message)
+
+ wm.event_timer_remove(self._timer)
+ self._thread.join()
+ sf_state.uploading = False
+ return {'FINISHED'}
+
+ return {'PASS_THROUGH'}
+
+ def execute(self, context):
+ import json
+
+ if sf_state.uploading:
+ self.report({'WARNING'}, "Please wait till current upload is finished")
+ return {'CANCELLED'}
+
+ wm = context.window_manager
+ sf_state.model_url = ""
+ props = wm.sketchfab
+ if not props.token:
+ self.report({'ERROR'}, "Token is missing")
+ return {'CANCELLED'}
+
+ # Prepare to save the file
+ binary_path = bpy.app.binary_path
+ script_path = os.path.dirname(os.path.realpath(__file__))
+ basename, ext = os.path.splitext(bpy.data.filepath)
+ if not basename:
+ basename = os.path.join(basename, "temp")
+ if not ext:
+ ext = ".blend"
+ tempdir = tempfile.mkdtemp()
+ filepath = os.path.join(tempdir, "export-sketchfab" + ext)
+
+ try:
+ # save a copy of actual scene but don't interfere with the users models
+ bpy.ops.wm.save_as_mainfile(filepath=filepath, compress=True, copy=True)
+
+ with open(SKETCHFAB_EXPORT_DATA_FILE, 'w') as s:
+ json.dump({
+ "models": props.models,
+ "lights": props.lights,
+ }, s)
+
+ subprocess.check_call([
+ binary_path,
+ "--background",
+ "-noaudio",
+ filepath,
+ "--python", os.path.join(script_path, "pack_for_export.py"),
+ "--", tempdir
+ ])
+
+ os.remove(filepath)
+
+ # read subprocess call results
+ with open(SKETCHFAB_EXPORT_DATA_FILE, 'r') as s:
+ r = json.load(s)
+ size = r["size"]
+ props.filepath = r["filepath"]
+ filename = r["filename"]
+
+ except Exception as e:
+ self.report({'WARNING'}, "Error occurred while preparing your file: %s" % str(e))
+ return {'FINISHED'}
+
+ sf_state.uploading = True
+ sf_state.size_label = format_size(size)
+ self._thread = threading.Thread(
+ target=upload,
+ args=(props.filepath, filename),
+ )
+ self._thread.start()
+
+ wm.modal_handler_add(self)
+ self._timer = wm.event_timer_add(1.0, context.window)
+
+ return {'RUNNING_MODAL'}
+
+ def cancel(self, context):
+ wm = context.window_manager
+ wm.event_timer_remove(self._timer)
+ self._thread.join()
+
+
+# user interface
+class VIEW3D_PT_sketchfab(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_category = "File I/O"
+ bl_context = "objectmode"
+ bl_label = "Sketchfab"
+
+ def draw(self, context):
+ wm = context.window_manager
+ props = wm.sketchfab
+ if sf_state.token_reload:
+ sf_state.token_reload = False
+ if not props.token:
+ load_token()
+ layout = self.layout
+
+ layout.label(text="Export:")
+ col = layout.box().column(align=True)
+ col.prop(props, "models")
+ col.prop(props, "lights")
+
+ layout.label(text="Model info:")
+ col = layout.box().column(align=True)
+ col.prop(props, "title")
+ col.prop(props, "description")
+ col.prop(props, "tags")
+ col.prop(props, "private")
+ if props.private:
+ col.prop(props, "password")
+
+ layout.label(text="Sketchfab account:")
+ col = layout.box().column(align=True)
+ col.prop(props, "token")
+ row = col.row()
+ row.operator("wm.sketchfab_email_token", text="Claim Your Token")
+ row.alignment = 'RIGHT'
+ if sf_state.uploading:
+ layout.operator("export.sketchfab", text
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list