def download(asset_data, **kwargs): '''start the download thread''' user_preferences = bpy.context.preferences.addons['blenderkit'].preferences api_key = user_preferences.api_key scene_id = get_scene_id() tcom = ThreadCom() tcom.passargs = kwargs if kwargs.get('retry_counter', 0) > 3: sprops = utils.get_search_props() report = f"Maximum retries exceeded for {asset_data['name']}" sprops.report = report ui.add_report(report, 5, colors.RED) utils.p(sprops.report) return # incoming data can be either directly dict from python, or blender id property # (recovering failed downloads on reload) if type(asset_data) == dict: asset_data = copy.deepcopy(asset_data) else: asset_data = asset_data.to_dict() readthread = Downloader(asset_data, tcom, scene_id, api_key) readthread.start() global download_threads download_threads.append([readthread, asset_data, tcom])
def refresh_token_thread(): preferences = bpy.context.preferences.addons['blenderkit'].preferences if len(preferences.api_key_refresh) > 0 and preferences.refresh_in_progress == False: preferences.refresh_in_progress = True url = paths.get_bkit_url() thread = threading.Thread(target=refresh_token, args=([preferences.api_key_refresh, url]), daemon=True) thread.start() else: ui.add_report('Already Refreshing token, will be ready soon.')
def write_tokens(auth_token, refresh_token): utils.p('writing tokens') preferences = bpy.context.preferences.addons['blenderkit'].preferences preferences.api_key_refresh = refresh_token preferences.api_key = auth_token preferences.login_attempt = False props = utils.get_search_props() props.report = '' ui.add_report('BlenderKit Login success') search.get_profile() categories.fetch_categories_thread(auth_token)
def write_tokens(auth_token, refresh_token, oauth_response): utils.p('writing tokens') preferences = bpy.context.preferences.addons['blenderkit'].preferences preferences.api_key_refresh = refresh_token preferences.api_key = auth_token preferences.api_key_timeout = time.time() + oauth_response['expires_in'] preferences.api_key_life = oauth_response['expires_in'] preferences.login_attempt = False preferences.refresh_in_progress = False props = utils.get_search_props() if props is not None: props.report = '' ui.add_report('BlenderKit Re-Login success') search.get_profile() categories.fetch_categories_thread(auth_token)
def timer_update(): # this makes a first search after opening blender. showing latest assets. global first_time preferences = bpy.context.preferences.addons['blenderkit'].preferences if first_time: # first time first_time = False if preferences.show_on_start or preferences.first_run: # TODO here it should check if there are some results, and only open assetbar if this is the case, not search. #if bpy.context.scene.get('search results') is None: search() preferences.first_run = False if preferences.tips_on_start: ui.get_largest_3dview() ui.update_ui_size(ui.active_area, ui.active_region) ui.add_report(text='BlenderKit Tip: ' + random.choice(rtips), timeout=12, color=colors.GREEN) check_clipboard() global search_threads # don't do anything while dragging - this could switch asset during drag, and make results list length different, # causing a lot of throuble. if len(search_threads) == 0 or bpy.context.scene.blenderkitUI.dragging: return 1 for thread in search_threads: # TODO this doesn't check all processes when one gets removed, # but most of the time only one is running anyway if not thread[0].is_alive(): search_threads.remove(thread) # icons_dir = thread[1] scene = bpy.context.scene # these 2 lines should update the previews enum and set the first result as active. s = bpy.context.scene asset_type = thread[2] if asset_type == 'model': props = scene.blenderkit_models json_filepath = os.path.join(icons_dir, 'model_searchresult.json') search_name = 'bkit model search' if asset_type == 'scene': props = scene.blenderkit_scene json_filepath = os.path.join(icons_dir, 'scene_searchresult.json') search_name = 'bkit scene search' if asset_type == 'material': props = scene.blenderkit_mat json_filepath = os.path.join(icons_dir, 'material_searchresult.json') search_name = 'bkit material search' if asset_type == 'brush': props = scene.blenderkit_brush json_filepath = os.path.join(icons_dir, 'brush_searchresult.json') search_name = 'bkit brush search' s[search_name] = [] global reports if reports != '': props.report = str(reports) return .2 with open(json_filepath, 'r') as data_file: rdata = json.load(data_file) result_field = [] ok, error = check_errors(rdata) if ok: bpy.ops.object.run_assetbar_fix_context() for r in rdata['results']: # TODO remove this fix when filesSize is fixed. # this is a temporary fix for too big numbers from the server. try: r['filesSize'] = int(r['filesSize'] / 1024) except: utils.p('asset with no files-size') if r['assetType'] == asset_type: if len(r['files']) > 0: furl = None tname = None allthumbs = [] durl, tname = None, None for f in r['files']: if f['fileType'] == 'thumbnail': tname = paths.extract_filename_from_url( f['fileThumbnailLarge']) small_tname = paths.extract_filename_from_url( f['fileThumbnail']) allthumbs.append( tname ) # TODO just first thumb is used now. tdict = {} for i, t in enumerate(allthumbs): tdict['thumbnail_%i'] = t if f['fileType'] == 'blend': durl = f['downloadUrl'].split('?')[0] # fname = paths.extract_filename_from_url(f['filePath']) if durl and tname: tooltip = generate_tooltip(r) #for some reason, the id was still int on some occurances. investigate this. r['author']['id'] = str(r['author']['id']) asset_data = { 'thumbnail': tname, 'thumbnail_small': small_tname, # 'thumbnails':allthumbs, 'download_url': durl, 'id': r['id'], 'asset_base_id': r['assetBaseId'], 'name': r['name'], 'asset_type': r['assetType'], 'tooltip': tooltip, 'tags': r['tags'], 'can_download': r.get('canDownload', True), 'verification_status': r['verificationStatus'], 'author_id': r['author']['id'], # 'author': r['author']['firstName'] + ' ' + r['author']['lastName'] # 'description': r['description'], } asset_data['downloaded'] = 0 # parse extra params needed for blender here params = utils.params_to_dict(r['parameters']) if asset_type == 'model': if params.get('boundBoxMinX') != None: bbox = { 'bbox_min': (float(params['boundBoxMinX']), float(params['boundBoxMinY']), float(params['boundBoxMinZ'])), 'bbox_max': (float(params['boundBoxMaxX']), float(params['boundBoxMaxY']), float(params['boundBoxMaxZ'])) } else: bbox = { 'bbox_min': (-.5, -.5, 0), 'bbox_max': (.5, .5, 1) } asset_data.update(bbox) if asset_type == 'material': asset_data[ 'texture_size_meters'] = params.get( 'textureSizeMeters', 1.0) asset_data.update(tdict) if r['assetBaseId'] in scene.get( 'assets used', {}).keys(): asset_data['downloaded'] = 100 result_field.append(asset_data) # results = rdata['results'] s[search_name] = result_field s['search results'] = result_field s[search_name + ' orig'] = rdata s['search results orig'] = rdata load_previews() ui_props = bpy.context.scene.blenderkitUI if len(result_field) < ui_props.scrolloffset: ui_props.scrolloffset = 0 props.is_searching = False props.search_error = False props.report = 'Found %i results. ' % ( s['search results orig']['count']) if len(s['search results']) == 0: tasks_queue.add_task( (ui.add_report, ('No matching results found.', ))) # (rdata['next']) # if rdata['next'] != None: # search(False, get_next = True) else: print('error', error) props.report = error props.search_error = True # print('finished search thread') mt('preview loading finished') return .3
def start_upload(self, context, asset_type, reupload, upload_set): '''start upload process, by processing data''' # fix the name first utils.name_update() props = utils.get_upload_props() storage_quota_ok = check_storage_quota(props) if not storage_quota_ok: self.report({'ERROR_INVALID_INPUT'}, props.report) return {'CANCELLED'} location = get_upload_location(props) props.upload_state = 'preparing upload' auto_fix(asset_type=asset_type) # do this for fixing long tags in some upload cases props.tags = props.tags[:] props.name = props.name.strip() # TODO move this to separate function # check for missing metadata if asset_type == 'MODEL': get_missing_data_model(props) if asset_type == 'SCENE': get_missing_data_scene(props) elif asset_type == 'MATERIAL': get_missing_data_material(props) elif asset_type == 'BRUSH': get_missing_data_brush(props) if props.report != '': self.report({'ERROR_INVALID_INPUT'}, props.report) return {'CANCELLED'} if not reupload: props.asset_base_id = '' props.id = '' export_data, upload_data, eval_path_computing, eval_path_state, eval_path, props = get_upload_data(self, context, asset_type) # utils.pprint(upload_data) upload_data['parameters'] = params_to_dict( upload_data['parameters']) # weird array conversion only for upload, not for tooltips. 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() source_filepath = os.path.join(tempdir, "export_blenderkit" + ext) clean_file_path = paths.get_clean_filepath() data = { 'clean_file_path': clean_file_path, 'source_filepath': source_filepath, 'temp_dir': tempdir, 'export_data': export_data, 'upload_data': upload_data, 'debug_value': bpy.app.debug_value, 'upload_set': upload_set, } datafile = os.path.join(tempdir, BLENDERKIT_EXPORT_DATA_FILE) # check if thumbnail exists: if 'THUMBNAIL' in upload_set: if not os.path.exists(export_data["thumbnail_path"]): props.upload_state = 'Thumbnail not found' props.uploading = False return {'CANCELLED'} # first upload metadata to server, so it can be saved inside the current file url = paths.get_api_url() + 'assets/' headers = utils.get_headers(upload_data['token']) # upload_data['license'] = 'ovejajojo' json_metadata = upload_data # json.dumps(upload_data, ensure_ascii=False).encode('utf8') global reports if props.asset_base_id == '': try: r = rerequests.post(url, json=json_metadata, headers=headers, verify=True, immediate=True) # files = files, ui.add_report('uploaded metadata') utils.p(r.text) except requests.exceptions.RequestException as e: print(e) props.upload_state = str(e) props.uploading = False return {'CANCELLED'} else: url += props.id + '/' try: if upload_set != ['METADATA']: json_metadata["verificationStatus"] = "uploading" r = rerequests.put(url, json=json_metadata, headers=headers, verify=True, immediate=True) # files = files, ui.add_report('uploaded metadata') # parse the request # print('uploaded metadata') # print(r.text) except requests.exceptions.RequestException as e: print(e) props.upload_state = str(e) props.uploading = False return {'CANCELLED'} # props.upload_state = 'step 1' if upload_set == ['METADATA']: props.uploading = False props.upload_state = 'upload finished successfully' return {'FINISHED'} try: rj = r.json() utils.pprint(rj) # if r.status_code not in (200, 201): # if r.status_code == 401: # ui.add_report(r.detail, 5, colors.RED) # return {'CANCELLED'} if props.asset_base_id == '': props.asset_base_id = rj['assetBaseId'] props.id = rj['id'] upload_data['assetBaseId'] = props.asset_base_id upload_data['id'] = props.id # bpy.ops.wm.save_mainfile() # bpy.ops.wm.save_as_mainfile(filepath=filepath, compress=False, copy=True) props.uploading = True # save a copy of actual scene but don't interfere with the users models bpy.ops.wm.save_as_mainfile(filepath=source_filepath, compress=False, copy=True) with open(datafile, 'w') as s: json.dump(data, s) proc = subprocess.Popen([ binary_path, "--background", "-noaudio", clean_file_path, "--python", os.path.join(script_path, "upload_bg.py"), "--", datafile # ,filepath, tempdir ], bufsize=5000, stdout=subprocess.PIPE, stdin=subprocess.PIPE) bg_blender.add_bg_process(eval_path_computing=eval_path_computing, eval_path_state=eval_path_state, eval_path=eval_path, process_type='UPLOAD', process=proc, location=location) except Exception as e: props.upload_state = str(e) props.uploading = False print(e) return {'CANCELLED'} return {'FINISHED'}
def timer_update(): # this makes a first search after opening blender. showing latest assets. global first_time preferences = bpy.context.preferences.addons['blenderkit'].preferences if first_time: # first time first_time = False if preferences.show_on_start: # TODO here it should check if there are some results, and only open assetbar if this is the case, not search. # if bpy.context.scene.get('search results') is None: search() # preferences.first_run = False if preferences.tips_on_start: utils.get_largest_area() ui.update_ui_size(ui.active_area, ui.active_region) ui.add_report(text='BlenderKit Tip: ' + random.choice(rtips), timeout=12, color=colors.GREEN) return 3.0 # if preferences.first_run: # search() # preferences.first_run = False # check_clipboard() global search_threads if len(search_threads) == 0: return 1.0 # don't do anything while dragging - this could switch asset during drag, and make results list length different, # causing a lot of throuble. if bpy.context.scene.blenderkitUI.dragging: return 0.5 for thread in search_threads: # TODO this doesn't check all processes when one gets removed, # but most of the time only one is running anyway if not thread[0].is_alive(): search_threads.remove(thread) # icons_dir = thread[1] scene = bpy.context.scene # these 2 lines should update the previews enum and set the first result as active. s = bpy.context.scene asset_type = thread[2] if asset_type == 'model': props = scene.blenderkit_models # json_filepath = os.path.join(icons_dir, 'model_searchresult.json') if asset_type == 'scene': props = scene.blenderkit_scene # json_filepath = os.path.join(icons_dir, 'scene_searchresult.json') if asset_type == 'material': props = scene.blenderkit_mat # json_filepath = os.path.join(icons_dir, 'material_searchresult.json') if asset_type == 'brush': props = scene.blenderkit_brush # json_filepath = os.path.join(icons_dir, 'brush_searchresult.json') search_name = f'bkit {asset_type} search' s[search_name] = [] global reports if reports != '': props.report = str(reports) return .2 rdata = thread[0].result result_field = [] ok, error = check_errors(rdata) if ok: bpy.ops.object.run_assetbar_fix_context() for r in rdata['results']: asset_data = parse_result(r) if asset_data != None: result_field.append(asset_data) # results = rdata['results'] s[search_name] = result_field s['search results'] = result_field s[search_name + ' orig'] = copy.deepcopy(rdata) s['search results orig'] = s[search_name + ' orig'] load_previews() ui_props = bpy.context.scene.blenderkitUI if len(result_field) < ui_props.scrolloffset: ui_props.scrolloffset = 0 props.is_searching = False props.search_error = False props.report = 'Found %i results. ' % ( s['search results orig']['count']) if len(s['search results']) == 0: tasks_queue.add_task( (ui.add_report, ('No matching results found.', ))) else: print('error', error) props.report = error props.search_error = True # print('finished search thread') mt('preview loading finished') return .3
def timer_update2(): preferences = bpy.context.preferences.addons['blenderkit'].preferences if search.first_time: search.first_time = False if preferences.show_on_start: search() if preferences.tips_on_start: ui.get_largest_3dview() ui.update_ui_size(ui.active_area, ui.active_region) ui.add_report(text='BlenderKit Tip: ' + random.choice(search.rtips), timeout=12, color=colors.GREEN) if bpy.context.window_manager.clipboard != search.last_clipboard: last_clipboard = bpy.context.window_manager.clipboard instr = 'asset_base_id:' if last_clipboard[:len(instr)] == instr: atstr = 'asset_type:' ati = last_clipboard.find(atstr) if ati > -1: search_props = utils.get_search_props() search_props.search_keywords = last_clipboard if len(search.search_threads ) == 0 or bpy.context.scene.blenderkitUI.dragging: return 1 for thread in search.search_threads: if not thread[0].is_alive(): search.search_threads.remove(thread) # icons_dir = thread[1] scene = bpy.context.scene s = bpy.context.scene asset_type = thread[2] if asset_type == 'model': props = scene.blenderkit_models json_filepath = os.path.join(icons_dir, 'model_searchresult.json') search_name = 'bkit model search' if asset_type == 'scene': props = scene.blenderkit_scene json_filepath = os.path.join(icons_dir, 'scene_searchresult.json') search_name = 'bkit scene search' if asset_type == 'material': props = scene.blenderkit_mat json_filepath = os.path.join(icons_dir, 'material_searchresult.json') search_name = 'bkit material search' if asset_type == 'brush': props = scene.blenderkit_brush json_filepath = os.path.join(icons_dir, 'brush_searchresult.json') search_name = 'bkit brush search' s[search_name] = [] if search.reports != '': props.report = str(search.reports) return .2 with open(json_filepath, 'r') as data_file: rdata = json.load(data_file) result_field = [] ok, error = search.check_errors(rdata) if ok: bpy.ops.object.run_assetbar_fix_context() for r in rdata['results']: try: r['filesSize'] = int(r['filesSize'] / 1024) except: utils.p('asset with no files-size') if r['assetType'] == asset_type: if len(r['files']) > 0: tname = None allthumbs = [] durl, tname = None, None for f in r['files']: if f['fileType'] == 'thumbnail': tname = paths.extract_filename_from_url( f['fileThumbnailLarge']) small_tname = paths.extract_filename_from_url( f['fileThumbnail']) allthumbs.append(tname) tdict = {} for i, t in enumerate(allthumbs): tdict['thumbnail_%i'] = t if f['fileType'] == 'blend': durl = f['downloadUrl'].split('?')[0] if durl and tname: tooltip = search.generate_tooltip(r) asset_data = { 'thumbnail': tname, 'thumbnail_small': small_tname, 'download_url': durl, 'id': r['id'], 'asset_base_id': r['assetBaseId'], 'name': r['name'], 'asset_type': r['assetType'], 'tooltip': tooltip, 'tags': r['tags'], 'can_download': r.get('canDownload', True), 'verification_status': r['verificationStatus'], 'author_id': str(r['author']['id']) } asset_data['downloaded'] = 0 if 'description' in r: asset_data['description'] = r[ 'description'] if 'metadata' in r: asset_data['metadata'] = r['metadata'] if 'sku' in r: asset_data['sku'] = r['sku'] if 'client' in r: asset_data['client'] = r['client'] params = utils.params_to_dict(r['parameters']) if asset_type == 'model': if params.get('boundBoxMinX') is not None: bbox = { 'bbox_min': (float(params['boundBoxMinX']), float(params['boundBoxMinY']), float(params['boundBoxMinZ'])), 'bbox_max': (float(params['boundBoxMaxX']), float(params['boundBoxMaxY']), float(params['boundBoxMaxZ'])) } else: bbox = { 'bbox_min': (-.5, -.5, 0), 'bbox_max': (.5, .5, 1) } asset_data.update(bbox) if asset_type == 'material': asset_data[ 'texture_size_meters'] = params.get( 'textureSizeMeters', 1.0) asset_data.update(tdict) if r['assetBaseId'] in scene.get( 'assets used', {}).keys(): asset_data['downloaded'] = 100 result_field.append(asset_data) s[search_name] = result_field s['search results'] = result_field s[search_name + ' orig'] = rdata s['search results orig'] = rdata search.load_previews() ui_props = bpy.context.scene.blenderkitUI if len(result_field) < ui_props.scrolloffset: ui_props.scrolloffset = 0 props.is_searching = False props.search_error = False props.report = 'Found %i results. ' % ( s['search results orig']['count']) if len(s['search results']) == 0: tasks_queue.add_task( (ui.add_report, ('No matching results found.', ))) else: print('error', error) props.report = error props.search_error = True search.mt('preview loading finished') return .3