cs2tracker 2.1.9__py3-none-any.whl → 2.1.11__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/__init__.py +3 -0
- cs2tracker/app/application.py +255 -0
- cs2tracker/app/editor_frame.py +247 -0
- cs2tracker/app/scraper_frame.py +76 -0
- cs2tracker/constants.py +101 -115
- cs2tracker/data/config.ini +155 -156
- cs2tracker/main.py +2 -2
- cs2tracker/scraper/__init__.py +9 -0
- cs2tracker/scraper/background_task.py +109 -0
- cs2tracker/scraper/discord_notifier.py +86 -0
- cs2tracker/scraper/scraper.py +348 -0
- cs2tracker/util/__init__.py +9 -0
- cs2tracker/util/price_logs.py +100 -0
- cs2tracker/util/validated_config.py +117 -0
- {cs2tracker-2.1.9.dist-info → cs2tracker-2.1.11.dist-info}/METADATA +7 -4
- cs2tracker-2.1.11.dist-info/RECORD +25 -0
- cs2tracker/application.py +0 -270
- cs2tracker/scraper.py +0 -637
- cs2tracker-2.1.9.dist-info/RECORD +0 -16
- /cs2tracker/{padded_console.py → util/padded_console.py} +0 -0
- {cs2tracker-2.1.9.dist-info → cs2tracker-2.1.11.dist-info}/WHEEL +0 -0
- {cs2tracker-2.1.9.dist-info → cs2tracker-2.1.11.dist-info}/entry_points.txt +0 -0
- {cs2tracker-2.1.9.dist-info → cs2tracker-2.1.11.dist-info}/licenses/LICENSE.md +0 -0
- {cs2tracker-2.1.9.dist-info → cs2tracker-2.1.11.dist-info}/top_level.txt +0 -0
cs2tracker/data/config.ini
CHANGED
|
@@ -1,205 +1,204 @@
|
|
|
1
1
|
[User Settings]
|
|
2
|
-
|
|
3
|
-
discord_webhook_url
|
|
4
|
-
|
|
5
|
-
[App Settings]
|
|
6
|
-
use_proxy = False
|
|
7
|
-
discord_notifications = False
|
|
2
|
+
proxy_api_key ~
|
|
3
|
+
discord_webhook_url ~
|
|
8
4
|
|
|
9
5
|
[Custom Items]
|
|
10
|
-
copenhagen_flames_gold_2022 = 0 https://steamcommunity.com/market/listings/730/Sticker%20%7C%20Copenhagen%20Flames%20%28Gold%29%20%7C%20Antwerp%202022
|
|
11
6
|
|
|
12
7
|
[Cases]
|
|
13
|
-
revolution_case
|
|
14
|
-
recoil_case
|
|
15
|
-
dreams_and_nightmares_case
|
|
16
|
-
operation_riptide_case
|
|
17
|
-
snakebite_case
|
|
18
|
-
operation_broken_fang_case
|
|
19
|
-
fracture_case
|
|
20
|
-
chroma_case
|
|
21
|
-
chroma_2_case
|
|
22
|
-
chroma_3_case
|
|
23
|
-
clutch_case
|
|
24
|
-
csgo_weapon_case
|
|
25
|
-
csgo_weapon_case_2
|
|
26
|
-
csgo_weapon_case_3
|
|
27
|
-
cs20_case
|
|
28
|
-
danger_zone_case
|
|
29
|
-
esports_2013_case
|
|
30
|
-
esports_2013_winter_case
|
|
31
|
-
esports_2014_summer_case
|
|
32
|
-
falchion_case
|
|
33
|
-
gamma_case
|
|
34
|
-
gamma_2_case
|
|
35
|
-
glove_case
|
|
36
|
-
horizon_case
|
|
37
|
-
huntsman_case
|
|
38
|
-
operation_bravo_case
|
|
39
|
-
operation_breakout_case
|
|
40
|
-
operation_hydra_case
|
|
41
|
-
operation_phoenix_case
|
|
42
|
-
operation_vanguard_case
|
|
43
|
-
operation_wildfire_case
|
|
44
|
-
prisma_case
|
|
45
|
-
prisma_2_case
|
|
46
|
-
revolver_case
|
|
47
|
-
shadow_case
|
|
48
|
-
shattered_web_case
|
|
49
|
-
spectrum_case
|
|
50
|
-
spectrum_2_case
|
|
51
|
-
winter_offensive_case
|
|
52
|
-
kilowatt_case
|
|
53
|
-
gallery_case
|
|
54
|
-
fever_case
|
|
8
|
+
revolution_case ~ 0
|
|
9
|
+
recoil_case ~ 0
|
|
10
|
+
dreams_and_nightmares_case ~ 0
|
|
11
|
+
operation_riptide_case ~ 0
|
|
12
|
+
snakebite_case ~ 0
|
|
13
|
+
operation_broken_fang_case ~ 0
|
|
14
|
+
fracture_case ~ 0
|
|
15
|
+
chroma_case ~ 0
|
|
16
|
+
chroma_2_case ~ 0
|
|
17
|
+
chroma_3_case ~ 0
|
|
18
|
+
clutch_case ~ 0
|
|
19
|
+
csgo_weapon_case ~ 0
|
|
20
|
+
csgo_weapon_case_2 ~ 0
|
|
21
|
+
csgo_weapon_case_3 ~ 0
|
|
22
|
+
cs20_case ~ 0
|
|
23
|
+
danger_zone_case ~ 0
|
|
24
|
+
esports_2013_case ~ 0
|
|
25
|
+
esports_2013_winter_case ~ 0
|
|
26
|
+
esports_2014_summer_case ~ 0
|
|
27
|
+
falchion_case ~ 0
|
|
28
|
+
gamma_case ~ 0
|
|
29
|
+
gamma_2_case ~ 0
|
|
30
|
+
glove_case ~ 0
|
|
31
|
+
horizon_case ~ 0
|
|
32
|
+
huntsman_case ~ 0
|
|
33
|
+
operation_bravo_case ~ 0
|
|
34
|
+
operation_breakout_case ~ 0
|
|
35
|
+
operation_hydra_case ~ 0
|
|
36
|
+
operation_phoenix_case ~ 0
|
|
37
|
+
operation_vanguard_case ~ 0
|
|
38
|
+
operation_wildfire_case ~ 0
|
|
39
|
+
prisma_case ~ 0
|
|
40
|
+
prisma_2_case ~ 0
|
|
41
|
+
revolver_case ~ 0
|
|
42
|
+
shadow_case ~ 0
|
|
43
|
+
shattered_web_case ~ 0
|
|
44
|
+
spectrum_case ~ 0
|
|
45
|
+
spectrum_2_case ~ 0
|
|
46
|
+
winter_offensive_case ~ 0
|
|
47
|
+
kilowatt_case ~ 0
|
|
48
|
+
gallery_case ~ 0
|
|
49
|
+
fever_case ~ 0
|
|
55
50
|
|
|
56
51
|
[Katowice 2014 Sticker Capsule]
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
katowice_2014_legends ~ 0
|
|
53
|
+
katowice_2014_challengers ~ 0
|
|
59
54
|
|
|
60
55
|
[Cologne 2014 Sticker Capsule]
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
cologne_2014_legends ~ 0
|
|
57
|
+
cologne_2014_challengers ~ 0
|
|
63
58
|
|
|
64
59
|
[DreamHack 2014 Sticker Capsule]
|
|
65
|
-
|
|
60
|
+
dreamhack_2014_legends ~ 0
|
|
66
61
|
|
|
67
62
|
[Katowice 2015 Sticker Capsule]
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
katowice_2015_legends ~ 0
|
|
64
|
+
katowice_2015_challengers ~ 0
|
|
70
65
|
|
|
71
66
|
[Cologne 2015 Sticker Capsule]
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
cologne_2015_legends ~ 0
|
|
68
|
+
cologne_2015_challengers ~ 0
|
|
74
69
|
|
|
75
70
|
[Cluj-Napoca 2015 Sticker Capsule]
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
cluj_napoca_2015_legends ~ 0
|
|
72
|
+
cluj_napoca_2015_challengers ~ 0
|
|
73
|
+
cluj_napoca_2015_legends_autographs ~ 0
|
|
74
|
+
cluj_napoca_2015_challengers_autographs ~ 0
|
|
80
75
|
|
|
81
76
|
[Columbus 2016 Sticker Capsule]
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
columbus_2016_legends ~ 0
|
|
78
|
+
columbus_2016_challengers ~ 0
|
|
79
|
+
columbus_2016_legends_autographs ~ 0
|
|
80
|
+
columbus_2016_challengers_autographs ~ 0
|
|
86
81
|
|
|
87
82
|
[Cologne 2016 Sticker Capsule]
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
cologne_2016_legends ~ 0
|
|
84
|
+
cologne_2016_challengers ~ 0
|
|
85
|
+
cologne_2016_legends_autographs ~ 0
|
|
86
|
+
cologne_2016_challengers_autographs ~ 0
|
|
92
87
|
|
|
93
88
|
[Atlanta 2017 Sticker Capsule]
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
atlanta_2017_legends ~ 0
|
|
90
|
+
atlanta_2017_challengers ~ 0
|
|
91
|
+
atlanta_2017_legends_autographs ~ 0
|
|
92
|
+
atlanta_2017_challengers_autographs ~ 0
|
|
98
93
|
|
|
99
94
|
[Krakow 2017 Sticker Capsule]
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
krakow_2017_legends ~ 0
|
|
96
|
+
krakow_2017_challengers ~ 0
|
|
97
|
+
krakow_2017_legends_autographs ~ 0
|
|
98
|
+
krakow_2017_challengers_autographs ~ 0
|
|
104
99
|
|
|
105
100
|
[Boston 2018 Sticker Capsule]
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
boston_2018_legends ~ 0
|
|
102
|
+
boston_2018_minor_challengers ~ 0
|
|
103
|
+
boston_2018_returning_challengers ~ 0
|
|
104
|
+
boston_2018_attending_legends ~ 0
|
|
105
|
+
boston_2018_minor_challengers_with_flash_gaming ~ 0
|
|
106
|
+
boston_2018_legends_autographs ~ 0
|
|
107
|
+
boston_2018_minor_challengers_autographs ~ 0
|
|
108
|
+
boston_2018_returning_challengers_autographs ~ 0
|
|
109
|
+
boston_2018_attending_legends_autographs ~ 0
|
|
110
|
+
boston_2018_minor_challengers_with_flash_gaming_autographs ~ 0
|
|
116
111
|
|
|
117
112
|
[London 2018 Sticker Capsule]
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
113
|
+
london_2018_legends ~ 0
|
|
114
|
+
london_2018_minor_challengers ~ 0
|
|
115
|
+
london_2018_returning_challengers ~ 0
|
|
116
|
+
london_2018_legends_autographs ~ 0
|
|
117
|
+
london_2018_minor_challengers_autographs ~ 0
|
|
118
|
+
london_2018_returning_challengers_autographs ~ 0
|
|
124
119
|
|
|
125
120
|
[Katowice 2019 Sticker Capsule]
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
121
|
+
katowice_2019_legends ~ 0
|
|
122
|
+
katowice_2019_minor_challengers ~ 0
|
|
123
|
+
katowice_2019_returning_challengers ~ 0
|
|
124
|
+
katowice_2019_legends_autographs ~ 0
|
|
125
|
+
katowice_2019_minor_challengers_autographs ~ 0
|
|
126
|
+
katowice_2019_returning_challengers_autographs ~ 0
|
|
132
127
|
|
|
133
128
|
[Berlin 2019 Sticker Capsule]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
berlin_2019_legends ~ 0
|
|
130
|
+
berlin_2019_minor_challengers ~ 0
|
|
131
|
+
berlin_2019_returning_challengers ~ 0
|
|
132
|
+
berlin_2019_legends_autographs ~ 0
|
|
133
|
+
berlin_2019_minor_challengers_autographs ~ 0
|
|
134
|
+
berlin_2019_returning_challengers_autographs ~ 0
|
|
140
135
|
|
|
141
136
|
[2020 RMR Sticker Capsule]
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
rmr_2020_legends ~ 0
|
|
138
|
+
rmr_2020_challengers ~ 0
|
|
139
|
+
rmr_2020_contenders ~ 0
|
|
145
140
|
|
|
146
141
|
[Stockholm 2021 Sticker Capsule]
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
142
|
+
stockholm_2021_legends ~ 0
|
|
143
|
+
stockholm_2021_challengers ~ 0
|
|
144
|
+
stockholm_2021_contenders ~ 0
|
|
145
|
+
stockholm_2021_champions_autographs ~ 0
|
|
146
|
+
stockholm_2021_finalists_autographs ~ 0
|
|
152
147
|
|
|
153
148
|
[Antwerp 2022 Sticker Capsule]
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
149
|
+
antwerp_2022_legends ~ 0
|
|
150
|
+
antwerp_2022_challengers ~ 0
|
|
151
|
+
antwerp_2022_contenders ~ 0
|
|
152
|
+
antwerp_2022_champions_autographs ~ 0
|
|
153
|
+
antwerp_2022_challengers_autographs ~ 0
|
|
154
|
+
antwerp_2022_legends_autographs ~ 0
|
|
155
|
+
antwerp_2022_contenders_autographs ~ 0
|
|
161
156
|
|
|
162
157
|
[Rio 2022 Sticker Capsule]
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
158
|
+
rio_2022_legends ~ 0
|
|
159
|
+
rio_2022_challengers ~ 0
|
|
160
|
+
rio_2022_contenders ~ 0
|
|
161
|
+
rio_2022_champions_autographs ~ 0
|
|
162
|
+
rio_2022_challengers_autographs ~ 0
|
|
163
|
+
rio_2022_legends_autographs ~ 0
|
|
164
|
+
rio_2022_contenders_autographs ~ 0
|
|
170
165
|
|
|
171
166
|
[Paris 2023 Sticker Capsule]
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
167
|
+
paris_2023_legends ~ 0
|
|
168
|
+
paris_2023_challengers ~ 0
|
|
169
|
+
paris_2023_contenders ~ 0
|
|
170
|
+
paris_2023_champions_autographs ~ 0
|
|
171
|
+
paris_2023_challengers_autographs ~ 0
|
|
172
|
+
paris_2023_legends_autographs ~ 0
|
|
173
|
+
paris_2023_contenders_autographs ~ 0
|
|
179
174
|
|
|
180
175
|
[Copenhagen 2024 Sticker Capsule]
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
176
|
+
copenhagen_2024_legends ~ 0
|
|
177
|
+
copenhagen_2024_challengers ~ 0
|
|
178
|
+
copenhagen_2024_contenders ~ 0
|
|
179
|
+
copenhagen_2024_champions_autographs ~ 0
|
|
180
|
+
copenhagen_2024_challengers_autographs ~ 0
|
|
181
|
+
copenhagen_2024_legends_autographs ~ 0
|
|
182
|
+
copenhagen_2024_contenders_autographs ~ 0
|
|
188
183
|
|
|
189
184
|
[Shanghai 2024 Sticker Capsule]
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
185
|
+
shanghai_2024_legends ~ 0
|
|
186
|
+
shanghai_2024_challengers ~ 0
|
|
187
|
+
shanghai_2024_contenders ~ 0
|
|
188
|
+
shanghai_2024_champions_autographs ~ 0
|
|
189
|
+
shanghai_2024_challengers_autographs ~ 0
|
|
190
|
+
shanghai_2024_legends_autographs ~ 0
|
|
191
|
+
shanghai_2024_contenders_autographs ~ 0
|
|
197
192
|
|
|
198
193
|
[Austin 2025 Sticker Capsule]
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
194
|
+
austin_2025_legends ~ 0
|
|
195
|
+
austin_2025_challengers ~ 0
|
|
196
|
+
austin_2025_contenders ~ 0
|
|
197
|
+
austin_2025_champions_autographs ~ 0
|
|
198
|
+
austin_2025_challengers_autographs ~ 0
|
|
199
|
+
austin_2025_legends_autographs ~ 0
|
|
200
|
+
austin_2025_contenders_autographs ~ 0
|
|
201
|
+
|
|
202
|
+
[App Settings]
|
|
203
|
+
use_proxy ~ False
|
|
204
|
+
discord_notifications ~ False
|
cs2tracker/main.py
CHANGED
|
@@ -2,10 +2,10 @@ import sys
|
|
|
2
2
|
|
|
3
3
|
import urllib3
|
|
4
4
|
|
|
5
|
-
from cs2tracker.
|
|
5
|
+
from cs2tracker.app import Application
|
|
6
6
|
from cs2tracker.constants import AUTHOR_STRING, BANNER, OS, OSType
|
|
7
|
-
from cs2tracker.padded_console import PaddedConsole
|
|
8
7
|
from cs2tracker.scraper import Scraper
|
|
8
|
+
from cs2tracker.util import PaddedConsole
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def main():
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from cs2tracker.scraper.background_task import ( # noqa: F401 # pylint:disable=unused-import
|
|
2
|
+
BackgroundTask,
|
|
3
|
+
)
|
|
4
|
+
from cs2tracker.scraper.discord_notifier import ( # noqa: F401 # pylint:disable=unused-import
|
|
5
|
+
DiscordNotifier,
|
|
6
|
+
)
|
|
7
|
+
from cs2tracker.scraper.scraper import ( # noqa: F401 # pylint:disable=unused-import
|
|
8
|
+
Scraper,
|
|
9
|
+
)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from subprocess import DEVNULL, call
|
|
3
|
+
|
|
4
|
+
from cs2tracker.constants import (
|
|
5
|
+
BATCH_FILE,
|
|
6
|
+
OS,
|
|
7
|
+
PROJECT_DIR,
|
|
8
|
+
PYTHON_EXECUTABLE,
|
|
9
|
+
RUNNING_IN_EXE,
|
|
10
|
+
OSType,
|
|
11
|
+
)
|
|
12
|
+
from cs2tracker.util import PaddedConsole
|
|
13
|
+
|
|
14
|
+
WIN_BACKGROUND_TASK_NAME = "CS2Tracker Daily Calculation"
|
|
15
|
+
WIN_BACKGROUND_TASK_SCHEDULE = "DAILY"
|
|
16
|
+
WIN_BACKGROUND_TASK_TIME = "12:00"
|
|
17
|
+
WIN_BACKGROUND_TASK_CMD = (
|
|
18
|
+
f"powershell -WindowStyle Hidden -Command \"Start-Process '{BATCH_FILE}' -WindowStyle Hidden\""
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
console = PaddedConsole()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BackgroundTask:
|
|
25
|
+
@classmethod
|
|
26
|
+
def identify(cls):
|
|
27
|
+
"""
|
|
28
|
+
Search the OS for a daily background task that runs the scraper.
|
|
29
|
+
|
|
30
|
+
:return: True if a background task is found, False otherwise.
|
|
31
|
+
"""
|
|
32
|
+
if OS == OSType.WINDOWS:
|
|
33
|
+
cmd = ["schtasks", "/query", "/tn", WIN_BACKGROUND_TASK_NAME]
|
|
34
|
+
return_code = call(cmd, stdout=DEVNULL, stderr=DEVNULL)
|
|
35
|
+
found = return_code == 0
|
|
36
|
+
return found
|
|
37
|
+
else:
|
|
38
|
+
# TODO: implement finder for cron jobs
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def _toggle_batch_file(cls, enabled: bool):
|
|
43
|
+
"""
|
|
44
|
+
Create or delete a batch file that runs the scraper.
|
|
45
|
+
|
|
46
|
+
:param enabled: If True, the batch file will be created; if False, the batch
|
|
47
|
+
file will be deleted.
|
|
48
|
+
"""
|
|
49
|
+
if enabled:
|
|
50
|
+
with open(BATCH_FILE, "w", encoding="utf-8") as batch_file:
|
|
51
|
+
if RUNNING_IN_EXE:
|
|
52
|
+
# The python executable is set to the executable itself
|
|
53
|
+
# for executables created with PyInstaller
|
|
54
|
+
batch_file.write(f"{PYTHON_EXECUTABLE} --only-scrape\n")
|
|
55
|
+
else:
|
|
56
|
+
batch_file.write(f"cd {PROJECT_DIR}\n")
|
|
57
|
+
batch_file.write(f"{PYTHON_EXECUTABLE} -m cs2tracker --only-scrape\n")
|
|
58
|
+
else:
|
|
59
|
+
if os.path.exists(BATCH_FILE):
|
|
60
|
+
os.remove(BATCH_FILE)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def _toggle_windows(cls, enabled: bool):
|
|
64
|
+
"""
|
|
65
|
+
Create or delete a daily background task that runs the scraper on Windows.
|
|
66
|
+
|
|
67
|
+
:param enabled: If True, the task will be created; if False, the task will be
|
|
68
|
+
deleted.
|
|
69
|
+
"""
|
|
70
|
+
cls._toggle_batch_file(enabled)
|
|
71
|
+
if enabled:
|
|
72
|
+
cmd = [
|
|
73
|
+
"schtasks",
|
|
74
|
+
"/create",
|
|
75
|
+
"/tn",
|
|
76
|
+
WIN_BACKGROUND_TASK_NAME,
|
|
77
|
+
"/tr",
|
|
78
|
+
WIN_BACKGROUND_TASK_CMD,
|
|
79
|
+
"/sc",
|
|
80
|
+
WIN_BACKGROUND_TASK_SCHEDULE,
|
|
81
|
+
"/st",
|
|
82
|
+
WIN_BACKGROUND_TASK_TIME,
|
|
83
|
+
]
|
|
84
|
+
return_code = call(cmd, stdout=DEVNULL, stderr=DEVNULL)
|
|
85
|
+
if return_code == 0:
|
|
86
|
+
console.print("[bold green][+] Background task enabled.")
|
|
87
|
+
else:
|
|
88
|
+
console.print("[bold red][!] Failed to enable background task.")
|
|
89
|
+
else:
|
|
90
|
+
cmd = ["schtasks", "/delete", "/tn", WIN_BACKGROUND_TASK_NAME, "/f"]
|
|
91
|
+
return_code = call(cmd, stdout=DEVNULL, stderr=DEVNULL)
|
|
92
|
+
if return_code == 0:
|
|
93
|
+
console.print("[bold green][-] Background task disabled.")
|
|
94
|
+
else:
|
|
95
|
+
console.print("[bold red][!] Failed to disable background task.")
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def toggle(cls, enabled: bool):
|
|
99
|
+
"""
|
|
100
|
+
Create or delete a daily background task that runs the scraper.
|
|
101
|
+
|
|
102
|
+
:param enabled: If True, the task will be created; if False, the task will be
|
|
103
|
+
deleted.
|
|
104
|
+
"""
|
|
105
|
+
if OS == OSType.WINDOWS:
|
|
106
|
+
cls._toggle_windows(enabled)
|
|
107
|
+
else:
|
|
108
|
+
# TODO: implement toggle for cron jobs
|
|
109
|
+
pass
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from requests.exceptions import RequestException
|
|
3
|
+
|
|
4
|
+
from cs2tracker.util import PaddedConsole, PriceLogs
|
|
5
|
+
|
|
6
|
+
DC_WEBHOOK_USERNAME = "CS2Tracker"
|
|
7
|
+
DC_WEBHOOK_AVATAR_URL = "https://img.icons8.com/?size=100&id=uWQJp2tLXUH6&format=png&color=000000"
|
|
8
|
+
DC_RECENT_HISTORY_LIMIT = 5
|
|
9
|
+
|
|
10
|
+
console = PaddedConsole()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DiscordNotifier:
|
|
14
|
+
@classmethod
|
|
15
|
+
def _construct_recent_calculations_embeds(cls):
|
|
16
|
+
"""
|
|
17
|
+
Construct the embeds for the Discord message that will be sent after a price
|
|
18
|
+
calculation has been made.
|
|
19
|
+
|
|
20
|
+
:return: A list of embeds for the Discord message.
|
|
21
|
+
"""
|
|
22
|
+
dates, usd_prices, eur_prices = PriceLogs.read()
|
|
23
|
+
dates, usd_prices, eur_prices = reversed(dates), reversed(usd_prices), reversed(eur_prices)
|
|
24
|
+
|
|
25
|
+
date_history, usd_history, eur_history = [], [], []
|
|
26
|
+
for date, usd_log, eur_log in zip(dates, usd_prices, eur_prices):
|
|
27
|
+
if len(date_history) >= DC_RECENT_HISTORY_LIMIT:
|
|
28
|
+
break
|
|
29
|
+
date_history.append(date.strftime("%Y-%m-%d"))
|
|
30
|
+
usd_history.append(f"${usd_log:.2f}")
|
|
31
|
+
eur_history.append(f"€{eur_log:.2f}")
|
|
32
|
+
|
|
33
|
+
date_history = "\n".join(date_history)
|
|
34
|
+
usd_history = "\n".join(usd_history)
|
|
35
|
+
eur_history = "\n".join(eur_history)
|
|
36
|
+
|
|
37
|
+
embeds = [
|
|
38
|
+
{
|
|
39
|
+
"title": "📊 Recent Price History",
|
|
40
|
+
"color": 5814783,
|
|
41
|
+
"fields": [
|
|
42
|
+
{
|
|
43
|
+
"name": "Date",
|
|
44
|
+
"value": date_history,
|
|
45
|
+
"inline": True,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "USD Total",
|
|
49
|
+
"value": usd_history,
|
|
50
|
+
"inline": True,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "EUR Total",
|
|
54
|
+
"value": eur_history,
|
|
55
|
+
"inline": True,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
return embeds
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def notify(cls, webhook_url):
|
|
65
|
+
"""
|
|
66
|
+
Notify users via Discord about recent price calculations.
|
|
67
|
+
|
|
68
|
+
:param webhook_url: The Discord webhook URL to send the notification to.
|
|
69
|
+
"""
|
|
70
|
+
embeds = cls._construct_recent_calculations_embeds()
|
|
71
|
+
try:
|
|
72
|
+
response = requests.post(
|
|
73
|
+
url=webhook_url,
|
|
74
|
+
json={
|
|
75
|
+
"embeds": embeds,
|
|
76
|
+
"username": DC_WEBHOOK_USERNAME,
|
|
77
|
+
"avatar_url": DC_WEBHOOK_AVATAR_URL,
|
|
78
|
+
},
|
|
79
|
+
timeout=10,
|
|
80
|
+
)
|
|
81
|
+
response.raise_for_status()
|
|
82
|
+
console.print("[bold steel_blue3][+] Discord notification sent.\n")
|
|
83
|
+
except RequestException as error:
|
|
84
|
+
console.print(f"[bold red][!] Failed to send Discord notification: {error}\n")
|
|
85
|
+
except Exception as error:
|
|
86
|
+
console.print(f"[bold red][!] An unexpected error occurred: {error}\n")
|