Ejemplo n.º 1
0
def search_update(self, context):
    utils.p('search updater')
    # if self.search_keywords != '':
    ui_props = bpy.context.scene.blenderkitUI
    if ui_props.down_up != 'SEARCH':
        ui_props.down_up = 'SEARCH'

    # here we tweak the input if it comes form the clipboard. we need to get rid of asset type and set it to
    sprops = utils.get_search_props()
    instr = 'asset_base_id:'
    atstr = 'asset_type:'
    kwds = sprops.search_keywords
    idi = kwds.find(instr)
    ati = kwds.find(atstr)
    # if the asset type already isn't there it means this update function
    # was triggered by it's last iteration and needs to cancel
    if idi > -1 and ati == -1:
        return
    if ati > -1:
        at = kwds[ati:].lower()
        # uncertain length of the remaining string -  find as better method to check the presence of asset type
        if at.find('model') > -1:
            ui_props.asset_type = 'MODEL'
        elif at.find('material') > -1:
            ui_props.asset_type = 'MATERIAL'
        elif at.find('brush') > -1:
            ui_props.asset_type = 'BRUSH'
        # now we trim the input copypaste by anything extra that is there,
        # this is also a way for this function to recognize that it already has parsed the clipboard
        # the search props can have changed and this needs to transfer the data to the other field
        # this complex behaviour is here for the case where the user needs to paste manually into blender?
        sprops = utils.get_search_props()
        sprops.search_keywords = kwds[:ati].rstrip()
    search()
Ejemplo n.º 2
0
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])
Ejemplo n.º 3
0
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()
    if api_key == '':
        props = utils.get_search_props()
        props.report = 'Register online to use the free library.'
        return
    tcom = ThreadCom()

    tcom.passargs = kwargs

    # 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()

    # main_thread(asset_data, tcom, scene_id, api_key)
    readthread = threading.Thread(target=main_thread, args=([asset_data, tcom, scene_id, api_key]), daemon=True)
    readthread.start()

    global download_threads
    download_threads.append(
        [readthread, asset_data, tcom])
Ejemplo n.º 4
0
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 = 'Login success!'
    search.get_profile()
    categories.fetch_categories_thread(auth_token)
 def search_by_author(self, asset_index):
     sr = bpy.context.scene['search results']
     asset_data = sr[asset_index]
     a = asset_data['author']['id']
     if a is not None:
         sprops = utils.get_search_props()
         sprops.search_keywords = ''
         sprops.search_verification_status = 'ALL'
         utils.p('author:', a)
         search.search(author_id=a)
     return True
Ejemplo n.º 6
0
    def search_more(self):
        sro = bpy.context.window_manager.get('search results orig')
        if sro is None:
            return;
        if sro.get('next') is None:
            return
        search_props = utils.get_search_props()
        if search_props.is_searching:
            return

        blenderkit.search.search(get_next=True)
Ejemplo n.º 7
0
    def execute(self, context):
        # TODO ; this should all get transferred to properties of the search operator, so sprops don't have to be fetched here at all.
        sprops = utils.get_search_props()
        if self.author_id != '':
            sprops.search_keywords = ''
        if self.keywords != '':
            sprops.search_keywords = self.keywords

        search(category=self.category, get_next=self.get_next, author_id=self.author_id)
        # bpy.ops.view3d.blenderkit_asset_bar()

        return {'FINISHED'}
