rename bot and improve forwarding logic
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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": "Відправлено!"
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user