Skip to content

Commit 4c9a41e

Browse files
authored
rewrite (#4)
1 parent 7a526e9 commit 4c9a41e

26 files changed

+14785
-309
lines changed

.github/workflows/publish.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Upload Python Package
2+
on:
3+
release:
4+
types: [published]
5+
jobs:
6+
pypi:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Checkout
10+
uses: actions/checkout@v3
11+
with:
12+
fetch-depth: 0
13+
- run: python3 -m pip install --upgrade build && python3 -m build
14+
- name: Publish package
15+
uses: pypa/gh-action-pypi-publish@release/v1
16+
with:
17+
password: ${{ secrets.PYPI_API_TOKEN }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.vscode
2+
__pycache__
3+
/*.json
4+
jsons

README.md

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,95 @@
1-
# tf2-utils
2-
3-
```
4-
pip install tf2utils
5-
```
1+
# tf2-utils
2+
[![License](https://img.shields.io/github/license/offish/tf2-utils.svg)](https://github.com/offish/tf2-utils/blob/master/LICENSE)
3+
[![Stars](https://img.shields.io/github/stars/offish/tf2-utils.svg)](https://github.com/offish/tf2-utils/stargazers)
4+
[![Issues](https://img.shields.io/github/issues/offish/tf2-utils.svg)](https://github.com/offish/tf2-utils/issues)
5+
[![Size](https://img.shields.io/github/repo-size/offish/tf2-utils.svg)](https://github.com/offish/tf2-utils)
6+
[![Discord](https://img.shields.io/discord/467040686982692865?color=7289da&label=Discord&logo=discord)](https://discord.gg/t8nHSvA)
7+
[![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
8+
9+
Tools and utilities for TF2 trading. Use 3rd party inventory providers, get SKUs directly from inventories, listen to BackpackTF's websocket and more.
10+
11+
## Donate
12+
- BTC: `bc1qntlxs7v76j0zpgkwm62f6z0spsvyezhcmsp0z2`
13+
- [Steam Trade Offer](https://steamcommunity.com/tradeoffer/new/?partner=293059984&token=0-l_idZR)
14+
15+
## Usage
16+
17+
### Inventory fetching
18+
```python
19+
from tf2_utils import Inventory
20+
21+
# using 3rd party provider to avoid being rate-limited
22+
provider = Inventory("steamsupply", "9st947vs0qmgfpeqde1gj92l0oqmhysm")
23+
24+
# using steam as inventory provider
25+
provider = Inventory() # or Inventory("steamcommunity")
26+
27+
# get an inventory
28+
inventory = provider.fetch("76561198253325712")
29+
```
30+
31+
### Gettings SKUs from inventories
32+
**NOTE: NOT ALL SKU ATTRIBUTES ARE ADDED YET**
33+
#### Get SKUs implicitly
34+
```python
35+
from tf2_utils import Inventory, map_inventory
36+
37+
provider = Inventory("steamcommunity")
38+
39+
user_inventory = provider.fetch("76561198253325712")
40+
inventory = map_inventory(user_inventory, add_skus=True)
41+
```
42+
43+
#### Get a particular item's SKU
44+
```python
45+
from tf2_utils import get_sku
46+
47+
inventory = map_inventory(user_inventory)
48+
49+
for item in inventory:
50+
sku = get_sku(item)
51+
```
52+
53+
### BackpackTF Websocket
54+
#### Handle one listing at a time
55+
```python
56+
from tf2_utils import BackpackTFWebsocket
57+
58+
def my_function(data: dict):
59+
print("got data!", data)
60+
61+
socket = BackpackTFWebsocket(my_function)
62+
63+
socket.listen()
64+
```
65+
66+
#### Handle list of listings at a time
67+
```python
68+
from tf2_utils import BackpackTFWebsocket
69+
70+
def my_function(data: list[dict]):
71+
print("got listings")
72+
73+
for listing in data:
74+
print("listing", listing)
75+
76+
socket = BackpackTFWebsocket(my_function, solo_entries=False)
77+
78+
socket.listen()
79+
```
80+
81+
## Setup
82+
### Install
83+
```bash
84+
pip install tf2-utils
85+
# or
86+
python -m pip install tf2-utils
87+
```
88+
89+
### Upgrade
90+
```bash
91+
pip upgrade tf2-utils
92+
# or
93+
python -m pip upgrade tf2-utils
94+
```
95+

pyproject.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[build-system]
2+
requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "tf2-utils"
7+
authors = [
8+
{ name="offish", email="overutilization@gmail.com" },
9+
]
10+
description = "Tools and utilities for TF2 trading"
11+
readme = "README.md"
12+
requires-python = ">=3.7"
13+
keywords = ["tf2", "utils", "sku"]
14+
classifiers = [
15+
"Programming Language :: Python :: 3",
16+
"License :: OSI Approved :: MIT License",
17+
"Operating System :: OS Independent",
18+
]
19+
dependencies = ["tf2-sku", "requests", "websocket-client"]
20+
dynamic = ["version"]
21+
22+
[project.urls]
23+
"Homepage" = "https://github.com/offish/tf2-utils"
24+
"Bug Tracker" = "https://github.com/offish/tf2-utils/issues"
25+
26+
[tool.setuptools_scm]

setup.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,3 @@
1-
import setuptools
1+
from setuptools import setup
22

3-
with open("README.md", "r") as fh:
4-
long_description = fh.read()
5-
6-
setuptools.setup(
7-
name="tf2utils",
8-
version="1.0.0",
9-
author="offish",
10-
author_email="overutilization@gmail.com",
11-
description="Easily interact with multiple APIs associated with Team Fortress 2",
12-
long_description=long_description,
13-
long_description_content_type="text/markdown",
14-
url="https://github.com/offish/tf2utils",
15-
packages=setuptools.find_packages(),
16-
classifiers=[
17-
"Programming Language :: Python :: 3",
18-
"License :: OSI Approved :: MIT License",
19-
"Operating System :: OS Independent",
20-
],
21-
python_requires='>=3.7',
22-
)
3+
setup()

src/tf2_utils/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
__title__ = "tf2-utils"
2+
__author__ = "offish"
3+
__version__ = "1.0.0"
4+
__license__ = "MIT"
5+
6+
from .schema import Schema, IEconItems
7+
from .inventory import Inventory, map_inventory
8+
from .sku import get_sku, get_sku_properties
9+
from .utils import to_refined, to_scrap, refinedify
10+
from .backpack_tf import BackpackTFWebsocket

src/tf2_utils/backpack_tf.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import json
2+
3+
from websockets.sync.client import connect
4+
5+
6+
class BackpackTFWebsocket:
7+
URL = "wss://ws.backpack.tf/events"
8+
9+
def __init__(
10+
self,
11+
callback,
12+
solo_entries: bool = True,
13+
headers: dict = {"batch-test": True},
14+
max_size: int | None = None,
15+
settings: dict = {},
16+
) -> None:
17+
"""
18+
:param callback: Function pointer where you want the data to end up
19+
20+
:param solo_entries: If data to callback should be solo entries or a batched list
21+
:type solo_entries: bool
22+
:param headers: Additional headers to send to the socket
23+
:type headers: dict
24+
:param settings: Additional websocket settings as a dict to be unpacked
25+
:type settings: dict
26+
"""
27+
self.callback = callback
28+
self.solo_entries = solo_entries
29+
self.headers = headers
30+
self.max_size = max_size
31+
self.settings = settings
32+
33+
def process_messages(self, data: str) -> None:
34+
messages = json.loads(data)
35+
36+
if not self.solo_entries:
37+
self.callback(messages)
38+
return
39+
40+
for message in messages:
41+
payload = message["payload"]
42+
self.callback(payload)
43+
44+
def listen(self) -> None:
45+
"""Listen for messages from BackpackTF"""
46+
with connect(
47+
self.URL,
48+
additional_headers=self.headers,
49+
max_size=self.max_size,
50+
**self.settings,
51+
) as websocket:
52+
while True:
53+
data = websocket.recv()
54+
self.process_messages(data)

src/tf2_utils/inventory.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from .providers.steamcommunity import SteamCommunity
2+
from .providers.steamsupply import SteamSupply
3+
from .providers.steamapis import SteamApis
4+
from .sku import get_sku
5+
6+
import requests
7+
8+
9+
def map_inventory(inventory: dict, add_skus: bool = False) -> list[dict]:
10+
"""Matches classids and instanceids, merges these and
11+
adds `sku` to each item entry if `add_skus` is enabled"""
12+
mapped_inventory = []
13+
14+
for asset in inventory["assets"]:
15+
for desc in inventory["descriptions"]:
16+
if (
17+
desc["tradable"] != 1
18+
or asset["classid"] != desc["classid"]
19+
or asset["instanceid"] != desc["instanceid"]
20+
):
21+
continue
22+
23+
# ok, match
24+
if add_skus:
25+
mapped_inventory.append({"sku": get_sku(desc), **asset, **desc})
26+
else:
27+
mapped_inventory.append({**asset, **desc})
28+
break
29+
30+
return mapped_inventory
31+
32+
33+
class Inventory:
34+
PROVIDERS = [SteamSupply, SteamApis]
35+
36+
def __init__(
37+
self, provider_name: str = "steamcommunity", api_key: str = ""
38+
) -> None:
39+
# set default provider for intellisense
40+
self.provider = SteamCommunity()
41+
42+
# default to steam if no api_key is given
43+
if not api_key:
44+
return
45+
46+
if provider_name == "steamcommunity":
47+
# already set
48+
return
49+
50+
# loop through providers create object
51+
for i in self.PROVIDERS:
52+
if provider_name.lower() == i.__name__.lower():
53+
# set the first found provider and then stop
54+
self.provider = i(api_key)
55+
break
56+
57+
def fetch(self, steam_id: str, app_id: int = 440, context_id: int = 2) -> dict:
58+
url, params = self.provider.get_url_and_params(steam_id, app_id, context_id)
59+
response = requests.get(url, params=params)
60+
61+
try:
62+
return response.json()
63+
except:
64+
return {}

0 commit comments

Comments
 (0)