patch 24aacd1a117ef092876ee5e0bc9522563dcdfd0e Author: Peter Bui Date: Fri Jul 19 17:21:26 CEST 2019 * Periodically update channel voices Rather than checking on individual users, simply check the whole channel periodically... this is much more reliable than depending on messages for active users. diff -rN -u old-irgramd/irtelegramd.py new-irgramd/irtelegramd.py --- old-irgramd/irtelegramd.py 2024-11-23 02:57:46.108179829 +0100 +++ new-irgramd/irtelegramd.py 2024-11-23 02:57:46.108179829 +0100 @@ -17,8 +17,8 @@ # Configuration -NICK_MAX_LENGTH = 20 -USER_STATUS_DELAY = 300 +NICK_MAX_LENGTH = 20 +UPDATE_CHANNEL_VOICES_DELAY = 300 # Utilities @@ -102,16 +102,11 @@ self.iid_to_tid = {} self.irc_channels = collections.defaultdict(set) self.irc_nick = None - self.irc_online = set() + self.irc_voices = collections.defaultdict(set) def get_irc_user_mask(self, nick): return '{}!{}@{}'.format(nick, nick, self.hostname) - def schedule_irc_mode_update(self, nick, channel, force=False): - if nick not in self.irc_online or force: - self.ioloop.call_later(USER_STATUS_DELAY, self.update_irc_mode, nick, channel) - self.irc_online.add(nick) - async def send_irc_command(self, command): self.logger.debug('Send IRC Command: %s', command) command = command + '\r\n' @@ -187,12 +182,7 @@ )) # Update voices - for user_nick in voices: - await self.send_irc_command(':{} MODE {} +v {}'.format( - self.hostname, channel, user_nick, - )) - - self.schedule_irc_mode_update(user_nick, channel) + await self.update_channel_voices(channel, voices) async def part_irc_channel(self, nick, channel): self.irc_channels[channel].remove(nick) @@ -200,17 +190,29 @@ self.get_irc_user_mask(nick), channel )) - async def update_irc_mode(self, nick, channel): - tid = self.iid_to_tid[nick] - user = await self.telegram_client.get_entity(tid) - if isinstance(user.status, telethon.types.UserStatusOnline): - self.schedule_irc_mode_update(nick, channel, True) - else: - self.irc_online.remove(nick) + async def update_channel_voices(self, channel, voices=None): + # Get voices for channel if not provided + if not voices: + tid = self.iid_to_tid[channel] + _, voices = await self.get_telegram_channel_participants(tid) + + # Add new voices + for nick in voices: + if nick not in self.irc_voices[channel]: + self.irc_voices[channel].add(nick) + await self.send_irc_command(':{} MODE {} +v {}'.format( + self.hostname, channel, nick, + )) + + # Remove old voices + for nick in self.irc_voices[channel].difference(voices): + self.irc_voices[channel].remove(nick) await self.send_irc_command(':{} MODE {} -v {}'.format( self.hostname, channel, nick, )) + self.ioloop.call_later(UPDATE_CHANNEL_VOICES_DELAY, self.update_channel_voices, channel) + # Telegram async def initialize_telegram(self): @@ -279,7 +281,7 @@ async def get_telegram_channel_participants(self, tid): channel = self.tid_to_iid[tid] nicks = [] - voices = [] + voices = set() async for user in self.telegram_client.iter_participants(tid): if user.id not in self.tid_to_iid: user_nick = self.get_telegram_nick(user) @@ -289,7 +291,7 @@ user_nick = self.tid_to_iid[user.id] if isinstance(user.status, telethon.types.UserStatusOnline): - voices.append(user_nick) + voices.add(user_nick) nicks.append(user_nick) self.irc_channels[channel].add(user_nick) @@ -342,13 +344,6 @@ elif event.message.media and (event.message.sticker): messages.insert(0, 'Sticker: {}'.format(event.message.sticker.id)) - # Give voice and schedule IRC mode update - if nick not in self.irc_online: - await self.send_irc_command(':{} MODE {} +v {}'.format( - self.hostname, channel, nick, - )) - self.schedule_irc_mode_update(nick, channel) - # Send all messages to IRC for message in messages: await self.send_irc_command(':{} PRIVMSG {} :{}'.format( @@ -364,7 +359,7 @@ tid = event.action_message.to_id.chat_id finally: irc_channel = self.tid_to_iid[tid] - await get_telegram_channel_participants(tid) + await self.get_telegram_channel_participants(tid) try: # Join Chats irc_nick = await self.get_irc_nick_from_telegram_id(event.action_message.action.users[0])