From 88bd8bfefaa6ff31a4e8b196b06b3c1729b5b374 Mon Sep 17 00:00:00 2001 From: Yuriy Yuriev Date: Mon, 18 May 2026 19:30:15 +0700 Subject: [PATCH] fix comand --- handlers/commands.py | 323 +++++++++++++++++++++++++++++++------------ 1 file changed, 234 insertions(+), 89 deletions(-) diff --git a/handlers/commands.py b/handlers/commands.py index 52eeef4..fda592c 100644 --- a/handlers/commands.py +++ b/handlers/commands.py @@ -819,11 +819,14 @@ class BotInterface: f"Текущее: {cur}\n" f"Диапазон `2-5` или фиксированно `3`." ) + _d_mn = params.min_delay // 60 + _d_mx = params.max_delay // 60 + _d_cur = f"{_d_mn}–{_d_mx}" if _d_mn != _d_mx else str(_d_mn) delay_label = ( f"⏱️ *Пауза между циклами*\n" - f"Сколько секунд ждать после каждого цикла кликов.\n" - f"Текущая: {params.min_delay}–{params.max_delay} сек\n" - f"Диапазон `30-60` или фиксированно `45`." + f"Сколько минут ждать после каждого цикла кликов.\n" + f"Текущая: {_d_cur} мин\n" + f"Диапазон `2-5` или фиксированно `3`." ) else: perlink_label = ( @@ -873,12 +876,12 @@ class BotInterface: interface._user_input_state[uid] = { "task_id": task_id, "param": param, + "menu_msg_id": callback.message.message_id, } builder = InlineKeyboardBuilder() builder.row(InlineKeyboardButton(text="❌ Отмена", callback_data=f"utask_{task_id}")) - sent = await callback.message.answer(prompt, reply_markup=builder.as_markup()) - interface._user_input_state[uid]["prompt_msg_id"] = sent.message_id - await callback.answer(f"Введите значение") + await callback.message.edit_text(prompt, reply_markup=builder.as_markup()) + await callback.answer() @dp.callback_query(F.data == "confirm_buy") async def cb_confirm_buy(callback: CallbackQuery): @@ -1036,6 +1039,10 @@ class BotInterface: await interface._show_user_menu(callback.message, user_id=uid) await callback.answer("👤 Переключились в режим пользователя") + @dp.callback_query(F.data == "noop") + async def _cb_noop(callback: CallbackQuery): + await callback.answer() + @dp.callback_query(F.data == "cancel_new_task") async def cb_cancel_new_task(callback: CallbackQuery): uid = callback.from_user.id @@ -1048,6 +1055,16 @@ class BotInterface: await interface._show_user_tasks(callback.message, callback.from_user.id, edit=True) await callback.answer() + @dp.callback_query(F.data == "my_tasks_visits") + async def cb_my_tasks_visits(callback: CallbackQuery): + await interface._show_user_visits(callback.message, callback.from_user.id, edit=True) + await callback.answer() + + @dp.callback_query(F.data == "my_tasks_monitors") + async def cb_my_tasks_monitors(callback: CallbackQuery): + await interface._show_user_monitors(callback.message, callback.from_user.id, edit=True) + await callback.answer() + async def _get_user_task(callback: CallbackQuery, tid: str): uid = callback.from_user.id if not interface.auth_manager.is_authenticated(uid): @@ -1690,41 +1707,44 @@ class BotInterface: user_id = message.from_user.id state = self._user_input_state.pop(user_id) - # Удаляем prompt и ответ пользователя - prompt_id = state.get("prompt_msg_id") - if prompt_id: - await self._safe_delete(message.bot, message.chat.id, prompt_id) await self._safe_delete(message.bot, message.chat.id, message.message_id) task_id = state["task_id"] param = state["param"] + menu_msg_id = state.get("menu_msg_id") value = message.text.strip() if message.text else "" value = value.replace("'", "").replace('"', "").replace("`", "").strip() - + logger.info(f"Process param: {param} = {value}") - + if not value: - await message.answer("❌ Пустое значение. Попробуйте ещё раз.") + await self._send_temp(message, "❌ Пустое значение. Попробуйте ещё раз.") return - + + confirm = "" try: if param == "delay": if "-" in value: mn, mx = parse_range(value) else: mn = mx = int(value) - await self.task_manager.update_task(task_id, min_delay=mn, max_delay=mx) - await message.answer(f"✅ Задержка: {format_range(mn, mx)}с") - + task_obj = await self.task_manager.get_task(task_id) + if task_obj and task_obj.task_type == "user_visit": + await self.task_manager.update_task(task_id, min_delay=mn * 60, max_delay=mx * 60) + confirm = f"✅ Пауза: {format_range(mn, mx)} мин" + else: + await self.task_manager.update_task(task_id, min_delay=mn, max_delay=mx) + confirm = f"✅ Задержка: {format_range(mn, mx)}с" + elif param == "reading": if "-" in value: mn, mx = parse_range(value, default_min=1) else: mn = mx = int(value) await self.task_manager.update_task(task_id, min_reading=mn, max_reading=mx) - await message.answer(f"✅ Чтение: {format_range(mn, mx)}с") - + confirm = f"✅ Чтение: {format_range(mn, mx)}с" + elif param == "perlink": params_obj = await self.task_manager.get_task(task_id) if params_obj and params_obj.task_type == "user_visit": @@ -1734,11 +1754,11 @@ class BotInterface: mn = mx = int(value) await self.task_manager.update_task(task_id, min_series=mn, max_series=mx) lbl = f"{mn}–{mx}" if mn != mx else str(mn) - await message.answer(f"✅ Цикл: {lbl} кликов") + confirm = f"✅ Цикл: {lbl} кликов" else: await self.task_manager.update_task(task_id, visits_per_link=int(value)) - await message.answer(f"✅ На ссылку: {value}") - + confirm = f"✅ На ссылку: {value}" + elif param == "ctr": if "-" in value: parts_v = value.split("-", 1) @@ -1750,27 +1770,27 @@ class BotInterface: raise ValueError("CTR должен быть от 0 до 100, например 0.8-1") await self.task_manager.update_task(task_id, min_ctr=mn_c, max_ctr=mx_c) lbl = f"{mn_c}%–{mx_c}%" if mn_c != mx_c else f"{mn_c}%" - await message.answer(f"✅ CTR: {lbl}") + confirm = f"✅ CTR: {lbl}" elif param == "minutes": await self.task_manager.update_task(task_id, monitor_minutes=int(value)) - await message.answer(f"✅ Мониторинг: {value} мин") - + confirm = f"✅ Мониторинг: {value} мин" + elif param == "domains": if value.lower() in ["all", "все"]: await self.task_manager.update_task(task_id, allowed_domains=None) - await message.answer("✅ Домены: все") + confirm = "✅ Домены: все" else: domains = [d.strip().lower() for d in value.split(",") if d.strip()] await self.task_manager.update_task(task_id, allowed_domains=domains) - await message.answer(f"✅ Домены: {', '.join(domains)}") + confirm = f"✅ Домены: {', '.join(domains)}" elif param == "percent": pct = float(value.replace(",", ".")) if pct < 0 or pct > 100: raise ValueError("Значение от 0 до 100") await self.task_manager.update_task(task_id, visits_percent=pct) - await message.answer(f"✅ % зрителей: {pct}%" if pct > 0 else "✅ % зрителей отключён") + confirm = f"✅ % зрителей: {pct}%" if pct > 0 else "✅ % зрителей отключён" elif param == "clickdelay": if "-" in value: @@ -1778,27 +1798,93 @@ class BotInterface: else: mn = mx = int(value) await self.task_manager.update_task(task_id, min_click_delay=mn, max_click_delay=mx) - await message.answer(f"✅ Задержка между кликами: {format_range(mn, mx)}с") - - elif param == "ctr": - if "-" in value: - parts_v = value.split("-", 1) - mn_c = float(parts_v[0].replace(",", ".")) - mx_c = float(parts_v[1].replace(",", ".")) - else: - mn_c = mx_c = float(value.replace(",", ".")) - if not (0 < mn_c <= mx_c <= 100): - raise ValueError("CTR должен быть от 0 до 100, например 0.8-1") - await self.task_manager.update_task(task_id, min_ctr=mn_c, max_ctr=mx_c) - lbl = f"{mn_c}%–{mx_c}%" if mn_c != mx_c else f"{mn_c}%" - await message.answer(f"✅ CTR: {lbl}") + confirm = f"✅ Задержка между кликами: {format_range(mn, mx)}с" else: - await message.answer(f"❌ Неизвестный параметр: {param}") - + await self._send_temp(message, f"❌ Неизвестный параметр: {param}") + return + except ValueError as e: - await message.answer(f"❌ Ошибка: {e}") + await self._send_temp(message, f"❌ Ошибка: {e}") + return + + # Обновляем меню с параметрами (заменяем prompt обратно на настройки задачи) + updated = await self.task_manager.get_task(task_id) + if updated and menu_msg_id: + try: + await self._rebuild_user_task_menu( + message.bot, message.chat.id, menu_msg_id, task_id, updated, confirm + ) + return + except Exception: + pass + await self._send_temp(message, confirm, delay=4) + async def _rebuild_user_task_menu( + self, bot, chat_id: int, msg_id: int, + task_id: str, params: TaskParams, confirm: str = "" + ): + """Редактирует сообщение обратно в настройки задачи после ввода параметра.""" + if params.task_type == "user_visit": + series_range = ( + f"{params.min_series}–{params.max_series}" + if params.min_series != params.max_series + else str(params.min_series) + ) + info = ( + f"🔗 {params.url[:50]}\n" + f"📊 Выполнено: {params.successful_visits} из {params.max_visits} переходов\n\n" + f"🔢 Кликов в цикле: {series_range}\n" + f"⏳ Задержка между кликами: {params.min_click_delay}–{params.max_click_delay} сек\n" + f"⏱ Пауза между циклами: {params.min_delay // 60}–{params.max_delay // 60} мин\n" + f"📖 Время на странице: {params.min_reading}–{params.max_reading} сек" + ) + else: + domains = ", ".join(params.allowed_domains) if params.allowed_domains else "все" + ctr_str = ( + f"{params.min_ctr}%–{params.max_ctr}%" + if params.min_ctr != params.max_ctr + else f"{params.min_ctr}%" + ) + info = ( + f"📺 Стример: {params.channel}\n" + f"🌐 Домены: {domains}\n\n" + f"🔗 Ссылок найдено: {params.links_found}\n" + f"✅ Успешных кликов: {params.successful_visits}\n\n" + f"📊 CTR: {ctr_str}\n" + f"⏱ Пауза между кликами: {params.min_delay}–{params.max_delay} сек\n" + f"📖 Время на странице: {params.min_reading}–{params.max_reading} сек" + ) + + builder = InlineKeyboardBuilder() + if params.task_type == "user_visit": + builder.row( + InlineKeyboardButton(text="⏱️ Пауза (мин)", callback_data=f"uset_{task_id}_delay"), + InlineKeyboardButton(text="📖 Время на стр.", callback_data=f"uset_{task_id}_reading"), + ) + builder.row( + InlineKeyboardButton(text="🔢 Размер цикла", callback_data=f"uset_{task_id}_perlink"), + InlineKeyboardButton(text="⏳ Между кликами", callback_data=f"uset_{task_id}_clickdelay"), + ) + else: + builder.row( + InlineKeyboardButton(text="⏱️ Пауза (сек)", callback_data=f"uset_{task_id}_delay"), + InlineKeyboardButton(text="📖 Время на стр.", callback_data=f"uset_{task_id}_reading"), + ) + builder.row( + InlineKeyboardButton(text="📊 % CTR зрителей", callback_data=f"uset_{task_id}_ctr"), + InlineKeyboardButton(text="🌐 Домены", callback_data=f"uedit_{task_id}"), + ) + builder.row(InlineKeyboardButton(text="🔙 К задачам", callback_data="my_tasks")) + + prefix = f"{confirm}\n\n" if confirm else "" + await bot.edit_message_text( + f"{prefix}⚙️ Параметры задачи\n\n{info}", + chat_id=chat_id, + message_id=msg_id, + reply_markup=builder.as_markup() + ) + async def _show_user_task_detail(self, callback: CallbackQuery, task_id: str, params: TaskParams): if params.task_type == "user_visit": series_range = ( @@ -1811,7 +1897,7 @@ class BotInterface: f"📊 Выполнено: {params.successful_visits} из {params.max_visits} переходов\n\n" f"🔢 Кликов в цикле: {series_range}\n" f"⏳ Задержка между кликами: {params.min_click_delay}–{params.max_click_delay} сек\n" - f"⏱ Пауза между циклами: {params.min_delay}–{params.max_delay} сек\n" + f"⏱ Пауза между циклами: {params.min_delay // 60}–{params.max_delay // 60} мин\n" f"📖 Время на странице: {params.min_reading}–{params.max_reading} сек" ) else: @@ -1838,16 +1924,20 @@ class BotInterface: ) builder = InlineKeyboardBuilder() - builder.row( - InlineKeyboardButton(text="⏱️ Пауза (сек)", callback_data=f"uset_{task_id}_delay"), - InlineKeyboardButton(text="📖 Время на стр.", callback_data=f"uset_{task_id}_reading"), - ) if params.task_type == "user_visit": + builder.row( + InlineKeyboardButton(text="⏱️ Пауза (мин)", callback_data=f"uset_{task_id}_delay"), + InlineKeyboardButton(text="📖 Время на стр.", callback_data=f"uset_{task_id}_reading"), + ) builder.row( InlineKeyboardButton(text="🔢 Размер цикла", callback_data=f"uset_{task_id}_perlink"), InlineKeyboardButton(text="⏳ Между кликами", callback_data=f"uset_{task_id}_clickdelay"), ) else: + builder.row( + InlineKeyboardButton(text="⏱️ Пауза (сек)", callback_data=f"uset_{task_id}_delay"), + InlineKeyboardButton(text="📖 Время на стр.", callback_data=f"uset_{task_id}_reading"), + ) builder.row( InlineKeyboardButton(text="📊 % CTR зрителей", callback_data=f"uset_{task_id}_ctr"), InlineKeyboardButton(text="🌐 Домены", callback_data=f"uedit_{task_id}"), @@ -2146,55 +2236,106 @@ class BotInterface: all_tasks = await self.task_manager.get_all_tasks() user_tasks = {tid: p for tid, p in all_tasks.items() if p.user_id == user_id} + visits = {tid: p for tid, p in user_tasks.items() if p.task_type == "user_visit"} + monitors = {tid: p for tid, p in user_tasks.items() if p.task_type != "user_visit"} + + v_active = sum(1 for p in visits.values() if not p.completed and not p.stopped) + m_active = sum(1 for p in monitors.values() if not p.completed and not p.stopped) + if not user_tasks: text = f"📋 Задачи {str(user_id) if for_admin else ''}\n\nЗадач нет." else: header = f"📋 Задачи пользователя {user_id}\n\n" if for_admin else "📋 Мои задачи\n\n" text = header - for tid, p in list(user_tasks.items())[:10]: - if p.task_type == "user_visit": - text += ( - f"{p.get_status_emoji()} 🔗 {p.url[:40]}\n" - f" ✅ {p.successful_visits}/{p.max_visits} | 📊 {p.total_visits}\n" - ) - else: - domains = ", ".join(p.allowed_domains) if p.allowed_domains else "все" - text += ( - f"{p.get_status_emoji()} 📺 {p.channel} — 🌐 {domains}\n" - f" 🔗 {p.links_found} | ✅ {p.successful_visits} | 📊 {p.total_visits}\n" - ) + if visits: + text += f"🔗 Посещения — {v_active} акт. / {len(visits)} всего\n" + if monitors: + text += f"📺 Мониторинг — {m_active} акт. / {len(monitors)} всего\n" builder = InlineKeyboardBuilder() if for_admin: builder.row(InlineKeyboardButton(text="🔙 К пользователю", callback_data=f"udetail_{user_id}")) else: - for tid, p in list(user_tasks.items())[:8]: - if p.task_type == "user_visit": - domain = extract_domain(p.url)[:18] if p.url else "?" - label = f"🔗 {domain}" - else: - label = f"📺 {p.channel}" - if not p.completed and not p.stopped: - pause_btn = ( - InlineKeyboardButton(text="▶️", callback_data=f"uresume_{tid}") - if p.paused else - InlineKeyboardButton(text="⏸️", callback_data=f"upause_{tid}") - ) - builder.row( - InlineKeyboardButton(text=label, callback_data=f"utask_{tid}"), - pause_btn, - InlineKeyboardButton(text="⚙️", callback_data=f"utask_{tid}"), - InlineKeyboardButton(text="🗑️", callback_data=f"ustop_{tid}"), - ) - else: - builder.row(InlineKeyboardButton( - text=f"🗑️ {label} (завершена)", - callback_data=f"ustop_{tid}" - )) + builder.row( + InlineKeyboardButton( + text=f"🔗 Посещения ({len(visits)})", + callback_data="my_tasks_visits" + ), + InlineKeyboardButton( + text=f"📺 Мониторинг ({len(monitors)})", + callback_data="my_tasks_monitors" + ), + ) builder.row(InlineKeyboardButton(text="📝 Новая задача", callback_data="new_task")) builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data="user_menu")) await self._edit_or_send(message, text, builder.as_markup(), edit) + def _build_task_buttons(self, builder: InlineKeyboardBuilder, tasks: dict): + for tid, p in list(tasks.items())[:8]: + if p.task_type == "user_visit": + domain = extract_domain(p.url)[:16] if p.url else "?" + label = f"🔗 {domain}" + else: + label = f"📺 {p.channel}" + if not p.completed and not p.stopped: + pause_btn = ( + InlineKeyboardButton(text="▶️", callback_data=f"uresume_{tid}") + if p.paused else + InlineKeyboardButton(text="⏸️", callback_data=f"upause_{tid}") + ) + builder.row( + InlineKeyboardButton(text=label, callback_data=f"utask_{tid}"), + pause_btn, + InlineKeyboardButton(text="⚙️", callback_data=f"utask_{tid}"), + InlineKeyboardButton(text="🗑️", callback_data=f"ustop_{tid}"), + ) + else: + builder.row(InlineKeyboardButton( + text=f"🗑️ {label} (завершена)", + callback_data=f"ustop_{tid}" + )) + builder.row(InlineKeyboardButton(text="📝 Новая задача", callback_data="new_task")) + builder.row(InlineKeyboardButton(text="🔙 Мои задачи", callback_data="my_tasks")) + + async def _show_user_visits(self, message: Message, user_id: int, edit: bool = False): + all_tasks = await self.task_manager.get_all_tasks() + visits = { + tid: p for tid, p in all_tasks.items() + if p.user_id == user_id and p.task_type == "user_visit" + } + if not visits: + text = "🔗 Посещения\n\nЗадач нет." + else: + text = "🔗 Посещения\n\n" + for _, p in list(visits.items())[:8]: + text += ( + f"{p.get_status_emoji()} {p.url[:40]}\n" + f" ✅ {p.successful_visits}/{p.max_visits} | 📊 {p.total_visits}\n" + ) + builder = InlineKeyboardBuilder() + self._build_task_buttons(builder, visits) + await self._edit_or_send(message, text, builder.as_markup(), edit) + + async def _show_user_monitors(self, message: Message, user_id: int, edit: bool = False): + all_tasks = await self.task_manager.get_all_tasks() + monitors = { + tid: p for tid, p in all_tasks.items() + if p.user_id == user_id and p.task_type != "user_visit" + } + if not monitors: + text = "📺 Мониторинг\n\nЗадач нет." + else: + text = "📺 Мониторинг\n\n" + for _, p in list(monitors.items())[:8]: + domains = ", ".join(p.allowed_domains) if p.allowed_domains else "все" + text += ( + f"{p.get_status_emoji()} {p.channel} — {domains}\n" + f" 🔗 {p.links_found} | ✅ {p.successful_visits} | 📊 {p.total_visits}\n" + ) + builder = InlineKeyboardBuilder() + self._build_task_buttons(builder, monitors) + await self._edit_or_send(message, text, builder.as_markup(), edit) + async def _process_user_task_input(self, message: Message): user_id = message.from_user.id state = self._user_task_state[user_id] @@ -2303,18 +2444,22 @@ class BotInterface: sent = await message.answer( f"✅ Цикл: {series_label} кликов\n\n" "Шаг 4/4 — таймаут между циклами (в минутах)\n\n" - "Введите одно число, например `3` — пауза 3 минуты.", + "`3` — ровно 3 минуты.\n" + "`2-5` — случайно от 2 до 5 минут.", reply_markup=builder.as_markup() ) self._menu_msg[user_id] = sent.message_id elif state["step"] == "delay": try: - mn_d = mx_d = int(text) + if "-" in text: + mn_d, mx_d = parse_range(text, default_min=1) + else: + mn_d = mx_d = int(text) if mn_d < 1: raise ValueError except Exception: - await self._send_temp(message, "Введите целое число минут, например: `3`") + await self._send_temp(message, "Введите число или диапазон минут, например: `3` или `2-5`") return del self._user_task_state[user_id] @@ -2325,7 +2470,7 @@ class BotInterface: mn = state["min_series"] mx = state["max_series"] series_label = f"{mn}–{mx}" if mn != mx else str(mn) - delay_label = str(mn_d) + delay_label = f"{mn_d}–{mx_d}" if mn_d != mx_d else str(mn_d) task_id = f"u{user_id}_{extract_domain(url)[:12]}_{datetime.now().strftime('%H%M%S')}" params = TaskParams(