Skip to content

Commit 8fc643e

Browse files
author
Pyenb
committed
updater now checks for own updates. Added versioning, refactored
1 parent cab1174 commit 8fc643e

1 file changed

Lines changed: 87 additions & 32 deletions

File tree

updater.py

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,134 @@
1-
import requests, gdown, zipfile, os, ctypes, tempfile, shutil, subprocess, sys, json, logging
1+
import requests, gdown, zipfile, os, tempfile, shutil, subprocess, sys, json, logging, webbrowser
22
from tkinter import messagebox, filedialog
33

4+
45
def terminate():
56
logger.error("Terminating the program")
67
sys.exit()
78

9+
810
def get_appdata_path():
9-
appdata_path = os.getenv('APPDATA')
10-
folder_path = os.path.join(appdata_path, 'Keychron mice updater')
11-
11+
appdata_path = os.getenv("APPDATA")
12+
folder_path = os.path.join(appdata_path, "Keychron mice updater")
13+
1214
if not os.path.exists(folder_path):
1315
os.makedirs(folder_path)
14-
16+
1517
return folder_path
1618

19+
1720
def setup_logger():
18-
folder_path = get_appdata_path()
19-
log_file_path = os.path.join(folder_path, 'updater.log')
21+
log_file_path = os.path.join(get_appdata_path(), "updater.log")
2022

2123
logging.basicConfig(
2224
filename=log_file_path,
23-
format='%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)d - %(message)s',
25+
format="%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)d - %(message)s",
2426
level=logging.INFO,
25-
encoding='utf-8'
27+
encoding="utf-8",
2628
)
2729

2830
logger = logging.getLogger(__name__)
2931
return logger
3032

33+
3134
logger = setup_logger()
3235

36+
37+
def own_update_manager():
38+
try:
39+
online_GH_version = float(
40+
requests.get(
41+
"https://api.github.com/repos/Pyenb/Keychron_mice_software_updater/releases/latest"
42+
)
43+
.json()["tag_name"]
44+
.replace("v", "")
45+
)
46+
if online_GH_version > VERSION:
47+
logger.info("New version of the updater available")
48+
result = messagebox.askquestion(
49+
"New updater version available",
50+
f"Version {online_GH_version} of the updater is available. Do you want to check it out?",
51+
)
52+
if result == "yes":
53+
logger.info("User selected to update the updater")
54+
webbrowser.open(
55+
"https://github.com/Pyenb/Keychron_mice_software_updater/releases/latest"
56+
)
57+
else:
58+
logger.info("User selected not to update the updater")
59+
except Exception as e:
60+
logging.error(f"Failed to check for new updater version: {e}")
61+
62+
3363
def config_manager():
34-
folder_path = get_appdata_path()
35-
config_file = os.path.join(folder_path, "config.json")
64+
config_file = os.path.join(get_appdata_path(), "config.json")
3665

3766
if os.path.exists(config_file):
3867
with open(config_file, "r") as f:
3968
install_path = json.load(f)["install_path"]
40-
if os.path.exists(os.path.join(install_path, 'config.xml')):
69+
if os.path.exists(os.path.join(install_path, "config.xml")):
4170
return install_path
4271
else:
43-
logger.warning('config.xml not found in install_path')
72+
logger.warning(f"config.xml not found in {install_path}")
4473

4574
install_path = get_install_path()
4675
with open(config_file, "w") as f:
4776
json.dump({"install_path": install_path}, f)
48-
logger.info('install_path written to config.json')
77+
logger.info("install_path written to config.json")
4978

5079
return install_path
5180

81+
5282
def get_install_path():
5383
default_path = r"C:\Program Files (x86)\Keychron"
54-
if not os.path.exists(os.path.join(default_path, 'config.xml')):
55-
logger.warning(f"Keychron software is not installed in the default location: {default_path}")
56-
messagebox.showerror("Error", f"Keychron software is not installed in the default location: {default_path}")
57-
messagebox.showinfo("Info", "Please select the Keychron software installation folder")
84+
if not os.path.exists(os.path.join(default_path, "config.xml")):
85+
logger.warning(
86+
f"Keychron software is not installed in the default location: {default_path}"
87+
)
88+
messagebox.showerror(
89+
"Error",
90+
f"Keychron software is not installed in the default location: {default_path}",
91+
)
92+
messagebox.showinfo(
93+
"Info", "Please select the Keychron software installation folder"
94+
)
5895
install_path = filedialog.askdirectory().replace("/", "\\")
5996
logger.info(f"User selected installation folder: {install_path}")
6097
return install_path
6198
return default_path
6299

