diff --git a/README.md b/README.md index e1f0b6a..784c1a1 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Tools and utilities for TF2 trading. Use 3rd party inventory providers, get SKUs * Uses [tf2-sku](https://github.com/offish/tf2-sku) * Uses [tf2-data](https://github.com/offish/tf2-data) * Get SKUs directly from inventories/offers +* Convert name to SKU and vice versa * Fetch inventories using 3rd party providers (avoid being rate-limited) * Listen for Backpack.TF websocket events * Listen for Prices.TF websocket events @@ -23,7 +24,6 @@ Tools and utilities for TF2 trading. Use 3rd party inventory providers, get SKUs * Get item properties (`is_craft_hat`, `get_paint`, `get_effect` etc.) * Fetch TF2 Schema data * Convert SKU/defindex to item image URL -* Convert name to SKU * Calculate scrap and refined prices ## Setup diff --git a/src/tf2_utils/__init__.py b/src/tf2_utils/__init__.py index 2ea9c7a..53878e2 100644 --- a/src/tf2_utils/__init__.py +++ b/src/tf2_utils/__init__.py @@ -1,13 +1,13 @@ __title__ = "tf2-utils" __author__ = "offish" -__version__ = "2.0.3" +__version__ = "2.0.5" __license__ = "MIT" -from .schema import SchemaItems, IEconItems -from .inventory import Inventory, map_inventory -from .sku import get_sku, get_sku_properties +from .sku import get_sku, get_sku_properties, sku_to_defindex +from .item import Item +from .offer import Offer from .utils import to_refined, to_scrap, refinedify, account_id_to_steam_id +from .schema import SchemaItemsUtils from .sockets import BackpackTFSocket, PricesTFSocket from .prices_tf import PricesTF -from .item import Item -from .offer import Offer +from .inventory import Inventory, map_inventory diff --git a/src/tf2_utils/schema.py b/src/tf2_utils/schema.py index 1b49936..ebc50b3 100644 --- a/src/tf2_utils/schema.py +++ b/src/tf2_utils/schema.py @@ -1,20 +1,50 @@ -import time +from .sku import sku_to_defindex from tf2_data import SchemaItems from tf2_sku import to_sku -import requests -class SchemaItems(SchemaItems): +class SchemaItemsUtils(SchemaItems): def __init__( self, schema_items: str | list[dict] = "", defindex_names: str | dict = "" ) -> None: super().__init__(schema_items, defindex_names) - def defindex_to_image_url(self, defindex: int, large: bool = False) -> str: - if isinstance(defindex, str): - defindex = int(defindex) + def defindex_to_name(self, defindex: int) -> str: + return self.defindex_names.get(defindex, "") + + def name_to_defindex(self, name: str) -> int: + if name == "Random Craft Weapon": + return -50 + + if name == "Random Craft Hat": + return -100 + + defindexes = self.defindex_names.get(name, []) + + if not defindexes: + return -1 + + has_multiple_defindexes = len(defindexes) != 1 + + if not has_multiple_defindexes: + return defindexes[0] + + last_index = len(defindexes) - 1 + # could be first or last defindex + match name: + case "Mann Co. Supply Crate Key": + return defindexes[0] + + case "Name Tag": + return defindexes[last_index] + + case _: + # use first defindex as default + return defindexes[0] + + def defindex_to_image_url(self, defindex: int, large: bool = False) -> str: # random craft weapon => shotgun if defindex == -50: defindex = 9 @@ -32,7 +62,7 @@ def defindex_to_image_url(self, defindex: int, large: bool = False) -> str: return "" def sku_to_image_url(self, sku: str, large: bool = False) -> str: - defindex = sku.split(";")[:-1][0] + defindex = sku_to_defindex(sku) return self.defindex_to_image_url(defindex, large) def name_to_sku(self, name: str) -> str: @@ -57,10 +87,25 @@ def name_to_sku(self, name: str) -> str: case "Strange": quality = 11 + case "Haunted": + quality = 13 + + case "Collector's": + quality = 14 + defindex_name = name while True: - defindex = self.defindex_names.get(defindex_name, -1) + # try whole name, then remove everything till the + # first space for each iteration if defindex + # for that name doesnt exist + + # example: + # Uncraftable Strange Team Captain => -1 + # Strange Team Captain => -1 + # Team Captain => 378 != -1, so break + + defindex = self.name_to_defindex(defindex_name) if defindex != -1: break @@ -80,53 +125,6 @@ def name_to_sku(self, name: str) -> str: return to_sku(sku_properties) - -class IEconItems: - API_URL = "https://api.steampowered.com/IEconItems_440" - SCHEMA_OVERVIEW = API_URL + "/GetSchemaOverview/v0001" - PLAYER_ITEMS = API_URL + "/GetPlayerItems/v0001" - SCHEMA_ITEMS = API_URL + "/GetSchemaItems/v1" - STORE_DATA = API_URL + "/GetStoreMetaData/v1" - SCHEMA_URL = API_URL + "/GetSchemaURL/v1" - - def __init__(self, api_key: str) -> None: - self.api_key = api_key - - def __get(self, url: str, params: dict = {}) -> dict: - params["key"] = self.api_key - - res = requests.get(url, params=params) - - try: - return res.json() - except: - return {} - - def get_player_items(self, steamid: str) -> dict: - return self.__get(self.PLAYER_ITEMS, {"steamid": steamid}) - - def get_schema_items(self, start: int = 0, language: str = "en") -> dict: - return self.__get( - self.SCHEMA_ITEMS, {"language": language.lower(), "start": start} - ) - - def get_all_schema_items(self, language: str = "en", sleep: float = 5.0) -> list: - items = [] - start = 0 - - while start is not None: - response = self.get_schema_items(start, language=language)["result"] - items += response.get("items", []) - start = response.get("next") # None if not found - time.sleep(sleep) - - return items - - def get_schema_overview(self, language: str = "en") -> dict: - return self.__get(self.SCHEMA_OVERVIEW, {"language": language.lower()}) - - def get_schema_url(self) -> dict: - return self.__get(self.SCHEMA_URL, {}) - - def get_store_meta_data(self, language: str = "en") -> dict: - return self.__get(self.STORE_DATA, {"language": language.lower()}) + def sku_to_name(self, sku: str) -> str: + defindex = sku_to_defindex(sku) + return self.defindex_to_name(defindex) diff --git a/src/tf2_utils/sku.py b/src/tf2_utils/sku.py index c4490d4..2a7d499 100644 --- a/src/tf2_utils/sku.py +++ b/src/tf2_utils/sku.py @@ -46,6 +46,10 @@ def get_sku_properties(item: Item | dict) -> dict: return sku_properties +def sku_to_defindex(sku: str) -> int: + return int(sku.split(";")[:-1][0]) + + def get_sku(item: Item | dict) -> str: if isinstance(item, dict): item = Item(item) diff --git a/tests/test_schema.py b/tests/test_schema.py new file mode 100644 index 0000000..45852c6 --- /dev/null +++ b/tests/test_schema.py @@ -0,0 +1,70 @@ +from src.tf2_utils import SchemaItemsUtils + +from unittest import TestCase + + +schema_items = SchemaItemsUtils() # uses local files by default + + +class TestUtils(TestCase): + def test_map_defindex_names(self): + response = schema_items.map_defindex_name() + self.assertNotEqual({}, response) + + def test_name_to_sku_tod(self): + sku = schema_items.name_to_sku("Uncraftable Tour of Duty Ticket") + self.assertEqual("725;6;uncraftable", sku) + + def test_name_to_sku_key(self): + sku = schema_items.name_to_sku("Mann Co. Supply Crate Key") + self.assertEqual("5021;6", sku) + + def test_name_to_sku_name_tag(self): + sku = schema_items.name_to_sku("Name Tag") + self.assertEqual("5020;6", sku) + + def test_name_to_sku_pure(self): + ref = schema_items.name_to_sku("Refined Metal") + rec = schema_items.name_to_sku("Reclaimed Metal") + scrap = schema_items.name_to_sku("Scrap Metal") + + self.assertEqual("5002;6", ref) + self.assertEqual("5001;6", rec) + self.assertEqual("5000;6", scrap) + + def test_name_to_sku_non_existing(self): + # this item does not exist + item_name = "Non-Craftable Strange Team Captain" + sku = schema_items.name_to_sku(item_name) + defindex = schema_items.name_to_defindex(item_name) + + self.assertEqual("378;11;uncraftable", sku) + self.assertEqual(-1, defindex) + + def test_name_to_sku_qualities(self): + unique = schema_items.name_to_sku("Team Captain") + genuine = schema_items.name_to_sku("Genuine Team Captain") + haunted = schema_items.name_to_sku("Haunted Team Captain") + strange = schema_items.name_to_sku("Strange Team Captain") + vintage = schema_items.name_to_sku("Vintage Team Captain") + collectors = schema_items.name_to_sku("Collector's Team Captain") + + self.assertEqual("378;1", genuine) + self.assertEqual("378;3", vintage) + self.assertEqual("378;6", unique) + self.assertEqual("378;11", strange) + self.assertEqual("378;13", haunted) + self.assertEqual("378;14", collectors) + + def test_sku_to_name_tod(self): + name = schema_items.sku_to_name("725;6;uncraftable") + self.assertEqual("Tour of Duty Ticket", name) + + def test_sku_to_name_key(self): + name = schema_items.sku_to_name("5021;6") + self.assertEqual("Mann Co. Supply Crate Key", name) + + def test_image_equal(self): + ellis_cap = schema_items.defindex_to_image_url(263) + random_craft_hat = schema_items.sku_to_image_url("-100;6") + self.assertEqual(ellis_cap, random_craft_hat)