Why is my bot not able to detect when a user leaves in Telegram? - Stack Overflow
General Information: I am using Python 3.11.0 and python-telegram-bot==21.5
.
I am having some issues with my Telegram bot. The general idea of the bot is to keep track of a timer that is set for each new user entering the group. When the timer expires, the user is automatically kicked off. If the user leaves the group on their own accord, before the timer expires, the timer is not reset. If the user decides to join the group again, the timer will resume where it stopped. (e.g. If originally the timer starts with 10 minutes and the user leaves the group with 4 minutes remaining on the clock, when they join again the timer will be set for 4 minutes instead of 10). I am using Redis for storage.
This very simple idea is somehow causing me issues. The bot seems to not be able to detect the users leaving the group, or at least, the event is not triggered. The issue also seems to be isolated to either larger groups or other users. When I try it with a second of account of mine (to join, leave, and then join again), it works properly. When other users do the same thing, it doesn't work.
Take the following code as an approximation of what I have:
def memberJoin(chatMemberUpdate: ChatMemberUpdated):
status = chatMemberUpdate.difference().get("status")
old, new = status or (None, status)
if old in (None, ChatMember.BANNED, ChatMember.LEFT) and new == ChatMember.MEMBER:
return True
return False
def memberLeft(chatMemberUpdate: ChatMemberUpdated):
status = chatMemberUpdate.difference().get("status")
old, new = status or (None, status)
if old == ChatMember.MEMBER and new == ChatMember.LEFT:
return True
return False
async def check_status(update: Update, context: ContextTypes.DEFAULT_TYPE):
left = memberLeft(update.chat_member)
join = memberJoin(update.chat_member)
user_id = update.chat_member.from_user.id
chat_id = update.chat_member.chat.id
if join:
# If it's the user's first time joining...
if not memory.hexists(user_id, "join"):
memory.hset(user_id, "join", datetime.now().isoformat())
# ... some other stuff with JobQueue for the timer ...
else:
# If the user is re-joining the group before the timer expired.
memory.persist(user_id)
join_time = memory.hget(user_id, "join")
left_time = memory.hget(user_id, "left")
logger.info(f"Join Time: {join_time} +++++++ Left Time: {left_time}")
elapsed_time = (datetime.fromisoformat(left_time) - datetime.fromisoformat(join_time)).total_seconds()
remaining_time = 10 * 60 - elapsed_time # Remaining time on the timer.
if remaining_time > 0:
# ... again, some JobQueue stuff to kick user off ...
elif left:
logger.info(f"User {user_id} left at {datetime.now().isoformat()}.")
memory.hset(user_id, "left", datetime.now().isoformat())
memory.expire(user_id, timedelta(hours = 1))
# ... some JobQueue stuff to stop previous timer ...
if __name__ == "__main__":
app = ApplicationBuilder().token(API_KEY).build()
app.add_handler(ChatMemberHandler(check_status, ChatMemberHandler.CHAT_MEMBER))
app.run_polling(drop_pending_updates = True, allowed_updates = Update.ALL_TYPES)
It seems pretty logical to me and it's supposed to work. By the time the code is at the else-block inside of the "join" if-block, it should have collected both the "join" time and the "left" time. But somehow, the "left" time is always None
. This is an example of what the logger outputs when a user re-joins:
INFO:apscheduler.scheduler:Removed job 9065c10968444e8dba41593926032c99
INFO:__main__: Join Time: 2025-01-04T08:25:38.461033+00:00 +++++++ Left Time: None
ERROR:__main__:There has been an error: fromisoformat: argument must be str
INFO:apscheduler.scheduler:Added job "<JOB_NAME>" to job store "default"
As you can see, the "left" time is None
, so datetime.fromisoformat(left_time)
cannot be converted, and thus, the elapsed time cannot be calculated. I am currently dealing with it with try...except
and fixed a constant value. But it's obviously not a long-term solution. I am not sure if I am overlooking something that is right in front of my eyes, or if it's something else. Moreover, since the "left" event is not triggered, the logger.info
output in the "left" elif-block is nowhere to be seen in the terminal.
I hope someone can help me solve this issue, I would appreciate it so much!
Update
While debugging, I found out that another bot was interacting (unknowingly) with the group and kicking users out. While that is not really what is contributing majorly to the issue I was facing, it revealed the mystery of some users being kicked out prematurely and somehow messing with my own bot. After correcting this, I also noticed that my Redis DB was storing user IDs from earlier processes (because when I restarted my docker container, the JobQueue
would be canceled, thus, the user IDs would not be removed). I think that was also causing some problems but, again, it did not majorly contribute to the issue I was still somewhat facing.
I am not sure if I can say that the issue has been resolved but it seems to be working for now.
INFO:__main__: User <USER_ID> left at 2025-01-04T18:05:55.069938+00:00.
General Information: I am using Python 3.11.0 and python-telegram-bot==21.5
.
I am having some issues with my Telegram bot. The general idea of the bot is to keep track of a timer that is set for each new user entering the group. When the timer expires, the user is automatically kicked off. If the user leaves the group on their own accord, before the timer expires, the timer is not reset. If the user decides to join the group again, the timer will resume where it stopped. (e.g. If originally the timer starts with 10 minutes and the user leaves the group with 4 minutes remaining on the clock, when they join again the timer will be set for 4 minutes instead of 10). I am using Redis for storage.
This very simple idea is somehow causing me issues. The bot seems to not be able to detect the users leaving the group, or at least, the event is not triggered. The issue also seems to be isolated to either larger groups or other users. When I try it with a second of account of mine (to join, leave, and then join again), it works properly. When other users do the same thing, it doesn't work.
Take the following code as an approximation of what I have:
def memberJoin(chatMemberUpdate: ChatMemberUpdated):
status = chatMemberUpdate.difference().get("status")
old, new = status or (None, status)
if old in (None, ChatMember.BANNED, ChatMember.LEFT) and new == ChatMember.MEMBER:
return True
return False
def memberLeft(chatMemberUpdate: ChatMemberUpdated):
status = chatMemberUpdate.difference().get("status")
old, new = status or (None, status)
if old == ChatMember.MEMBER and new == ChatMember.LEFT:
return True
return False
async def check_status(update: Update, context: ContextTypes.DEFAULT_TYPE):
left = memberLeft(update.chat_member)
join = memberJoin(update.chat_member)
user_id = update.chat_member.from_user.id
chat_id = update.chat_member.chat.id
if join:
# If it's the user's first time joining...
if not memory.hexists(user_id, "join"):
memory.hset(user_id, "join", datetime.now().isoformat())
# ... some other stuff with JobQueue for the timer ...
else:
# If the user is re-joining the group before the timer expired.
memory.persist(user_id)
join_time = memory.hget(user_id, "join")
left_time = memory.hget(user_id, "left")
logger.info(f"Join Time: {join_time} +++++++ Left Time: {left_time}")
elapsed_time = (datetime.fromisoformat(left_time) - datetime.fromisoformat(join_time)).total_seconds()
remaining_time = 10 * 60 - elapsed_time # Remaining time on the timer.
if remaining_time > 0:
# ... again, some JobQueue stuff to kick user off ...
elif left:
logger.info(f"User {user_id} left at {datetime.now().isoformat()}.")
memory.hset(user_id, "left", datetime.now().isoformat())
memory.expire(user_id, timedelta(hours = 1))
# ... some JobQueue stuff to stop previous timer ...
if __name__ == "__main__":
app = ApplicationBuilder().token(API_KEY).build()
app.add_handler(ChatMemberHandler(check_status, ChatMemberHandler.CHAT_MEMBER))
app.run_polling(drop_pending_updates = True, allowed_updates = Update.ALL_TYPES)
It seems pretty logical to me and it's supposed to work. By the time the code is at the else-block inside of the "join" if-block, it should have collected both the "join" time and the "left" time. But somehow, the "left" time is always None
. This is an example of what the logger outputs when a user re-joins:
INFO:apscheduler.scheduler:Removed job 9065c10968444e8dba41593926032c99
INFO:__main__: Join Time: 2025-01-04T08:25:38.461033+00:00 +++++++ Left Time: None
ERROR:__main__:There has been an error: fromisoformat: argument must be str
INFO:apscheduler.scheduler:Added job "<JOB_NAME>" to job store "default"
As you can see, the "left" time is None
, so datetime.fromisoformat(left_time)
cannot be converted, and thus, the elapsed time cannot be calculated. I am currently dealing with it with try...except
and fixed a constant value. But it's obviously not a long-term solution. I am not sure if I am overlooking something that is right in front of my eyes, or if it's something else. Moreover, since the "left" event is not triggered, the logger.info
output in the "left" elif-block is nowhere to be seen in the terminal.
I hope someone can help me solve this issue, I would appreciate it so much!
Update
While debugging, I found out that another bot was interacting (unknowingly) with the group and kicking users out. While that is not really what is contributing majorly to the issue I was facing, it revealed the mystery of some users being kicked out prematurely and somehow messing with my own bot. After correcting this, I also noticed that my Redis DB was storing user IDs from earlier processes (because when I restarted my docker container, the JobQueue
would be canceled, thus, the user IDs would not be removed). I think that was also causing some problems but, again, it did not majorly contribute to the issue I was still somewhat facing.
I am not sure if I can say that the issue has been resolved but it seems to be working for now.
INFO:__main__: User <USER_ID> left at 2025-01-04T18:05:55.069938+00:00.
Share
Improve this question
edited 23 hours ago
Leah
asked yesterday
LeahLeah
771 silver badge7 bronze badges
1 Answer
Reset to default 0While I’m not entirely sure this’ll work, try using the my_chat_member
update type instead of just chat_member
. The former is specifically for updates related to the bot itself and may capture more reliable events.
Simply modify your handler:
app.add_handler(ChatMemberHandler(check_status, ChatMemberHandler.MY_CHAT_MEMBER))
- 谷歌强推安卓8.0系统:明年所有APP都必须支持
- Rambus联手微软:研究量子计算内存
- 英特尔CEO欧德宁:笔记本与平板电脑终将融合
- 从鼠标到触屏输入 另类角度深度分析PC进化
- python - How to solve this TensorflowTensorboard compatibility problem? - Stack Overflow
- Why has VS Code stopped discovering my python tests? - Stack Overflow
- laravel - Filament | Processing Attachment using API through Email via SendGrid - Stack Overflow
- python - Pipenv not working after Debian system upgrade--maybe partial uninstall? - Stack Overflow
- for loop - CSS masonry grid with dynamic rows width - Stack Overflow
- unity game engine - After commit to git, all gameobjects loose their assets - Stack Overflow
- c# - Is there a way to fill scriptable object field with a child class? - Stack Overflow
- javascript - The side menu bar(sticky) is overflowing unless I scroll - Stack Overflow
- python - Converting Document Docx with Comments to markit using markitdown - Stack Overflow
- intellij http client - How to use in place variable within handler scripts? - Stack Overflow
- java - XSLT 3.0 chained burst-streaming with saxon - memory consumption considerations - Stack Overflow
- system verilog - Do delta cycles occur at intermediate stages in SystemVerilog? - Stack Overflow
- tsx - Does Inversify actually require emitDecoratorMetadata for Typescript? - Stack Overflow