mrkts 0.2.0__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.
- mrkts-0.2.0/LICENSE +21 -0
- mrkts-0.2.0/PKG-INFO +269 -0
- mrkts-0.2.0/README.md +241 -0
- mrkts-0.2.0/mrkts/__init__.py +6 -0
- mrkts-0.2.0/mrkts/auth.py +12 -0
- mrkts-0.2.0/mrkts/client.py +145 -0
- mrkts-0.2.0/mrkts/market/client.py +11 -0
- mrkts-0.2.0/mrkts/market/gifts.py +195 -0
- mrkts-0.2.0/mrkts/market/offers.py +29 -0
- mrkts-0.2.0/mrkts/market/orders.py +155 -0
- mrkts-0.2.0/mrkts/pool.py +101 -0
- mrkts-0.2.0/mrkts/steam/client.py +56 -0
- mrkts-0.2.0/mrkts/steam/cs2/client.py +10 -0
- mrkts-0.2.0/mrkts/steam/cs2/offers.py +5 -0
- mrkts-0.2.0/mrkts/steam/cs2/orders.py +5 -0
- mrkts-0.2.0/mrkts/steam/cs2/skins.py +285 -0
- mrkts-0.2.0/mrkts/user.py +54 -0
- mrkts-0.2.0/mrkts/utils.py +75 -0
- mrkts-0.2.0/mrkts.egg-info/PKG-INFO +269 -0
- mrkts-0.2.0/mrkts.egg-info/SOURCES.txt +23 -0
- mrkts-0.2.0/mrkts.egg-info/dependency_links.txt +1 -0
- mrkts-0.2.0/mrkts.egg-info/requires.txt +7 -0
- mrkts-0.2.0/mrkts.egg-info/top_level.txt +1 -0
- mrkts-0.2.0/pyproject.toml +45 -0
- mrkts-0.2.0/setup.cfg +4 -0
mrkts-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aiofake
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mrkts-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mrkts
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Asynchronous Python client for the MRKT API
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/aiofake/mrkts
|
|
7
|
+
Project-URL: Repository, https://github.com/aiofake/mrkts
|
|
8
|
+
Project-URL: Issues, https://github.com/aiofake/mrkts/issues
|
|
9
|
+
Keywords: telegram,markets,sdk,mrkt
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
22
|
+
Requires-Dist: kurigram
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
26
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# MRKT Python Client
|
|
30
|
+
|
|
31
|
+
An asynchronous Python library for the [MRKT](https://t.me/mrkt) API.
|
|
32
|
+
`MrktClient` provides the main transport, while the API is organized into
|
|
33
|
+
separate Market, Steam, and User classes. These API classes can be used with
|
|
34
|
+
the main client or directly with a custom HTTP transport.
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- Access token and Telegram session authentication
|
|
39
|
+
- Market methods for gifts, orders, and offers
|
|
40
|
+
- Steam methods, including CS2
|
|
41
|
+
- User profile, balance, and transaction methods
|
|
42
|
+
- Raw requests through the available HTTP session
|
|
43
|
+
- Concurrent multi-account operations with `MrktPool`
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
Python 3.10 or newer is required.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python -m pip install mrkts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The importable module is named `mrkts`.
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
The client and its API modules are asynchronous. Provide an access token and
|
|
58
|
+
list the modules you need in `preload`:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import asyncio
|
|
62
|
+
|
|
63
|
+
from mrkts import MrktClient
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
async def main() -> None:
|
|
67
|
+
async with MrktClient(
|
|
68
|
+
token="YOUR_ACCESS_TOKEN",
|
|
69
|
+
preload=("market", "user"),
|
|
70
|
+
) as client:
|
|
71
|
+
gifts = await client.market.gifts.collections()
|
|
72
|
+
profile = await client.user.me()
|
|
73
|
+
print(gifts)
|
|
74
|
+
print(profile)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
asyncio.run(main())
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`preload` is empty by default. Available values are `"market"`, `"steam"`, and
|
|
81
|
+
`"user"`. Use `client.steam` for Steam methods; CS2 methods are available under
|
|
82
|
+
`client.steam.cs2`, for example `client.steam.cs2.skins`.
|
|
83
|
+
|
|
84
|
+
The HTTP session is created when entering `async with` or calling
|
|
85
|
+
`await client.start()`, and is closed when exiting the context. If you do not
|
|
86
|
+
use the context manager, make sure to call `await client.close()`.
|
|
87
|
+
|
|
88
|
+
## Authentication
|
|
89
|
+
|
|
90
|
+
### Access Token
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
async with MrktClient(
|
|
94
|
+
token="YOUR_ACCESS_TOKEN",
|
|
95
|
+
preload=("market",),
|
|
96
|
+
) as client:
|
|
97
|
+
listings = await client.market.gifts.saling(count=10)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Telegram Session
|
|
101
|
+
|
|
102
|
+
To authenticate with a Telegram session, install the project dependencies and
|
|
103
|
+
provide the session name and the directory containing the session files:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import asyncio
|
|
107
|
+
|
|
108
|
+
from mrkts import MrktClient
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
async def main() -> None:
|
|
112
|
+
client = await MrktClient.session(
|
|
113
|
+
"my_telegram_session",
|
|
114
|
+
workdir=".",
|
|
115
|
+
preload=("user",),
|
|
116
|
+
)
|
|
117
|
+
async with client:
|
|
118
|
+
print(await client.user.me())
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
asyncio.run(main())
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## API Methods
|
|
125
|
+
|
|
126
|
+
### Market
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN", preload=("market",)) as client:
|
|
130
|
+
collections = await client.market.gifts.collections()
|
|
131
|
+
listings = await client.market.gifts.saling(
|
|
132
|
+
collectionNames=["Plush Pepe"],
|
|
133
|
+
count=20,
|
|
134
|
+
ordering="Price",
|
|
135
|
+
lowToHigh=True,
|
|
136
|
+
)
|
|
137
|
+
inventory = await client.market.gifts.inventory(isListed=False, count=20)
|
|
138
|
+
orders = await client.market.orders.list(
|
|
139
|
+
collectionNames=["Plush Pepe"],
|
|
140
|
+
count=10,
|
|
141
|
+
)
|
|
142
|
+
activities = await client.market.offers.activities(count=20)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`client.market` provides `gifts`, `orders`, and `offers`. Gift methods include
|
|
146
|
+
`collections`, `models`, `backdrops`, `saling`, `inventory`, `history`, `feed`,
|
|
147
|
+
`buy`, and `sale`.
|
|
148
|
+
|
|
149
|
+
### User
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN", preload=("user",)) as client:
|
|
153
|
+
profile = await client.user.me()
|
|
154
|
+
balance = await client.user.balance()
|
|
155
|
+
transactions = await client.user.transactions()
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Steam / CS2
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
async with MrktClient(
|
|
162
|
+
token="YOUR_ACCESS_TOKEN",
|
|
163
|
+
preload=("steam", "user"),
|
|
164
|
+
) as client:
|
|
165
|
+
steam_link = await client.steam.connect()
|
|
166
|
+
is_connected = await client.steam.connected
|
|
167
|
+
# Use client.steam.cs2.skins to query the CS2 catalog.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Raw HTTP Requests
|
|
171
|
+
|
|
172
|
+
After `MrktClient` starts, its `http` attribute is an `aiohttp.ClientSession`
|
|
173
|
+
configured with the API base URL and authentication headers. Use it to call
|
|
174
|
+
endpoints that are not yet covered by the library's API methods:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN") as client:
|
|
178
|
+
response = await client.http.get("gifts/collections")
|
|
179
|
+
response.raise_for_status()
|
|
180
|
+
collections = await response.json()
|
|
181
|
+
print(collections)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For POST requests, pass the request body through `json`:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN") as client:
|
|
188
|
+
response = await client.http.post(
|
|
189
|
+
"gifts/saling",
|
|
190
|
+
json={"count": 10, "collectionNames": ["Plush Pepe"]},
|
|
191
|
+
)
|
|
192
|
+
response.raise_for_status()
|
|
193
|
+
listings = await response.json()
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Pass paths relative to the client's base URL:
|
|
197
|
+
`https://api.tgmrkt.io/api/v1/`. Raw requests should also be made inside the
|
|
198
|
+
client context so that the HTTP session has been initialized.
|
|
199
|
+
|
|
200
|
+
## Using API Classes Without `preload` or `MrktClient`
|
|
201
|
+
|
|
202
|
+
With this approach, you are responsible for the base URL, authentication
|
|
203
|
+
headers, and closing the HTTP session. To use the built-in authentication and
|
|
204
|
+
transport while still creating API classes independently of `preload`, pass
|
|
205
|
+
an instance of `MrktClient` to them:
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from mrkts import MrktClient
|
|
209
|
+
from mrkts.market.gifts import Gifts
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
async def main() -> None:
|
|
213
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN") as transport:
|
|
214
|
+
gifts = Gifts(transport)
|
|
215
|
+
print(await gifts.collections())
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Multiple Accounts
|
|
219
|
+
|
|
220
|
+
`MrktPool` runs one coroutine for each client in the pool. Open each client
|
|
221
|
+
with `async with` inside the callback:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
import asyncio
|
|
225
|
+
|
|
226
|
+
from mrkts import MrktPool
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
async def get_balance(client) -> dict:
|
|
230
|
+
async with client as api:
|
|
231
|
+
response = await api.http.get("balance")
|
|
232
|
+
response.raise_for_status()
|
|
233
|
+
return await response.json()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def main() -> None:
|
|
237
|
+
async with MrktPool(tokens=["TOKEN_1", "TOKEN_2"]) as pool:
|
|
238
|
+
results = await pool.map(get_balance, concurrency=2)
|
|
239
|
+
for result in results:
|
|
240
|
+
if isinstance(result, Exception):
|
|
241
|
+
print(f"Request failed: {result}")
|
|
242
|
+
else:
|
|
243
|
+
print(result)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
asyncio.run(main())
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
To create a pool from Telegram sessions, use
|
|
250
|
+
`await MrktPool.from_sessions(...)`.
|
|
251
|
+
|
|
252
|
+
## API Structure
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
MrktClient
|
|
256
|
+
├── market
|
|
257
|
+
│ ├── gifts
|
|
258
|
+
│ ├── orders
|
|
259
|
+
│ └── offers
|
|
260
|
+
├── steam
|
|
261
|
+
│ └── cs2
|
|
262
|
+
│ ├── skins
|
|
263
|
+
│ ├── orders
|
|
264
|
+
│ └── offers
|
|
265
|
+
└── user
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Specify `"market"`, `"steam"`, or `"user"` in `preload` to access the
|
|
269
|
+
corresponding module through `MrktClient`.
|
mrkts-0.2.0/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# MRKT Python Client
|
|
2
|
+
|
|
3
|
+
An asynchronous Python library for the [MRKT](https://t.me/mrkt) API.
|
|
4
|
+
`MrktClient` provides the main transport, while the API is organized into
|
|
5
|
+
separate Market, Steam, and User classes. These API classes can be used with
|
|
6
|
+
the main client or directly with a custom HTTP transport.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Access token and Telegram session authentication
|
|
11
|
+
- Market methods for gifts, orders, and offers
|
|
12
|
+
- Steam methods, including CS2
|
|
13
|
+
- User profile, balance, and transaction methods
|
|
14
|
+
- Raw requests through the available HTTP session
|
|
15
|
+
- Concurrent multi-account operations with `MrktPool`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Python 3.10 or newer is required.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m pip install mrkts
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The importable module is named `mrkts`.
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
The client and its API modules are asynchronous. Provide an access token and
|
|
30
|
+
list the modules you need in `preload`:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import asyncio
|
|
34
|
+
|
|
35
|
+
from mrkts import MrktClient
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def main() -> None:
|
|
39
|
+
async with MrktClient(
|
|
40
|
+
token="YOUR_ACCESS_TOKEN",
|
|
41
|
+
preload=("market", "user"),
|
|
42
|
+
) as client:
|
|
43
|
+
gifts = await client.market.gifts.collections()
|
|
44
|
+
profile = await client.user.me()
|
|
45
|
+
print(gifts)
|
|
46
|
+
print(profile)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
asyncio.run(main())
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`preload` is empty by default. Available values are `"market"`, `"steam"`, and
|
|
53
|
+
`"user"`. Use `client.steam` for Steam methods; CS2 methods are available under
|
|
54
|
+
`client.steam.cs2`, for example `client.steam.cs2.skins`.
|
|
55
|
+
|
|
56
|
+
The HTTP session is created when entering `async with` or calling
|
|
57
|
+
`await client.start()`, and is closed when exiting the context. If you do not
|
|
58
|
+
use the context manager, make sure to call `await client.close()`.
|
|
59
|
+
|
|
60
|
+
## Authentication
|
|
61
|
+
|
|
62
|
+
### Access Token
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
async with MrktClient(
|
|
66
|
+
token="YOUR_ACCESS_TOKEN",
|
|
67
|
+
preload=("market",),
|
|
68
|
+
) as client:
|
|
69
|
+
listings = await client.market.gifts.saling(count=10)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Telegram Session
|
|
73
|
+
|
|
74
|
+
To authenticate with a Telegram session, install the project dependencies and
|
|
75
|
+
provide the session name and the directory containing the session files:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import asyncio
|
|
79
|
+
|
|
80
|
+
from mrkts import MrktClient
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async def main() -> None:
|
|
84
|
+
client = await MrktClient.session(
|
|
85
|
+
"my_telegram_session",
|
|
86
|
+
workdir=".",
|
|
87
|
+
preload=("user",),
|
|
88
|
+
)
|
|
89
|
+
async with client:
|
|
90
|
+
print(await client.user.me())
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
asyncio.run(main())
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API Methods
|
|
97
|
+
|
|
98
|
+
### Market
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN", preload=("market",)) as client:
|
|
102
|
+
collections = await client.market.gifts.collections()
|
|
103
|
+
listings = await client.market.gifts.saling(
|
|
104
|
+
collectionNames=["Plush Pepe"],
|
|
105
|
+
count=20,
|
|
106
|
+
ordering="Price",
|
|
107
|
+
lowToHigh=True,
|
|
108
|
+
)
|
|
109
|
+
inventory = await client.market.gifts.inventory(isListed=False, count=20)
|
|
110
|
+
orders = await client.market.orders.list(
|
|
111
|
+
collectionNames=["Plush Pepe"],
|
|
112
|
+
count=10,
|
|
113
|
+
)
|
|
114
|
+
activities = await client.market.offers.activities(count=20)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`client.market` provides `gifts`, `orders`, and `offers`. Gift methods include
|
|
118
|
+
`collections`, `models`, `backdrops`, `saling`, `inventory`, `history`, `feed`,
|
|
119
|
+
`buy`, and `sale`.
|
|
120
|
+
|
|
121
|
+
### User
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN", preload=("user",)) as client:
|
|
125
|
+
profile = await client.user.me()
|
|
126
|
+
balance = await client.user.balance()
|
|
127
|
+
transactions = await client.user.transactions()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Steam / CS2
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
async with MrktClient(
|
|
134
|
+
token="YOUR_ACCESS_TOKEN",
|
|
135
|
+
preload=("steam", "user"),
|
|
136
|
+
) as client:
|
|
137
|
+
steam_link = await client.steam.connect()
|
|
138
|
+
is_connected = await client.steam.connected
|
|
139
|
+
# Use client.steam.cs2.skins to query the CS2 catalog.
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Raw HTTP Requests
|
|
143
|
+
|
|
144
|
+
After `MrktClient` starts, its `http` attribute is an `aiohttp.ClientSession`
|
|
145
|
+
configured with the API base URL and authentication headers. Use it to call
|
|
146
|
+
endpoints that are not yet covered by the library's API methods:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN") as client:
|
|
150
|
+
response = await client.http.get("gifts/collections")
|
|
151
|
+
response.raise_for_status()
|
|
152
|
+
collections = await response.json()
|
|
153
|
+
print(collections)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
For POST requests, pass the request body through `json`:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN") as client:
|
|
160
|
+
response = await client.http.post(
|
|
161
|
+
"gifts/saling",
|
|
162
|
+
json={"count": 10, "collectionNames": ["Plush Pepe"]},
|
|
163
|
+
)
|
|
164
|
+
response.raise_for_status()
|
|
165
|
+
listings = await response.json()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Pass paths relative to the client's base URL:
|
|
169
|
+
`https://api.tgmrkt.io/api/v1/`. Raw requests should also be made inside the
|
|
170
|
+
client context so that the HTTP session has been initialized.
|
|
171
|
+
|
|
172
|
+
## Using API Classes Without `preload` or `MrktClient`
|
|
173
|
+
|
|
174
|
+
With this approach, you are responsible for the base URL, authentication
|
|
175
|
+
headers, and closing the HTTP session. To use the built-in authentication and
|
|
176
|
+
transport while still creating API classes independently of `preload`, pass
|
|
177
|
+
an instance of `MrktClient` to them:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from mrkts import MrktClient
|
|
181
|
+
from mrkts.market.gifts import Gifts
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async def main() -> None:
|
|
185
|
+
async with MrktClient(token="YOUR_ACCESS_TOKEN") as transport:
|
|
186
|
+
gifts = Gifts(transport)
|
|
187
|
+
print(await gifts.collections())
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Multiple Accounts
|
|
191
|
+
|
|
192
|
+
`MrktPool` runs one coroutine for each client in the pool. Open each client
|
|
193
|
+
with `async with` inside the callback:
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
import asyncio
|
|
197
|
+
|
|
198
|
+
from mrkts import MrktPool
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
async def get_balance(client) -> dict:
|
|
202
|
+
async with client as api:
|
|
203
|
+
response = await api.http.get("balance")
|
|
204
|
+
response.raise_for_status()
|
|
205
|
+
return await response.json()
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
async def main() -> None:
|
|
209
|
+
async with MrktPool(tokens=["TOKEN_1", "TOKEN_2"]) as pool:
|
|
210
|
+
results = await pool.map(get_balance, concurrency=2)
|
|
211
|
+
for result in results:
|
|
212
|
+
if isinstance(result, Exception):
|
|
213
|
+
print(f"Request failed: {result}")
|
|
214
|
+
else:
|
|
215
|
+
print(result)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
asyncio.run(main())
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
To create a pool from Telegram sessions, use
|
|
222
|
+
`await MrktPool.from_sessions(...)`.
|
|
223
|
+
|
|
224
|
+
## API Structure
|
|
225
|
+
|
|
226
|
+
```text
|
|
227
|
+
MrktClient
|
|
228
|
+
├── market
|
|
229
|
+
│ ├── gifts
|
|
230
|
+
│ ├── orders
|
|
231
|
+
│ └── offers
|
|
232
|
+
├── steam
|
|
233
|
+
│ └── cs2
|
|
234
|
+
│ ├── skins
|
|
235
|
+
│ ├── orders
|
|
236
|
+
│ └── offers
|
|
237
|
+
└── user
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Specify `"market"`, `"steam"`, or `"user"` in `preload` to access the
|
|
241
|
+
corresponding module through `MrktClient`.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
async def get_token(init_data: str, *, proxy: str | None = None) -> str:
|
|
2
|
+
from .client import MrktClient
|
|
3
|
+
|
|
4
|
+
async with MrktClient(token=None, proxy=proxy) as client:
|
|
5
|
+
return await client.auth(init_data)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def refresh_token(session: str, *, workdir: str = ".", proxy: str | None = None) -> str:
|
|
9
|
+
from .utils import get_init_data
|
|
10
|
+
|
|
11
|
+
init_data = await get_init_data(session, workdir=workdir, proxy=proxy)
|
|
12
|
+
return await get_token(init_data, proxy=proxy)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Main object of MRKT client"""
|
|
2
|
+
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
import random
|
|
5
|
+
from aiohttp import ClientSession
|
|
6
|
+
from .auth import get_token, refresh_token
|
|
7
|
+
|
|
8
|
+
_preloads = {
|
|
9
|
+
"market": (".market.client", "MarketClient"),
|
|
10
|
+
"steam": (".steam.client", "SteamClient"),
|
|
11
|
+
"user": (".user", "User"),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class MrktClient:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
token: str | None = None,
|
|
18
|
+
*,
|
|
19
|
+
session: str | None = None,
|
|
20
|
+
preload: tuple[str, ...] | None = None,
|
|
21
|
+
workdir: str = ".",
|
|
22
|
+
proxy: str | None = None,
|
|
23
|
+
headers: dict | None = None,
|
|
24
|
+
):
|
|
25
|
+
self.token = token
|
|
26
|
+
self._session = session
|
|
27
|
+
self.workdir = workdir
|
|
28
|
+
self.proxy = proxy
|
|
29
|
+
self.headers = headers or {}
|
|
30
|
+
self._closed = False
|
|
31
|
+
self.http: ClientSession | None = None
|
|
32
|
+
self.web = ClientSession | None = None
|
|
33
|
+
|
|
34
|
+
for name in preload or []:
|
|
35
|
+
self._preload(name)
|
|
36
|
+
|
|
37
|
+
def _setup_http(self):
|
|
38
|
+
chrome, edge = random.randint(120, 145), random.randint(120, 145)
|
|
39
|
+
|
|
40
|
+
headers = {
|
|
41
|
+
"accept": "application/json, text/plain, */*",
|
|
42
|
+
"accept-encoding": "gzip, deflate",
|
|
43
|
+
"accept-language": "ru,en;q=0.9,en-GB;q=0.8,en-US;q=0.7",
|
|
44
|
+
"content-type": "application/json",
|
|
45
|
+
"origin": "https://cdn.tgmrkt.io",
|
|
46
|
+
"priority": "u=1, i",
|
|
47
|
+
"referer": "https://cdn.tgmrkt.io/",
|
|
48
|
+
"sec-ch-ua": f'"Not=A?Brand";v="8", "Chromium";v="{chrome}", "Microsoft Edge";v="{edge}"',
|
|
49
|
+
"sec-ch-ua-mobile": "?0",
|
|
50
|
+
"sec-ch-ua-platform": random.choice(['"Windows"', '"macOS"', '"Linux"']),
|
|
51
|
+
"sec-fetch-dest": "empty",
|
|
52
|
+
"sec-fetch-mode": "cors",
|
|
53
|
+
"sec-fetch-site": "same-site",
|
|
54
|
+
"sec-fetch-storage-access": "active",
|
|
55
|
+
"user-agent": f"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{chrome}.0.0.0 Safari/537.36 Edg/{edge}.0.0.0",
|
|
56
|
+
}
|
|
57
|
+
if self.token:
|
|
58
|
+
headers["authorization"] = f"Bearer {self.token}"
|
|
59
|
+
headers["cookie"] = f"access_token={self.token}"
|
|
60
|
+
self.headers.update(headers)
|
|
61
|
+
|
|
62
|
+
self.http = ClientSession(
|
|
63
|
+
base_url="https://api.tgmrkt.io/api/v1/",
|
|
64
|
+
headers=self.headers,
|
|
65
|
+
proxy=self.proxy,
|
|
66
|
+
)
|
|
67
|
+
self._closed = False
|
|
68
|
+
|
|
69
|
+
async def auth(self, tgWebAppData: str) -> str:
|
|
70
|
+
if not self.http:
|
|
71
|
+
self._setup_http()
|
|
72
|
+
response = await self.http.post("auth", json={"data": tgWebAppData})
|
|
73
|
+
response.raise_for_status()
|
|
74
|
+
data = response.json()
|
|
75
|
+
token = data.get("token")
|
|
76
|
+
if not token:
|
|
77
|
+
raise ValueError(f"Auth failed: {data}")
|
|
78
|
+
return token
|
|
79
|
+
|
|
80
|
+
async def start(self) -> "MrktClient":
|
|
81
|
+
if not self.token and self._session:
|
|
82
|
+
self.token = await refresh_token(session=self._session, workdir=self.workdir, proxy=self.proxy)
|
|
83
|
+
if not self.http and self.token:
|
|
84
|
+
self._setup_http()
|
|
85
|
+
return self
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
async def session(
|
|
89
|
+
cls,
|
|
90
|
+
session: str,
|
|
91
|
+
*,
|
|
92
|
+
workdir: str = ".",
|
|
93
|
+
proxy: str | None = None,
|
|
94
|
+
**kwargs
|
|
95
|
+
):
|
|
96
|
+
token = await refresh_token(session, workdir=workdir, proxy=proxy)
|
|
97
|
+
return cls(token=token, workdir=workdir, proxy=proxy, **kwargs)
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
async def init_data(
|
|
101
|
+
cls,
|
|
102
|
+
init_data: str,
|
|
103
|
+
*,
|
|
104
|
+
workdir: str = ".",
|
|
105
|
+
proxy: str | None = None,
|
|
106
|
+
impersonate: str = "chrome124",
|
|
107
|
+
**kwargs,
|
|
108
|
+
) -> "MrktClient":
|
|
109
|
+
token = await get_token(init_data, proxy=proxy)
|
|
110
|
+
return cls(token=token, workdir=workdir, proxy=proxy, impersonate=impersonate, **kwargs)
|
|
111
|
+
|
|
112
|
+
def set_token(self, token: str) -> None:
|
|
113
|
+
self.token = token
|
|
114
|
+
self.headers["authorization"] = f"Bearer {token}"
|
|
115
|
+
self.headers["cookie"] = f"access_token={token}"
|
|
116
|
+
|
|
117
|
+
if self.http is None:
|
|
118
|
+
self._setup_http()
|
|
119
|
+
else:
|
|
120
|
+
self.http.headers.update({
|
|
121
|
+
"authorization": f"Bearer {token}",
|
|
122
|
+
"cookie": f"access_token={token}",
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
def _preload(self, name: str) -> None:
|
|
126
|
+
try:
|
|
127
|
+
module_name, class_name = _preloads[name]
|
|
128
|
+
except KeyError:
|
|
129
|
+
raise ValueError(f"Unknown preload: {name!r}") from None
|
|
130
|
+
|
|
131
|
+
module = import_module(module_name, package=__package__)
|
|
132
|
+
cls = getattr(module, class_name)
|
|
133
|
+
|
|
134
|
+
setattr(self, name, cls(self))
|
|
135
|
+
|
|
136
|
+
async def __aenter__(self):
|
|
137
|
+
return await self.start()
|
|
138
|
+
|
|
139
|
+
async def __aexit__(self, *args):
|
|
140
|
+
await self.close()
|
|
141
|
+
|
|
142
|
+
async def close(self):
|
|
143
|
+
if not self._closed and self.http:
|
|
144
|
+
await self.http.close()
|
|
145
|
+
self._closed = True
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'''Market object of MRKT client'''
|
|
2
|
+
|
|
3
|
+
from .gifts import Gifts
|
|
4
|
+
from .orders import Orders
|
|
5
|
+
from .offers import Offers
|
|
6
|
+
|
|
7
|
+
class MarketClient:
|
|
8
|
+
def __init__(self, client):
|
|
9
|
+
self.gifts = Gifts(client)
|
|
10
|
+
self.orders = Orders(client)
|
|
11
|
+
self.offers = Offers(client)
|