This commit is contained in:
Yuriy Yuriev
2026-05-18 21:19:05 +07:00
parent 88bd8bfefa
commit 0102461e78
4 changed files with 173 additions and 75 deletions
+84 -26
View File
@@ -436,13 +436,12 @@ class BotInterface:
"delay": (
"⏱️ *Пауза между переходами*\n"
"Сколько секунд ждать перед следующим кликом.\n"
"Диапазон `30-60` — каждый раз рандом от 30 до 60.\n"
"Одно число `45` — всегда фиксированно."
"Диапазон `30-60` — каждый раз рандом от 30 до 60."
),
"reading": (
"📖 *Время на странице*\n"
"Сколько секунд браузер будет листать страницу (имитация чтения).\n"
"Диапазон `45-90` или фиксированно `60`."
"Диапазон `45-90`."
),
"perlink": (
"🔗 *Резервное кол-во кликов*\n"
@@ -454,8 +453,7 @@ class BotInterface:
"📊 *CTR — процент от зрителей*\n"
"Формула: клики = зрители × CTR%.\n"
"Например: 120 зрителей × 1% = 1 клик.\n"
"Диапазон `0.8-1` — случайно в этом диапазоне.\n"
"Одно число `1` — фиксированно."
"Диапазон `0.8-1` — случайно в этом диапазоне."
),
"minutes": (
"⏰ *Длительность мониторинга*\n"
@@ -817,7 +815,7 @@ class BotInterface:
f"🔢 *Кликов в одном цикле*\n"
f"Сколько кликов подряд делать перед паузой.\n"
f"Текущее: {cur}\n"
f"Диапазон `2-5` или фиксированно `3`."
f"Диапазон `2-5`."
)
_d_mn = params.min_delay // 60
_d_mx = params.max_delay // 60
@@ -826,7 +824,7 @@ class BotInterface:
f"⏱️ *Пауза между циклами*\n"
f"Сколько минут ждать после каждого цикла кликов.\n"
f"Текущая: {_d_cur} мин\n"
f"Диапазон `2-5` или фиксированно `3`."
f"Диапазон `2-5`."
)
else:
perlink_label = (
@@ -840,7 +838,7 @@ class BotInterface:
f"⏱️ *Пауза между переходами*\n"
f"Сколько секунд ждать перед следующим кликом.\n"
f"Текущая: {params.min_delay}{params.max_delay} сек\n"
f"Диапазон `30-60` или фиксированно `45`."
f"Диапазон `30-60`."
)
prompts = {
"delay": delay_label,
@@ -848,13 +846,13 @@ class BotInterface:
f"📖 *Время на странице*\n"
f"Сколько секунд браузер листает страницу (имитация чтения).\n"
f"Текущее: {params.min_reading}{params.max_reading} сек\n"
f"Диапазон `45-90` или фиксированно `60`."
f"Диапазон `45-90`."
),
"percent": (
f"👥 *Кликов = % от зрителей*\n"
f"Количество кликов рассчитывается как % от числа зрителей стрима.\n"
f"Текущий: {params.visits_percent}%\n"
f"`0` — отключить, использовать фиксированное кол-во.\n"
f"`0` — отключить.\n"
f"Пример: `5` = 5 кликов на 100 зрителей."
),
"perlink": perlink_label,
@@ -862,13 +860,13 @@ class BotInterface:
f"⏳ *Задержка между кликами в цикле*\n"
f"Сколько секунд ждать между каждым кликом внутри одного цикла.\n"
f"Текущая: {params.min_click_delay}{params.max_click_delay} сек\n"
f"Диапазон `5-15` или фиксированно `10`."
f"Диапазон `5-15`."
),
"ctr": (
f"📊 *CTR — процент от зрителей*\n"
f"Формула: клики = зрители × CTR%.\n"
f"Текущий: {params.min_ctr}%{params.max_ctr}%\n"
f"Диапазон `0.8-1` или фиксированно `1`."
f"Диапазон `0.8-1`."
),
}
prompt = prompts.get(param, f"Введите значение для {param}:")
@@ -1089,6 +1087,59 @@ class BotInterface:
await callback.answer("🗑️ Задача удалена")
await interface._show_user_tasks(callback.message, uid, edit=True)
@dp.callback_query(F.data.startswith("urestart_"))
async def cb_user_restart_task(callback: CallbackQuery):
tid = callback.data.replace("urestart_", "", 1)
params, uid = await _get_user_task(callback, tid)
if not params:
return
balance = await interface.balance_storage.get_balance(uid)
if balance <= 0:
await callback.answer("❌ Недостаточно переходов", show_alert=True)
return
# Сбрасываем статистику и статус
await interface.task_manager.update_task(
tid,
completed=False,
stopped=False,
paused=False,
successful_visits=0,
total_visits=0,
)
if params.task_type == "user_visit":
await interface.background_tasks.cancel_task(tid)
success = await interface.background_tasks.start_task(
task_id=tid,
coro=interface._run_url_visits(tid, params, callback.message.bot),
task_type="user_visit",
metadata={"type": "user_visit", "url": params.url, "chat_id": params.chat_id},
)
else:
from types import SimpleNamespace
msg_mock = SimpleNamespace(
chat=SimpleNamespace(id=params.chat_id),
bot=callback.message.bot,
)
await interface.background_tasks.cancel_task(tid)
success = await interface.background_tasks.start_task(
task_id=tid,
coro=interface._run_twitch(tid, params, msg_mock),
task_type="twitch_irc",
metadata={"type": "twitch_irc", "channel": params.channel, "chat_id": params.chat_id},
)
if success:
if interface.storage:
await interface.storage.save_task(tid, params)
await callback.answer("🔄 Задача перезапущена")
else:
await callback.answer("❌ Ошибка перезапуска", show_alert=True)
await interface._show_user_tasks(callback.message, uid, edit=True)
@dp.callback_query(F.data.startswith("upause_"))
async def cb_user_pause_task(callback: CallbackQuery):
tid = callback.data.replace("upause_", "", 1)
@@ -2022,12 +2073,22 @@ class BotInterface:
def is_active():
return not params.paused and not params.stopped and not params.stream_offline
async def on_drain_fail():
await self.task_manager.pause_task(task_id)
await send_message_safe(
message.bot, params.chat_id,
f"⚠️ IRC #{params.channel}: ошибка соединения (3 попытки) — задача поставлена на паузу"
)
logger.info(f"🚀 IRC monitor: {params.channel}")
watcher = asyncio.create_task(self._stream_watcher(task_id, params, message))
try:
await irc.listen_for_messages(on_url, params.monitor_duration, params.allowed_domains, is_active=is_active)
await irc.listen_for_messages(
on_url, params.monitor_duration, params.allowed_domains,
is_active=is_active, on_drain_fail=on_drain_fail
)
if params.monitor_minutes > 0:
await self.task_manager.complete_task(task_id)
except asyncio.CancelledError:
@@ -2044,7 +2105,6 @@ class BotInterface:
async def _run_url_visits(self, task_id: str, params: TaskParams, bot):
"""Посещает URL циклами: sleep(межцикловая) → N кликов(+sleep между ними) → повтор."""
total_done = 0
max_v = params.max_visits or 1
async def _sleep_interruptible(seconds: int):
@@ -2056,7 +2116,7 @@ class BotInterface:
await asyncio.sleep(1)
try:
while total_done < max_v and not params.stopped:
while params.successful_visits < max_v and not params.stopped:
# --- пауза перед циклом ---
await _sleep_interruptible(params.get_delay())
if params.stopped:
@@ -2067,7 +2127,7 @@ class BotInterface:
# --- цикл кликов ---
for click_num in range(series_size):
if params.stopped or total_done >= max_v:
if params.stopped or params.successful_visits >= max_v:
break
while params.paused and not params.stopped:
@@ -2085,7 +2145,6 @@ class BotInterface:
try:
result = await self.browser_service.visit_page(params.url, reading)
params.total_visits += 1
total_done += 1
if result.success:
params.successful_visits += 1
await self.balance_storage.deduct(params.user_id, 1)
@@ -2093,10 +2152,10 @@ class BotInterface:
raise
except Exception as e:
logger.error(f"URL visit error: {e}")
total_done += 1
params.total_visits += 1
# задержка между кликами внутри цикла (кроме последнего)
if click_num < series_size - 1 and not params.stopped and total_done < max_v:
if click_num < series_size - 1 and not params.stopped and params.successful_visits < max_v:
await _sleep_interruptible(params.get_click_delay())
await self.task_manager.complete_task(task_id)
@@ -2290,10 +2349,11 @@ class BotInterface:
InlineKeyboardButton(text="🗑️", callback_data=f"ustop_{tid}"),
)
else:
builder.row(InlineKeyboardButton(
text=f"🗑️ {label} (завершена)",
callback_data=f"ustop_{tid}"
))
builder.row(
InlineKeyboardButton(text=label, callback_data=f"utask_{tid}"),
InlineKeyboardButton(text="🔄", callback_data=f"urestart_{tid}"),
InlineKeyboardButton(text="🗑️", callback_data=f"ustop_{tid}"),
)
builder.row(InlineKeyboardButton(text="📝 Новая задача", callback_data="new_task"))
builder.row(InlineKeyboardButton(text="🔙 Мои задачи", callback_data="my_tasks"))
@@ -2417,8 +2477,7 @@ class BotInterface:
f"✅ Переходов: {count}\n\n"
"Шаг 3/4 — сколько кликов в одном цикле?\n\n"
"Бот делает N кликов подряд, затем ждёт паузу и начинает следующий цикл.\n\n"
"Диапазон `2-5` — каждый цикл будет случайной длины от 2 до 5.\n"
"Одно число `3` — всегда ровно 3 клика.",
"Диапазон `2-5` — каждый цикл будет случайной длины от 2 до 5.",
reply_markup=builder.as_markup()
)
self._menu_msg[user_id] = sent.message_id
@@ -2444,7 +2503,6 @@ class BotInterface:
sent = await message.answer(
f"✅ Цикл: {series_label} кликов\n\n"
"Шаг 4/4 — таймаут между циклами (в минутах)\n\n"
"`3` — ровно 3 минуты.\n"
"`2-5` — случайно от 2 до 5 минут.",
reply_markup=builder.as_markup()
)