100+
63101
def get_installed_version(install_path):
64102
try:
65103
with open(install_path + "\\config.xml") as f:
66-
installed_version = f.read().split('<software caption="Keychron" version="')[1].split('"')[0]
104+
installed_version = (
105+
f.read()
106+
.split('<software caption="Keychron" version="')[1]
107+
.split('"')[0]
108+
)
67109
logger.info(f"Installed version found: {installed_version}")
68110
return installed_version
69111
except Exception as e:
70112
logger.error(f"Failed to get installed version: {e}")
71113
messagebox.showerror("Error", f"Failed to get installed version: {e}")
72114
terminate()
73115

116+
74117
def get_online_version_and_url():
75118
try:
76-
download_site = requests.get("https://www.keychron.com/pages/learn-more-how-to-use-keychron-mouse-software").text
77-
download_id = download_site.split('drive.google.com/file/d/')[1].split('/')[0].strip()
119+
download_site = requests.get(
120+
"https://www.keychron.com/pages/learn-more-how-to-use-keychron-mouse-software"
121+
).text
122+
download_id = (
123+
download_site.split("drive.google.com/file/d/")[1].split("/")[0].strip()
124+
)
78125
download_url = f"https://drive.google.com/uc?id={download_id}"
79126
logging.info(f"Download url obtained: {download_url}")
80127

81128
online_version = download_site.splitlines()
82129
for line in online_version:
83130
if "Version" in line and "updated on" in line:
84-
online_version = line.split('Version ')[1].split(' ')[0].strip()
131+
online_version = line.split("Version ")[1].split(" ")[0].strip()
85132
logging.info(f"Online version obtained: {online_version}")
86133
break
87134

@@ -91,16 +138,18 @@ def get_online_version_and_url():
91138
messagebox.showerror("Error", f"Failed to get online version and url: {e}")
92139
terminate()
93140

141+
94142
def download_and_extract_file(download_url, tmp_path):
95143
try:
96-
gdown.download(download_url, tmp_path + '\\Keychron.zip', quiet=True)
97-
with zipfile.ZipFile(tmp_path + '\\Keychron.zip', 'r') as zip_ref:
144+
gdown.download(download_url, tmp_path + "\\Keychron.zip", quiet=True)
145+
with zipfile.ZipFile(tmp_path + "\\Keychron.zip", "r") as zip_ref:
98146
zip_ref.extractall(tmp_path)
99147
except Exception as e:
100148
logging.error(f"Failed to download and extract file: {e}")
101149
messagebox.showerror("Error", f"Failed to download and extract file: {e}")
102150
terminate()
103151

152+
104153
def run_exe(tmp_path):
105154
try:
106155
for root, dirs, files in os.walk(tmp_path):
@@ -113,6 +162,7 @@ def run_exe(tmp_path):
113162
messagebox.showerror("Error", f"Failed to run exe: {e}")
114163
terminate()
115164

165+
116166
def main():
117167
logger.info("Starting the updater")
118168
install_path = config_manager()
@@ -121,24 +171,29 @@ def main():
121171
online_version, download_url = get_online_version_and_url()
122172

123173
if installed_version != online_version:
124-
logger.info('Update available')
125-
MessageBox = ctypes.windll.user32.MessageBoxW
126-
result = MessageBox(None, f'Version {online_version} of the Keychron software is available. Do you want to download it?', 'New version available', 1)
127-
if result == 1:
128-
logger.info('User selected to update the software')
174+
logger.info("Update available")
175+
result = messagebox.askquestion(
176+
"New version available",
177+
f"Version {online_version} of the Keychron software is available. Do you want to download it?",
178+
)
179+
if result == "yes":
180+
logger.info("User selected to update the software")
129181
tmp_path = tempfile.mkdtemp()
130182
download_and_extract_file(download_url, tmp_path)
131183
run_exe(tmp_path)
132184
shutil.rmtree(tmp_path)
133185
else:
134-
logger.info('User selected not to update the software')
186+
logger.info("User selected not to update the software")
135187
else:
136-
logger.info('No update available')
188+
logger.info("No update available")
137189
except Exception as e:
138190
logging.error(f"An error occurred in main function: {e}")
139191
messagebox.showerror("Error", f"An error occurred in main function: {e}")
140192
terminate()
141193
logger.info("Updater finished")
142194

195+
143196
if __name__ == "__main__":
144-
main()
197+
VERSION = 1.3
198+
own_update_manager()
199+
main()

0 commit comments

Comments
 (0)