Bases: PreLaunchHook
Disable TVPaint's modal "Write to file" permission popup.
Metadata storage and any george script output are based on george file writes. Each of them is blocked by the popup until the preference is disabled, which nobody can confirm when TVPaint is launched headlessly.
Source code in client/ayon_tvpaint/hooks/pre_george_write_popup.py
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 | class TvpaintGeorgeWritePopup(PreLaunchHook):
"""Disable TVPaint's modal "Write to file" permission popup.
Metadata storage and any george script output are based on george
file writes. Each of them is blocked by the popup until the
preference is disabled, which nobody can confirm when TVPaint is
launched headlessly.
"""
app_groups = {"tvpaint"}
launch_types = {LaunchTypes.local}
platforms = {"windows"}
def execute(self):
# NOTE config.ini does contain special byte characters that's why
# configparser.ConfigParser is NOT used to work with the file.
key = b"georgecanwritefiledisplaypopup"
found_config = False
for config_path in self._iter_tvpaint_config_files():
found_config = True
with open(config_path, "rb") as stream:
content = stream.read()
match = re.search(key + rb"[ \t]*=[ \t]*(\d+)", content)
if match is None:
self.log.warning(
f"Preference \"{key.decode()}\""
f" not found in \"{config_path}\"."
)
continue
if match.group(1) == b"0":
continue
content = (
content[:match.start()] + key + b"=0"
+ content[match.end():]
)
with open(config_path, "wb") as stream:
stream.write(content)
self.log.info(
f"Disabled george write popup in \"{config_path}\"."
)
if not found_config:
self.log.warning("Did not find any TVPaint 'config.ini'.")
def _iter_tvpaint_config_files(self):
"""Iterate over config files of installed TVPaint versions.
Yields:
str: Path to 'config.ini' of a TVPaint configuration.
"""
appdata = os.environ.get("APPDATA")
if not appdata:
return
for base in glob.glob(os.path.join(appdata, "tvp animation *")):
profile = "default"
system_ini = os.path.join(base, "system.ini")
if os.path.exists(system_ini):
parser = configparser.ConfigParser()
try:
parser.read(system_ini)
profile = parser.get(
"system", "config", fallback=profile
)
except configparser.Error:
pass
config_path = os.path.join(base, profile, "config.ini")
if os.path.exists(config_path):
yield config_path
|