a35abb0541
Completes TODO #5. Forwarding a post now asks whether to save it whole or extract its media; sending media directly is unchanged. Built on forwarding rather than copying file_ids. The bot already has the post in its private chat with the owner, so it stores message ids and forwards them back. forwardMessages takes a list and keeps an album intact, which is what made the caption-plus-album case tractable; ids must be strictly ascending, so they are sorted on the way out. - Vault rows live in their own table and every query is scoped to an owner_id, so a guessed id cannot reach someone else's saved post. Nothing in the vault is searchable inline, moderated or federated, and the separate table makes that structural rather than a flag. - Albums arrive as separate messages with no completion signal, so they are buffered by media_group_id behind a 1s debounce and prompt once. - The add path now takes a list of items, so extracting an album stores every piece under one set of keywords instead of asking repeatedly. - /vault searches keywords and the original caption, since the point of a vault is finding something you never got round to tagging. - Retrieval failures are reported: a message id is a pointer into the chat, not a self-contained file_id, so clearing history breaks it. Three near-identical keyword collectors are now one helper. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
119 lines
8.4 KiB
Markdown
119 lines
8.4 KiB
Markdown
# Memes Bot
|
|
|
|
ربات شخصی تلگرام برای ذخیره و جستجوی میم (عکس، گیف، ویدیو، صدا، موزیک، استیکر، فایل) با کلیدواژه.
|
|
|
|
[English](README.md)
|
|
|
|
---
|
|
|
|
### پیشنیازها
|
|
|
|
- یک سرور با [Docker](https://docs.docker.com/engine/install/) نصبشده
|
|
- توکن ربات تلگرام از [@BotFather](https://t.me/BotFather)
|
|
|
|
### راهاندازی
|
|
|
|
**۱. ساخت ربات در BotFather**
|
|
- `/newbot` ← توکن بگیرید
|
|
- `/setinline` ← حالت اینلاین را فعال کنید (مثلاً: `جستجوی میم...`)
|
|
|
|
**۲. پیدا کردن شناسه تلگرام**
|
|
|
|
برای وایتلیست کردن خودتان به ID عددی نیاز دارید.
|
|
|
|
- **سادهترین روش:** یک پیام به [@userinfobot](https://t.me/userinfobot) فوروارد کنید — شناسه شما را برمیگرداند
|
|
- **روش دیگر:** تلگرام وب را باز کنید، روی پروفایل کلیک کنید، عدد داخل URL شناسه شماست
|
|
- **برای چند کاربر:** ID هر نفر را با کاما جدا کنید
|
|
|
|
**۳. کلون و تنظیم**
|
|
|
|
```bash
|
|
git clone https://git.goyban.com/goyban/memes_bot
|
|
cd memes_bot
|
|
cp .env.example .env
|
|
```
|
|
|
|
فایل `.env` را ویرایش کنید:
|
|
|
|
```env
|
|
BOT_TOKEN=توکن_ربات_شما
|
|
ALLOWED_USERS=123456789,987654321
|
|
```
|
|
|
|
**۴. اجرا**
|
|
|
|
```bash
|
|
docker compose up -d --build
|
|
```
|
|
|
|
دیتابیس در مسیر `./bot_db/media.db` ذخیره میشود.
|
|
|
|
### نحوه استفاده
|
|
|
|
**افزودن میم** — یک عکس، گیف، ویدیو، صدا، موزیک، استیکر یا هر فایلی برای ربات بفرستید. ربات از شما کلیدواژه میخواهد. کلیدواژهها را یکییکی یا با کاما جدا بفرستید، سپس `/done` بزنید.
|
|
|
|
**جستجوی اینلاین** — در هر چتی بنویسید `@نام_ربات کلیدواژه` تا نتایج نمایش داده شود.
|
|
|
|
**دستورات**
|
|
|
|
| دستور | توضیح |
|
|
|---|---|
|
|
| `/list` | نمایش همه رسانههای ذخیرهشده |
|
|
| `/vault [search]` | بازیابی پستی که کامل ذخیره کردهاید |
|
|
| `/review` | بررسی یکبهیک ارسالهای در انتظار تأیید (فقط ادمین) |
|
|
| `/delete <id>` | حذف یک مورد (ID را از `/list` بگیرید) |
|
|
| `/cancel` | لغو عملیات جاری |
|
|
|
|
### گاوصندوق — ذخیره کامل یک پست
|
|
|
|
اگر رسانهای را مستقیم برای ربات بفرستید، مثل همیشه رفتار میکند: رسانه را جدا میکند و کلیدواژه میخواهد.
|
|
|
|
اما اگر پستی را **فوروارد** کنید، ربات میپرسد چه میخواهید:
|
|
|
|
- **ذخیره کل پست** — پست را دستنخورده با کپشن در گاوصندوق نگه میدارد. آلبوم هم آلبوم میماند.
|
|
- **جدا کردن رسانه** — همان رفتار قبلی؛ رسانه به کتابخانه قابل جستجو اضافه میشود.
|
|
|
|
با `/vault [search]` پستهای ذخیرهشده را پیدا کنید؛ جستجو هم روی کلیدواژهها و هم روی متن کپشن اصلی انجام میشود. کنار هر نتیجه یک دکمه برای فرستادن دوباره پست و یک دکمه برای حذف آن هست.
|
|
|
|
> **پستهای گاوصندوق فقط داخل خود ربات برمیگردند.** حالت inline تلگرام نمیتواند پیام موجود را فوروارد کند، پس `@yourbotusername keyword` به گاوصندوق دسترسی ندارد. پست را داخل ربات بگیرید و بعد هرجا خواستید فوروارد کنید.
|
|
|
|
گاوصندوق برای هر کاربر جداگانه و خصوصی است: در جدولی جدا از کتابخانه میمها ذخیره میشود، هر جستجو محدود به صاحب آن است، و هیچچیزِ آن بررسی یا به اشتراک گذاشته نمیشود.
|
|
|
|
ذخیرهسازی بهجای کپی رسانه، اشارهای به پیام موجود در چت شما با ربات را نگه میدارد. اگر تاریخچه چتتان با ربات را پاک کنید، آن پستها دیگر قابل بازیابی نیستند — ربات در این حالت به شما اطلاع میدهد تا دوباره فوروارد کنید.
|
|
|
|
### عمومیکردن ربات
|
|
|
|
با تنظیم `PUBLIC_MODE=true` ربات بهجای فهرست `ALLOWED_USERS`، به هر کسی که شرط عضویت را داشته باشد اجازه دسترسی میدهد:
|
|
|
|
```env
|
|
PUBLIC_MODE=true
|
|
ADMIN_USERS=123456789
|
|
REQUIRED_CHATS=@mychannel,@mygroup
|
|
REQUIRE_MODE=all
|
|
```
|
|
|
|
در `REQUIRED_CHATS` میتوانید `@username` یا شناسه عددی بنویسید. **ربات باید در هر کدام ادمین باشد**، وگرنه نمیتواند عضویت را بررسی کند و همه رد میشوند. ربات هنگام راهاندازی این را بررسی میکند و نام هر چتی را که نمیتواند بخواند در لاگ مینویسد. مقدار `all` یعنی عضویت در همه چتها لازم است و `any` یعنی یکی کافی است. اگر `REQUIRED_CHATS` خالی باشد ربات برای همه باز است.
|
|
|
|
کاربری که شرط را ندارد پیامی میبیند که فهرست چتهای لازم را نشان میدهد. در جستجوی inline هم بهجای نتیجه خالی و بدون توضیح، یک نوار قابل لمس میبیند که ربات را باز میکند و همین توضیح را میدهد.
|
|
|
|
> **قبل از روشنکردن این گزینه حتماً `ADMIN_USERS` را تنظیم کنید.** وقتی `ADMIN_USERS` خالی باشد، ربات خصوصی کاربرانش را ادمین حساب میکند؛ این برای ربات تکنفره راحت است اما در حالت عمومی یعنی همه ادمین میشوند. به همین دلیل در حالت عمومی تا وقتی `ADMIN_USERS` تنظیم نشده باشد هیچکس ادمین نیست و ربات هنگام راهاندازی خطا ثبت میکند.
|
|
|
|
پاسخ بررسی عضویت پنج دقیقه کش میشود، چون جستجوی inline در غیر این صورت با هر بار فشردن کلید از تلگرام سؤال میکرد. رد شدن فقط سی ثانیه کش میشود تا کاربری که تازه عضو شده تقریباً بلافاصله دسترسی پیدا کند.
|
|
|
|
### پذیرش ارسال کاربران
|
|
|
|
اگر در فایل `.env` مقدار `ACCEPT_SUBMISSIONS=true` را تنظیم کنید، کاربران غیرادمین هم میتوانند رسانه بفرستند. این موارد ذخیره میشوند اما تا وقتی یک ناظر تأییدشان نکند در جستجوی inline و `/list` دیده نمیشوند. رسانهای که خود ادمینها میفرستند مثل قبل مستقیم ذخیره میشود.
|
|
|
|
با دستور `/review` میتوانید صف را بررسی کنید. هر مورد همراه با کلیدواژههایش و چهار دکمه نمایش داده میشود: تأیید، رد، اصلاح کلیدواژهها، و توقف.
|
|
|
|
صف هیچ نشانگری ذخیره نمیکند و `/review` همیشه قدیمیترین مورد در انتظار را میآورد. برای همین میتوانید بعد از چند مورد متوقف شوید و فردا ادامه دهید، و چند ناظر هم میتوانند همزمان کار کنند — اگر دو نفر یک مورد را باز کنند، تصمیم اولی ثبت میشود و به دومی گفته میشود که قبلاً بررسی شده است.
|
|
|
|
> **تا وقتی مطمئن نیستید این گزینه را خاموش بگذارید.** وقتی `ALLOWED_USERS` خالی باشد همه کاربرِ مجاز حساب میشوند، پس روشنکردن این گزینه یعنی پذیرفتن رسانه از هر کسی که ربات را پیدا کند.
|
|
|
|
### انتقال به سرور دیگر
|
|
|
|
فقط کافی است این دو فایل را منتقل کنید:
|
|
|
|
- `.env`
|
|
- `bot_db/media.db`
|