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.

@@ -1,205 +1,204 @@
1
1
  [User Settings]
2
- api_key = None
3
- discord_webhook_url = None
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 = 0
14
- recoil_case = 0
15
- dreams_and_nightmares_case = 0
16
- operation_riptide_case = 0
17
- snakebite_case = 0
18
- operation_broken_fang_case = 0
19
- fracture_case = 0
20
- chroma_case = 0
21
- chroma_2_case = 0
22
- chroma_3_case = 0
23
- clutch_case = 0
24
- csgo_weapon_case = 0
25
- csgo_weapon_case_2 = 0
26
- csgo_weapon_case_3 = 0
27
- cs20_case = 0
28
- danger_zone_case = 0
29
- esports_2013_case = 0
30
- esports_2013_winter_case = 0
31
- esports_2014_summer_case = 0
32
- falchion_case = 0
33
- gamma_case = 0
34
- gamma_2_case = 0
35
- glove_case = 0
36
- horizon_case = 0
37
- huntsman_case = 0
38
- operation_bravo_case = 0
39
- operation_breakout_case = 0
40
- operation_hydra_case = 0
41
- operation_phoenix_case = 0
42
- operation_vanguard_case = 0
43
- operation_wildfire_case = 0
44
- prisma_case = 0
45
- prisma_2_case = 0
46
- revolver_case = 0
47
- shadow_case = 0
48
- shattered_web_case = 0
49
- spectrum_case = 0
50
- spectrum_2_case = 0
51
- winter_offensive_case = 0
52
- kilowatt_case = 0
53
- gallery_case = 0
54
- fever_case = 0
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
- katowice_legends = 0
58
- katowice_challengers = 0
52
+ katowice_2014_legends ~ 0
53
+ katowice_2014_challengers ~ 0
59
54
 
60
55
  [Cologne 2014 Sticker Capsule]
61
- cologne_legends = 0
62
- cologne_challengers = 0
56
+ cologne_2014_legends ~ 0
57
+ cologne_2014_challengers ~ 0
63
58
 
64
59
  [DreamHack 2014 Sticker Capsule]
65
- dreamhack_legends = 0
60
+ dreamhack_2014_legends ~ 0
66
61
 
67
62
  [Katowice 2015 Sticker Capsule]
68
- katowice_legends = 0
69
- katowice_challengers = 0
63
+ katowice_2015_legends ~ 0
64
+ katowice_2015_challengers ~ 0
70
65
 
71
66
  [Cologne 2015 Sticker Capsule]
72
- cologne_legends = 0
73
- cologne_challengers = 0
67
+ cologne_2015_legends ~ 0
68
+ cologne_2015_challengers ~ 0
74
69
 
75
70
  [Cluj-Napoca 2015 Sticker Capsule]
76
- cluj_napoca_legends = 0
77
- cluj_napoca_challengers = 0
78
- cluj_napoca_legends_autographs = 0
79
- cluj_napoca_challengers_autographs = 0
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
- columbus_legends = 0
83
- columbus_challengers = 0
84
- columbus_legends_autographs = 0
85
- columbus_challengers_autographs = 0
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
- cologne_legends = 0
89
- cologne_challengers = 0
90
- cologne_legends_autographs = 0
91
- cologne_challengers_autographs = 0
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
- atlanta_legends = 0
95
- atlanta_challengers = 0
96
- atlanta_legends_autographs = 0
97
- atlanta_challengers_autographs = 0
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
- krakow_legends = 0
101
- krakow_challengers = 0
102
- krakow_legends_autographs = 0
103
- krakow_challengers_autographs = 0
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
- boston_legends = 0
107
- boston_minor_challengers = 0
108
- boston_returning_challengers = 0
109
- boston_attending_legends = 0
110
- boston_minor_challengers_with_flash_gaming = 0
111
- boston_legends_autographs = 0
112
- boston_minor_challengers_autographs = 0
113
- boston_returning_challengers_autographs = 0
114
- boston_attending_legends_autographs = 0
115
- boston_minor_challengers_with_flash_gaming_autographs = 0
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
- london_legends = 0
119
- london_minor_challengers = 0
120
- london_returning_challengers = 0
121
- london_legends_autographs = 0
122
- london_minor_challengers_autographs = 0
123
- london_returning_challengers_autographs = 0
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
- katowice_legends = 0
127
- katowice_minor_challengers = 0
128
- katowice_returning_challengers = 0
129
- katowice_legends_autographs = 0
130
- katowice_minor_challengers_autographs = 0
131
- katowice_returning_challengers_autographs = 0
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
- berlin_legends = 0
135
- berlin_minor_challengers = 0
136
- berlin_returning_challengers = 0
137
- berlin_legends_autographs = 0
138
- berlin_minor_challengers_autographs = 0
139
- berlin_returning_challengers_autographs = 0
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
- rmr_legends = 0
143
- rmr_challengers = 0
144
- rmr_contenders = 0
137
+ rmr_2020_legends ~ 0
138
+ rmr_2020_challengers ~ 0
139
+ rmr_2020_contenders ~ 0
145
140
 
146
141
  [Stockholm 2021 Sticker Capsule]
147
- stockholm_legends = 0
148
- stockholm_challengers = 0
149
- stockholm_contenders = 0
150
- stockholm_champions_autographs = 0
151
- stockholm_finalists_autographs = 0
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
- antwerp_legends = 0
155
- antwerp_challengers = 0
156
- antwerp_contenders = 0
157
- antwerp_champions_autographs = 0
158
- antwerp_challengers_autographs = 0
159
- antwerp_legends_autographs = 0
160
- antwerp_contenders_autographs = 0
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
- rio_legends = 0
164
- rio_challengers = 0
165
- rio_contenders = 0
166
- rio_champions_autographs = 0
167
- rio_challengers_autographs = 0
168
- rio_legends_autographs = 0
169
- rio_contenders_autographs = 0
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
- paris_legends = 0
173
- paris_challengers = 0
174
- paris_contenders = 0
175
- paris_champions_autographs = 0
176
- paris_challengers_autographs = 0
177
- paris_legends_autographs = 0
178
- paris_contenders_autographs = 0
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
- copenhagen_legends = 0
182
- copenhagen_challengers = 0
183
- copenhagen_contenders = 0
184
- copenhagen_champions_autographs = 0
185
- copenhagen_challengers_autographs = 0
186
- copenhagen_legends_autographs = 0
187
- copenhagen_contenders_autographs = 0
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
- shanghai_legends = 0
191
- shanghai_challengers = 0
192
- shanghai_contenders = 0
193
- shanghai_champions_autographs = 0
194
- shanghai_challengers_autographs = 0
195
- shanghai_legends_autographs = 0
196
- shanghai_contenders_autographs = 0
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
- austin_legends = 0
200
- austin_challengers = 0
201
- austin_contenders = 0
202
- austin_champions_autographs = 0
203
- austin_challengers_autographs = 0
204
- austin_legends_autographs = 0
205
- austin_contenders_autographs = 0
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.application import Application
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")