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
22from tkinter import messagebox , filedialog
33
4+
45def terminate ():
56 logger .error ("Terminating the program" )
67 sys .exit ()
78
9+
810def 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+
1720def 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+
3134logger = 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+
3363def 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+
5282def 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+
63101def 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+
74117def 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+
94142def 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+
104153def 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+
116166def 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+
143196if __name__ == "__main__" :
144- main ()
197+ VERSION = 1.3
198+ own_update_manager ()
199+ main ()
0 commit comments