-
Notifications
You must be signed in to change notification settings - Fork 0
/
kindle-updater.py
182 lines (149 loc) · 9.02 KB
/
kindle-updater.py
1
2
3
4
5
6
7
8
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# ==================================== #
# Kindle Updater #
# Kindle Paperwhite 4 #
# 10th gen #
# ==================================== #
# ------------ import libs ----------- #
from urllib.request import urlopen # open URLs
from bs4 import BeautifulSoup # BeautifulSoup; parsing HTML
import re # regex; extract substrings
from distutils.version import LooseVersion, StrictVersion # versioning; compare versions // TODO: it's going to be removed in Python 3.12 → find alternative
import webbrowser # open browser and download file
import sys # sys.exit()
from sys import platform # check platform (Windows/macOS)
if platform == 'win32': # Windows
from colorama import init # colored input/output in terminal
init()
# from win10toast_click import ToastNotifier # Windows 10 notifications
# toaster = ToastNotifier() # initialize win10toast
from plyer import notification # Windows notification
elif platform == 'darwin': # macOS
import pync # macOS notifications
import time # calculate script's run time
from inputimeout import inputimeout, TimeoutOccurred # input timeout: https://pypi.org/project/inputimeout/
from termcolor import colored # colored input/output in terminal
# --------- fix opening page --------- #
import ssl # certificate issue fix: https://stackoverflow.com/questions/52805115/certificate-verify-failed-unable-to-get-local-issuer-certificate
import certifi # certificate issue fix: https://stackoverflow.com/questions/52805115/certificate-verify-failed-unable-to-get-local-issuer-certificate
from urllib.request import urlopen, Request # open URLs; Request to fix blocked user-agent: https://stackoverflow.com/questions/16627227/
# --------- start + run time --------- #
start_time = time.time() # run time start
print("Starting...")
# ------------- open URL ------------- #
page_url = 'https://www.amazon.com/gp/help/customer/display.html?nodeId=G54HPVAW86CHYHKS' # "Kindle E-Reader Software Updates" page
# try to open the URL, if fails then close the program
try:
print('Opening URL...')
# *NOTE: fix for 503 error
request = Request(page_url, headers={'User-Agent': 'XYZ/3.0'}) # using different agent to not get blocked
page = urlopen(request, timeout=5, context=ssl.create_default_context(cafile=certifi.where()))
except:
sys.exit("No internet connection. Program exiting...")
# --------- get software version --------- #
# if stored locally
software_version_local_file = "data/software_version.txt" # local file to store software version
print('Reading local file to get software version...')
try:
with open(software_version_local_file) as software_version_local_file: # open local file...
read_software_version_local_file = software_version_local_file.read() # ... and read it
except FileNotFoundError:
print("File not found. Looks like it's a first launch of this script. Using default version '5.0'.")
read_software_version_local_file = '5.0'
with open(software_version_local_file, "w", encoding="utf-8") as saveVersion:
print('Saving file...')
saveVersion.write(read_software_version_local_file) # save file locally
# get software version from user
timeout_time = 5 # seconds to wait
print(f'Script will wait {timeout_time} seconds for the input and then will continue with a default value.')
try:
question_diff_version = inputimeout(prompt="Version different than " + read_software_version_local_file + "?\ny/n: ", timeout=timeout_time) # check if user has different version
try:
if question_diff_version == "y":
my_version = inputimeout(prompt="Type your version: ", timeout=timeout_time)
with open("data/software_version.txt", "w") as file: # open file...
file.write(str(my_version)) # ... and write software version
else:
my_version = read_software_version_local_file # if "n" then what's in the file = existing software version
except TimeoutOccurred:
my_version = read_software_version_local_file
print(f"Time ran out. Selecting default value from file: {my_version}")
except TimeoutOccurred:
print(f"Time ran out. Selecting current version, {read_software_version_local_file}.")
my_version = read_software_version_local_file
except:
print(f"Some issue occurred when launched via SwiftBar. Selecting current version, {read_software_version_local_file}.")
my_version = read_software_version_local_file
# ---------- scrape website ---------- #
soup = BeautifulSoup(page, 'html.parser') # parse the page
# *NOTE: change if you want a different model
getLatestVersion = soup.select("#GUID-E5C7ABBF-B934-4B95-9B7A-872D0A77CD4B__GUID-F171BE14-35DC-40A8-B8FC-959677B72B68") # find Paperwhite on the list
getLatestVersion = str(getLatestVersion) # convert to string
getLatestVersion = re.search("(?<=>)(.*)(?=<)", getLatestVersion) # extract software version from <span> tag
getLatestVersion = getLatestVersion.group() # returns the part of the string where there was a match
getLatestVersion = getLatestVersion.strip() # remove space " " from the beginning of the string
# ---------- open update URL --------- #
# *NOTE: change if you want a different model
# for macOS
update_file_url = 'https://www.amazon.com/update_Kindle_Paperwhite_10th_Gen'
# for Windows
def open_url():
try:
webbrowser.open_new(update_file_url)
print('Opening URL...') # status
except:
print('Failed to open URL. Unsupported variable type.')
# --------- compare versions --------- #
latest_version = getLatestVersion
if LooseVersion(my_version) > LooseVersion(latest_version): # NOTE: no updates
print (colored("Newer version is installed. No updates available.", 'green')) # green output
if platform == "win32":
notification.notify(
title='Kindle Updater',
message=f"Your version is up to date.",
app_icon='icons/no_updates.ico')
elif platform == 'darwin':
pync.notify(f'Your version is up to date.', title='Kindle Updater', contentImage="https://i.ibb.co/tzkJDxY/no-updates.png", sound="") # appIcon="" doesn't work, using contentImage instead)
elif LooseVersion(my_version) == LooseVersion(latest_version): # NOTE: equal, no updates
print (colored("The newest version is installed. No updates available.", 'green')) # green output
if platform == "win32":
notification.notify(
title='Kindle Updater',
message=f"Your version is up to date.",
app_icon='icons/no_updates.ico')
elif platform == 'darwin':
pync.notify(f'Your version is up to date.', title='Kindle Updater', contentImage="https://i.ibb.co/tzkJDxY/no-updates.png", sound="") # appIcon="" doesn't work, using contentImage instead)
else: # NOTE: update available
print (colored("Update available: " + latest_version, 'red')) # red output
if platform == "win32":
notification.notify(
title='Kindle Updater',
message=f'Update available: {latest_version}',
app_icon='icons/updates.ico')
elif platform == 'darwin':
pync.notify(f'Update available: {latest_version}', title='Kindle Updater', contentImage="https://i.ibb.co/QYqJJqX/updates.png", sound="", open=update_file_url) # appIcon="" doesn't work, using contentImage instead) # NOTE: can't execute a function on notification click :/
# ---------- download update --------- #
timeout_time = 30
try:
question_download_update = inputimeout(prompt="Download now?\ny/n: ", timeout=timeout_time)
if question_download_update == "y":
print (colored("Downloading update: " + latest_version, 'yellow')) # yellow output
if platform == "win32":
notification.notify(
title='Kindle Updater',
message=f'Downloading update: {latest_version}',
app_icon='icons/downloading.ico')
elif platform == 'darwin':
pync.notify(f'Downloading update: {latest_version}', title='Kindle Updater', contentImage="https://i.ibb.co/VHjZfsB/downloading.png", sound="") # appIcon="" doesn't work, using contentImage instead)
webbrowser.open(update_file_url) # open `.bin` URL in browser and download the update
# ---- save new version to a file ---- #
write_new_version_to_local_file = open("data/software_version.txt", "w") # open file...
write_new_version_to_local_file.write(latest_version) # ... and write latest version there so file is up-to-date for checks in future
else:
print('Ok, not downloading.')
except TimeoutOccurred:
print("Time ran out. Not downloading.")
# input ("Press Enter to close the script >>>") # wait for input = window won't close
# ------------- run time ------------- #
end_time = time.time() # run time end
run_time = round(end_time-start_time,2)
print("Script run time:", run_time, "seconds. That's", round(run_time/60,2), "minutes.")