diff --git a/gui.py b/gui.py index a8437aa..a8754ee 100644 --- a/gui.py +++ b/gui.py @@ -12,22 +12,27 @@ from dataclasses import dataclass from tkinter.font import Font, nametofont from functools import partial, cached_property from datetime import datetime, timedelta, timezone -from tkinter import Tk, ttk, StringVar, DoubleVar, IntVar, PhotoImage +from tkinter import Tk, ttk, StringVar, DoubleVar, IntVar from typing import Any, Union, Tuple, TypedDict, NoReturn, Generic, TYPE_CHECKING import pystray -import win32api -import win32con -import win32gui from yarl import URL +from PIL.ImageTk import PhotoImage from PIL import Image as Image_module +if sys.platform == "win32": + import win32api + import win32con + import win32gui + from translate import _ from cache import ImageCache from exceptions import ExitRequest from utils import resource_path, Game, _T -from registry import RegistryKey, ValueType from constants import SELF_PATH, FORMATTER, WS_TOPICS_LIMIT, MAX_WEBSOCKETS, WINDOW_TITLE, State +if sys.platform == "win32": + from registry import RegistryKey, ValueType + if TYPE_CHECKING: from twitch import Twitch @@ -1502,16 +1507,17 @@ class SettingsPanel: tray = bool(self._vars["tray"].get()) self._settings.autostart = enabled self._settings.autostart_tray = tray - if enabled: - # NOTE: we need double quotes in case the path contains spaces - self_path = f'"{SELF_PATH.resolve()!s}"' - if tray: - self_path += " --tray" - with RegistryKey(self.AUTOSTART_KEY) as key: - key.set(self.AUTOSTART_NAME, ValueType.REG_SZ, self_path) - else: - with RegistryKey(self.AUTOSTART_KEY) as key: - key.delete(self.AUTOSTART_NAME, silent=True) + if sys.platform == "win32": + if enabled: + # NOTE: we need double quotes in case the path contains spaces + self_path = f'"{SELF_PATH.resolve()!s}"' + if tray: + self_path += " --tray" + with RegistryKey(self.AUTOSTART_KEY) as key: + key.set(self.AUTOSTART_NAME, ValueType.REG_SZ, self_path) + else: + with RegistryKey(self.AUTOSTART_KEY) as key: + key.delete(self.AUTOSTART_NAME, silent=True) def set_games(self, games: abc.Iterable[Game]) -> None: games_list = sorted(map(str, games)) @@ -1711,7 +1717,13 @@ class GUIManager: # withdraw immediately to prevent the window from flashing self._root.withdraw() # root.resizable(False, True) - root.iconbitmap(resource_path("pickaxe.ico")) # window icon + root.iconphoto( # window icon + True, + PhotoImage( + master=root, + image=Image_module.open(resource_path("pickaxe.ico")), + ) + ) root.title(WINDOW_TITLE) # window title root.bind_all("", self.unfocus) # pressing ESC unfocuses selection # Image cache for displaying images diff --git a/main.py b/main.py index ee692b2..a612ec0 100644 --- a/main.py +++ b/main.py @@ -17,23 +17,11 @@ if __name__ == "__main__": from tkinter import messagebox from typing import IO, NoReturn - # pre-import 3rd party libraries, handling missing ones with an exception - try: - import aiohttp # noqa - except ModuleNotFoundError as exc: - raise ImportError("You have to run 'pip install aiohttp' first") from exc - try: - import pystray # noqa - except ModuleNotFoundError as exc: - raise ImportError("You have to run 'pip install pystray' first") from exc - try: - import PIL # noqa - except ModuleNotFoundError as exc: - raise ImportError("You have to run 'pip install pillow' first") from exc - try: - import win32gui # noqa - except ModuleNotFoundError as exc: - raise ImportError("You have to run 'pip install pywin32' first") from exc + from PIL.ImageTk import PhotoImage + from PIL import Image as Image_module + + if sys.platform == "win32": + import win32gui from translate import _ from twitch import Twitch @@ -103,7 +91,9 @@ if __name__ == "__main__": root = tk.Tk() root.overrideredirect(True) root.withdraw() - root.iconbitmap(resource_path("pickaxe.ico")) + root.iconphoto( + True, PhotoImage(master=root, image=Image_module.open(resource_path("pickaxe.ico"))) + ) root.update() parser = Parser( SELF_PATH.name, @@ -135,16 +125,19 @@ if __name__ == "__main__": sys.exit(4) # dummy window isn't needed anymore root.destroy() + # get rid of unneeded objects + del root, parser # check if we're not already running - try: - exists = win32gui.FindWindow(None, WINDOW_TITLE) - except AttributeError: - # we're not on Windows - continue - exists = False - if exists and not settings.no_run_check: - # already running - exit - sys.exit(3) + if sys.platform == "win32": + try: + exists = win32gui.FindWindow(None, WINDOW_TITLE) + except AttributeError: + # we're not on Windows - continue + exists = False + if exists and not settings.no_run_check: + # already running - exit + sys.exit(3) # set language try: diff --git a/requirements.txt b/requirements.txt index e2cae20..f497250 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,8 @@ aiohttp>2.0,<4.0 Pillow pystray -pywin32 selenium-wire # use a fork that has an extra option of hiding the unneeded Chrome's console cmd window git+https://github.com/sebdelsol/undetected-chromedriver +# this is installed only on windows +pywin32; sys_platform == "win32" diff --git a/twitch.py b/twitch.py index e89e6d3..baf9c13 100644 --- a/twitch.py +++ b/twitch.py @@ -9,12 +9,14 @@ import logging from time import time from itertools import chain from functools import partial -from subprocess import CREATE_NO_WINDOW from collections import abc, deque, OrderedDict from datetime import datetime, timedelta, timezone from contextlib import suppress, asynccontextmanager from typing import Any, Literal, Final, NoReturn, overload, cast, TYPE_CHECKING +if sys.platform == "win32": + from subprocess import CREATE_NO_WINDOW + import aiohttp from yarl import URL try: