2025-07-01
This commit is contained in:
@@ -0,0 +1,501 @@
|
||||
# #### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from typing import Dict
|
||||
import os
|
||||
|
||||
try:
|
||||
import ConfigParser
|
||||
except Exception:
|
||||
import configparser as ConfigParser
|
||||
|
||||
from . import reporting
|
||||
from .modules.poliigon_core.addon import PoliigonUser
|
||||
from .modules.poliigon_core.api_remote_control_params import (
|
||||
CATEGORY_ALL,
|
||||
KEY_TAB_IMPORTED,
|
||||
KEY_TAB_MY_ASSETS,
|
||||
KEY_TAB_ONLINE)
|
||||
from .modules.poliigon_core.plan_manager import PoliigonSubscription
|
||||
|
||||
from .dialogs.utils_dlg import check_dpi
|
||||
from .notifications import build_writing_settings_failed_notification
|
||||
from .utils import (
|
||||
f_Ex,
|
||||
f_MDir)
|
||||
|
||||
|
||||
# Use _get_default_settings() to get the default settings.
|
||||
DEFAULT_SETTINGS = {
|
||||
"area": KEY_TAB_ONLINE,
|
||||
"auto_download": 1,
|
||||
"category": {
|
||||
KEY_TAB_IMPORTED: [CATEGORY_ALL],
|
||||
KEY_TAB_MY_ASSETS: [CATEGORY_ALL],
|
||||
KEY_TAB_ONLINE: [CATEGORY_ALL]
|
||||
},
|
||||
"conform": 0,
|
||||
"default_lod": "LOD1",
|
||||
"del_zip": 1,
|
||||
"disabled_dirs": [],
|
||||
"download_lods": 1,
|
||||
"download_prefer_blend": 1,
|
||||
"download_link_blend": 0,
|
||||
"hdri_use_jpg_bg": False,
|
||||
"hide_labels": 1,
|
||||
"hide_scene": 0,
|
||||
"hide_suggest": 0,
|
||||
"location": "Properties",
|
||||
"mapping_type": "UV + UberMapping",
|
||||
"mat_props": [],
|
||||
"mix_props": [],
|
||||
"new_release": "",
|
||||
"last_update": "",
|
||||
"new_top": 1,
|
||||
"notify": 5,
|
||||
"one_click_purchase": 1,
|
||||
"page": 10,
|
||||
"popup_welcome": 0,
|
||||
"popup_download": 0,
|
||||
"popup_preview": 0,
|
||||
"preview_size": 7, # 7 currently constant/hard coded
|
||||
"previews": 1,
|
||||
# Note on reporting rates:
|
||||
# These will only be changed upon successful update-requests
|
||||
# and only ever store custom rates from updater. Any default
|
||||
# values and/or forced sampling values will and must not be stored
|
||||
# here!
|
||||
"reporting_error_rate": -1, # no valid value
|
||||
"reporting_transaction_rate": -1, # no valid value
|
||||
"set_library": "",
|
||||
"show_active": 1,
|
||||
"show_add_dir": 1,
|
||||
"show_asset_info": 1,
|
||||
"show_credits": 1,
|
||||
"show_default_prefs": 1,
|
||||
"show_display_prefs": 1,
|
||||
"show_import_prefs": 1,
|
||||
"show_asset_browser_prefs": True,
|
||||
"show_mat_ops": 0,
|
||||
"show_mat_props": 0,
|
||||
"show_mat_texs": 0,
|
||||
"show_mix_props": 1,
|
||||
"show_pass": 0,
|
||||
"show_plan": 1,
|
||||
"show_feedback": 0,
|
||||
"show_settings": 0,
|
||||
"show_user": 0,
|
||||
"sorting": "Latest",
|
||||
"thumbsize": "Medium",
|
||||
"unzip": 1,
|
||||
"update_sel": 1,
|
||||
"use_16": 1,
|
||||
"use_ao": 1,
|
||||
"use_bump": 1,
|
||||
"use_disp": 1,
|
||||
"use_subdiv": 1,
|
||||
"version": None, # initialized in _get_default_settings()
|
||||
"win_scale": 1,
|
||||
"first_enabled_time": "",
|
||||
|
||||
"res": "2K",
|
||||
"lod": "NONE",
|
||||
"mres": "2K",
|
||||
"hdri": "1K",
|
||||
"hdrib": "8K",
|
||||
"hdrif": "EXR", # TODO(Andreas): constant and used in commented code, only
|
||||
"brush": "2K",
|
||||
|
||||
# TODO(Andreas): Why did we store a list of map types in settings???
|
||||
# "maps": cTB.vMaps,
|
||||
}
|
||||
|
||||
|
||||
def _get_default_settings(cTB) -> Dict[str, any]:
|
||||
"""Returns default settings from above dictionary, augmented with runtime
|
||||
infos like e.g. version.
|
||||
"""
|
||||
|
||||
settings = DEFAULT_SETTINGS
|
||||
settings["version"] = cTB.version
|
||||
return settings
|
||||
|
||||
|
||||
def _read_config(cTB):
|
||||
"""Safely reads the config or returns an empty one if corrupted."""
|
||||
|
||||
config = ConfigParser.ConfigParser()
|
||||
config.optionxform = str
|
||||
with cTB.lock_settings_file:
|
||||
try:
|
||||
config.read(cTB.path_settings)
|
||||
except ConfigParser.Error:
|
||||
# Corrupted file, return empty config.
|
||||
cTB.logger.exception(
|
||||
"Config parsing error, using fresh empty config instead.")
|
||||
config = ConfigParser.ConfigParser()
|
||||
config.optionxform = str
|
||||
return config
|
||||
|
||||
|
||||
def _get_settings_section_user(cTB, config: ConfigParser) -> bool:
|
||||
"""Returns False, if section 'user' is not found."""
|
||||
|
||||
if not config.has_section("user"):
|
||||
return False
|
||||
|
||||
if cTB.user is None:
|
||||
# Note: Marking non existing user by setting user ID None
|
||||
cTB.user = PoliigonUser(
|
||||
user_name="", user_id=None, plan=PoliigonSubscription())
|
||||
|
||||
user = cTB.user
|
||||
for _key in config.options("user"):
|
||||
if _key in cTB.skip_legacy_settings:
|
||||
continue
|
||||
if _key in ["credits", "credits_od"]:
|
||||
try:
|
||||
setattr(user, _key, int(config.get("user", _key)))
|
||||
except ValueError:
|
||||
setattr(user, _key, 0)
|
||||
elif _key == "token":
|
||||
token = config.get("user", "token")
|
||||
if token and token != "None":
|
||||
cTB._api.token = config.get("user", "token")
|
||||
elif _key == "user_name":
|
||||
setattr(user, _key, config.get("user", _key))
|
||||
elif _key == "id":
|
||||
try:
|
||||
user_id_config = config.get("user", _key)
|
||||
user.user_id = int(user_id_config)
|
||||
except ValueError:
|
||||
cTB.logger.exception(f"Couldn't set user '{user_id_config}':")
|
||||
user.user_id = None # mark user not existent
|
||||
elif _key == "user_id":
|
||||
pass # ignore, likely a remnant from a bug during development
|
||||
# elif _key == "plan_name":
|
||||
# user.plan.plan_name = config.get("user", _key)
|
||||
elif _key == "plan_credit":
|
||||
try:
|
||||
setattr(user.plan, _key, int(config.get("user", _key)))
|
||||
except ValueError:
|
||||
setattr(user.plan, _key, None)
|
||||
elif _key in ["plan_name", "plan_paused_at", "plan_paused_until"]:
|
||||
setattr(user.plan, _key, config.get("user", _key))
|
||||
elif _key == "plan_next_renew":
|
||||
user.plan.next_subscription_renewal_date = config.get("user", _key)
|
||||
elif _key == "plan_next_credits":
|
||||
user.plan.next_credit_renewal_date = config.get("user", _key)
|
||||
elif _key == "plan_paused":
|
||||
pass # we do get this info from addon-core, now
|
||||
elif _key == "is_free_user":
|
||||
pass # we do get this info from addon-core, now
|
||||
else:
|
||||
# TODO(Andreas): Remove, when working. Or add logging/reporting
|
||||
cTB.logger.debug("UNSET USER PARAM", _key)
|
||||
|
||||
if user.user_id is None:
|
||||
cTB.user = None
|
||||
else:
|
||||
reporting.assign_user(cTB.user.user_id)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _get_settings_section_settings(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("settings"):
|
||||
return
|
||||
|
||||
for _key in config.options("settings"):
|
||||
if _key.startswith("category"):
|
||||
try:
|
||||
vArea = _key.replace("category_", "")
|
||||
cTB.settings["category"][vArea] = config.get(
|
||||
"settings", _key
|
||||
).split("/")
|
||||
if "" in cTB.settings[_key]:
|
||||
cTB.settings["category"][vArea].remove("")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
cTB.settings[_key] = config.get("settings", _key)
|
||||
|
||||
if _key in [
|
||||
"add_dirs",
|
||||
"disabled_dirs",
|
||||
"mat_props",
|
||||
"mix_props",
|
||||
]:
|
||||
cTB.settings[_key] = cTB.settings[_key].split(";")
|
||||
if "" in cTB.settings[_key]:
|
||||
cTB.settings[_key].remove("")
|
||||
elif cTB.settings[_key] == "True":
|
||||
cTB.settings[_key] = 1
|
||||
elif cTB.settings[_key] == "False":
|
||||
cTB.settings[_key] = 0
|
||||
else:
|
||||
try:
|
||||
cTB.settings[_key] = int(cTB.settings[_key])
|
||||
except Exception:
|
||||
try:
|
||||
cTB.settings[_key] = float(cTB.settings[_key])
|
||||
except Exception:
|
||||
pass
|
||||
# Fallback, if lod was set to SOURCE
|
||||
if _key == "lod" and cTB.settings[_key] == "SOURCE":
|
||||
# TODO(Andreas): Fallback to LOD0 correct?
|
||||
cTB.settings[_key] = "LOD0"
|
||||
|
||||
|
||||
def _get_settings_section_presets(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("presets"):
|
||||
return
|
||||
|
||||
for _key in config.options("presets"):
|
||||
try:
|
||||
cTB.vPresets[_key] = [
|
||||
float(_value)
|
||||
for _value in config.get("presets", _key).split(";")
|
||||
]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _get_settings_section_mixpresets(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("mixpresets"):
|
||||
return
|
||||
|
||||
for _key in config.options("mixpresets"):
|
||||
try:
|
||||
cTB.vMixPresets[_key] = [
|
||||
float(_value)
|
||||
for _value in config.get("mixpresets", _key).split(";")
|
||||
]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _get_settings_section_download(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("download"):
|
||||
return
|
||||
|
||||
for _key in config.options("download"):
|
||||
if _key == "res":
|
||||
cTB.settings["res"] = config.get("download", _key)
|
||||
elif _key == "maps":
|
||||
value = config.get("download", _key)
|
||||
cTB.settings["maps"] = value.split(";")
|
||||
|
||||
|
||||
def get_settings_section_map_prefs(cTB) -> None:
|
||||
config = _read_config(cTB)
|
||||
if not config.has_section("map_preferences"):
|
||||
return
|
||||
|
||||
user_prefs = cTB.user.map_preferences
|
||||
if user_prefs is None:
|
||||
return
|
||||
|
||||
for _map_format in user_prefs.texture_maps:
|
||||
map_name = _map_format.map_type.name
|
||||
local_ext_pref = config.get(
|
||||
"map_preferences", str(map_name), fallback="")
|
||||
local_ext_available = _map_format.extensions.get(
|
||||
local_ext_pref.lower(), True)
|
||||
|
||||
if local_ext_pref in [None, ""] or not local_ext_available:
|
||||
continue
|
||||
elif local_ext_pref == "NONE":
|
||||
_map_format.selected = None
|
||||
_map_format.enabled = False
|
||||
else:
|
||||
_map_format.selected = local_ext_pref.lower()
|
||||
_map_format.enabled = True
|
||||
|
||||
|
||||
def get_settings(cTB) -> None:
|
||||
cTB.logger.debug("get_settings")
|
||||
|
||||
cTB.skip_legacy_settings = ["name", "email"]
|
||||
|
||||
cTB.settings = _get_default_settings(cTB)
|
||||
|
||||
check_dpi(cTB)
|
||||
|
||||
cTB.vPresets = {}
|
||||
cTB.vMixPresets = {}
|
||||
|
||||
cTB.vReleases = {}
|
||||
|
||||
if f_Ex(cTB.path_settings): # check done outside of lock should still be ok
|
||||
config = _read_config(cTB)
|
||||
|
||||
if not _get_settings_section_user(cTB, config):
|
||||
with cTB.lock_settings_file:
|
||||
os.remove(cTB.path_settings)
|
||||
config = ConfigParser.ConfigParser()
|
||||
|
||||
_get_settings_section_settings(cTB, config)
|
||||
_get_settings_section_presets(cTB, config)
|
||||
_get_settings_section_mixpresets(cTB, config)
|
||||
_get_settings_section_download(cTB, config)
|
||||
# Loading of map prefs works differently, as it happens upon
|
||||
# receiving map prefs from server.
|
||||
|
||||
if cTB.settings.get("library", "") == "":
|
||||
cTB.settings["set_library"] = cTB.dir_settings.replace(
|
||||
"Blender", "Library")
|
||||
|
||||
cTB.settings["show_user"] = 0
|
||||
cTB.settings["mat_props_edit"] = 0
|
||||
|
||||
cTB.settings["area"] = KEY_TAB_ONLINE
|
||||
cTB.settings["category"] = {
|
||||
KEY_TAB_ONLINE: [CATEGORY_ALL],
|
||||
KEY_TAB_IMPORTED: [CATEGORY_ALL],
|
||||
KEY_TAB_MY_ASSETS: [CATEGORY_ALL]
|
||||
}
|
||||
|
||||
save_settings(cTB)
|
||||
|
||||
|
||||
def _save_settings_section_user(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("user"):
|
||||
config.add_section("user")
|
||||
|
||||
# for vK in cTB.vUser.keys():
|
||||
# if vK in cTB.skip_legacy_settings:
|
||||
# config.remove_option("user", vK)
|
||||
# continue
|
||||
# config.set("user", vK, str(cTB.vUser[vK]))
|
||||
if cTB.user is not None:
|
||||
config.set("user", "id", str(cTB.user.user_id))
|
||||
config.set("user", "user_name", str(cTB.user.user_name))
|
||||
|
||||
# Save token as if cTB field, on load will be parsed to _api.token
|
||||
config.set("user", "token", str(cTB._api.token))
|
||||
|
||||
|
||||
def _save_settings_section_settings(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("settings"):
|
||||
config.add_section("settings")
|
||||
|
||||
for _key in cTB.settings.keys():
|
||||
if _key == "category":
|
||||
for _key_asset_type in cTB.settings[_key].keys():
|
||||
config.set(
|
||||
"settings",
|
||||
_key + "_" + _key_asset_type,
|
||||
"/".join(cTB.settings[_key][_key_asset_type])
|
||||
)
|
||||
elif _key in ["add_dirs", "disabled_dirs", "mat_props", "mix_props"]:
|
||||
config.set("settings", _key, ";".join(cTB.settings[_key]))
|
||||
else:
|
||||
config.set("settings", _key, str(cTB.settings[_key]))
|
||||
|
||||
|
||||
def _save_settings_section_presets(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("presets"):
|
||||
config.add_section("presets")
|
||||
|
||||
for _key in cTB.vPresets.keys():
|
||||
config.set(
|
||||
"presets", _key,
|
||||
";".join([str(_value) for _value in cTB.vPresets[_key]])
|
||||
)
|
||||
|
||||
|
||||
def _save_settings_section_mixpresets(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("mixpresets"):
|
||||
config.add_section("mixpresets")
|
||||
|
||||
for _key in cTB.vMixPresets.keys():
|
||||
config.set(
|
||||
"mixpresets",
|
||||
_key, ";".join([str(_value) for _value in cTB.vMixPresets[_key]])
|
||||
)
|
||||
|
||||
|
||||
def _save_settings_section_download(cTB, config: ConfigParser) -> None:
|
||||
if config.has_section("download"):
|
||||
config.remove_section("download")
|
||||
|
||||
config.add_section("download")
|
||||
|
||||
for _key in cTB.settings:
|
||||
if _key == "res":
|
||||
config.set("download", _key, cTB.settings[_key])
|
||||
elif _key == "maps":
|
||||
config.set("download", _key, ";".join(cTB.settings[_key]))
|
||||
|
||||
|
||||
def _remove_replaced_legacy_settings(cTB, config: ConfigParser) -> None:
|
||||
try:
|
||||
config.remove_option("settings", "library")
|
||||
except ConfigParser.NoSectionError:
|
||||
pass # it's fine if not existing
|
||||
try:
|
||||
config.remove_option("settings", "add_dirs")
|
||||
except ConfigParser.NoSectionError:
|
||||
pass # it's fine if not existing
|
||||
|
||||
|
||||
def _save_settings_section_map_prefs(cTB, config: ConfigParser) -> None:
|
||||
if not config.has_section("map_preferences"):
|
||||
config.add_section("map_preferences")
|
||||
|
||||
if cTB.user is None:
|
||||
return
|
||||
user_prefs = cTB.user.map_preferences
|
||||
if user_prefs is None:
|
||||
return
|
||||
|
||||
for _map_format in user_prefs.texture_maps:
|
||||
map_name = _map_format.map_type.name
|
||||
selected = _map_format.selected
|
||||
extension = selected if selected is not None else "NONE"
|
||||
|
||||
config.set("map_preferences", str(map_name), str(extension))
|
||||
|
||||
|
||||
def save_settings(cTB) -> None:
|
||||
cTB.logger.debug("save_settings")
|
||||
|
||||
config = _read_config(cTB)
|
||||
|
||||
_remove_replaced_legacy_settings(cTB, config)
|
||||
|
||||
_save_settings_section_user(cTB, config)
|
||||
_save_settings_section_settings(cTB, config)
|
||||
_save_settings_section_presets(cTB, config)
|
||||
_save_settings_section_mixpresets(cTB, config)
|
||||
_save_settings_section_download(cTB, config)
|
||||
_save_settings_section_map_prefs(cTB, config)
|
||||
|
||||
f_MDir(cTB.dir_settings)
|
||||
|
||||
with cTB.lock_settings_file:
|
||||
try:
|
||||
with open(cTB.path_settings, "w+") as file:
|
||||
config.write(file)
|
||||
except OSError as e:
|
||||
if e.errno != 28:
|
||||
# Below notice assumes the OSError is for disk space only,
|
||||
# so let's report if this ever isn't the case
|
||||
reporting.capture_exception(e)
|
||||
build_writing_settings_failed_notification(cTB, e.strerror)
|
||||
Reference in New Issue
Block a user