Ejemplo n.º 8
0
def check_clipboard():
    # clipboard monitoring to search assets from web
    global last_clipboard
    if bpy.context.window_manager.clipboard != last_clipboard:
        last_clipboard = bpy.context.window_manager.clipboard
        instr = 'asset_base_id:'
        # first check if contains asset id, then asset type
        if last_clipboard[:len(instr)] == instr:
            atstr = 'asset_type:'
            ati = last_clipboard.find(atstr)
            # this only checks if the asset_type keyword is there but let's the keywords update function do the parsing.
            if ati > -1:
                search_props = utils.get_search_props()
                search_props.search_keywords = last_clipboard
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
def check_clipboard():
    '''
    Checks clipboard for an exact string containing asset ID.
    The string is generated on www.blenderkit.com as for example here:
    https://www.blenderkit.com/get-blenderkit/54ff5c85-2c73-49e9-ba80-aec18616a408/
    '''

    # clipboard monitoring to search assets from web
    if platform.system() != 'Linux':
        global last_clipboard
        if bpy.context.window_manager.clipboard != last_clipboard:
            last_clipboard = bpy.context.window_manager.clipboard
            instr = 'asset_base_id:'
            # first check if contains asset id, then asset type
            if last_clipboard[:len(instr)] == instr:
                atstr = 'asset_type:'
                ati = last_clipboard.find(atstr)
                # this only checks if the asset_type keyword is there but let's the keywords update function do the parsing.
                if ati > -1:
                    search_props = utils.get_search_props()
                    search_props.search_keywords = last_clipboard
Ejemplo n.º 11
0
def timer_update(
):  # TODO might get moved to handle all blenderkit stuff, not to slow down.
    '''check for running and finished downloads and react. write progressbars too.'''
    global download_threads
    if len(download_threads) == 0:
        return 1
    s = bpy.context.scene
    for threaddata in download_threads:
        t = threaddata[0]
        asset_data = threaddata[1]
        tcom = threaddata[2]

        progress_bars = []
        downloaders = []

        if t.is_alive():  # set downloader size
            sr = bpy.context.scene.get('search results')
            if sr is not None:
                for r in sr:
                    if asset_data['id'] == r['id']:
                        r['downloaded'] = tcom.progress

        if not t.is_alive():
            if tcom.error:
                sprops = utils.get_search_props()
                sprops.report = tcom.report
                download_threads.remove(threaddata)
                return
            file_names = paths.get_download_filenames(asset_data)
            wm = bpy.context.window_manager

            at = asset_data['asset_type']
            if ((bpy.context.mode == 'OBJECT' and (at == 'model' \
                                                   or at == 'material'))) \
                    or ((at == 'brush') \
                        and wm.get(
                        'appendable') == True) or at == 'scene':  # don't do this stuff in editmode and other modes, just wait...
                download_threads.remove(threaddata)

                # duplicate file if the global and subdir are used in prefs
                if len(
                        file_names
                ) == 2:  # todo this should try to check if both files exist and are ok.
                    shutil.copyfile(file_names[0], file_names[1])

                utils.p('appending asset')
                # progress bars:

                # we need to check if mouse isn't down, which means an operator can be running.
                # Especially for sculpt mode, where appending a brush during a sculpt stroke causes crasehes
                #

                if tcom.passargs.get('redownload'):
                    # handle lost libraries here:
                    for l in bpy.data.libraries:
                        if l.get('asset_data') is not None and l['asset_data'][
                                'id'] == asset_data['id']:
                            l.filepath = file_names[-1]
                            l.reload()
                else:
                    done = try_finished_append(asset_data, **tcom.passargs)
                    if not done:
                        at = asset_data['asset_type']
                        tcom.passargs['retry_counter'] = tcom.passargs.get(
                            'retry_counter', 0) + 1
                        if at in ('model', 'material'):
                            download(asset_data, **tcom.passargs)
                        elif asset_data['asset_type'] == 'material':
                            download(asset_data, **tcom.passargs)
                        elif asset_data['asset_type'] == 'scene':
                            download(asset_data, **tcom.passargs)
                        elif asset_data['asset_type'] == 'brush' or asset_data[
                                'asset_type'] == 'texture':
                            download(asset_data, **tcom.passargs)
                    if bpy.context.scene['search results'] is not None and done:
                        for sres in bpy.context.scene['search results']:
                            if asset_data['id'] == sres['id']:
                                sres['downloaded'] = 100

                utils.p('finished download thread')
    return .5
