fpx-engine 0.3.2__tar.gz → 0.4.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.3.2/fpx_engine.egg-info → fpx_engine-0.4.0}/PKG-INFO +2 -1
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/README.md +1 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/runner.py +1 -1
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/category.py +22 -10
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/order.py +44 -9
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/review.py +17 -12
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/router.py +32 -22
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/main.py +6 -2
- {fpx_engine-0.3.2 → fpx_engine-0.4.0/fpx_engine.egg-info}/PKG-INFO +2 -1
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/pyproject.toml +1 -1
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/LICENSE +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/__init__.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/api/client.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/api/parsers.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/account.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/addons.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/category.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/chat.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/editor.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/lot.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/order.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/profile.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/review.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/chat.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/handler.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/fsm.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/middlewares/request_engine.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/models/account.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/models/chat.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/models/lots.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/utils/errors.py +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/SOURCES.txt +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/dependency_links.txt +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/requires.txt +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/top_level.txt +0 -0
- {fpx_engine-0.3.2 → fpx_engine-0.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fpx-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Автоматизация работы с FunPay
|
|
5
5
|
Author-email: Be My Code <gettofarmila@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/bymyforge/fpx
|
|
@@ -77,6 +77,7 @@ async def main():
|
|
|
77
77
|
await message.answer('Привет')
|
|
78
78
|
#запускаем приём событий
|
|
79
79
|
await fp.runner.start_polling(3, is_background=True)
|
|
80
|
+
await fp.runner.idle()
|
|
80
81
|
|
|
81
82
|
if __name__ == '__main__':
|
|
82
83
|
asyncio.run(main())
|
|
@@ -48,7 +48,7 @@ class Runner:
|
|
|
48
48
|
await asyncio.sleep(timer)
|
|
49
49
|
except fpx_err.FpxRequestError:
|
|
50
50
|
await asyncio.sleep(60)
|
|
51
|
-
except (httpx.
|
|
51
|
+
except (httpx.HTTPError, httpx.NetworkError):
|
|
52
52
|
await asyncio.sleep(timer)
|
|
53
53
|
except Exception as e:
|
|
54
54
|
raise fpx_err.FpxCriticalRunnerError(message=str(e))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import asyncio
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class CategoryRunner:
|
|
@@ -6,23 +6,35 @@ class CategoryRunner:
|
|
|
6
6
|
self.runner = runner
|
|
7
7
|
|
|
8
8
|
async def _update_lot_category_cache(self, lot_category_ids):
|
|
9
|
+
tasks = [
|
|
10
|
+
self.runner._account.category.get_lot_category_last_lot(cat_id)
|
|
11
|
+
for cat_id in lot_category_ids
|
|
12
|
+
]
|
|
13
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
9
14
|
new_cache = []
|
|
10
|
-
for category_id in lot_category_ids:
|
|
11
|
-
lots
|
|
15
|
+
for category_id, lots in zip(lot_category_ids, results):
|
|
16
|
+
if isinstance(lots, Exception):
|
|
17
|
+
continue
|
|
12
18
|
for lot in lots:
|
|
13
|
-
lot.category_id = category_id
|
|
19
|
+
lot.category_id = category_id
|
|
14
20
|
new_cache.append(lot)
|
|
15
|
-
self.runner._cache['old_lot_categories'] = self.runner._cache
|
|
21
|
+
self.runner._cache['old_lot_categories'] = self.runner._cache.get('lot_categories')
|
|
16
22
|
self.runner._cache['lot_categories'] = new_cache
|
|
17
23
|
|
|
18
24
|
async def _update_chip_category_cache(self, chip_category_ids):
|
|
25
|
+
tasks = [
|
|
26
|
+
self.runner._account.category.get_chip_category_last_lot(cat_id)
|
|
27
|
+
for cat_id in chip_category_ids
|
|
28
|
+
]
|
|
29
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
19
30
|
new_cache = []
|
|
20
|
-
for category_id in chip_category_ids:
|
|
21
|
-
lots
|
|
31
|
+
for category_id, lots in zip(chip_category_ids, results):
|
|
32
|
+
if isinstance(lots, Exception):
|
|
33
|
+
continue
|
|
22
34
|
for lot in lots:
|
|
23
35
|
lot.category_id = category_id
|
|
24
36
|
new_cache.append(lot)
|
|
25
|
-
self.runner._cache['old_chip_categories'] = self.runner._cache
|
|
37
|
+
self.runner._cache['old_chip_categories'] = self.runner._cache.get('chip_categories', [])
|
|
26
38
|
self.runner._cache['chip_categories'] = new_cache
|
|
27
39
|
|
|
28
40
|
async def _compare_lot_category_cache(self):
|
|
@@ -65,7 +77,7 @@ class CategoryRunner:
|
|
|
65
77
|
if lot.owner_username == self.runner._account.username:
|
|
66
78
|
continue
|
|
67
79
|
for handler in self.runner.handler._handlers['lot_category']:
|
|
68
|
-
|
|
80
|
+
asyncio.create_task(handler(lot))
|
|
69
81
|
|
|
70
82
|
async def _check_chip_categories(self, chip_category_ids):
|
|
71
83
|
await self._update_chip_category_cache(chip_category_ids)
|
|
@@ -75,4 +87,4 @@ class CategoryRunner:
|
|
|
75
87
|
if lot.owner_username == self.runner._account.username:
|
|
76
88
|
continue
|
|
77
89
|
for handler in self.runner.handler._handlers['chip_category']:
|
|
78
|
-
|
|
90
|
+
asyncio.create_task(handler(lot))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import inspect
|
|
2
|
+
import asyncio
|
|
2
3
|
|
|
3
4
|
from fpx.models.account import Order
|
|
4
5
|
from fpx.fsm import FSMContext
|
|
@@ -48,8 +49,8 @@ class OrderRunner:
|
|
|
48
49
|
order.finded_mapping = trigger
|
|
49
50
|
matched = True
|
|
50
51
|
break
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
if not matched:
|
|
53
|
+
return False
|
|
53
54
|
sig = inspect.signature(h_func)
|
|
54
55
|
has_state = False
|
|
55
56
|
for param in sig.parameters.values():
|
|
@@ -61,6 +62,33 @@ class OrderRunner:
|
|
|
61
62
|
else:
|
|
62
63
|
await h_func(order)
|
|
63
64
|
|
|
65
|
+
async def _check_trigger_for_command(self, order: Order, state_ctx: FSMContext):
|
|
66
|
+
if order.description is None:
|
|
67
|
+
return False
|
|
68
|
+
for cmd_handler in self.runner.handler._handlers['order_command']:
|
|
69
|
+
target_command = cmd_handler['trigger_command']
|
|
70
|
+
target_command_lower = {k.lower(): v for k, v in target_command.items()}
|
|
71
|
+
target_function = None
|
|
72
|
+
for command_name in target_command_lower:
|
|
73
|
+
if command_name in order.description.lower():
|
|
74
|
+
target_function = target_command_lower[command_name]
|
|
75
|
+
order.finded_mapping = command_name
|
|
76
|
+
break
|
|
77
|
+
if target_function is None:
|
|
78
|
+
continue
|
|
79
|
+
sig = inspect.signature(target_function)
|
|
80
|
+
has_state = False
|
|
81
|
+
for param in sig.parameters.values():
|
|
82
|
+
if param.annotation == FSMContext:
|
|
83
|
+
has_state = True
|
|
84
|
+
break
|
|
85
|
+
if has_state:
|
|
86
|
+
await target_function(order, state_ctx)
|
|
87
|
+
else:
|
|
88
|
+
await target_function(order)
|
|
89
|
+
return True
|
|
90
|
+
return False
|
|
91
|
+
|
|
64
92
|
async def _trigger_order_handlers(self, order: Order):
|
|
65
93
|
state_ctx = FSMContext(self.runner.storage, order.chat_id)
|
|
66
94
|
status = order.status.lower()
|
|
@@ -69,20 +97,27 @@ class OrderRunner:
|
|
|
69
97
|
if status in ('закрыт', 'closed', 'закрито'):
|
|
70
98
|
for handler in self.runner.handler._handlers['confirmed_order']:
|
|
71
99
|
await self._check_handler(handler, order, state_ctx)
|
|
72
|
-
elif status in('оплачен', 'оплачено', 'paid', '
|
|
100
|
+
elif status in ('оплачен', 'оплачено', 'paid', 'відкрито'):
|
|
73
101
|
for handler in self.runner.handler._handlers['new_order']:
|
|
74
102
|
await self._check_handler(handler, order, state_ctx)
|
|
103
|
+
await self._check_trigger_for_command(order, state_ctx)
|
|
75
104
|
elif status in ('возврат', 'повернення', 'refund'):
|
|
76
105
|
for handler in self.runner.handler._handlers['refund']:
|
|
77
106
|
await self._check_handler(handler, order, state_ctx)
|
|
78
107
|
|
|
108
|
+
async def _process_single_order(self, order: Order):
|
|
109
|
+
try:
|
|
110
|
+
order_info = await self.runner._account.order.get_order_details(order.order_id)
|
|
111
|
+
order.description = order_info.description
|
|
112
|
+
order.chat_id = order_info.chat_id
|
|
113
|
+
order._client = self.runner
|
|
114
|
+
await self._trigger_order_handlers(order)
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
|
|
79
118
|
async def _check_orders(self):
|
|
80
119
|
await self.runner._order._update_order_cache()
|
|
81
120
|
orders = await self.runner._order._compare_order_cache()
|
|
82
121
|
if orders:
|
|
83
|
-
for order in orders
|
|
84
|
-
|
|
85
|
-
order.description = order_info.description
|
|
86
|
-
order.chat_id = order_info.chat_id
|
|
87
|
-
order._client = self.runner
|
|
88
|
-
await self._trigger_order_handlers(order)
|
|
122
|
+
tasks = [self._process_single_order(order) for order in orders]
|
|
123
|
+
await asyncio.gather(*tasks)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
1
3
|
|
|
2
4
|
from fpx.models.account import CurReview, Order
|
|
3
5
|
|
|
@@ -10,7 +12,7 @@ class ReviewRunner:
|
|
|
10
12
|
async def _update_review_cache(self):
|
|
11
13
|
'''Обновляет кеш отзывов'''
|
|
12
14
|
profile = await self.runner._account.profile.profile()
|
|
13
|
-
self.runner._cache['old_reviews'] = self.runner._cache
|
|
15
|
+
self.runner._cache['old_reviews'] = self.runner._cache.get('reviews', [])
|
|
14
16
|
self.runner._cache['reviews'] = profile.reviews
|
|
15
17
|
|
|
16
18
|
async def _compare_review_cache(self):
|
|
@@ -23,19 +25,22 @@ class ReviewRunner:
|
|
|
23
25
|
return result
|
|
24
26
|
|
|
25
27
|
async def _target_review_processing(self, review: CurReview):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
try:
|
|
29
|
+
order = await self.runner._account.order.get_order_details(review.order_id)
|
|
30
|
+
review._client = self.runner
|
|
31
|
+
review.order = order
|
|
32
|
+
for handler in self.runner.handler._handlers['review']:
|
|
33
|
+
if handler['stars'] is None:
|
|
34
|
+
asyncio.create_task(handler['function'](review))
|
|
35
|
+
else:
|
|
36
|
+
if review.stars == handler['stars']:
|
|
37
|
+
await handler['function'](review)
|
|
38
|
+
except Exception:
|
|
39
|
+
pass
|
|
35
40
|
|
|
36
41
|
async def _check_reviews(self):
|
|
37
42
|
await self.runner._review._update_review_cache()
|
|
38
43
|
reviews = await self.runner._review._compare_review_cache()
|
|
39
44
|
if reviews:
|
|
40
|
-
for review in reviews
|
|
41
|
-
|
|
45
|
+
tasks = [self._target_review_processing(review) for review in reviews]
|
|
46
|
+
await asyncio.gather(*tasks)
|
|
@@ -14,12 +14,35 @@ class Router:
|
|
|
14
14
|
'chip_category': [],
|
|
15
15
|
'commands': [],
|
|
16
16
|
'error': [],
|
|
17
|
+
'order_command': [],
|
|
17
18
|
|
|
18
19
|
# системные
|
|
19
20
|
'startup': [],
|
|
20
21
|
'flood': []
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
def registrate_order_targets(self, target_dict: dict):
|
|
25
|
+
'''
|
|
26
|
+
Метод для регистрации команд автоматизации новых заказов.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
target_dict (dict): Словарь вида {'target': answer_new_def, 'моя пометка в описании': another_func}
|
|
30
|
+
'''
|
|
31
|
+
self._handlers['order_command'].append({
|
|
32
|
+
'trigger_command': target_dict
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
def registrate_message_command(self, command_dict: dict):
|
|
36
|
+
'''
|
|
37
|
+
Метод для регистрации команд автоматизации сообщений.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
target_dict (dict): Словарь вида {'command': answer_new_def, '!start': another_func}
|
|
41
|
+
'''
|
|
42
|
+
self._handlers['commands'].append({
|
|
43
|
+
'command': command_dict
|
|
44
|
+
})
|
|
45
|
+
|
|
23
46
|
def on_error(self):
|
|
24
47
|
'''Декоратор для отлова ошибок'''
|
|
25
48
|
def decorator(func):
|
|
@@ -31,8 +54,7 @@ class Router:
|
|
|
31
54
|
self,
|
|
32
55
|
text: str | None = None,
|
|
33
56
|
mapping: dict[str, str] | None = None,
|
|
34
|
-
state: str | None = None
|
|
35
|
-
command: dict | None = None
|
|
57
|
+
state: str | None = None
|
|
36
58
|
):
|
|
37
59
|
'''Декоратор отслеживает новые сообщения.
|
|
38
60
|
|
|
@@ -48,24 +70,13 @@ class Router:
|
|
|
48
70
|
- is_system (bool): Системное ли сообщение
|
|
49
71
|
- anwer (method): При указании текста в аргументах, отвечает на сообщение
|
|
50
72
|
'''
|
|
51
|
-
if command and (text is not None or mapping is not None):
|
|
52
|
-
raise fpx_err.FpxAttributeError('В декоратор on_message неправильно переданы аттрибуты, если вы передаёте command, остальные аргументы нельзя передавать.')
|
|
53
73
|
def decorator(func):
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'state': state
|
|
61
|
-
})
|
|
62
|
-
else:
|
|
63
|
-
self._handlers['message'].append({
|
|
64
|
-
'function': func,
|
|
65
|
-
'filter_text': text,
|
|
66
|
-
'mapping': mapping,
|
|
67
|
-
'state': state
|
|
68
|
-
})
|
|
74
|
+
self._handlers['message'].append({
|
|
75
|
+
'function': func,
|
|
76
|
+
'filter_text': text,
|
|
77
|
+
'mapping': mapping,
|
|
78
|
+
'state': state
|
|
79
|
+
})
|
|
69
80
|
return func
|
|
70
81
|
return decorator
|
|
71
82
|
|
|
@@ -117,9 +128,8 @@ class Router:
|
|
|
117
128
|
|
|
118
129
|
def on_new_order(
|
|
119
130
|
self,
|
|
120
|
-
mapping: list | None = None
|
|
121
|
-
|
|
122
|
-
):
|
|
131
|
+
mapping: list | None = None
|
|
132
|
+
):
|
|
123
133
|
'''
|
|
124
134
|
Декоратор, который отслеживает только новые заказы.
|
|
125
135
|
|
|
@@ -6,7 +6,10 @@ from fpx.fsm import MemoryStorage, BaseStorage
|
|
|
6
6
|
|
|
7
7
|
class FunPayTools:
|
|
8
8
|
def __init__(self, gkey, storage: BaseStorage | None = None):
|
|
9
|
-
self.cookies = {
|
|
9
|
+
self.cookies = {
|
|
10
|
+
'golden_key': gkey,
|
|
11
|
+
'locale': 'ru'
|
|
12
|
+
}
|
|
10
13
|
self.headers = {
|
|
11
14
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0",
|
|
12
15
|
"Accept-Language": "ru-RU,ru;q=0.9"
|
|
@@ -15,7 +18,8 @@ class FunPayTools:
|
|
|
15
18
|
http2=True,
|
|
16
19
|
cookies=self.cookies,
|
|
17
20
|
headers=self.headers,
|
|
18
|
-
base_url='https://funpay.com'
|
|
21
|
+
base_url='https://funpay.com',
|
|
22
|
+
follow_redirects=True
|
|
19
23
|
)
|
|
20
24
|
self.account = Account(self.client)
|
|
21
25
|
self.runner = Runner(self.account)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fpx-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Автоматизация работы с FunPay
|
|
5
5
|
Author-email: Be My Code <gettofarmila@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/bymyforge/fpx
|
|
@@ -77,6 +77,7 @@ async def main():
|
|
|
77
77
|
await message.answer('Привет')
|
|
78
78
|
#запускаем приём событий
|
|
79
79
|
await fp.runner.start_polling(3, is_background=True)
|
|
80
|
+
await fp.runner.idle()
|
|
80
81
|
|
|
81
82
|
if __name__ == '__main__':
|
|
82
83
|
asyncio.run(main())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|