cs2tracker 2.1.13__tar.gz → 2.1.15__tar.gz

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.

Files changed (57) hide show
  1. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/.isort.cfg +1 -1
  2. cs2tracker-2.1.15/.pre-commit-config.yaml +30 -0
  3. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/PKG-INFO +6 -6
  4. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/README.md +4 -5
  5. cs2tracker-2.1.15/assets/demo.gif +0 -0
  6. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/_version.py +2 -2
  7. cs2tracker-2.1.15/cs2tracker/app/app.py +283 -0
  8. cs2tracker-2.1.15/cs2tracker/app/editor_frame.py +670 -0
  9. cs2tracker-2.1.15/cs2tracker/app/history_frame.py +61 -0
  10. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/app/scraper_frame.py +34 -11
  11. cs2tracker-2.1.15/cs2tracker/config.py +263 -0
  12. cs2tracker-2.1.15/cs2tracker/constants.py +136 -0
  13. cs2tracker-2.1.15/cs2tracker/data/config.ini +207 -0
  14. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/data/convert_inventory.js +108 -28
  15. cs2tracker-2.1.15/cs2tracker/data/get_inventory.js +212 -0
  16. cs2tracker-2.1.15/cs2tracker/data/output.csv +0 -0
  17. cs2tracker-2.1.15/cs2tracker/logs.py +143 -0
  18. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/main.py +4 -19
  19. cs2tracker-2.1.15/cs2tracker/scraper/__init__.py +0 -0
  20. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/scraper/background_task.py +1 -1
  21. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/scraper/discord_notifier.py +34 -32
  22. cs2tracker-2.1.15/cs2tracker/scraper/parser.py +189 -0
  23. cs2tracker-2.1.15/cs2tracker/scraper/scraper.py +300 -0
  24. cs2tracker-2.1.15/cs2tracker/util/__init__.py +0 -0
  25. cs2tracker-2.1.15/cs2tracker/util/currency_conversion.py +84 -0
  26. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/util/padded_console.py +24 -0
  27. cs2tracker-2.1.15/cs2tracker/util/tkinter.py +55 -0
  28. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker.egg-info/PKG-INFO +6 -6
  29. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker.egg-info/SOURCES.txt +8 -3
  30. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker.egg-info/requires.txt +1 -0
  31. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/requirements.txt +1 -0
  32. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/setup.cfg +1 -0
  33. cs2tracker-2.1.13/.pre-commit-config.yaml +0 -30
  34. cs2tracker-2.1.13/cs2tracker/app/__init__.py +0 -3
  35. cs2tracker-2.1.13/cs2tracker/app/application.py +0 -255
  36. cs2tracker-2.1.13/cs2tracker/app/editor_frame.py +0 -474
  37. cs2tracker-2.1.13/cs2tracker/constants.py +0 -399
  38. cs2tracker-2.1.13/cs2tracker/data/config.ini +0 -204
  39. cs2tracker-2.1.13/cs2tracker/data/get_inventory.js +0 -148
  40. cs2tracker-2.1.13/cs2tracker/scraper/__init__.py +0 -9
  41. cs2tracker-2.1.13/cs2tracker/scraper/scraper.py +0 -380
  42. cs2tracker-2.1.13/cs2tracker/util/__init__.py +0 -9
  43. cs2tracker-2.1.13/cs2tracker/util/price_logs.py +0 -100
  44. cs2tracker-2.1.13/cs2tracker/util/validated_config.py +0 -164
  45. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/.flake8 +0 -0
  46. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/.gitignore +0 -0
  47. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/.pylintrc +0 -0
  48. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/LICENSE +0 -0
  49. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/MANIFEST.in +0 -0
  50. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/assets/icon.png +0 -0
  51. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/__init__.py +0 -0
  52. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker/__main__.py +0 -0
  53. /cs2tracker-2.1.13/cs2tracker/data/output.csv → /cs2tracker-2.1.15/cs2tracker/app/__init__.py +0 -0
  54. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker.egg-info/dependency_links.txt +0 -0
  55. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker.egg-info/entry_points.txt +0 -0
  56. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/cs2tracker.egg-info/top_level.txt +0 -0
  57. {cs2tracker-2.1.13 → cs2tracker-2.1.15}/pyproject.toml +0 -0
@@ -1,2 +1,2 @@
1
1
  [settings]
