| فیلد | مقدار |
|---|---|
| نام | `aioshad` |
| نسخه | `1.0.10` |
| نویسنده | aioshad contributors |
| مجوز | MIT |
| Python | 3, 3.11, 3.12, 3.13 |
لینکی در metadata ثبت نشده است.
# 🟦 aioshad
🚀 اولین و بزرگترین کتابخانهٔ سلف در پیامرسان شاد¶
aioshad یک کتابخانهٔ Python و asyncio برای ساخت Client / Self Account روی پیامرسان شاد است.
🎯 هدف پروژه این است که توسعهدهنده بتواند بهجای ساختن یک Bot API جداگانه، برنامه را روی همان اکانتی که با آن وارد شاد شده است اجرا کند.
✨ ویژگیهای اصلی¶
| بخش | قابلیت |
|---|---|
| 👤 Account | ورود با شماره، نگهداری Session و اجرای API روی همان اکانت |
| 💬 Messages | ارسال، ویرایش، حذف و Reply |
| 📎 Files | Upload و ارسال فایل |
| 🖼️ Photos | Upload، thumbnail و ارسال تصویر |
| 👤 Profile | تغییر نام، نام خانوادگی و Bio |
| ⏰ TimeName | نمایش ساعت/تاریخ کنار نام همان اکانت |
| 🤖 Auto Reply | پاسخ خودکار بر اساس متن دریافتی |
| 🎯 Filters | Command، Regex، Text، Private، Group، Channel، Media و ... |
| 🧩 Filter Logic | ترکیب فیلترها با &، | و ~ |
| 🔄 Dispatcher | دریافت Update و اجرای Handlerها |
| ⏱️ Scheduler | اجرای Taskهای دورهای |
| 🛡️ Rate Limit | محدودسازی نرخ درخواستها |
| 🌐 Network | HTTP/2، Retry، Backoff و Host Failover |
| 🔐 Session | Session قابل ذخیره و رمزنگاریشده |
| 🎙️ Voice Chat | متدهای موجود برای Voice Chat در پروتکل پایه |
| 🧰 Raw RPC | فراخوانی متدهای Authenticated که wrapper ندارند |
| 🧱 Typed Models | مدلهای Message، Chat و User |
📦 نصب¶
آخرین نسخه:
Python موردنیاز پروژه: 3.11 یا بالاتر.
⚡ شروع سریع¶
سادهترین حالت استفاده از کتابخانه:
import asyncio
from aioshad import Client
app = Client(
"0937xxxxxxxx",
session_directory="./sessions",
)
async def main():
await app.start()
asyncio.run(main())
در اولین اجرا، فرآیند ورود انجام میشود و Session ذخیره خواهد شد. در اجراهای بعدی، کتابخانه از Session موجود استفاده میکند تا تا حد امکان از ورود مجدد جلوگیری شود.
👤 Self Account چگونه کار میکند؟¶
aioshad برای یک اکانت کاربری شاد طراحی شده است. یعنی هویت برنامه همان اکانتی است که Session آن ایجاد شده است.
پس ساختار استفاده شبیه یک Bot API مستقل نیست؛ عملیات اصلی از طریق Session اکانت اجرا میشوند.
🔐 Session¶
بهتر است Sessionها را در یک پوشهٔ جداگانه نگهداری کنید:
در صورت نیاز میتوان برای ذخیرهٔ Session از کلید رمزنگاری استفاده کرد:
app = Client(
"0937xxxxxxxx",
session_directory="./sessions",
session_encryption_key="یک-راز-قوی",
)
یا در محیط سیستم:
⚠️ نکته امنیتی¶
فایل Session را مثل یک credential حساس در نظر بگیرید. آن را داخل Git، ZIP عمومی یا کانال عمومی منتشر نکنید.
🧠 Client¶
کلاس اصلی کتابخانه:
سازندهٔ Client¶
Client(
phone_number: str,
session_directory: str = ".",
messenger_host: str | None = None,
*,
config: ClientConfig | None = None,
session_encryption_key: str | None = None,
)
پارامترها¶
| پارامتر | توضیح |
|---|---|
phone_number |
شماره اکانت |
session_directory |
محل ذخیره Session |
messenger_host |
Host سفارشی در صورت نیاز |
config |
تنظیمات ClientConfig |
session_encryption_key |
کلید رمزنگاری Session |
🔌 چرخهٔ اتصال¶
connect()¶
اتصال به سرویس و آمادهسازی Session:
start()¶
اتصال + شروع Dispatcher و نگهداشتن برنامه تا زمان توقف:
start_in_background()¶
اتصال و اجرای Dispatcher بدون قفلکردن جریان اصلی برنامه:
run_until_disconnected()¶
روش جایگزین برای اجرای طولانیمدت:
stop()¶
توقف Dispatcher، قابلیتهای background، Transport و ذخیره Session:
is_connected¶
بررسی وضعیت اتصال:
💬 ارسال پیام¶
send_message()¶
Signature:
await app.send_message(
object_guid: str,
text: str = "",
reply_to_message_id: str | None = None,
file_inline: dict | None = None,
)
Reply¶
✏️ ویرایش پیام¶
🗑️ حذف پیام¶
یک پیام¶
چند پیام¶
delete_type دو مقدار دارد:
مثال:
📁 فایلها¶
upload_file()¶
فایل را Upload میکند و اطلاعات فایل آپلودشده را برمیگرداند:
ورودی میتواند Path یا bytes باشد:
Signature:
Upload در این نسخه فایل را ابتدا در حافظه آماده میکند؛ برای فایلهای بسیار بزرگ مصرف RAM را در نظر بگیرید.
🖼️ ارسال تصویر¶
پشتیبانی از ورودی str، bytes و Path وجود دارد.
Reply با عکس:
await app.send_photo(
"g0...",
"./photo.jpg",
caption="پاسخ تصویری",
reply_to_message_id="123456",
)
📄 ارسال فایل¶
همچنین میتوان نام فایل و MIME را مشخص کرد:
👤 اطلاعات اکانت و کاربران¶
get_me()¶
اطلاعات اکانت لاگینشده:
get_user_info()¶
مدل User¶
User شامل این فیلدهاست:
✍️ مدیریت پروفایل¶
API مستقیم¶
ProfileManager¶
کتابخانه یک مدیر پروفایل آماده نیز دارد:
await app.profile.set_name("aioshad")
await app.profile.set_first_name("AioShad")
await app.profile.set_last_name("Client")
await app.profile.set_bio("Async Shad Client")
⏰ TimeName¶
یکی از قابلیتهای اصلی aioshad، تغییر دورهای نام همان اکانت برای نمایش ساعت/تاریخ است.
from aioshad import Client, TimeName
app = Client(
"0937xxxxxxxx",
session_directory="./sessions",
)
async def main():
await app.connect()
await app.presence.start_time_name(
TimeName(
format="⏰ {time}",
timezone="Asia/Tehran",
interval=60,
)
)
await app.run_until_disconnected()
asyncio.run(main())
تنظیمات TimeName¶
Placeholderها¶
| Placeholder | مقدار |
|---|---|
{time} |
ساعت 24 ساعته مثل 18:45 |
{time_12} |
ساعت 12 ساعته |
{date} |
تاریخ YYYY-MM-DD |
{day} |
نام روز |
{timestamp} |
Unix timestamp |
مثال:
حداقل interval در نسخهٔ فعلی ۵ ثانیه است.
توقف TimeName¶
🤖 Auto Reply¶
سیستم پاسخ خودکار روی همان حساب:
app.autoreply.add(
"سلام",
"سلام! پیام شما دریافت شد.",
)
app.autoreply.set_default(
"پیامت دریافت شد.",
)
await app.autoreply.enable()
غیرفعالسازی:
نکته¶
پاسخدهی خودکار برای جلوگیری از پاسخ به پیامهای ارسالی خود همان Session طراحی شده است.
🎯 Message Handler¶
دریافت پیامها با Decorator:
from aioshad import Client, filters
app = Client("0937xxxxxxxx")
@app.on_message(filters.command("ping"))
async def ping(message):
await message.reply("pong")
asyncio.run(app.start())
Handler میتواند sync یا async باشد:
یا:
Dispatcher نتیجهٔ Awaitable را در صورت وجود await میکند.
🧩 تمام Filterهای موجود¶
ماژول اصلی:
فیلترهای پایه¶
| Filter | کاربرد |
|---|---|
filters.all |
همهٔ پیامها |
filters.text |
پیام دارای متن |
filters.private |
چت خصوصی |
filters.group |
گروه |
filters.channel |
کانال |
filters.reply |
پیام Reply شده |
filters.edited |
پیام ویرایششده |
filters.media |
پیامهای Media |
command¶
چند Command:
Prefixهای متعدد:
حساسیت به حروف:
🔎 RegexFilter¶
@app.on_message(filters.regex(r"^hello\s+.+$"))
async def hello(message):
await message.reply("Hello!")
با Flags:
🔤 TextFilter¶
فقط پیامهایی که متن غیرخالی دارند:
👤 PrivateFilter¶
@app.on_message(filters.private)
async def private_message(message):
await message.reply("پیام خصوصی دریافت شد")
👥 GroupFilter¶
📢 ChannelFilter¶
↩️ ReplyFilter¶
✏️ EditedFilter¶
🆔 AuthorFilter¶
برای یک کاربر:
برای چند کاربر:
مثال:
💬 ChatFilter¶
یا:
🧵 ContainsFilter¶
@app.on_message(filters.contains("سلام"))
async def contains(message):
await message.reply("کلمهٔ سلام در پیام وجود داشت")
بهصورت پیشفرض مقایسه Case-insensitive است.
▶️ StartsWithFilter¶
🖼️ MediaFilter¶
فیلتر Media بهصورت پیشفرض این نوعها را بررسی میکند:
مثال:
نوعهای سفارشی:
🛠️ CustomFilter¶
میتوان Filter دلخواه ساخت:
def long_message(message):
return len(message.text) > 50
@app.on_message(filters.create(long_message))
async def long_text(message):
await message.reply("پیام طولانی بود")
تابع async نیز قابل استفاده است:
async def custom(message):
return message.text.startswith("aioshad")
@app.on_message(filters.create(custom))
async def handler(message):
...
🔗 ترکیب Filterها¶
AND — &¶
هر دو شرط باید برقرار باشند:
@app.on_message(filters.private & filters.text)
async def private_text(message):
print(message.text)
مثال پیشرفته:
@app.on_message(
filters.group & filters.contains("سلام")
)
async def group_hello(message):
await message.reply("سلام گروه")
OR — |¶
حداقل یکی از شروط:
@app.on_message(
filters.private | filters.group
)
async def chat_message(message):
print(message.text)
NOT — ~¶
معکوسکردن یک شرط:
ترکیب چندگانه¶
handler_filter = (
(filters.private | filters.group)
& filters.text
& ~filters.edited
)
@app.on_message(handler_filter)
async def handler(message):
print(message.text)
📨 کلاس Message¶
پیامی که به Handler داده میشود از نوع Message است.
فیلدهای اصلی:
Reply¶
Reply با عکس¶
Reply با فایل¶
Edit¶
Delete¶
یا:
گرفتن Chat¶
گرفتن Author¶
دسترسی به داده خام¶
یا:
💬 کلاس Chat¶
Chat برای کار با یک گفتوگو استفاده میشود.
فیلدهای اصلی:
ارسال پیام از خود Chat¶
ارسال عکس¶
ارسال فایل¶
تاریخچه¶
پیامها¶
حذف پیام¶
یا:
📚 مدیریت Chatها¶
get_chats()¶
get_chat_info()¶
get_chat_info_by_username()¶
🕘 تاریخچه و پیامها¶
get_messages()¶
پارامترهای صفحهبندی:
get_chat_history()¶
این متد خروجی را به فهرست Message تبدیل میکند:
messages = await app.get_chat_history(
"g0...",
limit=50,
)
for message in messages:
print(message.id, message.text)
🔄 Updateها¶
get_chats_updates()¶
get_messages_updates()¶
Dispatcher داخلی نیز از updateهای چت برای دریافت پیامها استفاده میکند.
📡 Dispatcher¶
Dispatcher مسئول دریافت Update و اجرای Handlerهاست.
ویژگیهای اصلی:
- Polling دورهای
- اجرای Filter قبل از Handler
- اجرای همزمان Handlerها
- ثبت و حذف Handler
- جلوگیری از پردازش تکراری Messageهای دیدهشده
- کنترل خطاهای متوالی
- توقف تمیز
حذف Handler¶
remove_handler() تعداد Handlerهای حذفشده را برمیگرداند.
⏱️ Scheduler¶
برای اجرای Taskهای دورهای:
حداقل interval برابر ۵ ثانیه است.
توقف تمام Taskها:
🛡️ Rate Limiting¶
aioshad در Transport از محدودسازی نرخ درخواست استفاده میکند.
تنظیم پیشفرض:
قابل تنظیم از طریق ClientConfig:
from aioshad import Client, ClientConfig
config = ClientConfig(
max_requests_per_second=3,
)
app = Client(
"0937xxxxxxxx",
config=config,
)
⚙️ ClientConfig¶
کلاس تنظیمات:
مقادیر اصلی نسخهٔ فعلی:
| گزینه | مقدار پیشفرض |
|---|---|
timeout |
30.0 |
poll_interval |
1.5 |
error_backoff |
3.0 |
max_consecutive_errors |
10 |
max_requests_per_second |
5.0 |
retry_attempts |
3 |
upload_chunk_size |
131072 |
app_version |
4.4.26 |
platform |
Web |
package |
web.shad.ir |
language |
fa |
مثال:
🌐 Network و Host¶
کتابخانه Transport خود را دارد و برای ارتباط شبکهای از HTTP/2 استفاده میکند.
قابلیتهای لایهٔ شبکه:
- Timeout
- Retry
- Backoff
- Rate Limit
- Host Failover
- Upload Chunk
Hostهای پیشفرض پروژه:
shadmessenger60.iranlms.ir
shadmessenger145.iranlms.ir
shadmessenger40.iranlms.ir
shadmessenger23.iranlms.ir
shadmessenger57.iranlms.ir
برای انتخاب Host دستی:
Hostهای واقعی سرویس ممکن است تغییر کنند. این فهرست مربوط به مقادیری است که در نسخهٔ فعلی پروژه تعریف شدهاند.
🎙️ Voice Chat¶
متدهای زیر در Client وجود دارند:
await app.create_voice_chat("g0...")
await app.join_voice_chat(
"g0...",
voice_chat_id="...",
sdp_offer_data="...",
)
await app.leave_voice_chat(
"g0...",
voice_chat_id="...",
)
await app.get_voice_chat_participants(
"g0...",
voice_chat_id="...",
)
await app.discard_voice_chat(
"g0...",
voice_chat_id="...",
)
await app.set_voice_chat_state(
"g0...",
voice_chat_id="...",
activity="Speaking",
)
Chat نیز wrapperهای مربوط به Join/Leave/Participants را ارائه میکند.
جزئیات SDP و رفتار نهایی Voice Chat به پروتکل/endpoint فعال شاد وابسته است.
🚫 Block / Unblock¶
برای مسدود یا آزادکردن کاربر:
و:
این دو متد در Client به یک RPC احرازشدهٔ مربوط به Block متصل هستند.
🧰 Raw RPC¶
اگر یک متد Authenticated در wrapperهای سطحبالای aioshad وجود نداشته باشد، میتوانید از invoke() استفاده کنید:
مثال با دادههای متعدد:
این API عمداً generic است تا برای متدهای جدید پروتکل لازم نباشد هستهٔ Client تغییر کند.
نام Method و پارامترهای RPC باید مطابق endpoint و payload واقعی سرویس باشد؛
aioshadبرای RPCهای ناشناخته payload حدسی تولید نمیکند.
🧱 API کامل Client — Reference¶
تمام متدهای عمومی Client در نسخهٔ فعلی:
| متد | خروجی | کاربرد |
|---|---|---|
connect() |
Client |
اتصال/احراز هویت |
start() |
None |
شروع کامل Client |
start_in_background() |
None |
شروع بدون idle داخلی |
run_until_disconnected() |
None |
اجرای طولانیمدت |
stop() |
None |
توقف تمیز |
on_message() |
Handler | ثبت Message Handler |
remove_handler() |
int |
حذف Handler |
send_message() |
Message |
ارسال پیام |
edit_message() |
Message |
ویرایش پیام |
delete_messages() |
dict |
حذف چند پیام |
delete_message() |
dict |
حذف یک پیام |
upload_file() |
dict |
Upload فایل |
send_photo() |
Message |
ارسال عکس |
send_file() |
Message |
ارسال فایل |
get_user_info() |
User |
اطلاعات کاربر |
get_me() |
User |
اطلاعات حساب فعلی |
update_profile() |
bool |
تغییر پروفایل |
get_chats() |
dict |
دریافت Chatها |
get_messages() |
dict |
دریافت پیامها |
get_chats_updates() |
dict |
دریافت updateهای چت |
get_messages_updates() |
dict |
دریافت updateهای پیام |
get_chat_history() |
list[Message] |
تاریخچهٔ Chat |
register_device() |
dict |
ثبت/بررسی Device |
get_chat_info() |
Chat |
اطلاعات Chat |
get_chat_info_by_username() |
Chat |
Chat با Username |
join_voice_chat() |
dict |
Join Voice Chat |
leave_voice_chat() |
dict |
Leave Voice Chat |
get_voice_chat_participants() |
dict |
Participants |
create_voice_chat() |
dict |
ساخت Voice Chat |
discard_voice_chat() |
dict |
حذف/Discard Voice Chat |
set_voice_chat_state() |
dict |
تغییر وضعیت Voice Chat |
invoke() |
dict |
RPC خام |
block_user() |
dict |
Block |
unblock_user() |
dict |
Unblock |
set_messenger_host() |
None |
تعیین Host |
🧩 API کلاس Message — Reference¶
متدهای عمومی Message:
مثال کامل:
@app.on_message(filters.command("demo"))
async def demo(message):
await message.edit("پیام ویرایش شد")
await message.reply("Reply")
chat = await message.get_chat()
user = await message.get_author()
print(chat.title)
print(user.name)
💬 API کلاس Chat — Reference¶
متدهای عمومی Chat:
send_message()
send_photo()
send_file()
get_chat_history()
get_messages()
delete_messages()
delete_message()
join_voice_chat()
leave_voice_chat()
get_voice_chat_participants()
get()
__getitem__()
👤 API کلاس User¶
User یک مدل دادهای سبک است و فیلدهای زیر را ارائه میکند:
⏰ API قابلیتها¶
ProfileManager¶
PresenceManager¶
AutoResponder¶
Scheduler¶
🧩 API Filter — Reference کامل¶
کلاسهای موجود:
Filter
AndFilter
OrFilter
InvertFilter
CustomFilter
CommandFilter
RegexFilter
TextFilter
PrivateFilter
GroupFilter
ChannelFilter
ReplyFilter
EditedFilter
AuthorFilter
ChatFilter
AllFilter
ContainsFilter
StartsWithFilter
MediaFilter
Aliasهای راحت نیز وجود دارند:
command
regex
author
chat
create
text
private
group
channel
reply
edited
all
contains
startswith
media
🧯 مدیریت خطاها¶
استثناهای اصلی کتابخانه:
from aioshad import (
AioShadError,
AuthenticationError,
InvalidSessionError,
RPCError,
RateLimitError,
UnsupportedMethodError,
)
ساختار کلی:
AioShadError
├── AuthenticationError
│ └── InvalidSessionError
├── RateLimitError
├── UnsupportedMethodError
└── RPCError
نمونه:
from aioshad import AuthenticationError, RPCError
try:
await app.connect()
except AuthenticationError:
print("خطای احراز هویت")
except RPCError as exc:
print("RPC error:", exc)
🧪 یک نمونه پروژهٔ کامل¶
import asyncio
from aioshad import Client, TimeName, filters
app = Client(
"0937xxxxxxxx",
session_directory="./sessions",
)
@app.on_message(filters.command("ping"))
async def ping(message):
await message.reply("pong 🏓")
@app.on_message(filters.private & filters.text)
async def private_text(message):
print("Private:", message.text)
@app.on_message(filters.media)
async def media(message):
print("Media:", message.message_type)
async def main():
await app.connect()
# تغییر نام بر اساس زمان
await app.presence.start_time_name(
TimeName(
format="⏰ {time}",
timezone="Asia/Tehran",
interval=60,
)
)
# پاسخ خودکار
app.autoreply.add("سلام", "سلام! 👋")
await app.autoreply.enable()
await app.run_until_disconnected()
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
🗂️ ساختار پروژه¶
ساختار نسخهٔ فعلی:
aioshad/
├── aioshad/
│ ├── __init__.py
│ ├── client.py
│ ├── config.py
│ ├── crypto.py
│ ├── dispatcher.py
│ ├── errors.py
│ ├── features.py
│ ├── filters.py
│ ├── methods.py
│ ├── network.py
│ ├── rate_limit.py
│ ├── session.py
│ ├── py.typed
│ └── types/
│ ├── __init__.py
│ ├── chat.py
│ ├── message.py
│ └── user.py
│
├── examples/
│ ├── selfbot.py
│ └── time_name.py
│
├── tests/
│ └── test_core.py
│
├── pyproject.toml
├── setup.py
├── requirements.txt
├── MANIFEST.in
├── CHANGELOG.md
├── LICENSE
└── README.md
🧠 معماری داخلی¶
┌─────────────────┐
│ Client │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
Dispatcher Methods Features
│ │ ┌──────┼──────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
Filters Transport Profile TimeName AutoReply
│
┌────────┼────────┐
▼ ▼ ▼
HTTP/2 Retry Rate Limit
│
▼
Shad
📋 وابستگیها¶
پروژه بهصورت رسمی این وابستگیها را تعریف میکند:
🧪 تست¶
برای اجرای تستهای پروژه:
تستهای موجود روی بخشهای هسته مانند Session، Modelها، Filterها، Rate Limiter و Config متمرکزند.
تست زندهٔ شبکه بهصورت پیشفرض نیازمند یک اکانت معتبر و سرویس فعال است.
⚠️ محدودیتها و نکات سازگاری¶
aioshad مستقیماً به پروتکل و endpointهای شاد وابسته است. در نتیجه ممکن است با تغییر سمت سرویس، بعضی متدها نیاز به بهروزرسانی داشته باشند.
چند نکتهٔ مهم:
- APIهای داخلی شاد ممکن است تغییر کنند.
- Hostهای سرویس ممکن است جابهجا یا غیرفعال شوند.
- رفتار Voice Chat به endpoint و payload فعال وابسته است.
invoke()برای RPCهای جدید یا wrapperنشده وجود دارد.- قابلیتهای ادعاشده در این README بر اساس API موجود در نسخهٔ فعلی پروژه مستند شدهاند؛ قابلیتهایی که در سورس وجود ندارند عمداً بهعنوان API رسمی این نسخه معرفی نشدهاند.
🔒 امنیت¶
برای استفادهٔ امن:
✅ Session را خصوصی نگه دارید
✅ Token/Key را در کد عمومی نگذارید
✅ پوشهٔ sessions را به Git اضافه نکنید
✅ از Session اکانت دیگران استفاده نکنید
✅ Rate Limit را جدی بگیرید
پیشنهاد برای .gitignore:
📜 مجوز¶
این پروژه با مجوز MIT ارائه شده است.
👨💻 سازنده¶
ابوالفضل سلیمانی¶
توسعهدهندهٔ پروژهٔ aioshad.
🔗 GitHub:
https://github.com/shanduzgil
📢 Telegram:
https://t.me/hacker_king_sog
⭐ پشتیبانی و توسعه¶
برای توسعهٔ پروژه، Issue و Pull Request را از طریق GitHub ارسال کنید:
https://github.com/shanduzgil
Lifecycle (1.0.5)¶
import asyncio
from aioshad import Client
app = Client(
phone_number="0937xxxxxxxx",
session_directory="./sessions",
)
async def main():
await app.start()
if __name__ == "__main__":
asyncio.run(main())
برای اجرای background:
connect() اتصال را آماده میکند؛ start() چرخهٔ کامل اجرا را شروع میکند؛
run_until_disconnected() برای اجرای طولانیمدت است؛ و stop() باید shutdown را کامل کند.
Changelog¶
v1.0.10¶
- 🎉 Stable release
- 🐛 TimeName:
preserve_first_name=Trueworks correctly - 🐛 TimeName:
stop_time_name()restores the original first name - 🐛 TimeName: added
time_full(HH:MM:SS) format variable - 🐛 TimeName:
intervalminimum enforced at 60s (shad rate limit) - 🐛 TimeName: automatic retry with backoff on
TOO_REQUESTS - 🐛 Scheduler.every: works as a decorator:
@scheduler.every(30) - 🐛 filters.media: instance (no
()needed) - 🐛 filters.command(prefixes="/"): works without
commands - 🐛 Clearer
TypeErrorfor filter classes without() - 🐛 Add missing
import re(methods.py, features.py) - 🐛 Replace deprecated
asyncio.iscoroutinefunction - 🔇 Reduce
httpxlog verbosity[aioshad در PyPI](https://pypi.org/project/aioshad/)