rename bot and improve forwarding logic

This commit is contained in:
2026-07-02 21:07:36 +03:00
parent c5d096b19b
commit f397916816
8 changed files with 65 additions and 20 deletions
+1
View File
@@ -3,3 +3,4 @@
BOT_TOKEN=123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ BOT_TOKEN=123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ
GROUP_CHAT_ID=-100123456789 GROUP_CHAT_ID=-100123456789
ADMIN_IDS=123456789,987654321 ADMIN_IDS=123456789,987654321
DISABLE_CAPTCHA=False
+2 -1
View File
@@ -16,7 +16,7 @@ A Telegram bot designed for secure message forwarding with captcha verification.
1. **Clone the repository**: 1. **Clone the repository**:
```bash ```bash
git clone <repository_url> git clone <repository_url>
cd Frankenstein-bot cd AWB
``` ```
2. **Install dependencies**: 2. **Install dependencies**:
@@ -38,6 +38,7 @@ A Telegram bot designed for secure message forwarding with captcha verification.
- `BOT_TOKEN`: Your Telegram Bot token from @BotFather. - `BOT_TOKEN`: Your Telegram Bot token from @BotFather.
- `GROUP_CHAT_ID`: The ID of the group where messages should be redirected. - `GROUP_CHAT_ID`: The ID of the group where messages should be redirected.
- `ADMIN_IDS`: A comma-separated list of Telegram User IDs who can access admin commands. - `ADMIN_IDS`: A comma-separated list of Telegram User IDs who can access admin commands.
- `DISABLE_CAPTCHA`: Set to `True` to disable the captcha verification step (optional, defaults to `False`).
## Usage ## Usage
+1
View File
@@ -9,6 +9,7 @@ class Settings(BaseSettings):
bot_token: SecretStr bot_token: SecretStr
group_chat_id: int group_chat_id: int
admin_ids: str admin_ids: str
disable_captcha: bool = False
@property @property
def admins(self) -> list[int]: def admins(self) -> list[int]:
+48 -10
View File
@@ -1,4 +1,4 @@
from aiogram import Router, F, Bot from aiogram import Router, F, Bot, html
from aiogram.filters import CommandStart from aiogram.filters import CommandStart
from aiogram.types import Message, BufferedInputFile from aiogram.types import Message, BufferedInputFile
from aiogram.fsm.context import FSMContext from aiogram.fsm.context import FSMContext
@@ -34,20 +34,21 @@ async def process_captcha(message: Message, state: FSMContext, bot: Bot, locale:
target_chat_id = settings.group_chat_id target_chat_id = settings.group_chat_id
if data.get('has_media'): if data.get('has_media'):
new_caption = prefix new_caption = html.quote(prefix)
if data.get('original_caption'): if data.get('original_caption'):
new_caption += f"\n{data.get('original_caption')}" new_caption += f"\n{html.quote(data.get('original_caption'))}"
await bot.copy_message( await bot.copy_message(
chat_id=target_chat_id, chat_id=target_chat_id,
from_chat_id=message.chat.id, from_chat_id=message.chat.id,
message_id=original_msg_id, message_id=original_msg_id,
caption=new_caption caption=new_caption,
parse_mode=None # Use default or specific? Default is HTML.
) )
elif data.get('is_text'): elif data.get('is_text'):
await bot.send_message( await bot.send_message(
chat_id=target_chat_id, chat_id=target_chat_id,
text=f"{prefix}\n{data.get('original_text')}" text=f"{html.quote(prefix)}\n{html.quote(data.get('original_text'))}"
) )
else: else:
# Other types (stickers, etc.) # Other types (stickers, etc.)
@@ -56,7 +57,7 @@ async def process_captcha(message: Message, state: FSMContext, bot: Bot, locale:
from_chat_id=message.chat.id, from_chat_id=message.chat.id,
message_id=original_msg_id message_id=original_msg_id
) )
await bot.send_message(chat_id=target_chat_id, text=prefix) await bot.send_message(chat_id=target_chat_id, text=html.quote(prefix))
await message.answer(_("captcha_solved", locale=locale)) await message.answer(_("captcha_solved", locale=locale))
@@ -73,16 +74,53 @@ async def process_captcha(message: Message, state: FSMContext, bot: Bot, locale:
) )
@router.message(F.chat.type == "private") @router.message(F.chat.type == "private")
async def handle_any_message(message: Message, state: FSMContext, locale: str): async def handle_any_message(message: Message, state: FSMContext, bot: Bot, locale: str):
# Log everything # Log everything
db_msg_id = db.log_message(message) db_msg_id = db.log_message(message)
# Generate captcha
captcha_text, captcha_img = generate_captcha()
has_media = bool(message.photo or message.video or message.document or message.audio or message.voice) has_media = bool(message.photo or message.video or message.document or message.audio or message.voice)
is_text = bool(message.text) is_text = bool(message.text)
if settings.disable_captcha:
try:
wait_message = await message.answer(_("processing_message", locale=locale))
prefix = f"Forwarding, ID [{db_msg_id}]:"
target_chat_id = settings.group_chat_id
if has_media:
new_caption = html.quote(prefix)
if message.caption:
new_caption += f"\n{html.quote(message.caption)}"
await bot.copy_message(
chat_id=target_chat_id,
from_chat_id=message.chat.id,
message_id=message.message_id,
caption=new_caption
)
elif is_text:
await bot.send_message(
chat_id=target_chat_id,
text=f"{html.quote(prefix)}\n{html.quote(message.text)}"
)
else:
await bot.copy_message(
chat_id=target_chat_id,
from_chat_id=message.chat.id,
message_id=message.message_id
)
await bot.send_message(chat_id=target_chat_id, text=html.quote(prefix))
await wait_message.edit_text(_("message_processed", locale=locale))
return
except Exception as e:
print(f"Error forwarding without captcha: {e}")
# Fallback to captcha if something goes wrong?
# Or just ignore. Usually, we want to proceed.
pass
# Generate captcha
captcha_text, captcha_img = generate_captcha()
await state.set_state(CaptchaStates.waiting_for_captcha) await state.set_state(CaptchaStates.waiting_for_captcha)
await state.update_data( await state.update_data(
captcha_text=captcha_text, captcha_text=captcha_text,
+3 -1
View File
@@ -11,5 +11,7 @@
"recent_messages": "Recent messages:", "recent_messages": "Recent messages:",
"msg_not_found": "Message with ID {id} not found.", "msg_not_found": "Message with ID {id} not found.",
"msg_details": "Message ID: {id}\nUser: {full_name} (@{username}) [ID: {user_id}]\nType: {content_type}\nTimestamp: {timestamp}\n\nContent:\n{text}", "msg_details": "Message ID: {id}\nUser: {full_name} (@{username}) [ID: {user_id}]\nType: {content_type}\nTimestamp: {timestamp}\n\nContent:\n{text}",
"id_command": "Current Chat ID: <code>{id}</code>" "id_command": "Current Chat ID: <code>{id}</code>",
"processing_message": "Forwarding your message...",
"message_processed": "Forwarded!"
} }
+3 -1
View File
@@ -11,5 +11,7 @@
"recent_messages": "Останні повідомлення:", "recent_messages": "Останні повідомлення:",
"msg_not_found": "Повідомлення з ID {id} не знайдено.", "msg_not_found": "Повідомлення з ID {id} не знайдено.",
"msg_details": "ID повідомлення: {id}\nКористувач: {full_name} (@{username}) [ID: {user_id}]\nТип: {content_type}\nЧас: {timestamp}\n\nВміст:\n{text}", "msg_details": "ID повідомлення: {id}\nКористувач: {full_name} (@{username}) [ID: {user_id}]\nТип: {content_type}\nЧас: {timestamp}\n\nВміст:\n{text}",
"id_command": "Поточний ID чату: <code>{id}</code>" "id_command": "Поточний ID чату: <code>{id}</code>",
"processing_message": "Відправляємо ваше повідомлення...",
"message_processed": "Відправлено!"
} }
+2 -2
View File
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
async def main(): async def main():
logger.info("Initializing Frankenstein Bot...") logger.info("Initializing AWB...")
# Initialize Bot instance with default HTML parsing mode # Initialize Bot instance with default HTML parsing mode
bot = Bot( bot = Bot(
@@ -75,4 +75,4 @@ if __name__ == "__main__":
try: try:
asyncio.run(main()) asyncio.run(main())
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
logger.info("Frankenstein Bot execution stopped.") logger.info("AWB execution stopped.")
+5 -5
View File
@@ -7,7 +7,7 @@ aiofiles==25.1.0 \
aiogram==3.29.1 \ aiogram==3.29.1 \
--hash=sha256:63cd0123e8ab065f78974ad58ff57c1a5c8c35aac1055761859c4a5ad27eaf04 \ --hash=sha256:63cd0123e8ab065f78974ad58ff57c1a5c8c35aac1055761859c4a5ad27eaf04 \
--hash=sha256:7ac92c64b71d33eb8e3656de4517a1533a88b61728e5dd00b1e11393b669b521 --hash=sha256:7ac92c64b71d33eb8e3656de4517a1533a88b61728e5dd00b1e11393b669b521
# via frankenstein-bot # via awb
aiohappyeyeballs==2.7.1 \ aiohappyeyeballs==2.7.1 \
--hash=sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d \ --hash=sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d \
--hash=sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472 --hash=sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472
@@ -63,7 +63,7 @@ aiosignal==1.4.0 \
aiosqlite==0.22.1 \ aiosqlite==0.22.1 \
--hash=sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650 \ --hash=sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650 \
--hash=sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb --hash=sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb
# via frankenstein-bot # via awb
annotated-types==0.7.0 \ annotated-types==0.7.0 \
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
@@ -75,7 +75,7 @@ attrs==26.1.0 \
captcha==0.7.1 \ captcha==0.7.1 \
--hash=sha256:8b73b5aba841ad1e5bdb856205bf5f09560b728ee890eb9dae42901219c8c599 \ --hash=sha256:8b73b5aba841ad1e5bdb856205bf5f09560b728ee890eb9dae42901219c8c599 \
--hash=sha256:a1b462bcc633a64d8db5efa7754548a877c698d98f87716c620a707364cabd6b --hash=sha256:a1b462bcc633a64d8db5efa7754548a877c698d98f87716c620a707364cabd6b
# via frankenstein-bot # via awb
certifi==2026.6.17 \ certifi==2026.6.17 \
--hash=sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432 \ --hash=sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432 \
--hash=sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db --hash=sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db
@@ -258,7 +258,7 @@ pydantic==2.13.4 \
--hash=sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6 --hash=sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6
# via # via
# aiogram # aiogram
# frankenstein-bot # awb
# pydantic-settings # pydantic-settings
pydantic-core==2.46.4 \ pydantic-core==2.46.4 \
--hash=sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e \ --hash=sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e \
@@ -296,7 +296,7 @@ pydantic-core==2.46.4 \
pydantic-settings==2.14.2 \ pydantic-settings==2.14.2 \
--hash=sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440 \ --hash=sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440 \
--hash=sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f --hash=sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f
# via frankenstein-bot # via awb
python-dotenv==1.2.2 \ python-dotenv==1.2.2 \
--hash=sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a \ --hash=sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a \
--hash=sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3 --hash=sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3