cs2tracker 2.1.12__py3-none-any.whl → 2.1.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cs2tracker might be problematic. Click here for more details.
- cs2tracker/_version.py +2 -2
- cs2tracker/app/application.py +84 -88
- cs2tracker/app/editor_frame.py +451 -143
- cs2tracker/app/scraper_frame.py +43 -9
- cs2tracker/constants.py +66 -451
- cs2tracker/data/config.ini +153 -153
- cs2tracker/data/convert_inventory.js +187 -0
- cs2tracker/data/get_inventory.js +191 -0
- cs2tracker/main.py +2 -2
- cs2tracker/scraper/background_task.py +4 -4
- cs2tracker/scraper/discord_notifier.py +4 -4
- cs2tracker/scraper/parsers.py +192 -0
- cs2tracker/scraper/scraper.py +146 -224
- cs2tracker/util/__init__.py +2 -2
- cs2tracker/util/padded_console.py +32 -0
- cs2tracker/util/validated_config.py +117 -16
- cs2tracker-2.1.14.dist-info/METADATA +148 -0
- cs2tracker-2.1.14.dist-info/RECORD +28 -0
- cs2tracker-2.1.14.dist-info/licenses/LICENSE +402 -0
- cs2tracker-2.1.12.dist-info/METADATA +0 -82
- cs2tracker-2.1.12.dist-info/RECORD +0 -25
- cs2tracker-2.1.12.dist-info/licenses/LICENSE.md +0 -21
- {cs2tracker-2.1.12.dist-info → cs2tracker-2.1.14.dist-info}/WHEEL +0 -0
- {cs2tracker-2.1.12.dist-info → cs2tracker-2.1.14.dist-info}/entry_points.txt +0 -0
- {cs2tracker-2.1.12.dist-info → cs2tracker-2.1.14.dist-info}/top_level.txt +0 -0
cs2tracker/_version.py
CHANGED
cs2tracker/app/application.py
CHANGED
|
@@ -15,6 +15,7 @@ from cs2tracker.app.scraper_frame import ScraperFrame
|
|
|
15
15
|
from cs2tracker.constants import ICON_FILE, OS, OUTPUT_FILE, OSType
|
|
16
16
|
from cs2tracker.scraper import BackgroundTask, Scraper
|
|
17
17
|
from cs2tracker.util import PriceLogs
|
|
18
|
+
from cs2tracker.util.validated_config import get_config
|
|
18
19
|
|
|
19
20
|
APPLICATION_NAME = "CS2Tracker"
|
|
20
21
|
WINDOW_SIZE = "630x335"
|
|
@@ -24,52 +25,89 @@ SCRAPER_WINDOW_TITLE = "CS2Tracker Scraper"
|
|
|
24
25
|
SCRAPER_WINDOW_SIZE = "900x750"
|
|
25
26
|
|
|
26
27
|
CONFIG_EDITOR_TITLE = "Config Editor"
|
|
27
|
-
CONFIG_EDITOR_SIZE = "
|
|
28
|
+
CONFIG_EDITOR_SIZE = "900x750"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
config = get_config()
|
|
28
32
|
|
|
29
33
|
|
|
30
34
|
class Application:
|
|
31
35
|
def __init__(self):
|
|
32
36
|
self.scraper = Scraper()
|
|
33
|
-
self.application_window = None
|
|
34
37
|
|
|
35
38
|
def run(self):
|
|
36
|
-
"""Run the main application window
|
|
37
|
-
|
|
38
|
-
"""
|
|
39
|
-
self.application_window = self._configure_window()
|
|
39
|
+
"""Run the main application window."""
|
|
40
|
+
window = self._configure_window()
|
|
40
41
|
|
|
41
42
|
if DARK_THEME:
|
|
42
43
|
sv_ttk.use_dark_theme()
|
|
43
44
|
else:
|
|
44
45
|
sv_ttk.use_light_theme()
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
window.mainloop()
|
|
48
|
+
|
|
49
|
+
def _configure_window(self):
|
|
50
|
+
"""Configure the main application window."""
|
|
51
|
+
window = tk.Tk()
|
|
52
|
+
window.title(APPLICATION_NAME)
|
|
53
|
+
window.geometry(WINDOW_SIZE)
|
|
54
|
+
|
|
55
|
+
if OS == OSType.WINDOWS:
|
|
56
|
+
app_id = "cs2tracker.unique.id"
|
|
57
|
+
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
|
|
58
|
+
|
|
59
|
+
icon = tk.PhotoImage(file=ICON_FILE)
|
|
60
|
+
window.wm_iconphoto(True, icon)
|
|
61
|
+
|
|
62
|
+
main_frame = MainFrame(window, self.scraper)
|
|
63
|
+
main_frame.pack(expand=True, fill="both")
|
|
64
|
+
|
|
65
|
+
return window
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MainFrame(ttk.Frame):
|
|
69
|
+
# pylint: disable=too-many-instance-attributes,attribute-defined-outside-init
|
|
70
|
+
def __init__(self, parent, scraper):
|
|
71
|
+
super().__init__(parent, padding=15)
|
|
72
|
+
self.parent = parent
|
|
73
|
+
self.scraper = scraper
|
|
74
|
+
self._add_widgets()
|
|
47
75
|
|
|
48
|
-
def
|
|
76
|
+
def _add_widgets(self):
|
|
77
|
+
"""Add widgets to the main frame."""
|
|
78
|
+
self.columnconfigure(0, weight=1)
|
|
79
|
+
self.columnconfigure(1, weight=1)
|
|
80
|
+
self.rowconfigure(0, weight=1)
|
|
81
|
+
|
|
82
|
+
self._configure_button_frame()
|
|
83
|
+
self.button_frame.grid(row=0, column=0, padx=10, pady=(7, 20), sticky="nsew")
|
|
84
|
+
self._configure_checkbox_frame()
|
|
85
|
+
self.checkbox_frame.grid(row=0, column=1, padx=10, pady=(0, 20), sticky="nsew")
|
|
86
|
+
|
|
87
|
+
def _add_button(self, text, command, row):
|
|
49
88
|
"""Create and style a button for the button frame."""
|
|
50
89
|
grid_pos = {"row": row, "column": 0, "sticky": "ew", "padx": 10, "pady": 10}
|
|
51
|
-
button = ttk.Button(
|
|
90
|
+
button = ttk.Button(self.button_frame, text=text, command=command)
|
|
52
91
|
button.grid(**grid_pos)
|
|
53
92
|
|
|
54
|
-
def _configure_button_frame(self
|
|
93
|
+
def _configure_button_frame(self):
|
|
55
94
|
"""Configure the button frame of the application main frame."""
|
|
56
|
-
button_frame = ttk.Frame(
|
|
57
|
-
button_frame.columnconfigure(0, weight=1)
|
|
58
|
-
button_frame.grid(row=0, column=0, padx=10, pady=(7, 20), sticky="nsew")
|
|
95
|
+
self.button_frame = ttk.Frame(self, style="Card.TFrame", padding=15)
|
|
96
|
+
self.button_frame.columnconfigure(0, weight=1)
|
|
59
97
|
|
|
60
|
-
self._add_button(
|
|
61
|
-
self._add_button(
|
|
62
|
-
self._add_button(
|
|
63
|
-
self._add_button(
|
|
64
|
-
self._add_button(
|
|
98
|
+
self._add_button("Run!", self.scrape_prices, 0)
|
|
99
|
+
self._add_button("Edit Config", self._edit_config, 1)
|
|
100
|
+
self._add_button("Show History", self._draw_plot, 2)
|
|
101
|
+
self._add_button("Export History", self._export_log_file, 3)
|
|
102
|
+
self._add_button("Import History", self._import_log_file, 4)
|
|
65
103
|
|
|
66
104
|
def _add_checkbox(
|
|
67
|
-
self,
|
|
68
|
-
): # pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
105
|
+
self, text, variable, command, row
|
|
106
|
+
): # pylint: disable=too-many-arguments,too-many-positional-arguments,attribute-defined-outside-init
|
|
69
107
|
"""Create and style a checkbox for the checkbox frame."""
|
|
70
108
|
grid_pos = {"row": row, "column": 0, "sticky": "w", "padx": (10, 0), "pady": 5}
|
|
71
109
|
checkbox = ttk.Checkbutton(
|
|
72
|
-
|
|
110
|
+
self.checkbox_frame,
|
|
73
111
|
text=text,
|
|
74
112
|
variable=variable,
|
|
75
113
|
command=command,
|
|
@@ -77,92 +115,50 @@ class Application:
|
|
|
77
115
|
)
|
|
78
116
|
checkbox.grid(**grid_pos)
|
|
79
117
|
|
|
80
|
-
def _configure_checkbox_frame(self
|
|
118
|
+
def _configure_checkbox_frame(self):
|
|
81
119
|
"""Configure the checkbox frame for background tasks and settings."""
|
|
82
|
-
checkbox_frame = ttk.LabelFrame(
|
|
83
|
-
checkbox_frame.grid(row=0, column=1, padx=10, pady=(0, 20), sticky="nsew")
|
|
120
|
+
self.checkbox_frame = ttk.LabelFrame(self, text="Settings", padding=15)
|
|
84
121
|
|
|
85
|
-
background_checkbox_value = tk.BooleanVar(value=BackgroundTask.identify())
|
|
122
|
+
self.background_checkbox_value = tk.BooleanVar(value=BackgroundTask.identify())
|
|
86
123
|
self._add_checkbox(
|
|
87
|
-
checkbox_frame,
|
|
88
124
|
"Background Task",
|
|
89
|
-
background_checkbox_value,
|
|
90
|
-
lambda: self._toggle_background_task(background_checkbox_value.get()),
|
|
125
|
+
self.background_checkbox_value,
|
|
126
|
+
lambda: self._toggle_background_task(self.background_checkbox_value.get()),
|
|
91
127
|
0,
|
|
92
128
|
)
|
|
93
129
|
|
|
94
|
-
discord_webhook_checkbox_value = tk.BooleanVar(
|
|
95
|
-
value=
|
|
96
|
-
"App Settings", "discord_notifications", fallback=False
|
|
97
|
-
)
|
|
130
|
+
self.discord_webhook_checkbox_value = tk.BooleanVar(
|
|
131
|
+
value=config.getboolean("App Settings", "discord_notifications", fallback=False)
|
|
98
132
|
)
|
|
99
133
|
self._add_checkbox(
|
|
100
|
-
checkbox_frame,
|
|
101
134
|
"Discord Notifications",
|
|
102
|
-
discord_webhook_checkbox_value,
|
|
103
|
-
lambda: discord_webhook_checkbox_value.set(
|
|
104
|
-
self._toggle_discord_webhook(discord_webhook_checkbox_value.get())
|
|
135
|
+
self.discord_webhook_checkbox_value,
|
|
136
|
+
lambda: self.discord_webhook_checkbox_value.set(
|
|
137
|
+
self._toggle_discord_webhook(self.discord_webhook_checkbox_value.get())
|
|
105
138
|
),
|
|
106
139
|
1,
|
|
107
140
|
)
|
|
108
141
|
|
|
109
|
-
use_proxy_checkbox_value = tk.BooleanVar(
|
|
110
|
-
value=
|
|
142
|
+
self.use_proxy_checkbox_value = tk.BooleanVar(
|
|
143
|
+
value=config.getboolean("App Settings", "use_proxy", fallback=False)
|
|
111
144
|
)
|
|
112
145
|
self._add_checkbox(
|
|
113
|
-
checkbox_frame,
|
|
114
146
|
"Proxy Requests",
|
|
115
|
-
use_proxy_checkbox_value,
|
|
116
|
-
lambda: use_proxy_checkbox_value.set(
|
|
117
|
-
self._toggle_use_proxy(use_proxy_checkbox_value.get())
|
|
147
|
+
self.use_proxy_checkbox_value,
|
|
148
|
+
lambda: self.use_proxy_checkbox_value.set(
|
|
149
|
+
self._toggle_use_proxy(self.use_proxy_checkbox_value.get())
|
|
118
150
|
),
|
|
119
151
|
2,
|
|
120
152
|
)
|
|
121
153
|
|
|
122
|
-
# pylint: disable=attribute-defined-outside-init
|
|
123
154
|
self.dark_theme_checkbox_value = tk.BooleanVar(value=DARK_THEME)
|
|
124
|
-
self._add_checkbox(
|
|
125
|
-
checkbox_frame, "Dark Theme", self.dark_theme_checkbox_value, sv_ttk.toggle_theme, 3
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
def _configure_main_frame(self, window):
|
|
129
|
-
"""Configure the main frame of the application window with buttons and
|
|
130
|
-
checkboxes.
|
|
131
|
-
"""
|
|
132
|
-
main_frame = ttk.Frame(window, padding=15)
|
|
133
|
-
main_frame.columnconfigure(0, weight=1)
|
|
134
|
-
main_frame.columnconfigure(1, weight=1)
|
|
135
|
-
main_frame.rowconfigure(0, weight=1)
|
|
136
|
-
|
|
137
|
-
self._configure_button_frame(main_frame)
|
|
138
|
-
self._configure_checkbox_frame(main_frame)
|
|
139
|
-
|
|
140
|
-
main_frame.pack(expand=True, fill="both")
|
|
141
|
-
|
|
142
|
-
def _configure_window(self):
|
|
143
|
-
"""Configure the main application window UI and add buttons for the main
|
|
144
|
-
functionalities.
|
|
145
|
-
"""
|
|
146
|
-
window = tk.Tk()
|
|
147
|
-
window.title(APPLICATION_NAME)
|
|
148
|
-
window.geometry(WINDOW_SIZE)
|
|
149
|
-
|
|
150
|
-
if OS == OSType.WINDOWS:
|
|
151
|
-
app_id = "cs2tracker.unique.id"
|
|
152
|
-
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
|
|
153
|
-
|
|
154
|
-
icon = tk.PhotoImage(file=ICON_FILE)
|
|
155
|
-
window.wm_iconphoto(True, icon)
|
|
156
|
-
|
|
157
|
-
self._configure_main_frame(window)
|
|
158
|
-
|
|
159
|
-
return window
|
|
155
|
+
self._add_checkbox("Dark Theme", self.dark_theme_checkbox_value, sv_ttk.toggle_theme, 3)
|
|
160
156
|
|
|
161
157
|
def scrape_prices(self):
|
|
162
158
|
"""Scrape prices from the configured sources, print the total, and save the
|
|
163
159
|
results to a file.
|
|
164
160
|
"""
|
|
165
|
-
scraper_window = tk.Toplevel(self.
|
|
161
|
+
scraper_window = tk.Toplevel(self.parent)
|
|
166
162
|
scraper_window.geometry(SCRAPER_WINDOW_SIZE)
|
|
167
163
|
scraper_window.title(SCRAPER_WINDOW_TITLE)
|
|
168
164
|
|
|
@@ -177,11 +173,11 @@ class Application:
|
|
|
177
173
|
|
|
178
174
|
def _edit_config(self):
|
|
179
175
|
"""Open a new window with a config editor GUI."""
|
|
180
|
-
config_editor_window = tk.Toplevel(self.
|
|
176
|
+
config_editor_window = tk.Toplevel(self.parent)
|
|
181
177
|
config_editor_window.geometry(CONFIG_EDITOR_SIZE)
|
|
182
178
|
config_editor_window.title(CONFIG_EDITOR_TITLE)
|
|
183
179
|
|
|
184
|
-
editor_frame = ConfigEditorFrame(config_editor_window
|
|
180
|
+
editor_frame = ConfigEditorFrame(config_editor_window)
|
|
185
181
|
editor_frame.pack(expand=True, fill="both")
|
|
186
182
|
|
|
187
183
|
def _draw_plot(self):
|
|
@@ -228,28 +224,28 @@ class Application:
|
|
|
228
224
|
|
|
229
225
|
def _toggle_use_proxy(self, enabled: bool):
|
|
230
226
|
"""Toggle whether the scraper should use proxy servers for requests."""
|
|
231
|
-
proxy_api_key =
|
|
227
|
+
proxy_api_key = config.get("User Settings", "proxy_api_key", fallback=None)
|
|
232
228
|
if not proxy_api_key and enabled:
|
|
233
229
|
messagebox.showerror(
|
|
234
230
|
"Config Error",
|
|
235
231
|
"You need to enter a valid crawlbase API key into the configuration to use this feature.",
|
|
232
|
+
parent=self.parent,
|
|
236
233
|
)
|
|
237
234
|
return False
|
|
238
235
|
|
|
239
|
-
|
|
236
|
+
config.toggle_use_proxy(enabled)
|
|
240
237
|
return True
|
|
241
238
|
|
|
242
239
|
def _toggle_discord_webhook(self, enabled: bool):
|
|
243
240
|
"""Toggle whether the scraper should send notifications to a Discord webhook."""
|
|
244
|
-
discord_webhook_url =
|
|
245
|
-
"User Settings", "discord_webhook_url", fallback=None
|
|
246
|
-
)
|
|
241
|
+
discord_webhook_url = config.get("User Settings", "discord_webhook_url", fallback=None)
|
|
247
242
|
if not discord_webhook_url and enabled:
|
|
248
243
|
messagebox.showerror(
|
|
249
244
|
"Config Error",
|
|
250
245
|
"You need to enter a valid Discord webhook URL into the configuration to use this feature.",
|
|
246
|
+
parent=self.parent,
|
|
251
247
|
)
|
|
252
248
|
return False
|
|
253
249
|
|
|
254
|
-
|
|
250
|
+
config.toggle_discord_webhook(enabled)
|
|
255
251
|
return True
|