fix click
This commit is contained in:
+80
-7
@@ -483,9 +483,14 @@ class BotInterface:
|
||||
if not await require_admin(callback):
|
||||
return
|
||||
tid = callback.data.replace("tdelete_", "", 1)
|
||||
params = await interface.task_manager.get_task(tid)
|
||||
is_visit = params and params.task_type in ("visit", "user_visit")
|
||||
await interface.task_manager.remove_task(tid)
|
||||
await callback.answer("🗑️ Удалена")
|
||||
await interface._show_streamers_list(callback.message, edit=True)
|
||||
if is_visit:
|
||||
await interface._show_tasks_list(callback.message, edit=True)
|
||||
else:
|
||||
await interface._show_streamers_list(callback.message, edit=True)
|
||||
|
||||
|
||||
@dp.callback_query(F.data.startswith("treset_"))
|
||||
@@ -1690,9 +1695,67 @@ class BotInterface:
|
||||
await self._edit_or_send(message, text, builder.as_markup(), edit)
|
||||
|
||||
async def _show_tasks_list(self, message: Message, edit: bool = False):
|
||||
"""Все задачи."""
|
||||
text = await self.task_manager.format_task_list()
|
||||
"""Все задачи — посещения и мониторинг."""
|
||||
active = await self.task_manager.get_active_tasks()
|
||||
completed = await self.task_manager.get_completed_tasks()
|
||||
|
||||
visit_active = {tid: p for tid, p in active.items() if p.task_type in ("visit", "user_visit")}
|
||||
visit_done = {tid: p for tid, p in completed.items() if p.task_type in ("visit", "user_visit")}
|
||||
twitch_active = {tid: p for tid, p in active.items() if p.task_type == "twitch_irc"}
|
||||
twitch_done = {tid: p for tid, p in completed.items() if p.task_type == "twitch_irc"}
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
if not any([visit_active, visit_done, twitch_active, twitch_done]):
|
||||
text = "📊 Задачи\n\nЗадач нет."
|
||||
else:
|
||||
text = "📊 Задачи\n\n"
|
||||
|
||||
if twitch_active:
|
||||
text += "📺 Twitch — активные:\n"
|
||||
for tid, p in list(twitch_active.items())[:10]:
|
||||
em = p.get_status_emoji()
|
||||
domains = ", ".join(p.allowed_domains) if p.allowed_domains else "все"
|
||||
text += f"{em} {p.channel}\n 🔗{p.links_found} | 📊{p.total_visits} | 🌐{domains}\n"
|
||||
builder.row(InlineKeyboardButton(
|
||||
text=f"{em} 📺 {p.channel} (🔗{p.links_found})",
|
||||
callback_data=f"tdetail_{tid}"
|
||||
))
|
||||
|
||||
if twitch_done:
|
||||
text += "\n📺 Twitch — завершённые:\n"
|
||||
for tid, p in list(twitch_done.items())[:5]:
|
||||
em = p.get_status_emoji()
|
||||
text += f"{em} {p.channel}\n"
|
||||
builder.row(InlineKeyboardButton(
|
||||
text=f"{em} 📺 {p.channel} (завершена)",
|
||||
callback_data=f"tdetail_{tid}"
|
||||
))
|
||||
|
||||
if visit_active:
|
||||
text += "\n🔗 Посещения — активные:\n"
|
||||
for tid, p in list(visit_active.items())[:10]:
|
||||
em = p.get_status_emoji()
|
||||
url_s = (p.url or "")[:35]
|
||||
uid_tag = f" | uid:{p.user_id}" if p.user_id else ""
|
||||
text += f"{em} {url_s}{uid_tag}\n ✅{p.successful_visits}/{p.max_visits} | 📊{p.total_visits}\n"
|
||||
builder.row(InlineKeyboardButton(
|
||||
text=f"{em} 🔗 {url_s[:28]} ({p.successful_visits}/{p.max_visits})",
|
||||
callback_data=f"tdetail_{tid}"
|
||||
))
|
||||
|
||||
if visit_done:
|
||||
text += "\n🔗 Посещения — завершённые:\n"
|
||||
for tid, p in list(visit_done.items())[:5]:
|
||||
em = p.get_status_emoji()
|
||||
url_s = (p.url or "")[:35]
|
||||
uid_tag = f" | uid:{p.user_id}" if p.user_id else ""
|
||||
text += f"{em} {url_s}{uid_tag}\n"
|
||||
builder.row(InlineKeyboardButton(
|
||||
text=f"{em} 🔗 {url_s[:28]} (завершена)",
|
||||
callback_data=f"tdetail_{tid}"
|
||||
))
|
||||
|
||||
builder.row(InlineKeyboardButton(text="🔄 Обновить", callback_data="menu_tasks"))
|
||||
builder.row(InlineKeyboardButton(text="🔙 В меню", callback_data="menu_main"))
|
||||
await self._edit_or_send(message, text, builder.as_markup(), edit)
|
||||
@@ -1802,7 +1865,8 @@ class BotInterface:
|
||||
InlineKeyboardButton(text="🗑️ Удалить", callback_data=f"tdelete_{task_id}")
|
||||
)
|
||||
|
||||
builder.row(InlineKeyboardButton(text="🔙 К списку", callback_data="menu_streamers"))
|
||||
back_target = "menu_tasks" if params.task_type in ("visit", "user_visit") else "menu_streamers"
|
||||
builder.row(InlineKeyboardButton(text="🔙 К списку", callback_data=back_target))
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
@@ -2230,6 +2294,7 @@ class BotInterface:
|
||||
break
|
||||
|
||||
# --- Серия кликов ---
|
||||
loop = asyncio.get_event_loop()
|
||||
for click_num in range(series_size):
|
||||
if params.stopped or params.successful_visits >= max_v:
|
||||
break
|
||||
@@ -2240,6 +2305,11 @@ class BotInterface:
|
||||
await send_message_safe(bot, params.chat_id, "⚠️ Баланс исчерпан — задача остановлена")
|
||||
return
|
||||
|
||||
# Фиксируем старт тика до посещения
|
||||
is_last = (click_num == series_size - 1)
|
||||
click_delay = 0 if is_last else params.get_click_delay()
|
||||
tick_start = loop.time()
|
||||
|
||||
try:
|
||||
visitor = self.browser_pool or self.browser_service
|
||||
result = await visitor.visit_page(params.url, params.get_reading_time())
|
||||
@@ -2267,9 +2337,12 @@ class BotInterface:
|
||||
logger.info(f"⏸️ Paused after click {click_num+1}/{series_size}, {remaining_clicks} saved")
|
||||
break
|
||||
|
||||
# Задержка между кликами (кроме последнего)
|
||||
if click_num < series_size - 1 and params.successful_visits < max_v:
|
||||
await _sleep_interruptible(params.get_click_delay())
|
||||
# Задержка между кликами строго по таймеру: спим только остаток
|
||||
if not is_last and params.successful_visits < max_v:
|
||||
elapsed = loop.time() - tick_start
|
||||
remaining_wait = int(click_delay - elapsed)
|
||||
if remaining_wait > 0:
|
||||
await _sleep_interruptible(remaining_wait)
|
||||
|
||||
await self.task_manager.complete_task(task_id)
|
||||
remaining = await self.balance_storage.get_balance(params.user_id)
|
||||
|
||||
@@ -272,8 +272,12 @@ class TaskManager:
|
||||
return await self.get_tasks_by_type("twitch_irc")
|
||||
|
||||
async def get_visit_tasks(self) -> Dict[str, TaskParams]:
|
||||
"""Только задачи посещения."""
|
||||
return await self.get_tasks_by_type("visit")
|
||||
"""Задачи посещения (admin и user)."""
|
||||
async with self._lock:
|
||||
return {
|
||||
tid: p for tid, p in self._tasks.items()
|
||||
if p.task_type in ("visit", "user_visit")
|
||||
}
|
||||
|
||||
async def get_stats(self) -> dict:
|
||||
"""Общая статистика."""
|
||||
@@ -281,7 +285,7 @@ class TaskManager:
|
||||
for p in self._tasks.values():
|
||||
if p.task_type == "twitch_irc":
|
||||
twitch += 1
|
||||
elif p.task_type == "visit":
|
||||
elif p.task_type in ("visit", "user_visit"):
|
||||
visit += 1
|
||||
if p.paused:
|
||||
paused += 1
|
||||
@@ -300,12 +304,18 @@ class TaskManager:
|
||||
status = params.get_status_emoji()
|
||||
|
||||
if params.task_type == "twitch_irc":
|
||||
user_tag = f" | 👤uid:{params.user_id}" if params.user_id else ""
|
||||
return (
|
||||
f"{status} 📺 **{params.channel}**\n"
|
||||
f" `{task_id[:12]}...`\n"
|
||||
f" 👤 @{params.target_username} | "
|
||||
f"🔗{params.links_found} | "
|
||||
f"📊{params.total_visits}\n"
|
||||
f" `{task_id[:12]}...`{user_tag}\n"
|
||||
f" 🔗{params.links_found} | 📊{params.total_visits}\n"
|
||||
)
|
||||
elif params.task_type == "user_visit":
|
||||
user_tag = f" | 👤uid:{params.user_id}" if params.user_id else ""
|
||||
return (
|
||||
f"{status} 🔗 `{params.url[:40]}`\n"
|
||||
f" `{task_id[:12]}...`{user_tag}\n"
|
||||
f" ✅{params.successful_visits}/{params.max_visits} | 📊{params.total_visits}\n"
|
||||
)
|
||||
else:
|
||||
return (
|
||||
|
||||
@@ -56,6 +56,7 @@ class VisitScheduler:
|
||||
Statistics dict
|
||||
"""
|
||||
total_reading_time = 0
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
try:
|
||||
while True:
|
||||
@@ -63,15 +64,18 @@ class VisitScheduler:
|
||||
logger.info(f"Visit limit reached: {self.max_visits}")
|
||||
break
|
||||
|
||||
# Randomize parameters
|
||||
# Randomize parameters once per cycle
|
||||
current_reading = random.randint(self.min_reading, self.max_reading)
|
||||
current_delay = random.randint(self.min_delay, self.max_delay)
|
||||
|
||||
self.visit_count += 1
|
||||
|
||||
# Record start time so the next visit fires strictly on the timer
|
||||
tick_start = loop.time()
|
||||
|
||||
logger.info(
|
||||
f"Visit {self.visit_count}/{'∞' if not self.max_visits else self.max_visits}: "
|
||||
f"reading={current_reading}s"
|
||||
f"reading={current_reading}s delay={current_delay}s"
|
||||
)
|
||||
|
||||
# Visit page
|
||||
@@ -94,11 +98,16 @@ class VisitScheduler:
|
||||
if self.max_visits and self.visit_count >= self.max_visits:
|
||||
break
|
||||
|
||||
# Wait before next visit
|
||||
# Wait only the remaining time so that the period between visit
|
||||
# starts is exactly current_delay (independent of visit duration)
|
||||
elapsed = loop.time() - tick_start
|
||||
remaining = current_delay - elapsed
|
||||
|
||||
if self.on_progress:
|
||||
await self.on_progress(self.visit_count, current_delay)
|
||||
|
||||
await asyncio.sleep(current_delay)
|
||||
if remaining > 0:
|
||||
await asyncio.sleep(remaining)
|
||||
|
||||
except asyncio.CancelledError:
|
||||
logger.info("Visit scheduler cancelled")
|
||||
|
||||
Reference in New Issue
Block a user