Ejemplo n.º 12
0
def timer_update():  # TODO might get moved to handle all blenderkit stuff.
    # 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 = 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(rtips),
                          timeout=12,
                          color=colors.GREEN)

    # clipboard monitoring to search assets from web
    global last_clipboard
    if bpy.context.window_manager.clipboard != 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:
                at = last_clipboard[ati:]

            search_props = utils.get_search_props()
            search_props.search_keywords = last_clipboard
            search()

    global search_threads
    # don't do anything while dragging - this could switch asset type during drag, and make results list length different,
    # causing a lot of throuble literally.
    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)
                                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': str(r['author']['id'])
                                    # 'author': r['author']['firstName'] + ' ' + r['author']['lastName']
                                    # 'description': r['description'],
                                    # 'author': 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 on_invoke(self, context, event):

        if self.do_search:
            #TODO: move the search behaviour to separate operator, since asset bar can be already woken up from a timer.

            # we erase search keywords for cateogry search now, since these combinations usually return nothing now.
            # when the db gets bigger, this can be deleted.
            if self.category != '':
                sprops = utils.get_search_props()
                sprops.search_keywords = ''
            search.search(category=self.category)

        ui_props = context.scene.blenderkitUI
        if ui_props.assetbar_on:
            #TODO solve this otehrwise to enable more asset bars?

            # we don't want to run the assetbar many times, that's why it has a switch on/off behaviour,
            # unless being called with 'keep_running' prop.
            if not self.keep_running:
                # this sends message to the originally running operator, so it quits, and then it ends this one too.
                # If it initiated a search, the search will finish in a thread. The switch off procedure is run
                # by the 'original' operator, since if we get here, it means
                # same operator is already running.
                ui_props.turn_off = True
                # if there was an error, we need to turn off these props so we can restart after 2 clicks
                ui_props.assetbar_on = False

            else:
                pass
            return False

        ui_props.assetbar_on = True

        self.active_index = -1

        widgets_panel = self.widgets_panel
        widgets_panel.extend(self.buttons)
        widgets_panel.extend(self.asset_buttons)
        widgets_panel.extend(self.validation_icons)

        widgets = [self.panel]

        widgets += widgets_panel
        widgets.append(self.tooltip_panel)
        widgets += self.tooltip_widgets

        self.init_widgets(context, widgets)

        self.panel.add_widgets(widgets_panel)
        self.tooltip_panel.add_widgets(self.tooltip_widgets)

        # Open the panel at the mouse location
        # self.panel.set_location(bpy.context.area.width - event.mouse_x,
        #                         bpy.context.area.height - event.mouse_y + 20)
        self.panel.set_location(self.bar_x, self.bar_y)

        self.context = context
        args = (self, context)

        # self._handle_2d_tooltip = bpy.types.SpaceView3D.draw_handler_add(draw_callback_tooltip, args, 'WINDOW', 'POST_PIXEL')
        return True
