diff --git a/addon/i3dio/.gitignore b/addon/i3dio/.gitignore index 49d4825..907ecbc 100644 --- a/addon/i3dio/.gitignore +++ b/addon/i3dio/.gitignore @@ -1,2 +1,2 @@ exporter_old.py - +**/i3dConverter.exe \ No newline at end of file diff --git a/addon/i3dio/ui/addon_preferences.py b/addon/i3dio/ui/addon_preferences.py index 6e69c20..c3880af 100644 --- a/addon/i3dio/ui/addon_preferences.py +++ b/addon/i3dio/ui/addon_preferences.py @@ -3,7 +3,7 @@ import bpy from bpy.types import AddonPreferences -from bpy.props import (StringProperty, EnumProperty) +from bpy.props import (StringProperty, EnumProperty, BoolProperty) from .. import xml_i3d @@ -78,6 +78,7 @@ def draw(self, context): row.prop(self, 'i3d_converter_path') if(next((True for addon in addon_utils.modules() if addon.bl_info.get("name") == "GIANTS I3D Exporter Tools"), False)): row.operator('i3dio.i3d_converter_path_from_giants_addon', text="", icon="EVENT_G") + row.operator("i3dio.download_i3d_converter", text="", icon='WORLD_DATA') case 'AUTOMATIC': #row = c_box.row() #row.operator("i3dio.download_i3d_converter", text="Manage Automatic Download") @@ -101,11 +102,79 @@ def execute(self, context): class I3D_IO_OT_download_i3d_converter(bpy.types.Operator): bl_idname = "i3dio.download_i3d_converter" bl_label = "Download I3D Converter" - bl_description = "Download I3D Converter" + bl_description = "Download from Giants Developer Network (Requires valid login)" bl_options = {'INTERNAL'} + email: StringProperty(name="Email", default="") + password: StringProperty(name="Password", default="", subtype="PASSWORD") + def execute(self, context): - return {"FINISHED"} + import re + from io import BytesIO + from requests import Session + from zipfile import (ZipFile, BadZipfile) + from shutil import copyfileobj + + # Attempt to login using provided credentials + session = Session() + request = session.post('https://gdn.giants-software.com/index.php', data={'greenstoneX':'1', 'redstoneX':self.email, 'bluestoneX':self.password}) + + ## Clear email and password after usage + self.email = "" + self.password = "" + + # Check if login was successful + if '
  • Logout
  • ' not in request.text: + self.report({'WARNING'}, f"Could not login to https://gdn.giants-software.com/index.php with provided credentials!") + return {'CANCELLED'} + + # Get download page + request = session.get('https://gdn.giants-software.com/downloads.php') + + # Find the download IDs for the all Giants Blender Exporters (As long as Giants names them the same way) + result = re.findall(r'href="download.php\?downloadId=([0-9]+)">Blender Exporter Plugins v([0-9]+.[0-9]+.[0-9]+)', request.text) + + # Assume the first found is the newest + download_id, exporter_version = result[0] + + # Request download of Giants I3D Exporter + download_url = f'https://gdn.giants-software.com/download.php?downloadId={download_id}' + request = session.get(download_url) + + try: + # Create in-memory zipfile from downloaded content + zipfile = ZipFile(BytesIO(request.content), 'r') + # Find path to this exporter addon + binary_path = 'i3dConverter.exe' + for addon in addon_utils.modules(): + if addon.bl_info.get("name") == "Unofficial GIANTS I3D Exporter Tools": + binary_path = pathlib.PurePath(addon.__file__).parent.joinpath(binary_path) + # Extract I3D Converter Binary from zipfile and save to disk + with zipfile.open('io_export_i3d/util/i3dConverter.exe') as zipped_binary, open(binary_path, 'wb') as saved_binary: + copyfileobj(zipped_binary, saved_binary) + # Set I3D Converter Binary path to newly downloaded converter + bpy.context.preferences.addons['i3dio'].preferences.i3d_converter_path = str(binary_path) + except (BadZipfile, KeyError, OSError) as e: + self.report({'WARNING'}, f"The Community I3D Exporter did not succesfully fetch and install the Giants I3D Converter binary! ({e})") + return {'CANCELLED'} + + self.report({'INFO'}, f"Fetched i3dConverter.exe from version {exporter_version} of the Giants Exporter downloaded from {download_url}") + return {'FINISHED'} + + def invoke(self, context, event): + wm = bpy.context.window_manager + # Width increased to fit the warning about the download freezing the UI + return wm.invoke_props_dialog(self, width=350) + + def draw(self, context): + layout = self.layout + row = layout.row() + row.prop(self, "email") + row = layout.row() + row.prop(self, "password") + row = layout.row() + row.alignment = "CENTER" + row.label(text="Blender UI will appear frozen during file download (~15MB) ", icon="ERROR") def register():