cs2tracker 2.1.17__tar.gz → 2.1.19__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 (48) hide show
  1. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/.gitignore +7 -8
  2. cs2tracker-2.1.19/Makefile +13 -0
  3. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/PKG-INFO +12 -11
  4. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/README.md +11 -10
  5. cs2tracker-2.1.19/assets/icon.ico +0 -0
  6. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/_version.py +2 -2
  7. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/app/editor_frame.py +68 -27
  8. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/config.py +41 -28
  9. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/constants.py +4 -3
  10. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/data/config.ini +24 -44
  11. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/data/convert_inventory.js +66 -20
  12. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/data/get_inventory.js +58 -24
  13. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker.egg-info/PKG-INFO +12 -11
  14. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker.egg-info/SOURCES.txt +3 -0
  15. cs2tracker-2.1.19/setup.iss +42 -0
  16. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/.flake8 +0 -0
  17. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/.isort.cfg +0 -0
  18. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/.pre-commit-config.yaml +0 -0
  19. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/.pylintrc +0 -0
  20. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/LICENSE +0 -0
  21. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/MANIFEST.in +0 -0
  22. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/assets/demo.gif +0 -0
  23. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/assets/icon.png +0 -0
  24. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/__init__.py +0 -0
  25. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/__main__.py +0 -0
  26. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/app/__init__.py +0 -0
  27. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/app/app.py +0 -0
  28. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/app/history_frame.py +0 -0
  29. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/app/scraper_frame.py +0 -0
  30. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/data/output.csv +0 -0
  31. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/logs.py +0 -0
  32. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/main.py +0 -0
  33. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/scraper/__init__.py +0 -0
  34. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/scraper/background_task.py +0 -0
  35. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/scraper/discord_notifier.py +0 -0
  36. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/scraper/parser.py +0 -0
  37. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/scraper/scraper.py +0 -0
  38. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/util/__init__.py +0 -0
  39. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/util/currency_conversion.py +0 -0
  40. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/util/padded_console.py +0 -0
  41. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker/util/tkinter.py +0 -0
  42. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker.egg-info/dependency_links.txt +0 -0
  43. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker.egg-info/entry_points.txt +0 -0
  44. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker.egg-info/requires.txt +0 -0
  45. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/cs2tracker.egg-info/top_level.txt +0 -0
  46. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/pyproject.toml +0 -0
  47. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/requirements.txt +0 -0
  48. {cs2tracker-2.1.17 → cs2tracker-2.1.19}/setup.cfg +0 -0
@@ -1,21 +1,20 @@
1
+ # Miscellaneous
1
2
  .vscode
2
-
3
- # Python venv and cache
4
3
  __pycache__
5
- venv
6
- venv-test
7
- venv-wsl
4
+ venv*
8
5
 
9
6
  # Python build output
10
- build
11
7
  dist
12
- cs2tracker.egg-info
8
+ *.egg-info
13
9
 
14
10
  # Auto generated version file on build
15
11
  _version.py
16
12
 
17
- # PyInstaller output
13
+ # PyInstaller files
18
14
  output
15
+ dist
16
+ *.spec
17
+ build/cs2tracker
19
18
 
20
19
  # Files generated by the program
21
20
  cs2tracker_scraper.bat
@@ -0,0 +1,13 @@
1
+ .PHONY: build
2
+
3
+ build:
4
+ pwsh -NoProfile ./build/build.ps1
5
+
6
+ clean:
7
+ rm -rf ./build/cs2tracker
8
+ rm -rf ./build/venv
9
+ rm -rf ./build/node_modules
10
+ rm -f ./build/package-lock.json
11
+ rm -f ./build/package.json
12
+ rm -f ./cs2tracker.spec
13
+ rm -rf ./dist
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cs2tracker
3
- Version: 2.1.17
3
+ Version: 2.1.19
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
@@ -76,7 +76,7 @@ Dynamic: license-file
76
76
 
77
77
  Simply download the program and run it:
78
78
 
79
- - [Windows](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-windows.zip)
79
+ - [Windows](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-setup.exe)
80
80
  - [Linux](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-linux.zip)
81
81
 
82
82
  #### Method 2: Install via Pip
@@ -120,29 +120,30 @@ This will open the config editor where you can change any setting by double clic
120
120
 
121
121
  - Enable **Daily Background Calculations** to automatically run a daily calculation of your investment in the background.
122
122
  - Use **Receive Discord Notifications** to receive a notification on your Discord server whenever the program has finished calculating your investment.
123
- - You need to set up a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) in your Discord server and enter the webhook url into the `discord_webhook_url` field in the config `User Settings`.
123
+ - You need to set up a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) in your Discord server and enter the webhook URL into the `discord_webhook_url` field in the config `User Settings`.
124
124
  - Enable **Proxy Requests** to prevent your requests from being rate limited by the steamcommunity server.
125
125
  - You need to register for a free API key on [Crawlbase](crawlbase.com) and enter it into the `proxy_api_key` field in the config `User Settings`.
126
126
 
127
127
  ## FAQ
128
128
 