2
- known_third_party = bs4,currency_converter,matplotlib,nodejs,requests,rich,sv_ttk,tenacity,tksheet,ttk_text,urllib3
2
+ known_third_party = bs4,currency_converter,matplotlib,nodejs,requests,requests_cache,rich,sv_ttk,tenacity,tksheet,ttk_text,urllib3
@@ -0,0 +1,30 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: check-yaml
6
+ - id: end-of-file-fixer
7
+ - id: trailing-whitespace
8
+ - repo: https://github.com/asottile/seed-isort-config
9
+ rev: v2.2.0
10
+ hooks:
11
+ - id: seed-isort-config
12
+ - repo: https://github.com/ambv/black
13
+ rev: 25.1.0
14
+ hooks:
15
+ - id: black
16
+ - repo: https://github.com/PyCQA/flake8
17
+ rev: 7.3.0
18
+ hooks:
19
+ - id: flake8
20
+ - repo: https://github.com/timothycrosley/isort
21
+ rev: 6.0.1
22
+ hooks:
23
+ - id: isort
24
+ args: ["--profile=black"]
25
+ - repo: https://github.com/PyCQA/docformatter
26
+ rev: v1.7.6
27
+ hooks:
28
+ - id: docformatter
29
+ additional_dependencies: [tomli]
30
+ args: [--in-place]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cs2tracker
3
- Version: 2.1.13
3
+ Version: 2.1.15
4
4
  Summary: Tracking the steam market prices of CS2 items
5
5
  Home-page: https://github.com/ashiven/cs2tracker
6
6
  Author: Jannik Novak
@@ -23,6 +23,7 @@ Requires-Dist: sv_ttk==2.6.1
23
23
  Requires-Dist: tksheet==7.5.12
24
24
  Requires-Dist: nodejs-bin==18.4.0a4
25
25
  Requires-Dist: ttk-text==0.2.0
26
+ Requires-Dist: requests-cache==1.2.1
26
27
  Dynamic: license-file
27
28
 
28
29
  <p align="center">