Ejemplo n.º 14
0
    def draw(self, context):
        s = context.scene
        ui_props = s.blenderkitUI
        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
        wm = bpy.context.window_manager
        layout = self.layout

        # layout.prop_tabs_enum(ui_props, "asset_type", icon_only = True)

        row = layout.row()
        # row.scale_x = 1.6
        # row.scale_y = 1.6
        #
        row.prop(ui_props, 'down_up', expand=True, icon_only=False)
        # row.label(text='')
        # row = row.split().row()
        # layout.alert = True
        # layout.alignment = 'CENTER'
        # row = layout.row(align = True)
        # split = row.split(factor=.5)
        # row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
        # row = layout.column(align = False)
        layout.prop(ui_props, 'asset_type', expand=False, text='')

        w = context.region.width
        if user_preferences.login_attempt:
            draw_login_progress(layout)
            return

        if len(user_preferences.api_key) < 20 and user_preferences.asset_counter > 20:
            if user_preferences.enable_oauth:
                draw_login_buttons(layout)
            else:
                op = layout.operator("wm.url_open", text="Get your API Key",
                                     icon='QUESTION')
                op.url = paths.BLENDERKIT_SIGNUP_URL
                layout.label(text='Paste your API Key:')
                layout.prop(user_preferences, 'api_key', text='')
            layout.separator()
        # if bpy.data.filepath == '':
        #     layout.alert = True
        #     label_multiline(layout, text="It's better to save your file first.", width=w)
        #     layout.alert = False
        #     layout.separator()

        if ui_props.down_up == 'SEARCH':
            if utils.profile_is_validator():
                search_props = utils.get_search_props()
                layout.prop(search_props, 'search_verification_status')
            if ui_props.asset_type == 'MODEL':
                # noinspection PyCallByClass
                draw_panel_model_search(self, context)
            if ui_props.asset_type == 'SCENE':
                # noinspection PyCallByClass
                draw_panel_scene_search(self, context)

            elif ui_props.asset_type == 'MATERIAL':
                draw_panel_material_search(self, context)
            elif ui_props.asset_type == 'BRUSH':
                if context.sculpt_object or context.image_paint_object:
                    # noinspection PyCallByClass
                    draw_panel_brush_search(self, context)
                else:
                    label_multiline(layout, text='switch to paint or sculpt mode.', width=context.region.width)
                    return


        elif ui_props.down_up == 'UPLOAD':
            if not ui_props.assetbar_on:
                text = 'Show asset preview - ;'
            else:
                text = 'Hide asset preview - ;'
            op = layout.operator('view3d.blenderkit_asset_bar', text=text, icon='EXPORT')
            op.keep_running = False
            op.do_search = False
            op.tooltip = 'Show/Hide asset preview'

            e = s.render.engine
            if e not in ('CYCLES', 'BLENDER_EEVEE'):
                rtext = 'Only Cycles and EEVEE render engines are currently supported. ' \
                        'Please use Cycles for all assets you upload to BlenderKit.'
                label_multiline(layout, rtext, icon='ERROR', width=w)
                return;

            if ui_props.asset_type == 'MODEL':
                # label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR')
                if bpy.context.view_layer.objects.active is not None:
                    draw_panel_model_upload(self, context)
                else:
                    layout.label(text='selet object to upload')
            elif ui_props.asset_type == 'SCENE':
                draw_panel_scene_upload(self, context)

            elif ui_props.asset_type == 'MATERIAL':
                # label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR')

                if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
                    draw_panel_material_upload(self, context)
                else:
                    label_multiline(layout, text='select object with material to upload materials', width=w)

            elif ui_props.asset_type == 'BRUSH':
                if context.sculpt_object or context.image_paint_object:
                    draw_panel_brush_upload(self, context)
                else:
                    layout.label(text='switch to paint or sculpt mode.')

        elif ui_props.down_up == 'RATING':  # the poll functions didn't work here, don't know why.

            if ui_props.asset_type == 'MODEL':
                # TODO improve poll here to parenting structures
                if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.get(
                        'asset_data') != None:
                    ad = bpy.context.active_object.get('asset_data')
                    layout.label(text=ad['name'])
                    draw_panel_model_rating(self, context)
            if ui_props.asset_type == 'MATERIAL':
                if bpy.context.view_layer.objects.active is not None and \
                        bpy.context.active_object.active_material is not None and \
                        bpy.context.active_object.active_material.blenderkit.asset_base_id != '':
                    layout.label(text=bpy.context.active_object.active_material.blenderkit.name + ' :')
                    # noinspection PyCallByClass
                    draw_panel_material_ratings(self, context)
            if ui_props.asset_type == 'BRUSH':
                if context.sculpt_object or context.image_paint_object:
                    props = utils.get_brush_props(context)
                    if props.asset_base_id != '':
                        layout.label(text=props.name + ' :')
                        # noinspection PyCallByClass
                        draw_panel_brush_ratings(self, context)
            if ui_props.asset_type == 'TEXTURE':
                layout.label(text='not yet implemented')
Ejemplo n.º 15
0
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