129
- **Q: Is it safe to login with my Steam account?**
129
+ - **Q: Is it safe to login with my Steam account?**
130
+ - **A:** Yes, the program uses the [SteamUser](https://github.com/DoctorMcKay/node-steam-user?tab=readme-ov-file#methods-) and [Globaloffensive](https://github.com/DoctorMcKay/node-globaloffensive) libraries to sign in and import your Storage Units (the same method is used by [casemove](https://github.com/nombersDev/casemove)) and all of the login-related code is transparently available in [this file](cs2tracker/data/get_inventory.js).
130
131
 
131
- **A:** Yes, the program uses the [SteamUser](https://github.com/DoctorMcKay/node-steam-user?tab=readme-ov-file#methods-) and [Globaloffensive](https://github.com/DoctorMcKay/node-globaloffensive) libraries to sign in and import your Storage Units (the same method is used by [casemove](https://github.com/nombersDev/casemove)) and all of the login-related code is transparently available in [this file](cs2tracker/data/get_inventory.js).
132
132
 
133
+ - **Q: Do I have to login with my Steam account?**
134
+ - **A:** No, you can also manually specify the number of items you own in the config editor.
133
135
 
134
- **Q: Do I have to login with my Steam account?**
135
136
 
136
- **A:** No, you can also manually specify the number of items you own in the config editor.
137
+ - **Q: Can I get VAC-banned for using this program?**
138
+ - **A:** No, this program does not interact with the game in any way and only reads your Storage Units.
137
139
 
138
140
 
139
- **Q: Can I get VAC-banned for using this program?**
140
-
141
- **A:** No, this program does not interact with the game in any way and only reads your Storage Units.
141
+ - **Q: Why does Windows Defender flag this program as potentially harmful?**
142
+ - **A:** This is because the program is not signed with a [Code Signing Certificate](https://www.globalsign.com/en/code-signing-certificate/what-is-code-signing-certificate), which Windows uses to verify the identity of publishers. These certificates are very expensive and not something I am willing to invest in for a free and open source project like this.
142
143
 
143
144
  ## Contributing
144
145
 
145
- Please feel free to submit a pull request or open an issue. See [issues](https://github.com/ashiven/cs2tracker/issues) and [pull requests](https://github.com/ashiven/cs2tracker/pulls) for current work.
146
+ Please feel free to submit a [pull request](https://github.com/ashiven/cs2tracker/pulls) or open an [issue](https://github.com/ashiven/cs2tracker/issues).
146
147
 
147
148
  1. Fork the repository
148
149
  2. Create a new branch: `git checkout -b feature-name`.
@@ -48,7 +48,7 @@
48
48
 
49
49
  Simply download the program and run it:
50
50
 
51
- - [Windows](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-windows.zip)
51
+ - [Windows](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-setup.exe)
52
52
  - [Linux](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-linux.zip)
53
53
 
54
54
  #### Method 2: Install via Pip
@@ -92,29 +92,30 @@ This will open the config editor where you can change any setting by double clic
92
92
 
93
93
  - Enable **Daily Background Calculations** to automatically run a daily calculation of your investment in the background.
94
94
  - Use **Receive Discord Notifications** to receive a notification on your Discord server whenever the program has finished calculating your investment.
95
- - You need to set up a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) in your Discord server and enter the webhook url into the `discord_webhook_url` field in the config `User Settings`.
95
+ - You need to set up a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) in your Discord server and enter the webhook URL into the `discord_webhook_url` field in the config `User Settings`.
96
96
  - Enable **Proxy Requests** to prevent your requests from being rate limited by the steamcommunity server.
97
97
  - You need to register for a free API key on [Crawlbase](crawlbase.com) and enter it into the `proxy_api_key` field in the config `User Settings`.
98
98
 
99
99
  ## FAQ
100
100
 
101
- **Q: Is it safe to login with my Steam account?**
101
+ - **Q: Is it safe to login with my Steam account?**
102
+ - **A:** Yes, the program uses the [SteamUser](https://github.com/DoctorMcKay/node-steam-user?tab=readme-ov-file#methods-) and [Globaloffensive](https://github.com/DoctorMcKay/node-globaloffensive) libraries to sign in and import your Storage Units (the same method is used by [casemove](https://github.com/nombersDev/casemove)) and all of the login-related code is transparently available in [this file](cs2tracker/data/get_inventory.js).
102
103
 
103
- **A:** Yes, the program uses the [SteamUser](https://github.com/DoctorMcKay/node-steam-user?tab=readme-ov-file#methods-) and [Globaloffensive](https://github.com/DoctorMcKay/node-globaloffensive) libraries to sign in and import your Storage Units (the same method is used by [casemove](https://github.com/nombersDev/casemove)) and all of the login-related code is transparently available in [this file](cs2tracker/data/get_inventory.js).
104
104
 
105
+ - **Q: Do I have to login with my Steam account?**
106
+ - **A:** No, you can also manually specify the number of items you own in the config editor.
105
107
 
106
- **Q: Do I have to login with my Steam account?**
107
108
 
108
- **A:** No, you can also manually specify the number of items you own in the config editor.
109
+ - **Q: Can I get VAC-banned for using this program?**
110
+ - **A:** No, this program does not interact with the game in any way and only reads your Storage Units.
109
111
 
110
112
 
111
- **Q: Can I get VAC-banned for using this program?**
112
-
113
- **A:** No, this program does not interact with the game in any way and only reads your Storage Units.
113
+ - **Q: Why does Windows Defender flag this program as potentially harmful?**
114
+ - **A:** This is because the program is not signed with a [Code Signing Certificate](https://www.globalsign.com/en/code-signing-certificate/what-is-code-signing-certificate), which Windows uses to verify the identity of publishers. These certificates are very expensive and not something I am willing to invest in for a free and open source project like this.
114
115
 
115
116
  ## Contributing
116
117
 
117
- Please feel free to submit a pull request or open an issue. See [issues](https://github.com/ashiven/cs2tracker/issues) and [pull requests](https://github.com/ashiven/cs2tracker/pulls) for current work.
118
+ Please feel free to submit a [pull request](https://github.com/ashiven/cs2tracker/pulls) or open an [issue](https://github.com/ashiven/cs2tracker/issues).
118
119
 
119
120
  1. Fork the repository
120
121
  2. Create a new branch: `git checkout -b feature-name`.
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.17'
21
- __version_tuple__ = version_tuple = (2, 1, 17)
20
+ __version__ = version = '2.1.19'
21
+ __version_tuple__ = version_tuple = (2, 1, 19)
@@ -8,7 +8,7 @@ from tkinter import messagebox, ttk
8
8
  from nodejs import node
9
9
  from ttk_text import ThemedText
10
10
 
11
- from cs2tracker.config import get_config
11
+ from cs2tracker.config import CUSTOM_SECTIONS, get_config
12
12
  from cs2tracker.constants import (
13
13
  CONFIG_FILE,
14
14
  CONFIG_FILE_BACKUP,
@@ -18,7 +18,7 @@ from cs2tracker.constants import (
18
18
  )
19
19
  from cs2tracker.util.tkinter import centered, size_info
20
20
 
21
- ADD_CUSTOM_ITEM_TITLE = "Add Custom Item"
21
+ ADD_CUSTOM_ITEM_TITLE = "Add Item"
22
22
  ADD_CUSTOM_ITEM_SIZE = "500x230"
23
23
 
24
24
  IMPORT_INVENTORY_TITLE = "Import Steam Inventory"
@@ -131,7 +131,7 @@ class ConfigEditorFrame(ttk.Frame):
131
131
  if selected:
132
132
  item = selected[0]
133
133
  section_name = self.tree.parent(item)
134
- if section_name in ("Stickers", "Skins"):
134
+ if section_name in CUSTOM_SECTIONS:
135
135
  next_option = self.tree.next(item)
136
136
  self.tree.delete(item)
137
137
  self.save_config()
@@ -169,31 +169,24 @@ class ConfigEditorFrame(ttk.Frame):
169
169
  continue
170
170
 
171
171
  section_level = self.tree.insert("", "end", iid=section, text=section)
172
-
173
- # Items in the Stickers, Cases, and Skins sections should be displayed alphabetically sorted
174
172
  section_items = config.items(section)
175
- if section in ("Stickers", "Cases", "Skins"):
173
+
174
+ # Major Sticker Capsules should remain sorted by year
175
+ if section != "Major Sticker Capsules":
176
176
  section_items = sorted(section_items)
177
177
 
178
178
  for config_option, value in section_items:
179
179
  if section not in ("User Settings", "App Settings"):
180
180
  option_name = config.option_to_name(config_option, href=True)
181
- self.tree.insert(
182
- section_level,
183
- "end",
184
- iid=f"{section}-{option_name}",
185
- text=option_name,
186
- values=[value],
187
- )
188
181
  else:
189
182
  option_name = config.option_to_name(config_option)
190
- self.tree.insert(
191
- section_level,
192
- "end",
193
- iid=f"{section}-{option_name}",
194
- text=option_name,
195
- values=[value],
196
- )
183
+ self.tree.insert(
184
+ section_level,
185
+ "end",
186
+ iid=f"{section}-{option_name}",
187
+ text=option_name,
188
+ values=[value],
189
+ )
197
190
 
198
191
  self.tree.focus("User Settings")
199
192
  self.tree.selection_set("User Settings")
@@ -267,6 +260,25 @@ class ConfigEditorButtonFrame(ttk.Frame):
267
260
  custom_item_button = ttk.Button(self, text="Add Item", command=self._add_custom_item)
268
261
  custom_item_button.pack(side="left", expand=True, padx=5)
269
262
 
263
+ def open_custom_enter(_):
264
+ selected = self.editor_frame.tree.selection()
265
+ if selected and not self.editor_frame.tree.parent(selected[0]):
266
+ selected_section = self.editor_frame.tree.item(selected[0], "text")
267
+ if selected_section in CUSTOM_SECTIONS and not self.editor_frame.tree.get_children(
268
+ selected_section
269
+ ):
270
+ custom_item_button.invoke()
271
+
272
+ def open_custom_click(event):
273
+ selected_section = self.editor_frame.tree.identify_row(event.y)
274
+ if selected_section in CUSTOM_SECTIONS and not self.editor_frame.tree.get_children(
275
+ selected_section
276
+ ):
277
+ custom_item_button.invoke()
278
+
279
+ self.editor_frame.tree.bind("<Return>", open_custom_enter, add="+")
280
+ self.editor_frame.tree.bind("<Double-1>", open_custom_click, add="+")
281
+
270
282
  import_inventory_button = ttk.Button(
271
283
  self, text="Import Steam Inventory", command=self._import_steam_inventory
272
284
  )
@@ -397,6 +409,36 @@ class CustomItemFrame(ttk.Frame):
397
409
  break
398
410
  return insert_index
399
411
 
412
+ def _identify_custom_section(self, item_name):
413
+ # pylint: disable=too-many-return-statements,too-many-branches
414
+ """Given an item name, identify the custom section it belongs to."""
415
+ if "Patch Pack" in item_name or "Patch Collection" in item_name:
416
+ return "Patch Packs"
417
+ elif "Patch |" in item_name:
418
+ return "Patches"
419
+ elif "Sticker |" in item_name:
420
+ return "Stickers"
421
+ elif "Charm |" in item_name:
422
+ return "Charms"
423
+ elif "Music Kit |" in item_name:
424
+ return "Music Kits"
425
+ elif "Souvenir" in item_name and "|" not in item_name:
426
+ return "Souvenirs"
427
+ elif "★ " in item_name:
428
+ return "Special Items"
429
+ elif " | " in item_name and "(" in item_name and ")" in item_name:
430
+ return "Skins"
431
+ elif "Pins Capsule" in item_name:
432
+ return "Pins Capsules"
433
+ elif "Capsule" in item_name:
434
+ return "Sticker Capsules"
435
+ elif "Pin" in item_name:
436
+ return "Collectible Pins"
437
+ elif " | " in item_name:
438
+ return "Agents"
439
+ else:
440
+ return "Others"
441
+
400
442
  def _add_custom_item(self, item_href, item_owned):
401
443
  """Add a custom item to the configuration."""
402
444
  if not item_href or not item_owned:
@@ -404,7 +446,7 @@ class CustomItemFrame(ttk.Frame):
404
446
  "Input Error", "All fields must be filled out.", parent=self.window
405
447
  )
406
448
  return
407
- if config.option_exists(item_href, exclude_sections=("Stickers", "Skins")):
449
+ if config.option_exists(item_href, exclude_sections=CUSTOM_SECTIONS):
408
450
  messagebox.showerror(
409
451
  "Item Exists", "This item already exists in another section.", parent=self.window
410
452
  )
@@ -416,12 +458,11 @@ class CustomItemFrame(ttk.Frame):
416
458
  messagebox.showerror("Invalid URL", str(error), parent=self.window)
417
459
  return
418
460
 
419
- if self._update_existing("Stickers", item_name, item_owned):
420
- return
421
- if self._update_existing("Skins", item_name, item_owned):
422
- return
461
+ for section in CUSTOM_SECTIONS:
462
+ if self._update_existing(section, item_name, item_owned):
463
+ return
423
464
 
424
- section = "Stickers" if item_name.startswith("Sticker") else "Skins"
465
+ section = self._identify_custom_section(item_name)
425
466
  insert_index = self._get_insert_index(item_name, section)
426
467
  self.editor_frame.tree.insert(
427
468
  section,
@@ -500,7 +541,7 @@ class InventoryImportFrame(ttk.Frame):
500
541
  self.import_sticker_capsules_value = tk.BooleanVar(value=True)
501
542
  self.import_sticker_capsules_checkbox = ttk.Checkbutton(
502
543
  self.checkbox_frame,
503
- text="Import Sticker Capsules",
544
+ text="Import Major Sticker Capsules",
504
545
  variable=self.import_sticker_capsules_value,
505
546
  style="Switch.TCheckbutton",
506
547
  )
@@ -3,12 +3,33 @@ import re
3
3
  from configparser import ConfigParser, ParsingError
4
4
  from urllib.parse import quote, unquote
5
5
 
6
- from cs2tracker.constants import CAPSULE_PAGES, CONFIG_FILE, INVENTORY_IMPORT_FILE
6
+ from cs2tracker.constants import (
7
+ CONFIG_FILE,
8
+ INVENTORY_IMPORT_FILE,
9
+ )
7
10
  from cs2tracker.util.padded_console import get_console
8
11
 
9
12
  STEAM_MARKET_LISTING_BASEURL_CS2 = "https://steamcommunity.com/market/listings/730/"
10
13
  STEAM_MARKET_LISTING_REGEX = r"^https://steamcommunity.com/market/listings/\d+/.+$"
11
14
 
15
+ CUSTOM_SECTIONS = [
16
+ "Skins",
17
+ "Special Items",
18
+ "Agents",
19
+ "Charms",
20
+ "Patches",
21
+ "Patch Packs",
22
+ "Stickers",
23
+ "Souvenirs",
24
+ "Sticker Capsules",
25
+ "Others",
26
+ "Collectible Pins",
27
+ "Pins Capsules",
28
+ "Music Kits",
29
+ ]
30
+
31
+ PRECONFIGURED_SECTIONS = ["Cases", "Major Sticker Capsules", "App Settings", "User Settings"]
32
+
12
33
  console = get_console()
13
34
 
14
35
 
@@ -46,19 +67,12 @@ class ValidatedConfig(ConfigParser):
46
67
 
47
68
  def _validate_config_sections(self):
48
69
  """Validate that the configuration file has all required sections."""
49
- if not self.has_section("User Settings"):
50
- raise ValueError("Missing 'User Settings' section in the configuration file.")
51
- if not self.has_section("App Settings"):
52
- raise ValueError("Missing 'App Settings' section in the configuration file.")
53
- if not self.has_section("Stickers"):
54
- raise ValueError("Missing 'Stickers' section in the configuration file.")
55
- if not self.has_section("Cases"):
56
- raise ValueError("Missing 'Cases' section in the configuration file.")
57
- if not self.has_section("Skins"):
58
- raise ValueError("Missing 'Skins' section in the configuration file.")
59
- for capsule_section in CAPSULE_PAGES:
60
- if not self.has_section(capsule_section):
61
- raise ValueError(f"Missing '{capsule_section}' section in the configuration file.")
70
+ for section in CUSTOM_SECTIONS:
71
+ if not self.has_section(section):
72
+ raise ValueError(f"Missing '{section}' section in the configuration file.")
73
+ for section in PRECONFIGURED_SECTIONS:
74
+ if not self.has_section(section):
75
+ raise ValueError(f"Missing '{section}' section in the configuration file.")
62
76
 
63
77
  def _validate_config_values(self):
64
78
  # pylint: disable=too-many-branches
@@ -136,23 +150,22 @@ class ValidatedConfig(ConfigParser):
136
150
  try:
137
151
  with open(INVENTORY_IMPORT_FILE, "r", encoding="utf-8") as inventory_file:
138
152
  inventory_data = json.load(inventory_file)
139
- sorted_inventory_data = dict(sorted(inventory_data.items()))
140
153
 
141
154
  added_to_config = set()
142
- for item_name, item_owned in sorted_inventory_data.items():
143
- option = self.name_to_option(item_name, href=True)
144
- for section in self.sections():
145
- if option in self.options(section):
146
- self.set(section, option, str(item_owned))
147
- added_to_config.add(item_name)
148
-
149
- for item_name, item_owned in sorted_inventory_data.items():
150
- if item_name not in added_to_config:
155
+ for _, item_infos in inventory_data.items():
156
+ for item_name, item_owned in item_infos.items():
151
157
  option = self.name_to_option(item_name, href=True)
152
- if item_name.startswith("Sticker"):
153
- self.set("Stickers", option, str(item_owned))
154
- else:
155
- self.set("Skins", option, str(item_owned))
158
+ for section in self.sections():
159
+ if option in self.options(section):
160
+ self.set(section, option, str(item_owned))
161
+ added_to_config.add(item_name)
162
+
163
+ for section, item_infos in inventory_data.items():
164
+ sorted_item_infos = dict(sorted(item_infos.items()))
165
+ for item_name, item_owned in sorted_item_infos.items():
166
+ if item_name not in added_to_config:
167
+ option = self.name_to_option(item_name, href=True)
168
+ self.set(section, option, str(item_owned))
156
169
 
157
170
  self.write_to_file()
158
171
  except (FileNotFoundError, json.JSONDecodeError) as error:
@@ -41,9 +41,9 @@ PYTHON_EXECUTABLE = sys.executable
41
41
  RUNNING_IN_EXE = getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS")
42
42
 
43
43
  if RUNNING_IN_EXE:
44
- MEIPASS_DIR = sys._MEIPASS # type: ignore pylint: disable=protected-access
45
- MODULE_DIR = MEIPASS_DIR
46
- PROJECT_DIR = MEIPASS_DIR
44
+ EXECUTABLE_DIR = sys._MEIPASS # type: ignore pylint: disable=protected-access
45
+ MODULE_DIR = EXECUTABLE_DIR
46
+ PROJECT_DIR = EXECUTABLE_DIR
47
47
 
48
48
  if OS == OSType.WINDOWS:
49
49
  APP_DATA_DIR = os.path.join(os.path.expanduser("~"), "AppData", "Local")
@@ -187,6 +187,7 @@ AUTHOR_STRING = (
187
187
  f"Version: {VERSION} - {datetime.today().strftime('%Y/%m/%d')} - Jannik Novak @ashiven\n"
188
188
  )
189
189
 
190
+
190
191
  CAPSULE_PAGES = {
191
192
  "Katowice 2014 Sticker Capsule": "https://steamcommunity.com/market/search?q=katowice+2014+legends+challengers",
192
193
  "Cologne 2014 Sticker Capsule": "https://steamcommunity.com/market/search?q=cologne+2014+legends+challengers",
@@ -4,13 +4,33 @@ discord_notifications ~ False
4
4
  conversion_currency ~ EUR
5
5
 
6
6
  [User Settings]
7
- proxy_api_key ~
8
7
  discord_webhook_url ~
8
+ proxy_api_key ~
9
9
 
10
10
  [Skins]
11
11
 
12
+ [Special Items]
13
+
14
+ [Agents]
15
+
16
+ [Charms]
17
+
18
+ [Patches]
19
+
20
+ [Patch Packs]
21
+
12
22
  [Stickers]
13
23
 
24
+ [Souvenirs]
25
+
26
+ [Sticker Capsules]
27
+
28
+ [Collectible Pins]
29
+
30
+ [Pins Capsules]
31
+
32
+ [Music Kits]
33
+
14
34
  [Cases]
15
35
  https://steamcommunity.com/market/listings/730/CS%3AGO%20Weapon%20Case ~ 0
16
36
  https://steamcommunity.com/market/listings/730/CS%3AGO%20Weapon%20Case%202 ~ 0
@@ -55,56 +75,36 @@ https://steamcommunity.com/market/listings/730/eSports%202013%20Case ~ 0
55
75
  https://steamcommunity.com/market/listings/730/eSports%202013%20Winter%20Case ~ 0
56
76
  https://steamcommunity.com/market/listings/730/eSports%202014%20Summer%20Case ~ 0
57
77
 
58
- [Katowice 2014 Sticker Capsule]
78
+ [Major Sticker Capsules]
59
79
  https://steamcommunity.com/market/listings/730/EMS%20Katowice%202014%20Legends ~ 0
60
80
  https://steamcommunity.com/market/listings/730/EMS%20Katowice%202014%20Challengers ~ 0
61
-
62
- [Cologne 2014 Sticker Capsule]
63
81
  https://steamcommunity.com/market/listings/730/ESL%20One%20Cologne%202014%20Legends ~ 0
64
82
  https://steamcommunity.com/market/listings/730/ESL%20One%20Cologne%202014%20Challengers ~ 0
65
-
66
- [DreamHack 2014 Sticker Capsule]
67
83
  https://steamcommunity.com/market/listings/730/DreamHack%202014%20Legends%20%28Holo-Foil%29 ~ 0
68
-
69
- [Katowice 2015 Sticker Capsule]
70
84
  https://steamcommunity.com/market/listings/730/ESL%20One%20Katowice%202015%20Legends%20%28Holo-Foil%29 ~ 0
71
85
  https://steamcommunity.com/market/listings/730/ESL%20One%20Katowice%202015%20Challengers%20%28Holo-Foil%29 ~ 0
72
-
73
- [Cologne 2015 Sticker Capsule]
74
86
  https://steamcommunity.com/market/listings/730/ESL%20One%20Cologne%202015%20Legends%20%28Foil%29 ~ 0
75
87
  https://steamcommunity.com/market/listings/730/ESL%20One%20Cologne%202015%20Challengers%20%28Foil%29 ~ 0
76
-
77
- [Cluj-Napoca 2015 Sticker Capsule]
78
88
  https://steamcommunity.com/market/listings/730/DreamHack%20Cluj-Napoca%202015%20Legends%20%28Foil%29 ~ 0
79
89
  https://steamcommunity.com/market/listings/730/DreamHack%20Cluj-Napoca%202015%20Challengers%20%28Foil%29 ~ 0
80
90
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Legends%20%28Foil%29%20%7C%20Cluj-Napoca%202015 ~ 0
81
91
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Challengers%20%28Foil%29%20%7C%20Cluj-Napoca%202015 ~ 0
82
-
83
- [Columbus 2016 Sticker Capsule]
84
92
  https://steamcommunity.com/market/listings/730/MLG%20Columbus%202016%20Legends%20%28Holo-Foil%29 ~ 0
85
93
  https://steamcommunity.com/market/listings/730/MLG%20Columbus%202016%20Challengers%20%28Holo-Foil%29 ~ 0
86
94
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Legends%20%28Foil%29%20%7C%20MLG%20Columbus%202016 ~ 0
87
95
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Challengers%20%28Foil%29%20%7C%20MLG%20Columbus%202016 ~ 0
88
-
89
- [Cologne 2016 Sticker Capsule]
90
96
  https://steamcommunity.com/market/listings/730/Cologne%202016%20Legends%20%28Holo-Foil%29 ~ 0
91
97
  https://steamcommunity.com/market/listings/730/Cologne%202016%20Challengers%20%28Holo-Foil%29 ~ 0
92
98
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Legends%20%28Foil%29%20%7C%20Cologne%202016 ~ 0
93
99
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Challengers%20%28Foil%29%20%7C%20Cologne%202016 ~ 0
94
-
95
- [Atlanta 2017 Sticker Capsule]
96
100
  https://steamcommunity.com/market/listings/730/Atlanta%202017%20Legends%20%28Holo-Foil%29 ~ 0
97
101
  https://steamcommunity.com/market/listings/730/Atlanta%202017%20Challengers%20%28Holo-Foil%29 ~ 0
98
102
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Legends%20%28Foil%29%20%7C%20Atlanta%202017 ~ 0
99
103
  https://steamcommunity.com/market/listings/730/Autograph%20Capsule%20%7C%20Challengers%20%28Foil%29%20%7C%20Atlanta%202017 ~ 0
100
-
101
- [Krakow 2017 Sticker Capsule]
102
104
  https://steamcommunity.com/market/listings/730/Krakow%202017%20Legends%20%28Holo-Foil%29 ~ 0
103
105
  https://steamcommunity.com/market/listings/730/Krakow%202017%20Challengers%20%28Holo-Foil%29 ~ 0
104
106
  https://steamcommunity.com/market/listings/730/Krakow%202017%20Legends%20Autograph%20Capsule ~ 0
105
107
  https://steamcommunity.com/market/listings/730/Krakow%202017%20Challengers%20Autograph%20Capsule ~ 0
106
-
107
- [Boston 2018 Sticker Capsule]
108
108
  https://steamcommunity.com/market/listings/730/Boston%202018%20Legends%20%28Holo-Foil%29 ~ 0
109
109
  https://steamcommunity.com/market/listings/730/Boston%202018%20Minor%20Challengers%20%28Holo-Foil%29 ~ 0
110
110
  https://steamcommunity.com/market/listings/730/Boston%202018%20Returning%20Challengers%20%28Holo-Foil%29 ~ 0
@@ -115,44 +115,32 @@ https://steamcommunity.com/market/listings/730/Boston%202018%20Minor%20Challenge
115
115
  https://steamcommunity.com/market/listings/730/Boston%202018%20Returning%20Challengers%20Autograph%20Capsule ~ 0
116
116
  https://steamcommunity.com/market/listings/730/Boston%202018%20Attending%20Legends%20Autograph%20Capsule ~ 0
117
117
  https://steamcommunity.com/market/listings/730/Boston%202018%20Minor%20Challengers%20with%20Flash%20Gaming%20Autograph%20Capsule ~ 0
118
-
119
- [London 2018 Sticker Capsule]
120
118
  https://steamcommunity.com/market/listings/730/London%202018%20Legends%20%28Holo-Foil%29 ~ 0
121
119
  https://steamcommunity.com/market/listings/730/London%202018%20Minor%20Challengers%20%28Holo-Foil%29 ~ 0
122
120
  https://steamcommunity.com/market/listings/730/London%202018%20Returning%20Challengers%20%28Holo-Foil%29 ~ 0
123
121
  https://steamcommunity.com/market/listings/730/London%202018%20Legends%20Autograph%20Capsule ~ 0
124
122
  https://steamcommunity.com/market/listings/730/London%202018%20Minor%20Challengers%20Autograph%20Capsule ~ 0
125
123
  https://steamcommunity.com/market/listings/730/London%202018%20Returning%20Challengers%20Autograph%20Capsule ~ 0
126
-
127
- [Katowice 2019 Sticker Capsule]
128
124
  https://steamcommunity.com/market/listings/730/Katowice%202019%20Legends%20%28Holo-Foil%29 ~ 0
129
125
  https://steamcommunity.com/market/listings/730/Katowice%202019%20Minor%20Challengers%20%28Holo-Foil%29 ~ 0
130
126
  https://steamcommunity.com/market/listings/730/Katowice%202019%20Returning%20Challengers%20%28Holo-Foil%29 ~ 0
131
127
  https://steamcommunity.com/market/listings/730/Katowice%202019%20Legends%20Autograph%20Capsule ~ 0
132
128
  https://steamcommunity.com/market/listings/730/Katowice%202019%20Minor%20Challengers%20Autograph%20Capsule ~ 0
133
129
  https://steamcommunity.com/market/listings/730/Katowice%202019%20Returning%20Challengers%20Autograph%20Capsule ~ 0
134
-
135
- [Berlin 2019 Sticker Capsule]
136
130
  https://steamcommunity.com/market/listings/730/Berlin%202019%20Legends%20%28Holo-Foil%29 ~ 0
137
131
  https://steamcommunity.com/market/listings/730/Berlin%202019%20Minor%20Challengers%20%28Holo-Foil%29 ~ 0
138
132
  https://steamcommunity.com/market/listings/730/Berlin%202019%20Returning%20Challengers%20%28Holo-Foil%29 ~ 0
139
133
  https://steamcommunity.com/market/listings/730/Berlin%202019%20Legends%20Autograph%20Capsule ~ 0
140
134
  https://steamcommunity.com/market/listings/730/Berlin%202019%20Minor%20Challengers%20Autograph%20Capsule ~ 0
141
135
  https://steamcommunity.com/market/listings/730/Berlin%202019%20Returning%20Challengers%20Autograph%20Capsule ~ 0
142
-
143
- [2020 RMR Sticker Capsule]
144
136
  https://steamcommunity.com/market/listings/730/2020%20RMR%20Legends ~ 0
145
137
  https://steamcommunity.com/market/listings/730/2020%20RMR%20Challengers ~ 0
146
138
  https://steamcommunity.com/market/listings/730/2020%20RMR%20Contenders ~ 0
147
-
148
- [Stockholm 2021 Sticker Capsule]
149
139
  https://steamcommunity.com/market/listings/730/Stockholm%202021%20Legends%20Sticker%20Capsule ~ 0
150
140
  https://steamcommunity.com/market/listings/730/Stockholm%202021%20Challengers%20Sticker%20Capsule ~ 0
151
141
  https://steamcommunity.com/market/listings/730/Stockholm%202021%20Contenders%20Sticker%20Capsule ~ 0
152
142
  https://steamcommunity.com/market/listings/730/Stockholm%202021%20Champions%20Autograph%20Capsule ~ 0
153
143
  https://steamcommunity.com/market/listings/730/Stockholm%202021%20Finalists%20Autograph%20Capsule ~ 0
154
-
155
- [Antwerp 2022 Sticker Capsule]
156
144
  https://steamcommunity.com/market/listings/730/Antwerp%202022%20Legends%20Sticker%20Capsule ~ 0
157
145
  https://steamcommunity.com/market/listings/730/Antwerp%202022%20Challengers%20Sticker%20Capsule ~ 0
158
146
  https://steamcommunity.com/market/listings/730/Antwerp%202022%20Contenders%20Sticker%20Capsule ~ 0
@@ -160,8 +148,6 @@ https://steamcommunity.com/market/listings/730/Antwerp%202022%20Champions%20Auto
160
148
  https://steamcommunity.com/market/listings/730/Antwerp%202022%20Challengers%20Autograph%20Capsule ~ 0
161
149
  https://steamcommunity.com/market/listings/730/Antwerp%202022%20Legends%20Autograph%20Capsule ~ 0
162
150
  https://steamcommunity.com/market/listings/730/Antwerp%202022%20Contenders%20Autograph%20Capsule ~ 0
163
-
164
- [Rio 2022 Sticker Capsule]
165
151
  https://steamcommunity.com/market/listings/730/Rio%202022%20Legends%20Sticker%20Capsule ~ 0
166
152
  https://steamcommunity.com/market/listings/730/Rio%202022%20Challengers%20Sticker%20Capsule ~ 0
167
153
  https://steamcommunity.com/market/listings/730/Rio%202022%20Contenders%20Sticker%20Capsule ~ 0
@@ -169,8 +155,6 @@ https://steamcommunity.com/market/listings/730/Rio%202022%20Champions%20Autograp
169
155
  https://steamcommunity.com/market/listings/730/Rio%202022%20Challengers%20Autograph%20Capsule ~ 0
170
156
  https://steamcommunity.com/market/listings/730/Rio%202022%20Legends%20Autograph%20Capsule ~ 0
171
157
  https://steamcommunity.com/market/listings/730/Rio%202022%20Contenders%20Autograph%20Capsule ~ 0
172
-
173
- [Paris 2023 Sticker Capsule]
174
158
  https://steamcommunity.com/market/listings/730/Paris%202023%20Legends%20Sticker%20Capsule ~ 0
175
159
  https://steamcommunity.com/market/listings/730/Paris%202023%20Challengers%20Sticker%20Capsule ~ 0
176
160
  https://steamcommunity.com/market/listings/730/Paris%202023%20Contenders%20Sticker%20Capsule ~ 0
@@ -178,8 +162,6 @@ https://steamcommunity.com/market/listings/730/Paris%202023%20Champions%20Autogr
178
162
  https://steamcommunity.com/market/listings/730/Paris%202023%20Challengers%20Autograph%20Capsule ~ 0
179
163
  https://steamcommunity.com/market/listings/730/Paris%202023%20Legends%20Autograph%20Capsule ~ 0
180
164
  https://steamcommunity.com/market/listings/730/Paris%202023%20Contenders%20Autograph%20Capsule ~ 0
181
-
182
- [Copenhagen 2024 Sticker Capsule]
183
165
  https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Legends%20Sticker%20Capsule ~ 0
184
166
  https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Challengers%20Sticker%20Capsule ~ 0
185
167
  https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Contenders%20Sticker%20Capsule ~ 0
@@ -187,8 +169,6 @@ https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Champions%20A
187
169
  https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Challengers%20Autograph%20Capsule ~ 0
188
170
  https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Legends%20Autograph%20Capsule ~ 0
189
171
  https://steamcommunity.com/market/listings/730/Copenhagen%202024%20Contenders%20Autograph%20Capsule ~ 0
190
-
191
- [Shanghai 2024 Sticker Capsule]
192
172
  https://steamcommunity.com/market/listings/730/Shanghai%202024%20Legends%20Sticker%20Capsule ~ 0
193
173
  https://steamcommunity.com/market/listings/730/Shanghai%202024%20Challengers%20Sticker%20Capsule ~ 0
194
174
  https://steamcommunity.com/market/listings/730/Shanghai%202024%20Contenders%20Sticker%20Capsule ~ 0
@@ -196,8 +176,6 @@ https://steamcommunity.com/market/listings/730/Shanghai%202024%20Champions%20Aut
196
176
  https://steamcommunity.com/market/listings/730/Shanghai%202024%20Challengers%20Autograph%20Capsule ~ 0
197
177
  https://steamcommunity.com/market/listings/730/Shanghai%202024%20Legends%20Autograph%20Capsule ~ 0
198
178
  https://steamcommunity.com/market/listings/730/Shanghai%202024%20Contenders%20Autograph%20Capsule ~ 0
199
-
200
- [Austin 2025 Sticker Capsule]
201
179
  https://steamcommunity.com/market/listings/730/Austin%202025%20Legends%20Sticker%20Capsule ~ 0
202
180
  https://steamcommunity.com/market/listings/730/Austin%202025%20Challengers%20Sticker%20Capsule ~ 0
203
181
  https://steamcommunity.com/market/listings/730/Austin%202025%20Contenders%20Sticker%20Capsule ~ 0
@@ -205,3 +183,5 @@ https://steamcommunity.com/market/listings/730/Austin%202025%20Champions%20Autog
205
183
  https://steamcommunity.com/market/listings/730/Austin%202025%20Challengers%20Autograph%20Capsule ~ 0
206
184
  https://steamcommunity.com/market/listings/730/Austin%202025%20Legends%20Autograph%20Capsule ~ 0
207
185
  https://steamcommunity.com/market/listings/730/Austin%202025%20Contenders%20Autograph%20Capsule ~ 0
186
+
187
+ [Others]
@@ -11,6 +11,9 @@ const itemsGameLink =
11
11
  const translationsCacheFile = path.join(__dirname, "translations.json");
12
12
  const itemsCacheFile = path.join(__dirname, "items.json");
13
13
 
14
+ const translationRegex = /"(.+?)"\s+"(.+?)"/;
15
+ const souvenirRegex = /^csgo_crate_[a-z0-9]+_promo.*/;
16
+
14
17
  class ItemNameConverter {
15
18
  constructor() {
16
19
  this.translations = {};
@@ -38,7 +41,7 @@ class ItemNameConverter {
38
41
  const res = await axios.get(translationsLink);
39
42
  const lines = res.data.split(/\n/);
40
43
  for (const line of lines) {
41
- const match = line.match(/"(.+?)"\s+"(.+?)"/);
44
+ const match = line.match(translationRegex);
42
45
  if (match) {
43
46
  this.translations[match[1].toLowerCase()] = match[2];
44
47
  }
@@ -174,26 +177,72 @@ class ItemNameConverter {
174
177
 
175
178
  getItemType(item) {
176
179
  const def = this.items[item.def_index];
177
- if (def === undefined) return "unknown";
180
+ if (def === undefined) return "Unknown";
178
181
 
179
182
  if (def.item_name !== undefined) {
180
183
  let translatedName =
181
184
  def.item_name.replace("#", "").toLowerCase() || def.item_name;
182
185
  if (
183
- translatedName.startsWith("csgo_crate_sticker_pack") ||
186
+ (translatedName.startsWith("csgo_crate_sticker_pack") &&
187
+ (translatedName.includes("2014") ||
188
+ translatedName.includes("2015") ||
189
+ translatedName.includes("contenders") ||
190
+ translatedName.includes("challengers") ||
191
+ translatedName.includes("legends"))) ||
184
192
  translatedName.startsWith("csgo_crate_signature_pack")
185
193
  ) {
186
- return "sticker capsule";
187
- } else if (translatedName.startsWith("csgo_crate_community")) {
188
- return "case";
194
+ return "Major Sticker Capsules";
195
+ } else if (translatedName.startsWith("csgo_crate_sticker_pack")) {
196
+ return "Sticker Capsules";
197
+ } else if (translatedName.startsWith("csgo_crate_patch_pack")) {
198
+ return "Patch Packs";
199
+ } else if (translatedName.match(souvenirRegex)) {
200
+ return "Souvenirs";
201
+ } else if (
202
+ translatedName.startsWith("csgo_crate_community") ||
203
+ translatedName.startsWith("csgo_crate_gamma") ||
204
+ translatedName.startsWith("csgo_crate_valve") ||
205
+ translatedName.startsWith("csgo_crate_esports") ||
206
+ translatedName.startsWith("csgo_crate_operation")
207
+ ) {
208
+ return "Cases";
189
209
  } else if (translatedName.startsWith("csgo_tool_spray")) {
190
- return "graffiti kit";
210
+ return "Graffitis";
191
211
  } else if (translatedName.startsWith("csgo_tool_sticker")) {
192
- return "sticker";
212
+ return "Stickers";
213
+ } else if (translatedName.startsWith("csgo_tool_patch")) {
214
+ return "Patches";
215
+ } else if (translatedName.startsWith("csgo_tool_keychain")) {
216
+ return "Charms";
217
+ } else if (translatedName.startsWith("csgo_customplayer")) {
218
+ return "Agents";
219
+ } else if (translatedName.startsWith("csgo_collectible_pin")) {
220
+ return "Collectible Pins";
221
+ } else if (translatedName.startsWith("coupon_pins")) {
222
+ return "Pins Capsules";
193
223
  }
194
224
  }
195
225
 
196
- return "other";
226
+ if (item.quality === 3) {
227
+ return "Special Items";
228
+ }
229
+
230
+ if (def.prefab !== undefined) {
231
+ let prefab = this.prefabs[def.prefab];
232
+ if (
233
+ prefab !== undefined &&
234
+ prefab.image_inventory !== undefined &&
235
+ prefab.image_inventory.startsWith("econ/weapons/base_weapons")
236
+ ) {
237
+ return "Skins";
238
+ }
239
+ }
240
+
241
+ if (this.getItemName(item).startsWith("Music Kit |")) {
242
+ return "Music Kits";
243
+ }
244
+
245
+ return "Others";
197
246
  }
198
247
 
199
248
  getItemTradable(item) {
@@ -204,11 +253,13 @@ class ItemNameConverter {
204
253
  let translatedName =
205
254
  def.item_name.replace("#", "").toLowerCase() || def.item_name;
206
255
  if (
207
- translatedName.startsWith("csgo_collectible") ||
256
+ (translatedName.startsWith("csgo_collectible") &&
257
+ !translatedName.startsWith("csgo_collectible_pin")) ||
208
258
  translatedName.startsWith("csgo_tournamentpass") ||
209
259
  translatedName.startsWith("csgo_tournamentjournal") ||
210
260
  translatedName.startsWith("csgo_ticket") ||
211
- translatedName.startsWith("csgo_tool_casket_tag")
261
+ translatedName.startsWith("csgo_tool_casket_tag") ||
262
+ translatedName.startsWith("sfui_wpnhud_c4")
212
263
  ) {
213
264
  return false;
214
265
  }
@@ -221,14 +272,6 @@ class ItemNameConverter {
221
272
  return false;
222
273
  }
223
274
 
224
- // Base weapons with stickers/name tags
225
- if (
226
- def.image_inventory !== undefined &&
227
- def.image_inventory.startsWith("econ/weapons/base_weapons")
228
- ) {
229
- return false;
230
- }
231
-
232
275
  // Base weapons with stickers/name tags
233
276
  if (
234
277
  item.paint_index === undefined &&
@@ -239,7 +282,10 @@ class ItemNameConverter {
239
282
  if (
240
283
  prefab !== undefined &&
241
284
  prefab.image_inventory !== undefined &&
242
- prefab.image_inventory.startsWith("econ/weapons/base_weapons")
285
+ prefab.image_inventory.startsWith("econ/weapons/base_weapons") &&
286
+ !prefab.image_inventory.startsWith(
287
+ "econ/weapons/base_weapons/weapon_knife",
288
+ )
243
289
  ) {
244
290
  return false;
245
291
  }
@@ -91,16 +91,12 @@ console.error = (...args) => {
91
91
 
92
92
  if (importInventory) {
93
93
  const inventoryItemCounts = await processInventory();
94
- for (const [itemName, count] of Object.entries(inventoryItemCounts)) {
95
- finalItemCounts[itemName] = (finalItemCounts[itemName] || 0) + count;
96
- }
94
+ mergeItemCounts(finalItemCounts, inventoryItemCounts);
97
95
  }
98
96
 
99
97
  if (importStorageUnits) {
100
98
  const storageUnitItemCounts = await processStorageUnits();
101
- for (const [itemName, count] of Object.entries(storageUnitItemCounts)) {
102
- finalItemCounts[itemName] = (finalItemCounts[itemName] || 0) + count;
103
- }
99
+ mergeItemCounts(finalItemCounts, storageUnitItemCounts);
104
100
  }
105
101
 
106
102
  paddedLog("Saving config...");
@@ -127,7 +123,7 @@ console.error = (...args) => {
127
123
  const convertedItems =
128
124
  nameConverter.convertInventory(prefilteredInventory);
129
125
  const filteredItems = filterItems(convertedItems);
130
- const itemCounts = countItems(filteredItems);
126
+ const itemCounts = groupAndCountItems(filteredItems);
131
127
  paddedLog(`${filteredItems.length} items found in inventory`);
132
128
  console.log(itemCounts);
133
129
  return itemCounts;
@@ -145,10 +141,8 @@ console.error = (...args) => {
145
141
  const items = await getCasketContentsAsync(cs2, unitId);
146
142
  const convertedItems = nameConverter.convertInventory(items);
147
143
  const filteredItems = filterItems(convertedItems);
148
- const itemCounts = countItems(filteredItems);
149
- for (const [itemName, count] of Object.entries(itemCounts)) {
150
- finalItemCounts[itemName] = (finalItemCounts[itemName] || 0) + count;
151
- }
144
+ const itemCounts = groupAndCountItems(filteredItems);
145
+ mergeItemCounts(finalItemCounts, itemCounts);
152
146
  paddedLog(
153
147
  `${filteredItems.length} items found in storage unit: ${unitIndex + 1}/${storageUnitIds.length}`,
154
148
  );
@@ -181,16 +175,32 @@ console.error = (...args) => {
181
175
  }
182
176
 
183
177
  function filterItems(items) {
178
+ const otherItemTypes = [
179
+ "Skins",
180
+ "Special Items",
181
+ "Agents",
182
+ "Charms",
183
+ "Patches",
184
+ "Patch Packs",
185
+ "Souvenirs",
186
+ "Others",
187
+ "Sticker Capsules",
188
+ "Collectible Pins",
189
+ "Pins Capsules",
190
+ "Music Kits",
191
+ ];
184
192
  let filteredItems = [];
193
+
185
194
  items.forEach((item) => {
186
195
  if (!item.item_tradable) {
187
196
  return;
188
197
  }
189
198
  if (
190
- (item.item_type === "case" && importCases) ||
191
- (item.item_type === "sticker capsule" && importStickerCapsules) ||
192
- (item.item_type === "sticker" && importStickers) ||
193
- (item.item_type === "other" && importOthers)
199
+ (item.item_type === "Cases" && importCases) ||
200
+ (item.item_type === "Major Sticker Capsules" &&
201
+ importStickerCapsules) ||
202
+ (item.item_type === "Stickers" && importStickers) ||
203
+ (otherItemTypes.includes(item.item_type) && importOthers)
194
204
  ) {
195
205
  filteredItems.push(item);
196
206
  }
@@ -198,15 +208,39 @@ console.error = (...args) => {
198
208
  return filteredItems;
199
209
  }
200
210
 
201
- function countItems(items) {
202
- let itemCounts = {};
203
- items.forEach((item) => {
204
- if (itemCounts[item.item_name]) {
205
- itemCounts[item.item_name]++;
206
- } else {
207
- itemCounts[item.item_name] = 1;
211
+ function groupAndCountItems(items) {
212
+ let groupedItems = items.reduce((acc, item) => {
213
+ const { item_name, item_type } = item;
214
+
215
+ if (!acc[item_type]) {
216
+ acc[item_type] = {};
208
217
  }
209
- });
210
- return itemCounts;
218
+
219
+ if (!acc[item_type][item_name]) {
220
+ acc[item_type][item_name] = 0;
221
+ }
222
+
223
+ acc[item_type][item_name]++;
224
+ return acc;
225
+ }, {});
226
+
227
+ return groupedItems;
228
+ }
229
+
230
+ function mergeItemCounts(finalItemCounts, currentItemCounts) {
231
+ for (const item_type in currentItemCounts) {
232
+ if (!finalItemCounts[item_type]) {
233
+ finalItemCounts[item_type] = {};
234
+ }
235
+
236
+ for (const item_name in currentItemCounts[item_type]) {
237
+ if (!finalItemCounts[item_type][item_name]) {
238
+ finalItemCounts[item_type][item_name] = 0;
239
+ }
240
+
241
+ finalItemCounts[item_type][item_name] +=
242
+ currentItemCounts[item_type][item_name];
243
+ }
244
+ }
211
245
  }
212
246
  })();
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cs2tracker
3
- Version: 2.1.17
3
+ Version: 2.1.19
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
@@ -76,7 +76,7 @@ Dynamic: license-file
76
76
 
77
77
  Simply download the program and run it:
78
78
 
79
- - [Windows](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-windows.zip)
79
+ - [Windows](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-setup.exe)
80
80
  - [Linux](https://github.com/ashiven/cs2tracker/releases/latest/download/cs2tracker-linux.zip)
81
81
 
82
82
  #### Method 2: Install via Pip
@@ -120,29 +120,30 @@ This will open the config editor where you can change any setting by double clic
120
120
 
121
121
  - Enable **Daily Background Calculations** to automatically run a daily calculation of your investment in the background.
122
122
  - Use **Receive Discord Notifications** to receive a notification on your Discord server whenever the program has finished calculating your investment.
123
- - You need to set up a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) in your Discord server and enter the webhook url into the `discord_webhook_url` field in the config `User Settings`.
123
+ - You need to set up a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) in your Discord server and enter the webhook URL into the `discord_webhook_url` field in the config `User Settings`.
124
124
  - Enable **Proxy Requests** to prevent your requests from being rate limited by the steamcommunity server.
125
125
  - You need to register for a free API key on [Crawlbase](crawlbase.com) and enter it into the `proxy_api_key` field in the config `User Settings`.
126
126
 
127
127
  ## FAQ
128
128
 
129
- **Q: Is it safe to login with my Steam account?**
129
+ - **Q: Is it safe to login with my Steam account?**
130
+ - **A:** Yes, the program uses the [SteamUser](https://github.com/DoctorMcKay/node-steam-user?tab=readme-ov-file#methods-) and [Globaloffensive](https://github.com/DoctorMcKay/node-globaloffensive) libraries to sign in and import your Storage Units (the same method is used by [casemove](https://github.com/nombersDev/casemove)) and all of the login-related code is transparently available in [this file](cs2tracker/data/get_inventory.js).
130
131
 
131
- **A:** Yes, the program uses the [SteamUser](https://github.com/DoctorMcKay/node-steam-user?tab=readme-ov-file#methods-) and [Globaloffensive](https://github.com/DoctorMcKay/node-globaloffensive) libraries to sign in and import your Storage Units (the same method is used by [casemove](https://github.com/nombersDev/casemove)) and all of the login-related code is transparently available in [this file](cs2tracker/data/get_inventory.js).
132
132
 
133
+ - **Q: Do I have to login with my Steam account?**
134
+ - **A:** No, you can also manually specify the number of items you own in the config editor.
133
135
 
134
- **Q: Do I have to login with my Steam account?**
135
136
 
136
- **A:** No, you can also manually specify the number of items you own in the config editor.
137
+ - **Q: Can I get VAC-banned for using this program?**
138
+ - **A:** No, this program does not interact with the game in any way and only reads your Storage Units.
137
139
 
138
140
 
139
- **Q: Can I get VAC-banned for using this program?**
140
-
141
- **A:** No, this program does not interact with the game in any way and only reads your Storage Units.
141
+ - **Q: Why does Windows Defender flag this program as potentially harmful?**
142
+ - **A:** This is because the program is not signed with a [Code Signing Certificate](https://www.globalsign.com/en/code-signing-certificate/what-is-code-signing-certificate), which Windows uses to verify the identity of publishers. These certificates are very expensive and not something I am willing to invest in for a free and open source project like this.
142
143
 
143
144
  ## Contributing
144
145
 
145
- Please feel free to submit a pull request or open an issue. See [issues](https://github.com/ashiven/cs2tracker/issues) and [pull requests](https://github.com/ashiven/cs2tracker/pulls) for current work.
146
+ Please feel free to submit a [pull request](https://github.com/ashiven/cs2tracker/pulls) or open an [issue](https://github.com/ashiven/cs2tracker/issues).
146
147
 
147
148
  1. Fork the repository
148
149
  2. Create a new branch: `git checkout -b feature-name`.
@@ -5,11 +5,14 @@
5
5
  .pylintrc
6
6
  LICENSE
7
7
  MANIFEST.in
8
+ Makefile
8
9
  README.md
9
10
  pyproject.toml
10
11
  requirements.txt
11
12
  setup.cfg
13
+ setup.iss
12
14
  assets/demo.gif
15
+ assets/icon.ico
13
16
  assets/icon.png
14
17
  cs2tracker/__init__.py
15
18
  cs2tracker/__main__.py
@@ -0,0 +1,42 @@
1
+ #define MyAppName "CS2Tracker"
2
+ #define MyAppVersion "latest"
3
+ #define MyAppPublisher "Jannik Novak"
4
+ #define MyAppURL "https://github.com/ashiven"
5
+ #define MyAppExeName "cs2tracker.exe"
6
+
7
+ [Setup]
8
+ AppId={{B3CA78AD-7671-4DF3-9FB3-5EDCA729E689}
9
+ AppName={#MyAppName}
10
+ AppVersion={#MyAppVersion}
11
+ AppPublisher={#MyAppPublisher}
12
+ AppPublisherURL={#MyAppURL}
13
+ AppSupportURL={#MyAppURL}
14
+ AppUpdatesURL={#MyAppURL}
15
+ DefaultDirName={autopf}\{#MyAppName}
16
+ UninstallDisplayIcon={app}\{#MyAppExeName}
17
+ ArchitecturesAllowed=x64compatible
18
+ ArchitecturesInstallIn64BitMode=x64compatible
19
+ DisableProgramGroupPage=yes
20
+ LicenseFile=LICENSE
21
+ PrivilegesRequired=lowest
22
+ OutputBaseFilename=cs2tracker-setup
23
+ SetupIconFile=assets\icon.ico
24
+ SolidCompression=yes
25
+ WizardStyle=modern
26
+
27
+ [Languages]
28
+ Name: "english"; MessagesFile: "compiler:Default.isl"
29
+
30
+ [Tasks]
31
+ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
32
+
33
+ [Files]
34
+ Source: "dist\cs2tracker\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
35
+ Source: "dist\cs2tracker\_internal\*"; DestDir: "{app}\_internal"; Flags: ignoreversion recursesubdirs createallsubdirs
36
+
37
+ [Icons]
38
+ Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
39
+ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
40
+
41
+ [Run]
42
+ Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes