Ejemplo n.º 1
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.º 2
0
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.')
Ejemplo n.º 3
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 = ''
    ui.add_report('BlenderKit Login success')
    search.get_profile()
    categories.fetch_categories_thread(auth_token)
Ejemplo n.º 4
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.º 5
0
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
Ejemplo n.º 6
0
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'}
Ejemplo n.º 7
0
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
Ejemplo n.º 8
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