Implement autostart querying upon application start

This commit is contained in:
DevilXD committed 2024-07-01 19:25:16 +02:00
1 parent 5ade35d6a5
commit 14a9154366
5 files changed
+87 -46

No files matched your search

+7
View File
@@ -121,6 +121,13 @@ WATCH_INTERVAL = timedelta(seconds=20)
# Strings # Strings
WINDOW_TITLE = f"Twitch Drops Miner v{__version__} (by DevilXD)" WINDOW_TITLE = f"Twitch Drops Miner v{__version__} (by DevilXD)"
# Logging # Logging
LOGGING_LEVELS = {
0: logging.ERROR,
1: logging.WARNING,
2: logging.INFO,
3: CALL,
4: logging.DEBUG,
}
FILE_FORMATTER = logging.Formatter( FILE_FORMATTER = logging.Formatter(
"{asctime}.{msecs:03.0f}:\t{levelname:>7}:\t{message}", "{asctime}.{msecs:03.0f}:\t{levelname:>7}:\t{message}",
style='{', style='{',
+70 -28
View File
@@ -33,10 +33,16 @@ from cache import ImageCache
from exceptions import MinerException, ExitRequest from exceptions import MinerException, ExitRequest
from utils import resource_path, set_root_icon, webopen, Game, _T from utils import resource_path, set_root_icon, webopen, Game, _T
from constants import ( from constants import (
SELF_PATH, OUTPUT_FORMATTER, WS_TOPICS_LIMIT, MAX_WEBSOCKETS, WINDOW_TITLE, State SELF_PATH,
WINDOW_TITLE,
LOGGING_LEVELS,
MAX_WEBSOCKETS,
WS_TOPICS_LIMIT,
OUTPUT_FORMATTER,
State,
) )
if sys.platform == "win32": if sys.platform == "win32":
from registry import RegistryKey, ValueType from registry import RegistryKey, ValueType, ValueNotFound
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -1492,7 +1498,7 @@ class SettingsPanel:
self._vars: _SettingsVars = { self._vars: _SettingsVars = {
"proxy": StringVar(master, str(self._settings.proxy)), "proxy": StringVar(master, str(self._settings.proxy)),
"tray": IntVar(master, self._settings.autostart_tray), "tray": IntVar(master, self._settings.autostart_tray),
"autostart": IntVar(master, self._settings.autostart), "autostart": IntVar(master, 0),
"priority_only": IntVar(master, self._settings.priority_only), "priority_only": IntVar(master, self._settings.priority_only),
"tray_notifications": IntVar(master, self._settings.tray_notifications), "tray_notifications": IntVar(master, self._settings.tray_notifications),
} }
@@ -1647,6 +1653,8 @@ class SettingsPanel:
command=self._twitch.state_change(State.INVENTORY_FETCH), command=self._twitch.state_change(State.INVENTORY_FETCH),
).grid(column=1, row=0) ).grid(column=1, row=0)
self._vars["autostart"].set(self._query_autostart())
def clear_selection(self) -> None: def clear_selection(self) -> None:
self._priority_list.selection_clear(0, "end") self._priority_list.selection_clear(0, "end")
self._exclude_list.selection_clear(0, "end") self._exclude_list.selection_clear(0, "end")
@@ -1654,45 +1662,79 @@ class SettingsPanel:
def update_notifications(self) -> None: def update_notifications(self) -> None:
self._settings.tray_notifications = bool(self._vars["tray_notifications"].get()) self._settings.tray_notifications = bool(self._vars["tray_notifications"].get())
def _get_autostart_path(self, tray: bool) -> str: def _get_self_path(self) -> str:
self_path = f'"{SELF_PATH.resolve()!s}"'
if tray:
self_path += " --tray"
return self_path
def update_autostart(self) -> None:
enabled = bool(self._vars["autostart"].get())
tray = bool(self._vars["tray"].get())
self._settings.autostart = enabled
self._settings.autostart_tray = tray
if sys.platform == "win32":
if enabled:
# NOTE: we need double quotes in case the path contains spaces # NOTE: we need double quotes in case the path contains spaces
autostart_path = self._get_autostart_path(tray) return f'"{SELF_PATH.resolve()!s}"'
with RegistryKey(self.AUTOSTART_KEY) as key:
key.set(self.AUTOSTART_NAME, ValueType.REG_SZ, autostart_path) def _get_autostart_path(self) -> str:
else: flags: list[str] = [''] # this will add a space between self path and flags
with RegistryKey(self.AUTOSTART_KEY) as key: # if non-zero, include the current logging level as well
key.delete(self.AUTOSTART_NAME, silent=True) if self._settings.logging_level > 0:
elif sys.platform == "linux": for lvl_idx, lvl_value in LOGGING_LEVELS.items():
if lvl_value == self._settings.logging_level:
flags.append(f"-{'v' * lvl_idx}")
break
if self._vars["tray"].get():
flags.append("--tray")
return self._get_self_path() + ' '.join(flags)
def _get_linux_autostart_filepath(self) -> Path:
autostart_folder: Path = Path("~/.config/autostart").expanduser() autostart_folder: Path = Path("~/.config/autostart").expanduser()
if (config_home := os.environ.get("XDG_CONFIG_HOME")) is not None: if (config_home := os.environ.get("XDG_CONFIG_HOME")) is not None:
config_autostart: Path = Path(config_home, "autostart").expanduser() config_autostart: Path = Path(config_home, "autostart").expanduser()
if config_autostart.exists(): if config_autostart.exists():
autostart_folder = config_autostart autostart_folder = config_autostart
autostart_file: Path = autostart_folder / f"{self.AUTOSTART_NAME}.desktop" return autostart_folder / f"{self.AUTOSTART_NAME}.desktop"
def _query_autostart(self) -> bool:
if sys.platform == "win32":
with RegistryKey(self.AUTOSTART_KEY, read_only=True) as key:
try:
value_type, value = key.get(self.AUTOSTART_NAME)
except ValueNotFound:
return False
if (
value_type is not ValueType.REG_SZ
or self._get_self_path() not in value
):
# TODO: Consider deleting the old value to avoid autostart errors
return False
return True
elif sys.platform == "linux":
autostart_file: Path = self._get_linux_autostart_filepath()
if not autostart_file.exists():
return False
with autostart_file.open('r', encoding="utf8") as file:
# TODO: Consider deleting the old file to avoid autostart errors
return self._get_self_path() not in file.read()
def update_autostart(self) -> None:
enabled = bool(self._vars["autostart"].get())
self._settings.autostart_tray = bool(self._vars["tray"].get())
if sys.platform == "win32":
if enabled: if enabled:
autostart_path = self._get_autostart_path(tray) with RegistryKey(self.AUTOSTART_KEY) as key:
file_contents = dedent( key.set(
self.AUTOSTART_NAME,
ValueType.REG_SZ,
self._get_autostart_path(),
)
else:
with RegistryKey(self.AUTOSTART_KEY) as key:
key.delete(self.AUTOSTART_NAME, silent=True)
elif sys.platform == "linux":
autostart_file: Path = self._get_linux_autostart_filepath()
if enabled:
file_contents: str = dedent(
f""" f"""
[Desktop Entry] [Desktop Entry]
Type=Application Type=Application
Name=Twitch Drops Miner Name=Twitch Drops Miner
Description=Mine timed drops on Twitch Description=Mine timed drops on Twitch
Exec=sh -c '{autostart_path}' Exec=sh -c '{self._get_autostart_path()}'
""" """
) )
with autostart_file.open("w", encoding="utf8") as file: with autostart_file.open('w', encoding="utf8") as file:
file.write(file_contents) file.write(file_contents)
else: else:
autostart_file.unlink(missing_ok=True) autostart_file.unlink(missing_ok=True)
+2 -8
View File
@@ -28,7 +28,7 @@ if __name__ == "__main__":
from version import __version__ from version import __version__
from exceptions import CaptchaRequired from exceptions import CaptchaRequired
from utils import lock_file, resource_path, set_root_icon from utils import lock_file, resource_path, set_root_icon
from constants import CALL, SELF_PATH, FILE_FORMATTER, LOG_PATH, LOCK_PATH from constants import LOGGING_LEVELS, SELF_PATH, FILE_FORMATTER, LOG_PATH, LOCK_PATH
warnings.simplefilter("default", ResourceWarning) warnings.simplefilter("default", ResourceWarning)
@@ -58,13 +58,7 @@ if __name__ == "__main__":
# TODO: replace int with union of literal values once typeshed updates # TODO: replace int with union of literal values once typeshed updates
@property @property
def logging_level(self) -> int: def logging_level(self) -> int:
return { return LOGGING_LEVELS[min(self._verbose, 4)]
0: logging.ERROR,
1: logging.WARNING,
2: logging.INFO,
3: CALL,
4: logging.DEBUG,
}[min(self._verbose, 4)]
@property @property
def debug_ws(self) -> int: def debug_ws(self) -> int:
+8 -7
View File
@@ -10,7 +10,7 @@ class RegistryError(Exception):
pass pass
class ValueNotExists(RegistryError): class ValueNotFound(RegistryError):
pass pass
@@ -58,13 +58,14 @@ class ValueType(Enum):
class RegistryKey: class RegistryKey:
def __init__(self, path: str): def __init__(self, path: str, *, read_only: bool = False):
main_key, _, path = path.replace('/', '\\').partition('\\') main_key, _, path = path.replace('/', '\\').partition('\\')
self.main_key = MainKey[main_key] self.main_key = MainKey[main_key]
self.path = path self.path = path
self._handle = reg.OpenKey( access_flags = Access.KEY_QUERY_VALUE
self.main_key.value, path, access=(Access.KEY_QUERY_VALUE | Access.KEY_SET_VALUE).value if not read_only:
) access_flags |= Access.KEY_SET_VALUE
self._handle = reg.OpenKey(self.main_key.value, path, access=access_flags.value)
def __enter__(self) -> RegistryKey: def __enter__(self) -> RegistryKey:
return self return self
@@ -77,7 +78,7 @@ class RegistryKey:
value, value_type = reg.QueryValueEx(self._handle, name) value, value_type = reg.QueryValueEx(self._handle, name)
except FileNotFoundError: except FileNotFoundError:
# TODO: consider returning None for missing values # TODO: consider returning None for missing values
raise ValueNotExists(name) raise ValueNotFound(name)
return (ValueType(value_type), value) return (ValueType(value_type), value)
def set(self, name: str, value_type: ValueType, value: Any) -> bool: def set(self, name: str, value_type: ValueType, value: Any) -> bool:
@@ -89,7 +90,7 @@ class RegistryKey:
reg.DeleteValue(self._handle, name) reg.DeleteValue(self._handle, name)
except FileNotFoundError: except FileNotFoundError:
if not silent: if not silent:
raise ValueNotExists(name) raise ValueNotFound(name)
return False return False
return True return True
-3
View File
@@ -14,7 +14,6 @@ if TYPE_CHECKING:
class SettingsFile(TypedDict): class SettingsFile(TypedDict):
proxy: URL proxy: URL
language: str language: str
autostart: bool
exclude: set[str] exclude: set[str]
priority: list[str] priority: list[str]
priority_only: bool priority_only: bool
@@ -27,7 +26,6 @@ default_settings: SettingsFile = {
"proxy": URL(), "proxy": URL(),
"priority": [], "priority": [],
"exclude": set(), "exclude": set(),
"autostart": False,
"priority_only": True, "priority_only": True,
"autostart_tray": False, "autostart_tray": False,
"connection_quality": 1, "connection_quality": 1,
@@ -48,7 +46,6 @@ class Settings:
# from settings file # from settings file
proxy: URL proxy: URL
language: str language: str
autostart: bool
exclude: set[str] exclude: set[str]
priority: list[str] priority: list[str]
priority_only: bool priority_only: bool