fpx-engine 0.1.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.
- fpx_engine-0.1.0/LICENSE +21 -0
- fpx_engine-0.1.0/PKG-INFO +72 -0
- fpx_engine-0.1.0/README.md +56 -0
- fpx_engine-0.1.0/fpx/__init__.py +6 -0
- fpx_engine-0.1.0/fpx/api/client.py +134 -0
- fpx_engine-0.1.0/fpx/api/parsers.py +373 -0
- fpx_engine-0.1.0/fpx/classes/account/account.py +34 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/addons.py +20 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/category.py +39 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/chat.py +75 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/editor.py +66 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/lot.py +78 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/order.py +44 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/profile.py +103 -0
- fpx_engine-0.1.0/fpx/classes/account/subclasses/review.py +52 -0
- fpx_engine-0.1.0/fpx/classes/runner/runner.py +92 -0
- fpx_engine-0.1.0/fpx/classes/runner/subclasses/category.py +54 -0
- fpx_engine-0.1.0/fpx/classes/runner/subclasses/chat.py +49 -0
- fpx_engine-0.1.0/fpx/classes/runner/subclasses/handler.py +13 -0
- fpx_engine-0.1.0/fpx/classes/runner/subclasses/order.py +53 -0
- fpx_engine-0.1.0/fpx/classes/runner/subclasses/review.py +30 -0
- fpx_engine-0.1.0/fpx/classes/runner/subclasses/router.py +163 -0
- fpx_engine-0.1.0/fpx/main.py +22 -0
- fpx_engine-0.1.0/fpx/middlewares/request_engine.py +52 -0
- fpx_engine-0.1.0/fpx/models/account.py +43 -0
- fpx_engine-0.1.0/fpx/models/chat.py +33 -0
- fpx_engine-0.1.0/fpx/models/lots.py +28 -0
- fpx_engine-0.1.0/fpx/utils/errors.py +71 -0
- fpx_engine-0.1.0/fpx_engine.egg-info/PKG-INFO +72 -0
- fpx_engine-0.1.0/fpx_engine.egg-info/SOURCES.txt +33 -0
- fpx_engine-0.1.0/fpx_engine.egg-info/dependency_links.txt +1 -0
- fpx_engine-0.1.0/fpx_engine.egg-info/requires.txt +2 -0
- fpx_engine-0.1.0/fpx_engine.egg-info/top_level.txt +1 -0
- fpx_engine-0.1.0/pyproject.toml +25 -0
- fpx_engine-0.1.0/setup.cfg +4 -0
fpx_engine-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Be My Code
|
|
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.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fpx-engine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Автоматизация работы с FunPay
|
|
5
|
+
Author-email: Be My Code <gettofarmila@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/bymyforge/fpx
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: httpx>=0.24.0
|
|
14
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<img src="https://img.shields.io/badge/python-3.11+-blue.svg" alt="Python Version">
|
|
19
|
+
<img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License">
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<h1 align="center">fpx</h1>
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<strong>fpx</strong> - асинхронный Python-фреймворк и библиотека для упрощения взаимодействия с <a href="https://funpay.com">funpay.com</a>.
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
Оригинальный сайт не предоставляет публичного API для разработчиков. Наш проект нацелен на то, чтобы облегчить написание различных автоматизаций. Используя **fpx**, разработчик может полностью сфокусироваться на логике своего приложения, не отвлекаясь на написание парсеров и ручную сборку HTTP-запросов, кеширование. Фреймворк делает всю грязную работу под капотом.
|
|
31
|
+
|
|
32
|
+
## ✨ Особенности
|
|
33
|
+
* **Два в одном:** работает и как полноценный событийный фреймворк на хэндлерах и декораторах, и как гибкая библиотека для точечных запросов.
|
|
34
|
+
* **Полная асинхронность:** построен на базе `httpx`
|
|
35
|
+
* **Автоматизация из коробки:** встроенный движок для отслеживания событий.
|
|
36
|
+
|
|
37
|
+
## 🚀 Пример использования
|
|
38
|
+
|
|
39
|
+
Получение нового сообщения и автоматический ответ на него:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import asyncio
|
|
43
|
+
from fpx import FunPayTools
|
|
44
|
+
|
|
45
|
+
async def main():
|
|
46
|
+
# Инициализируем аккаунт (замените 'gkey' на golden_key вашего аккаунта)
|
|
47
|
+
fp = FunPayTools('gkey')
|
|
48
|
+
|
|
49
|
+
# Ловим новое сообщение
|
|
50
|
+
@fp.handler.on_message()
|
|
51
|
+
async def get_message(message):
|
|
52
|
+
print(f'Пришло сообщение: {message.text} от {message.sender}')
|
|
53
|
+
|
|
54
|
+
# Отвечаем в чат
|
|
55
|
+
new_message = await fp.account.chat.send_message(message.chat_id, 'Привет, я на связи!')
|
|
56
|
+
if new_message:
|
|
57
|
+
print('Успешно ответил на сообщение')
|
|
58
|
+
else:
|
|
59
|
+
print('Не удалось отправить сообщение!')
|
|
60
|
+
|
|
61
|
+
# Запускаем слушатель событий в фоновом режиме (опрос каждые 3 секунды)
|
|
62
|
+
await fp.runner.runner_polling(3, is_background=True)
|
|
63
|
+
|
|
64
|
+
# Зацикливаем программу, чтобы фоновые функции не останавливались
|
|
65
|
+
await fp.runner.idle()
|
|
66
|
+
|
|
67
|
+
if __name__ == '__main__':
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
## ⚠️ Статус проекта
|
|
71
|
+
Проект находится в процессе активной разработки. Будем рады любой обратной связи!
|
|
72
|
+
Если вы обнаружили баг, у вас есть предложения по улучшению или вопросы по работе фреймворка, просьба сообщать в Telegram: @sanyalca.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.shields.io/badge/python-3.11+-blue.svg" alt="Python Version">
|
|
3
|
+
<img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License">
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<h1 align="center">fpx</h1>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<strong>fpx</strong> - асинхронный Python-фреймворк и библиотека для упрощения взаимодействия с <a href="https://funpay.com">funpay.com</a>.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Оригинальный сайт не предоставляет публичного API для разработчиков. Наш проект нацелен на то, чтобы облегчить написание различных автоматизаций. Используя **fpx**, разработчик может полностью сфокусироваться на логике своего приложения, не отвлекаясь на написание парсеров и ручную сборку HTTP-запросов, кеширование. Фреймворк делает всю грязную работу под капотом.
|
|
15
|
+
|
|
16
|
+
## ✨ Особенности
|
|
17
|
+
* **Два в одном:** работает и как полноценный событийный фреймворк на хэндлерах и декораторах, и как гибкая библиотека для точечных запросов.
|
|
18
|
+
* **Полная асинхронность:** построен на базе `httpx`
|
|
19
|
+
* **Автоматизация из коробки:** встроенный движок для отслеживания событий.
|
|
20
|
+
|
|
21
|
+
## 🚀 Пример использования
|
|
22
|
+
|
|
23
|
+
Получение нового сообщения и автоматический ответ на него:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import asyncio
|
|
27
|
+
from fpx import FunPayTools
|
|
28
|
+
|
|
29
|
+
async def main():
|
|
30
|
+
# Инициализируем аккаунт (замените 'gkey' на golden_key вашего аккаунта)
|
|
31
|
+
fp = FunPayTools('gkey')
|
|
32
|
+
|
|
33
|
+
# Ловим новое сообщение
|
|
34
|
+
@fp.handler.on_message()
|
|
35
|
+
async def get_message(message):
|
|
36
|
+
print(f'Пришло сообщение: {message.text} от {message.sender}')
|
|
37
|
+
|
|
38
|
+
# Отвечаем в чат
|
|
39
|
+
new_message = await fp.account.chat.send_message(message.chat_id, 'Привет, я на связи!')
|
|
40
|
+
if new_message:
|
|
41
|
+
print('Успешно ответил на сообщение')
|
|
42
|
+
else:
|
|
43
|
+
print('Не удалось отправить сообщение!')
|
|
44
|
+
|
|
45
|
+
# Запускаем слушатель событий в фоновом режиме (опрос каждые 3 секунды)
|
|
46
|
+
await fp.runner.runner_polling(3, is_background=True)
|
|
47
|
+
|
|
48
|
+
# Зацикливаем программу, чтобы фоновые функции не останавливались
|
|
49
|
+
await fp.runner.idle()
|
|
50
|
+
|
|
51
|
+
if __name__ == '__main__':
|
|
52
|
+
asyncio.run(main())
|
|
53
|
+
```
|
|
54
|
+
## ⚠️ Статус проекта
|
|
55
|
+
Проект находится в процессе активной разработки. Будем рады любой обратной связи!
|
|
56
|
+
Если вы обнаружили баг, у вас есть предложения по улучшению или вопросы по работе фреймворка, просьба сообщать в Telegram: @sanyalca.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import urllib.parse
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class FunPayClient:
|
|
6
|
+
def __init__(self, account, http_client):
|
|
7
|
+
self._account = account
|
|
8
|
+
self.client = http_client
|
|
9
|
+
|
|
10
|
+
async def get_chats_page(self) -> str:
|
|
11
|
+
r = await self._account._request_engine.execute('GET', '/chat/')
|
|
12
|
+
return r.text
|
|
13
|
+
|
|
14
|
+
async def get_finance_page(self) -> str:
|
|
15
|
+
r = await self._account._request_engine.execute('GET', '/account/balance')
|
|
16
|
+
return r.text
|
|
17
|
+
|
|
18
|
+
async def send_message_request(self, node_name, last_msg, text):
|
|
19
|
+
request_data = {
|
|
20
|
+
"action": "chat_message",
|
|
21
|
+
"data": {
|
|
22
|
+
"node": node_name,
|
|
23
|
+
"last_message": last_msg,
|
|
24
|
+
"content": text
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
payload = {
|
|
28
|
+
'request': json.dumps(request_data)
|
|
29
|
+
}
|
|
30
|
+
headers = {
|
|
31
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
32
|
+
"Referer": f"https://funpay.com/chat/?node={node_name.split('-')[-1]}"
|
|
33
|
+
}
|
|
34
|
+
r = await self._account._request_engine.execute('POST', '/runner/', data=payload, headers=headers)
|
|
35
|
+
return r.json()
|
|
36
|
+
|
|
37
|
+
async def get_current_chat(self, chat_id):
|
|
38
|
+
r = await self._account._request_engine.execute('GET', f'/chat/?node={chat_id}')
|
|
39
|
+
return r.text
|
|
40
|
+
|
|
41
|
+
async def get_user_profile(self, user_id):
|
|
42
|
+
r = await self._account._request_engine.execute('GET', f'/users/{user_id}/')
|
|
43
|
+
return r.text
|
|
44
|
+
|
|
45
|
+
async def lot_menu_by_category(self, category_id):
|
|
46
|
+
r = await self._account._request_engine.execute('GET', f'/lots/{category_id}/trade')
|
|
47
|
+
return r.text
|
|
48
|
+
|
|
49
|
+
async def get_main_menu(self):
|
|
50
|
+
r = await self._account._request_engine.execute('GET', '/')
|
|
51
|
+
return r.text
|
|
52
|
+
|
|
53
|
+
async def raise_lot(self, node_id, game_id):
|
|
54
|
+
payload = {
|
|
55
|
+
'game_id': game_id,
|
|
56
|
+
'node_id': node_id
|
|
57
|
+
}
|
|
58
|
+
headers = {
|
|
59
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
60
|
+
}
|
|
61
|
+
r = await self._account._request_engine.execute('POST', '/lots/raise', data=payload, headers=headers)
|
|
62
|
+
if "application/json" in r.headers.get("Content-Type", ""):
|
|
63
|
+
response = r.json()
|
|
64
|
+
return response.get('msg')
|
|
65
|
+
else:
|
|
66
|
+
return {"error": "not_json", "status": r.status_code}
|
|
67
|
+
|
|
68
|
+
async def get_lot_info(self, lot_id):
|
|
69
|
+
r = await self._account._request_engine.execute('GET', f'/lots/offer?id={lot_id}')
|
|
70
|
+
return r.text
|
|
71
|
+
|
|
72
|
+
async def get_my_sells(self):
|
|
73
|
+
r = await self._account._request_engine.execute('GET', '/orders/trade')
|
|
74
|
+
return r.text
|
|
75
|
+
|
|
76
|
+
async def refund_order(self, csrf_token, order_id):
|
|
77
|
+
url = f'/orders/refund'
|
|
78
|
+
payload = {
|
|
79
|
+
'id': order_id
|
|
80
|
+
}
|
|
81
|
+
r = await self._account._request_engine.execute('POST', url, data=payload)
|
|
82
|
+
return r
|
|
83
|
+
|
|
84
|
+
async def get_order_info(self, order_id):
|
|
85
|
+
r = await self._account._request_engine.execute('GET', f'/orders/{order_id}/')
|
|
86
|
+
return r.text
|
|
87
|
+
|
|
88
|
+
async def get_lot_editor_data(self, lot_id):
|
|
89
|
+
r = await self._account._request_engine.execute('GET', f'/lots/offerEdit?offer={lot_id}')
|
|
90
|
+
return r.text
|
|
91
|
+
|
|
92
|
+
async def edit_lot(self, lot, active=None):
|
|
93
|
+
payload = {
|
|
94
|
+
'form_created_at': lot.form_created_at,
|
|
95
|
+
'offer_id': lot.offer_id,
|
|
96
|
+
'node_id': lot.node_id,
|
|
97
|
+
'location': lot.location if lot.location else 'offer',
|
|
98
|
+
'deleted': lot.deleted,
|
|
99
|
+
}
|
|
100
|
+
payload.update(lot.fields)
|
|
101
|
+
payload.pop('query', None)
|
|
102
|
+
if active is not None:
|
|
103
|
+
if active:
|
|
104
|
+
payload['active'] = 'on'
|
|
105
|
+
else:
|
|
106
|
+
payload.pop('active', None)
|
|
107
|
+
headers = {
|
|
108
|
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
|
109
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
110
|
+
'Referer': f'https://funpay.com/lots/offerEdit?node={lot.node_id}&offer={lot.offer_id}&location=offer',
|
|
111
|
+
}
|
|
112
|
+
r = await self._account._request_engine.execute('POST', '/lots/offerSave', data=payload, headers=headers)
|
|
113
|
+
return r
|
|
114
|
+
|
|
115
|
+
async def answer_review(self, authorid: str, text: str, orderid: str):
|
|
116
|
+
payload = {
|
|
117
|
+
'authorId': authorid,
|
|
118
|
+
'text': text,
|
|
119
|
+
'rating': '',
|
|
120
|
+
'orderId': orderid
|
|
121
|
+
}
|
|
122
|
+
headers = {
|
|
123
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
124
|
+
}
|
|
125
|
+
response = await self._account._request_engine.execute('POST', '/orders/review', data=payload, headers=headers)
|
|
126
|
+
return response
|
|
127
|
+
|
|
128
|
+
async def get_chip_category(self, chip_category_id):
|
|
129
|
+
r = await self._account._request_engine.execute('GET', f'/chips/{chip_category_id}/')
|
|
130
|
+
return r.text
|
|
131
|
+
|
|
132
|
+
async def get_lot_category(self, lot_category_id):
|
|
133
|
+
r = await self._account._request_engine.execute('GET', f'/lots/{lot_category_id}/')
|
|
134
|
+
return r.text
|