Skip to content

v2.2.0 #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add mplc and new sku features
  • Loading branch information
offish committed Mar 20, 2024
commit 735d94b72b17e6f3dd04e61c08d7b4425e5805c4
6 changes: 3 additions & 3 deletions src/tf2_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# flake8: noqa
__title__ = "tf2-utils"
__author__ = "offish"
__version__ = "2.1.2"
__version__ = "2.1.3"
__license__ = "MIT"

from .sku import (
Expand Down Expand Up @@ -38,5 +39,4 @@
)
from .inventory import Inventory, map_inventory
from .currency import CurrencyExchange

# flake8: noqa
from .marketplace_tf import SKUDoesNotMatch, MarketplaceTF
3 changes: 2 additions & 1 deletion src/tf2_utils/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ def is_unusual_cosmetic(self) -> bool:
return self.is_unusual() and self.is_cosmetic()

def is_australium(self) -> bool:
return "Australium" in self.name
# strange eliminates australium paint
return "Australium" in self.name and self.is_strange()

def is_pure(self) -> bool:
return (
Expand Down
108 changes: 108 additions & 0 deletions src/tf2_utils/marketplace_tf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from .schema import SchemaItemsUtils
from .sku import sku_to_quality_name, sku_is_craftable

import requests


class SKUDoesNotMatch(Exception):
pass


class MarketplaceTF:
def __init__(self):
self.schema = SchemaItemsUtils()
self.data = {}

@staticmethod
def _format_url(item_name: str, quality: str, craftable: bool) -> str:
url = "https://api.backpack.tf/item/get_third_party_prices/"
craftable = "Craftable" if craftable else "Non-Craftable"

return f"{url}/{quality}/{item_name}/Tradable/{craftable}"

def _format_url_sku(self, sku: str) -> str:
item_name = self.schema.sku_to_base_name(sku)
quality = sku_to_quality_name(sku)

return self._format_url(item_name, quality, sku_is_craftable(sku))

@staticmethod
def _format_price_to_float(price: str) -> float:
return float(price.replace("$", ""))

def _set_data(self, data: dict) -> None:
self.data = data["prices"]["mp"]

def fetch_item_raw(self, item_name: str, quality: str, craftable: bool) -> dict:
url = self._format_url(item_name, quality, craftable)
self._set_data(requests.get(url).json())

return self.data

def fetch_item(self, sku: str) -> dict:
url = self._format_url_sku(sku)
self._set_data(requests.get(url).json())
mptf_sku = self.get_sku()

if mptf_sku != sku:
raise SKUDoesNotMatch(f"SKU {sku} does not match {mptf_sku}")

return self.data

def get_item_data(self) -> dict:
return self.data

def get_lowest_price(self) -> float:
price = self.data.get("lowest_price")

if price is None:
return 0.0

return self._format_price_to_float(price)

def get_price(self) -> float:
return self.get_lowest_price()

def get_highest_buy_order(self) -> float:
price = self.data.get("highest_buy_order")

if price is None:
return 0.0

return self._format_price_to_float(price)

def get_buy_order(self) -> float:
return self.get_highest_buy_order()

def get_stock(self) -> int:
return self.data.get("num_for_sale", 0)

def get_sku(self) -> str:
return self.data.get("sku", "")

def fetch_lowest_price(self, sku: str) -> float:
price = self.fetch_item_data(sku).get("lowest_price")

if price is None:
return 0.0

return self._format_price_to_float(price)

def fetch_price(self, sku: str) -> float:
return self.fetch_lowest_price(sku)

def fetch_highest_buy_order(self, sku: str) -> float:
price = self.fetch_item_data(sku).get("highest_buy_order")

if price is None:
return 0.0

return self._format_price_to_float(price)

def fetch_buy_order(self, sku: str) -> float:
return self.fetch_highest_buy_order(sku)

def fetch_stock(self, sku: str) -> int:
return self.fetch_item_data(sku).get("num_for_sale", 0)

# {"prices":{"mp":{"sku":"357;6;kt-2","lowest_price":"$1.85","num_for_sale":5}}}
54 changes: 48 additions & 6 deletions src/tf2_utils/schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from .sku import sku_to_defindex

from tf2_data import SchemaItems
from .sku import (
sku_to_defindex,
sku_to_quality_name,
sku_is_uncraftable,
get_sku_effect,
get_sku_killstreak,
strange_in_sku,
)

from tf2_data import SchemaItems, EFFECTS, KILLSTREAKS
from tf2_sku import to_sku


Expand Down Expand Up @@ -131,8 +138,43 @@ def name_to_sku(self, name: str) -> str:

return to_sku(sku_properties)

def sku_to_name(self, sku: str) -> str:
def sku_to_base_name(self, sku: str) -> str:
defindex = sku_to_defindex(sku)
# TODO: add qualities and uncraftable here
# "reverse" name_to_sku
return self.defindex_to_name(defindex)

def sku_to_name(self, sku: str, use_uncraftable: bool = True) -> str:
name = self.sku_to_base_name(sku)
craftable = ""
quality = sku_to_quality_name(sku)
effect = get_sku_effect(sku)
killstreak = get_sku_killstreak(sku)
strange = strange_in_sku(sku)

if quality not in ["Unusual", "Unique"]:
quality += " "
else:
quality = ""

if effect != -1:
effect = EFFECTS[str(effect)] + " "

if killstreak != -1:
killstreak = KILLSTREAKS[str(killstreak)] + " "

if strange:
strange = "Strange "

if sku_is_uncraftable(sku):
if use_uncraftable:
craftable = "Uncraftable "
else:
craftable = "Non-Craftable "

# TODO: add killstreaks and other properties (strange unusual etc.)
# festive
# festivzed
# wear

return "".join(
[killstreak, strange, festive, festivized, craftable, quality, name, wear]
)
73 changes: 54 additions & 19 deletions src/tf2_utils/sku.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .item import Item

from tf2_data import EFFECTS, COLORS
from tf2_data import EFFECTS, COLORS, QUALITIES
from tf2_sku import to_sku


Expand All @@ -11,7 +11,6 @@ def get_sku_properties(item: Item | dict) -> dict:
quality = item.get_quality_id()
effect = item.get_effect()

# TODO: add rest
sku_properties = {
"defindex": item.get_defindex(),
"quality": quality,
Expand All @@ -20,21 +19,14 @@ def get_sku_properties(item: Item | dict) -> dict:
"wear": item.get_exterior_id(),
"killstreak_tier": item.get_killstreak_id(),
"festivized": item.is_festivized(),
#
# "effect": "u{}",
# "australium": "australium",
# "craftable": "uncraftable",
# "wear": "w{}",
# "skin": "pk{}",
# "strange": "strange",
# "killstreak_tier": "kt-{}",
# "target_defindex": "td-{}",
# "festivized": "festive",
# "craft_number": "n{}",
# "crate_number": "c{}",
# "output_defindex": "od-{}",
# "output_quality": "oq-{}",
}
# TODO: add rest
# "skin": "pk{}",
# "target_defindex": "td-{}",
# "craft_number": "n{}",
# "crate_number": "c{}",
# "output_defindex": "od-{}",
# "output_quality": "oq-{}",

if effect:
sku_properties["effect"] = EFFECTS[effect]
Expand Down Expand Up @@ -75,10 +67,23 @@ def get_metal(sku: str) -> int:
return 1


def get_property(sku: str, index: int) -> str:
def get_properties(sku: str) -> list[str]:
assert is_sku(sku), f"sku {sku} is not valid"

return sku.split(";")[index]
return sku.split(";")


def get_property(sku: str, index: int) -> str:
return get_sku_properties(sku)[index]


def get_property_by_key(sku: str, key: str) -> str:
for p in get_properties(sku):
# so n{} does not match with strange etc.
if f";{key}" in f";{p}":
return p

return ""


def sku_to_defindex(sku: str) -> int:
Expand All @@ -89,12 +94,42 @@ def sku_to_quality(sku: str) -> int:
return int(get_property(sku, 1))


def sku_to_quality_name(sku: str) -> str:
return QUALITIES[str(sku_to_quality(sku))]


def sku_to_color(sku: str) -> str:
return COLORS[str(sku_to_quality(sku))]


def sku_is_craftable(sku: str) -> bool:
return ";uncraftable" in sku


def sku_is_uncraftable(sku: str) -> bool:
return sku.find(";uncraftable") != -1
return not sku_is_craftable(sku)


def strange_in_sku(sku: str) -> bool:
return ";strange" in sku


def get_sku_killstreak(sku: str) -> int:
value = get_property_by_key(sku, "kt-")

if not value:
return -1

return int(value.replace("kt-", ""))


def get_sku_effect(sku: str) -> int:
value = get_property_by_key(sku, "u")

if not value:
return -1

return int(value.replace("u", ""))


def get_sku(item: Item | dict) -> str:
Expand Down