feat(ui): add inline historical scrape buttons to monitored sources cards

This commit is contained in:
mamad
2026-08-27 21:08:13 +03:30
parent 963d7f365f
commit f23ce3a383
+57 -29
View File
@@ -17,7 +17,7 @@ def get_main_menu_keyboard():
[Button.text("🔑 Request Login Code", resize=True), Button.text("📊 Fleet Statistics", resize=True)],
[Button.text("📡 Monitored Sources", resize=True), Button.text("🎯 Target Channels", resize=True)],
[Button.text(" Add Source Guide", resize=True), Button.text(" Add Target Guide", resize=True)],
[Button.text("📥 Scrape History Guide", resize=True), Button.text("❓ Help & Documentation", resize=True)]
[Button.text("❓ Help & Documentation", resize=True)]
]
class AdminBotService:
@@ -137,21 +137,7 @@ class AdminBotService:
result = await self.collector.submit_password(pwd)
await status_msg.edit(result, parse_mode="html", buttons=get_main_menu_keyboard())
# --- History Scraper Commands ---
@self.client.on(events.NewMessage(pattern=r"(?i)^(📥 Scrape History Guide)$"))
async def cmd_scrape_guide(event: events.NewMessage.Event):
if not self.is_admin(event.sender_id):
return
guide = (
"📥 <b>Historical Channel Scraper:</b>\n\n"
"Import previous/past posts from any channel:\n"
"<code>/scrape_history &lt;channel_id&gt; [number_of_posts]</code>\n\n"
"<i>Example (Scrape last 30 posts):</i>\n"
"<code>/scrape_history -1001234567890 30</code>\n\n"
"<i>(Default is 20 posts if count is omitted).</i>"
)
await event.reply(guide, parse_mode="html")
# --- Direct History Scraper Command ---
@self.client.on(events.NewMessage(pattern=r"^/scrape_history\s+(-?\d+)(?:\s+(\d+))?"))
async def cmd_scrape_history(event: events.NewMessage.Event):
if not self.is_admin(event.sender_id):
@@ -191,19 +177,31 @@ class AdminBotService:
)
await event.reply(text, parse_mode="html", buttons=get_main_menu_keyboard())
# --- Sources Management ---
# --- Sources Management with Interactive Scrape Buttons ---
@self.client.on(events.NewMessage(pattern=r"(?i)^(/sources|📡 Monitored Sources)$"))
async def cmd_sources(event: events.NewMessage.Event):
if not self.is_admin(event.sender_id):
return
sources = await self.repo.get_active_sources()
if not sources:
await event.reply("No active source channels configured.\nUse <code> Add Source Guide</code> to add one.", parse_mode="html")
await event.reply("No active source channels configured.\nTap <b> Add Source Guide</b> below to add one.", parse_mode="html", buttons=get_main_menu_keyboard())
return
lines = ["<b>📡 Active Monitored Sources:</b>\n"]
await event.reply(f"📡 <b>Monitored Sources ({len(sources)} Active):</b>\nTap any button below to scrape past posts:", parse_mode="html")
for s in sources:
lines.append(f"• ID: <code>{s.channel_id}</code> | <b>{s.title or 'N/A'}</b> (@{s.username or 'none'})")
await event.reply("\n".join(lines), parse_mode="html", buttons=get_main_menu_keyboard())
card = (
f"📢 <b>{s.title or 'Channel'}</b>\n"
f"• ID: <code>{s.channel_id}</code>\n"
f"• Username: @{s.username or 'none'}"
)
buttons = [
[
Button.inline(f"📥 Scrape 20 Posts", data=f"hist:{s.channel_id}:20"),
Button.inline(f"📥 Scrape 50 Posts", data=f"hist:{s.channel_id}:50"),
]
]
await event.reply(card, parse_mode="html", buttons=buttons)
@self.client.on(events.NewMessage(pattern=r"(?i)^( Add Source Guide)$"))
async def cmd_add_source_guide(event: events.NewMessage.Event):
@@ -226,7 +224,18 @@ class AdminBotService:
title = event.pattern_match.group(2)
username = event.pattern_match.group(3)
await self.repo.add_source(channel_id=ch_id, title=title, username=username)
await event.reply(f"✅ Added source channel <b>{title}</b> (<code>{ch_id}</code>) to monitoring.", parse_mode="html", buttons=get_main_menu_keyboard())
buttons = [
[
Button.inline(f"📥 Scrape 20 Posts Now", data=f"hist:{ch_id}:20"),
Button.inline(f"📥 Scrape 50 Posts Now", data=f"hist:{ch_id}:50")
]
]
await event.reply(
f"✅ Added source channel <b>{title}</b> (<code>{ch_id}</code>).\n\nWould you like to scrape past posts now?",
parse_mode="html",
buttons=buttons
)
# --- Targets Management ---
@self.client.on(events.NewMessage(pattern=r"(?i)^(/targets|🎯 Target Channels)$"))
@@ -290,15 +299,13 @@ class AdminBotService:
return
help_text = (
"📖 <b>Copykar Bot Quick Help</b>\n\n"
"1. <b>Authentication:</b> Click <code>🔑 Request Login Code</code> and submit via <code>/code &lt;12345&gt;</code>.\n"
"2. <b>Monitored Sources:</b> Add channels via <code>/add_source</code>.\n"
"3. <b>Historical Posts:</b> Backfill existing posts using <code>/scrape_history &lt;channel_id&gt; [limit]</code>.\n"
"4. <b>Review Flow:</b> AI scans posts, checks duplicates, and sends drafts to the review channel with inline approval buttons.\n"
"5. <b>Publishing:</b> Approved posts are published to your target channels strictly according to their interval minutes."
"1. <b>Monitored Sources:</b> Tap <code>📡 Monitored Sources</code> to view channels and click <code>[📥 Scrape Posts]</code> on any channel.\n"
"2. <b>Review Flow:</b> AI scans posts, checks duplicates, and sends drafts to the review channel with inline approval buttons.\n"
"3. <b>Publishing:</b> Approved posts are published to your target channels strictly according to their interval minutes."
)
await event.reply(help_text, parse_mode="html", buttons=get_main_menu_keyboard())
# --- Review Keyboard Callbacks ---
# --- Inline Callback Queries ---
@self.client.on(events.CallbackQuery)
async def on_callback(event: events.CallbackQuery.Event):
if not self.is_admin(event.sender_id):
@@ -306,7 +313,27 @@ class AdminBotService:
return
data = event.data.decode("utf-8")
if data.startswith("appr:"):
# 1. Historical Scraping Callbacks
if data.startswith("hist:"):
_, ch_id_str, limit_str = data.split(":")
ch_id = int(ch_id_str)
limit = int(limit_str)
if not self.collector:
await event.answer("Collector service not linked.", alert=True)
return
await event.edit(f"⏳ <b>Scraping the last {limit} posts</b> from <code>{ch_id}</code>...", parse_mode="html", buttons=None)
async def progress_notify(txt: str):
await event.edit(txt, parse_mode="html")
await self.collector.scrape_channel_history(channel_id=ch_id, limit=limit, progress_callback=progress_notify)
await event.answer(f"Started scraping {limit} posts!")
# 2. Approval Callbacks
elif data.startswith("appr:"):
_, post_id_str, target_id_str = data.split(":")
post_id = int(post_id_str)
target_id = int(target_id_str)
@@ -324,6 +351,7 @@ class AdminBotService:
)
await event.answer(f"Approved for {target_title}!")
# 3. Reject Callbacks
elif data.startswith("rej:"):
_, post_id_str = data.split(":")
post_id = int(post_id_str)