@@ -40,9 +41,8 @@ Dynamic: license-file
40
41
  [![PyPI version](https://badge.fury.io/py/cs2tracker.svg)](https://badge.fury.io/py/cs2tracker)
41
42
  [![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/ashiven/cs2tracker)](https://github.com/ashiven/cs2tracker/issues)
42
43
  [![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr/ashiven/cs2tracker)](https://github.com/ashiven/cs2tracker/pulls)
43
- ![GitHub Repo stars](https://img.shields.io/github/stars/ashiven/cs2tracker)
44
44
 
45
- <img src="https://github.com/user-attachments/assets/9585afb2-bf1a-473c-be5d-cccbb3349b9a"/>
45
+ <img src="./assets/demo.gif"/>
46
46
  </div>
47
47
 
48
48
  ## Table of Contents
@@ -60,9 +60,9 @@ Dynamic: license-file
60
60
  ## Features
61
61
 
62
62
  - ⚡ Rapidly import your Storage Units
63
- - 🔍 Track CS2 Steam Market prices
63
+ - 🔍 Track prices on Steam, Buff163, Youpin898
64
64
  - 📈 View investment price history
65
- - 🧾 Export/Import price data
65
+ - 🧾 Export/Import history data
66
66
  - 📤 Discord notifications on updates
67
67
  - 📅 Daily background calculations
68
68
  - 🛡️ Proxy support to avoid rate limits
@@ -106,7 +106,7 @@ Dynamic: license-file
106
106
  ## Configuration
107
107
 
108
108
  You can configure the app settings via the **Edit Config** option.
109
- This will open the config editor where you can change any setting by simply double clicking on it. On top of that, the config editor allows you to:
109
+ This will open the config editor where you can change any setting by double clicking on it or navigating to it with the arrow keys and hitting enter. On top of that, the config editor allows you to:
110
110
 
111
111
  - Automatically import items from your Storage Units
112
112
  - Manually Specify the number of items you own
@@ -13,9 +13,8 @@
13
13
  [![PyPI version](https://badge.fury.io/py/cs2tracker.svg)](https://badge.fury.io/py/cs2tracker)
14
14
  [![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/ashiven/cs2tracker)](https://github.com/ashiven/cs2tracker/issues)
15
15
  [![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr/ashiven/cs2tracker)](https://github.com/ashiven/cs2tracker/pulls)
16
- ![GitHub Repo stars](https://img.shields.io/github/stars/ashiven/cs2tracker)
17
16
 
18
- <img src="https://github.com/user-attachments/assets/9585afb2-bf1a-473c-be5d-cccbb3349b9a"/>
17
+ <img src="./assets/demo.gif"/>
19
18
  </div>
20
19
 
21
20
  ## Table of Contents
@@ -33,9 +32,9 @@
33
32
  ## Features
34
33
 
35
34
  - ⚡ Rapidly import your Storage Units
36
- - 🔍 Track CS2 Steam Market prices
35
+ - 🔍 Track prices on Steam, Buff163, Youpin898
37
36
  - 📈 View investment price history
38
- - 🧾 Export/Import price data
37
+ - 🧾 Export/Import history data
39
38
  - 📤 Discord notifications on updates
40
39
  - 📅 Daily background calculations
41
40
  - 🛡️ Proxy support to avoid rate limits
@@ -79,7 +78,7 @@
79
78
  ## Configuration
80
79
 
81
80
  You can configure the app settings via the **Edit Config** option.
82
- This will open the config editor where you can change any setting by simply double clicking on it. On top of that, the config editor allows you to:
81
+ This will open the config editor where you can change any setting by double clicking on it or navigating to it with the arrow keys and hitting enter. On top of that, the config editor allows you to:
83
82
 
84
83
  - Automatically import items from your Storage Units
85
84
  - Manually Specify the number of items you own
Binary file
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '2.1.13'
21
- __version_tuple__ = version_tuple = (2, 1, 13)
20
+ __version__ = version = '2.1.15'
21
+ __version_tuple__ = version_tuple = (2, 1, 15)
@@ -0,0 +1,283 @@
1
+ import ctypes
2
+ import tkinter as tk
3
+ from shutil import copy
4
+ from tkinter import messagebox, ttk
5
+ from tkinter.filedialog import askopenfilename, asksaveasfile
6
+
7
+ import sv_ttk
8
+
9
+ from cs2tracker.app.editor_frame import ConfigEditorFrame
10
+ from cs2tracker.app.history_frame import PriceHistoryFrame
11
+ from cs2tracker.app.scraper_frame import ScraperFrame
12
+ from cs2tracker.config import get_config
13
+ from cs2tracker.constants import ICON_FILE, OS, OUTPUT_FILE, OSType
14
+ from cs2tracker.logs import PriceLogs
15
+ from cs2tracker.scraper.background_task import BackgroundTask
16
+ from cs2tracker.scraper.scraper import Scraper
17
+ from cs2tracker.util.currency_conversion import CURRENCY_SYMBOLS
18
+ from cs2tracker.util.tkinter import centered, fix_sv_ttk, size_info
19
+
20
+ APPLICATION_NAME = "CS2Tracker"
21
+ WINDOW_SIZE = "630x335"
22
+ DARK_THEME = True
23
+
24
+ SCRAPER_WINDOW_TITLE = "Price Overview"
25
+ SCRAPER_WINDOW_SIZE = "900x750"
26
+
27
+ CONFIG_EDITOR_TITLE = "Config Editor"
28
+ CONFIG_EDITOR_SIZE = "850x750"
29
+
30
+ PRICE_HISTORY_TITLE = "Price History"
31
+ PRICE_HISTORY_SIZE = "900x700"
32
+
33
+ config = get_config()
34
+
35
+
36
+ class Application:
37
+ def __init__(self):
38
+ self.scraper = Scraper()
39
+
40
+ def run(self):
41
+ """Run the main application window."""
42
+ window = self._configure_window()
43
+
44
+ if DARK_THEME:
45
+ sv_ttk.use_dark_theme()
46
+ else:
47
+ sv_ttk.use_light_theme()
48
+
49
+ fix_sv_ttk(ttk.Style())
50
+
51
+ window.mainloop()
52
+
53
+ def _configure_window(self):
54
+ """Configure the main application window."""
55
+ window = tk.Tk()
56
+ window.title(APPLICATION_NAME)
57
+ window.geometry(centered(window, WINDOW_SIZE))
58
+ window.minsize(*size_info(WINDOW_SIZE))
59
+
60
+ if OS == OSType.WINDOWS:
61
+ app_id = "cs2tracker.unique.id"
62
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
63
+
64
+ icon = tk.PhotoImage(file=ICON_FILE)
65
+ window.wm_iconphoto(True, icon)
66
+
67
+ main_frame = MainFrame(window, self.scraper)
68
+ main_frame.pack(expand=True, fill="both")
69
+
70
+ return window
71
+
72
+
73
+ class MainFrame(ttk.Frame):
74
+ # pylint: disable=too-many-instance-attributes,attribute-defined-outside-init
75
+ def __init__(self, parent, scraper):
76
+ super().__init__(parent, padding=15)
77
+ self.parent = parent
78
+ self.scraper = scraper
79
+ self._add_widgets()
80
+
81
+ def _add_widgets(self):
82
+ """Add widgets to the main frame."""
83
+ self.columnconfigure(0, weight=1)
84
+ self.columnconfigure(1, weight=1)
85
+ self.rowconfigure(0, weight=1)
86
+
87
+ self._configure_button_frame()
88
+ self.button_frame.grid(row=0, column=0, padx=10, pady=(0, 20), sticky="nsew")
89
+ self._configure_settings_frame()
90
+ self.settings_frame.grid(row=0, column=1, padx=10, pady=(0, 20), sticky="nsew")
91
+
92
+ def _add_button(self, text, command, row):
93
+ """Create and style a button for the button frame."""
94
+ grid_pos = {"row": row, "column": 0, "sticky": "ew", "padx": 10, "pady": 10}
95
+ button = ttk.Button(self.button_frame, text=text, command=command)
96
+ button.grid(**grid_pos)
97
+
98
+ def _configure_button_frame(self):
99
+ """Configure the button frame of the application main frame."""
100
+ self.button_frame = ttk.Frame(self, style="Card.TFrame", padding=15)
101
+ self.button_frame.columnconfigure(0, weight=1)
102
+
103
+ self._add_button("Run!", self.scrape_prices, 0)
104
+ self._add_button("Edit Config", self._edit_config, 1)
105
+ self._add_button("Show History", self._show_history, 2)
106
+ self._add_button("Export History", self._export_log_file, 3)
107
+ self._add_button("Import History", self._import_log_file, 4)
108
+
109
+ def _add_checkbox(
110
+ self, text, variable, command, row
111
+ ): # pylint: disable=too-many-arguments,too-many-positional-arguments,attribute-defined-outside-init
112
+ """Create and style a checkbox for the checkbox frame."""
113
+ grid_pos = {"row": row, "column": 0, "sticky": "w", "padx": (10, 0), "pady": 5}
114
+ checkbox = ttk.Checkbutton(
115
+ self.settings_frame,
116
+ text=text,
117
+ variable=variable,
118
+ command=command,
119
+ style="Switch.TCheckbutton",
120
+ )
121
+ checkbox.grid(**grid_pos)
122
+
123
+ def _configure_settings_frame(self):
124
+ """Configure the settings frame for background tasks and other settings."""
125
+ self.settings_frame = ttk.LabelFrame(self, text="Settings", padding=15)
126
+ self.settings_frame.columnconfigure(0, weight=1)
127
+
128
+ self.background_checkbox_value = tk.BooleanVar(value=BackgroundTask.identify())
129
+ self._add_checkbox(
130
+ "Background Task",
131
+ self.background_checkbox_value,
132
+ lambda: self._toggle_background_task(self.background_checkbox_value.get()),
133
+ 0,
134
+ )
135
+
136
+ self.discord_webhook_checkbox_value = tk.BooleanVar(value=config.discord_notifications)
137
+ self._add_checkbox(
138
+ "Discord Notifications",
139
+ self.discord_webhook_checkbox_value,
140
+ lambda: self.discord_webhook_checkbox_value.set(
141
+ self._toggle_discord_webhook(self.discord_webhook_checkbox_value.get())
142
+ ),
143
+ 1,
144
+ )
145
+
146
+ self.use_proxy_checkbox_value = tk.BooleanVar(value=config.use_proxy)
147
+ self._add_checkbox(
148
+ "Proxy Requests",
149
+ self.use_proxy_checkbox_value,
150
+ lambda: self.use_proxy_checkbox_value.set(
151
+ self._toggle_use_proxy(self.use_proxy_checkbox_value.get())
152
+ ),
153
+ 2,
154
+ )
155
+
156
+ self.dark_theme_checkbox_value = tk.BooleanVar(value=DARK_THEME)
157
+ self._add_checkbox("Dark Theme", self.dark_theme_checkbox_value, self._toggle_theme, 3)
158
+
159
+ self.currency_selection_label = ttk.Label(self.settings_frame, text="Currency:")
160
+ self.currency_selection_label.grid(row=4, column=0, sticky="w", padx=(20, 0), pady=5)
161
+ self.currency_selection = ttk.Combobox(
162
+ self.settings_frame,
163
+ state="readonly",
164
+ values=list(CURRENCY_SYMBOLS),
165
+ postcommand=self.parent.focus_set,
166
+ )
167
+ self.currency_selection.set(config.conversion_currency)
168
+ self.currency_selection.grid(row=5, column=0, sticky="w", padx=(20, 0), pady=5)
169
+
170
+ def on_currency_change(_):
171
+ config.set_app_option("conversion_currency", self.currency_selection.get())
172
+ self.currency_selection.selection_clear()
173
+ self.parent.focus_set()
174
+
175
+ self.currency_selection.bind(
176
+ "<<ComboboxSelected>>",
177
+ on_currency_change,
178
+ )
179
+
180
+ def scrape_prices(self):
181
+ """Scrape prices from the configured sources, print the total, and save the
182
+ results to a file.
183
+ """
184
+ scraper_window = tk.Toplevel(self.parent)
185
+ scraper_window.geometry(centered(scraper_window, SCRAPER_WINDOW_SIZE))
186
+ scraper_window.minsize(*size_info(SCRAPER_WINDOW_SIZE))
187
+ scraper_window.title(SCRAPER_WINDOW_TITLE)
188
+
189
+ run_frame = ScraperFrame(
190
+ scraper_window,
191
+ self.scraper,
192
+ sheet_size=SCRAPER_WINDOW_SIZE,
193
+ dark_theme=self.dark_theme_checkbox_value.get(),
194
+ )
195
+ run_frame.pack(expand=True, fill="both")
196
+ run_frame.start()
197
+
198
+ def _edit_config(self):
199
+ """Open a new window with a config editor GUI."""
200
+ config_editor_window = tk.Toplevel(self.parent)
201
+ config_editor_window.geometry(centered(config_editor_window, CONFIG_EDITOR_SIZE))
202
+ config_editor_window.minsize(*size_info(CONFIG_EDITOR_SIZE))
203
+ config_editor_window.title(CONFIG_EDITOR_TITLE)
204
+
205
+ editor_frame = ConfigEditorFrame(config_editor_window)
206
+ editor_frame.pack(expand=True, fill="both")
207
+
208
+ def _show_history(self):
209
+ """Show a chart consisting of past calculations."""
210
+ if PriceLogs.empty():
211
+ return
212
+
213
+ price_history_window = tk.Toplevel(self.parent)
214
+ price_history_window.geometry(centered(price_history_window, PRICE_HISTORY_SIZE))
215
+ price_history_window.minsize(*size_info(PRICE_HISTORY_SIZE))
216
+ price_history_window.title(PRICE_HISTORY_TITLE)
217
+
218
+ history_frame = PriceHistoryFrame(price_history_window)
219
+ history_frame.pack(expand=True, fill="both")
220
+
221
+ def _export_log_file(self):
222
+ """Lets the user export the log file to a different location."""
223
+ if PriceLogs.empty():
224
+ return
225
+
226
+ export_path = asksaveasfile(
227
+ title="Export Log File",
228
+ defaultextension=".csv",
229
+ filetypes=[("CSV File", "*.csv")],
230
+ )
231
+ if export_path:
232
+ copy(OUTPUT_FILE, export_path.name)
233
+
234
+ def _import_log_file(self):
235
+ """Lets the user import a log file from a different location."""
236
+ import_path = askopenfilename(
237
+ title="Import Log File",
238
+ defaultextension=".csv",
239
+ filetypes=[("CSV files", "*.csv")],
240
+ )
241
+ if not PriceLogs.validate_file(import_path):
242
+ return
243
+ copy(import_path, OUTPUT_FILE)
244
+
245
+ def _toggle_background_task(self, enabled: bool):
246
+ """Toggle whether a daily price calculation should run in the background."""
247
+ BackgroundTask.toggle(enabled)
248
+
249
+ def _toggle_use_proxy(self, enabled: bool):
250
+ """Toggle whether the scraper should use proxy servers for requests."""
251
+ proxy_api_key = config.proxy_api_key
252
+ if not proxy_api_key and enabled:
253
+ messagebox.showerror(
254
+ "Config Error",
255
+ "You need to enter a valid crawlbase API key into the configuration to use this feature.",
256
+ parent=self.parent,
257
+ )
258
+ return False
259
+
260
+ config.toggle_app_option("use_proxy", enabled)
261
+ return True
262
+
263
+ def _toggle_discord_webhook(self, enabled: bool):
264
+ """Toggle whether the scraper should send notifications to a Discord webhook."""
265
+ discord_webhook_url = config.discord_webhook_url
266
+ if not discord_webhook_url and enabled:
267
+ messagebox.showerror(
268
+ "Config Error",
269
+ "You need to enter a valid Discord webhook URL into the configuration to use this feature.",
270
+ parent=self.parent,
271
+ )
272
+ return False
273
+
274
+ config.toggle_app_option("discord_webhook", enabled)
275
+ return True
276
+
277
+ def _toggle_theme(self):
278
+ """Toggle the theme of the application."""
279
+ if self.dark_theme_checkbox_value.get():
280
+ sv_ttk.use_dark_theme()
281
+ else:
282
+ sv_ttk.use_light_theme()
283
+ fix_sv_ttk(ttk.Style())