def send_message(self, msg: 'Message') -> 'Message': chat_info = msg.chat.uid.split('_') chat_type = chat_info[0] chat_uid = chat_info[1] messages = [] if msg.edit: try: asyncio.run_coroutine_threadsafe(self.bot.recall(int(msg.uid)), self.loop) except: print_exc() raise EFBOperationNotSupported("Failed to recall the message!\n" "This message may have already expired.") logging.getLogger(__name__).debug(f"Target: {msg.target}") if msg.type in [MsgType.Text, MsgType.Link]: if isinstance(msg.target, Message): max_length = 50 uin = msg.target.author.uid.split("_")[1] messages.append(At(target=int(uin), display="@")) tgt_text = process_quote_text(msg.target.text, max_length) msg.text = "%s\n\n%s" % (tgt_text, msg.text) messages.append(Plain(text=msg.text)) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/Sticker/Animation %s", msg.uid, msg.type) messages.append(Image(path=msg.file.name)) if msg.text: messages.append(Plain(text=msg.text)) else: raise EFBOperationNotSupported(f"Unsupported message type {msg.type}") return_message = self.mirai_send_messages(chat_type, chat_info, messages) self.logger.debug(return_message) msg.uid = return_message.messageId return msg
def react_to_message_status(self, status: ReactToMessage): if self.accept_message_reactions == "reject_one": raise EFBMessageReactionNotPossible( "Message reaction is rejected by flag.") if self.accept_message_reactions == "reject_all": raise EFBOperationNotSupported( "All message reactions are rejected by flag.") message = self.messages_sent.get(status.msg_id) if message is None: raise EFBOperationNotSupported("Message is not found.") if status.reaction is None: for idx, i in message.reactions.items(): message.reactions[idx] = [ j for j in i if not isinstance(j, SelfChatMember) ] else: if status.reaction not in message.reactions: message.reactions[status.reaction] = [] message.reactions[status.reaction].append(message.chat.self) coordinator.send_status( MessageReactionsUpdate(chat=message.chat, msg_id=message.uid, reactions=message.reactions))
def get_chat_picture(self, chat: EFBChat) -> IO[bytes]: uid = chat.chat_uid if uid in wxpy.Chat.SYSTEM_ACCOUNTS: wxpy_chat: wxpy.Chat = wxpy.Chat(wxpy.utils.wrap_user_name(uid), self.bot) else: wxpy_chat = wxpy.utils.ensure_one(self.bot.search(puid=uid)) f = None try: f = tempfile.NamedTemporaryFile(suffix='.jpg') data = wxpy_chat.get_avatar(None) if not data: raise EFBOperationNotSupported() f.write(data) f.seek(0) return f except (TypeError, ResponseError): if f is not None: f.close() raise EFBOperationNotSupported()
def send_status(self, status: EFBStatus): if isinstance(status, EFBMessageRemoval): if not status.message.author.is_self: raise EFBMessageError(self._('You can only recall your own messages.')) try: ews_utils.message_to_dummy_message(status.message.uid, self).recall() except wxpy.ResponseError as e: raise EFBMessageError( self._('Failed to recall the message.') + '{0} ({1})'.format(e.err_msg, e.err_code)) else: raise EFBOperationNotSupported()
def get_message_by_id(self, chat_uid: str, msg_id: str) -> Optional['EFBMsg']: msg_log = self.db.get_msg_log(slave_origin_uid=chat_uid, slave_msg_id=msg_id) if msg_log is not None: if msg_log.pickle: return pickle.loads(msg_log.pickle) else: # Pickled data is not recorded. raise EFBOperationNotSupported(self._("Message is not possible to be retrieved.")) else: # Message is not found. return
def send_status(self, status: 'EFBStatus'): if isinstance(status, EFBMessageRemoval): if not status.message.author.is_self: raise EFBMessageError(self._('You can only recall your own messages.')) try: uid_type = status.message.uid.split('_') self.recall_message(uid_type[1]) except CoolQAPIFailureException: raise EFBMessageError( self._('Failed to recall the message. This message may have already expired.')) else: raise EFBOperationNotSupported()
def get_chat_picture(self, chat: EFBChat) -> IO[bytes]: chat = self.chats.search_chat(uid=chat.chat_uid) wxpy_chat: wxpy.Chat = chat.vendor_specific['wxpy_object'] f = None try: f = tempfile.NamedTemporaryFile(suffix='.jpg') wxpy_chat.get_avatar(f.name) f.seek(0) return f except TypeError: if hasattr(f, 'close'): f.close() raise EFBOperationNotSupported()
def send_status(self, status: Status): if isinstance(status, MessageRemoval): if not isinstance(status.message.author, SelfChatMember): raise EFBOperationNotSupported( self._('You can only recall your own messages.')) if status.message.uid: try: msg_ids = json.loads(status.message.uid) except JSONDecodeError: raise EFBMessageError( self._("ID of the message to recall is invalid.")) else: raise EFBMessageError( self._("ID of the message to recall is not found.")) failed = 0 if any(len(i) == 1 for i in msg_ids): # Message is not sent through EWS raise EFBOperationNotSupported( self._("You may only recall messages sent via EWS.") ) for i in msg_ids: try: ews_utils.message_id_to_dummy_message(i, self).recall() except wxpy.ResponseError: failed += 1 if failed: raise EFBMessageError( self.ngettext( 'Failed to recall {failed} of {total} message.', 'Failed to recall {failed} of {total} messages.', len(msg_ids) ).format(failed=failed, total=len(msg_ids))) else: val = (status.message.uid, len(msg_ids)) for i in msg_ids: self.slave_message.recall_msg_id_conversion[str( i[1])] = val else: raise EFBOperationNotSupported()
def get_message_by_id(self, chat: EFBChat, msg_id: MessageID) -> Optional['EFBMsg']: origin_uid = etm_utils.chat_id_to_str(chat=chat) msg_log = self.db.get_msg_log(slave_origin_uid=origin_uid, slave_msg_id=msg_id) if msg_log is not None: if msg_log.pickle: return ETMMsg.unpickle(msg_log.pickle, self.db) else: # Pickled data is not recorded. raise EFBOperationNotSupported( self._("Message is not possible to be retrieved.")) else: # Message is not found. return None
def send_status(self, status: Status): if isinstance(status, MessageRemoval): uid: str = cast(str, status.message.uid) rfind = uid.rfind('.') if rfind > 0 and uid[rfind + 1:].isdecimal(): uid = uid[:rfind] return self.client.unsend(uid) elif isinstance(status, ReactToMessage): try: self.client.reactToMessage( status.msg_id, status.reaction and MessageReaction(status.reaction)) except (FBchatException, ValueError) as e: self.logger.error(f"Error occurred while sending status: {e}") raise EFBMessageReactionNotPossible(*e.args) return # Other status types go here raise EFBOperationNotSupported()
def get_chat_picture(self, chat: Chat) -> BinaryIO: self.logger.debug("Getting picture of chat %s", chat) photo_url = chat.vendor_specific.get('profile_picture_url') self.logger.debug("[%s] has photo_url from cache: %s", chat.uid, photo_url) if not photo_url: thread = self.client.get_thread_info(chat.uid) photo_url = efms_utils.get_value( thread, ('messaging_actor', 'big_image_src', 'uri')) self.logger.debug("[%s] has photo_url from GraphQL: %s", chat.uid, photo_url) if not photo_url: thread = self.client.fetchThreadInfo(chat.uid)[chat.uid] photo_url = getattr(thread, 'photo', None) self.logger.debug("[%s] has photo_url from legacy API: %s", chat.uid, photo_url) if not photo_url: raise EFBOperationNotSupported('This chat has no picture.') photo = BytesIO(requests.get(photo_url).content) photo.seek(0) return photo
def send_message(self, msg: EFBMsg): # todo Add support for edited message """ self.logger.info("[%s] Sending message to WeChat:\n" "uid: %s\n" "Type: %s\n" "Text: %s\n" "Target Chat: %s\n" "Target uid: %s\n", msg.uid, msg.chat.chat_uid, msg.type, msg.text, repr(msg.target.chat), msg.target.uid) """ m = QQMsgProcessor(instance=self) chat_type = msg.chat.chat_uid.split('_') self.logger.debug('[%s] Is edited: %s', msg.uid, msg.edit) if msg.edit: if self.client_config['is_pro']: try: uid_type = msg.uid.split('_') self.recall_message(uid_type[1]) except CoolQAPIFailureException: raise EFBOperationNotSupported(self._("Failed to recall the message!\n" "This message may have already expired.")) if msg.type in [MsgType.Text, MsgType.Link]: if msg.text == "kick`": group_id = chat_type[1] user_id = msg.target.author.chat_uid.split('_')[1] self.coolq_api_query("set_group_kick", group_id=group_id, user_id=user_id) else: if isinstance(msg.target, EFBMsg): max_length = 50 tgt_text = coolq_text_encode(process_quote_text(msg.target.text, max_length)) user_type = msg.target.author.chat_uid.split('_') tgt_alias = "" if chat_type[0] != 'private' and not msg.target.author.is_self: tgt_alias += m.coolq_code_at_wrapper(user_type[1]) else: tgt_alias = "" msg.text = "%s%s\n\n%s" % (tgt_alias, tgt_text, coolq_text_encode(msg.text)) msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], msg.text) self.logger.debug('[%s] Sent as a text message. %s', msg.uid, msg.text) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/Sticker/Animation %s", msg.uid, msg.type) text = '' if not self.client_config['is_pro']: # CoolQ Air if self.client_config['air_option']['upload_to_smms']: text = '[Image] {}' smms_data = None try: smms_data = upload_image_smms(msg.file, msg.path) except CoolQUnknownException as e: text = '[Image]' self.deliver_alert_to_master(self._('Failed to upload the image to sm.ms! Return Msg: ') + getattr(e, 'message', repr(e))) else: if smms_data is not None: text = text.format(smms_data['url']) elif 'upload_to_vim_cn' in self.client_config['air_option'] \ and self.client_config['air_option']['upload_to_vim_cn']: text = '[Image] {}' vim_cn_data = None try: vim_cn_data = upload_image_vim_cn(msg.file, msg.path) except CoolQUnknownException as e: text = '[Image]' self.deliver_alert_to_master(self._('Failed to upload the image to vim-cn.com! Return Msg: ') + getattr(e, 'message', repr(e))) else: if vim_cn_data is not None: text = text.format(vim_cn_data) elif 'upload_to_mi' in self.client_config['air_option'] \ and self.client_config['air_option']['upload_to_mi']: text = '[Image] {}' mi_data = None try: mi_data = upload_image_mi(msg.file, msg.path) except CoolQUnknownException as e: text = '[Image]' self.deliver_alert_to_master(self._('Failed to upload the image to mi.com! Return Msg: ') + getattr(e, 'message', repr(e))) else: if mi_data is not None: text = text.format(mi_data) elif 'upload_to_sogou' in self.client_config['air_option'] \ and self.client_config['air_option']['upload_to_sogou']: text = '[Image] {}' sogou_data = None try: sogou_data = upload_image_sogou(msg.file, msg.path) except CoolQUnknownException as e: text = '[Image]' self.deliver_alert_to_master(self._('Failed to upload the image to sogou.com! Return Msg: ') + getattr(e, 'message', repr(e))) else: if sogou_data is not None: text = text.format(sogou_data) else: text = '[Image]' else: if msg.type != MsgType.Sticker: text += m.coolq_code_image_wrapper(msg.file, msg.path) else: with tempfile.NamedTemporaryFile(suffix=".gif") as f: img = Image.open(msg.file) try: alpha = img.split()[3] mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) except IndexError: mask = Image.eval(img.split()[0], lambda a: 0) img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) img.paste(255, mask) img.save(f, transparency=255) msg.file.close() f.seek(0) text += m.coolq_code_image_wrapper(f, f.name) msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], text) if msg.text: self.coolq_send_message(chat_type[0], chat_type[1], msg.text) # todo More MsgType Support return msg
def get_chat_picture(self, chat: Chat) -> BinaryIO: raise EFBOperationNotSupported()
def send_status(self, status: Status): raise EFBOperationNotSupported()
def get_chat(self, chat_uid: ChatID, member_uid: Optional[ChatID] = None) -> EFBChat: raise EFBOperationNotSupported()
def send_message(self, msg: EFBMsg) -> EFBMsg: """Send a message to WeChat. Supports text, image, sticker, and file. Args: msg (channel.EFBMsg): Message Object to be sent. Returns: This method returns nothing. Raises: EFBMessageTypeNotSupported: Raised when message type is not supported by the channel. """ chat: wxpy.Chat = self.chats.get_wxpy_chat_by_uid(msg.chat.chat_uid) r: wxpy.SentMessage self.logger.info("[%s] Sending message to WeChat:\n" "uid: %s\n" "UserName: %s\n" "NickName: %s\n" "Type: %s\n" "Text: %s", msg.uid, msg.chat.chat_uid, chat.user_name, chat.name, msg.type, msg.text) chat.mark_as_read() self.logger.debug('[%s] Is edited: %s', msg.uid, msg.edit) if msg.edit: if self.flag('delete_on_edit'): try: ews_utils.message_to_dummy_message(msg.uid, self).recall() except wxpy.ResponseError as e: self.logger.error("[%s] Trying to recall message but failed: %s", msg.uid, e) raise EFBMessageError(self._('Failed to recall message, edited message was not sent.')) else: raise EFBOperationNotSupported() if msg.type in [MsgType.Text, MsgType.Link]: if isinstance(msg.target, EFBMsg): max_length = self.flag("max_quote_length") qt_txt = "%s" % msg.target.text if max_length > 0: tgt_text = qt_txt[:max_length] if len(qt_txt) >= max_length: tgt_text += "…" tgt_text = "「%s」" % tgt_text elif max_length < 0: tgt_text = "「%s」" % qt_txt else: tgt_text = "" if isinstance(chat, wxpy.Group) and not msg.target.author.is_self: tgt_alias = "@%s\u2005 " % msg.target.author.display_name else: tgt_alias = "" msg.text = "%s%s\n\n%s" % (tgt_alias, tgt_text, msg.text) r = self._bot_send_msg(chat, msg.text) self.logger.debug('[%s] Sent as a text message. %s', msg.uid, msg.text) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/GIF/Sticker %s", msg.uid, msg.type) convert_to = None file = msg.file assert file is not None if self.flag('send_stickers_and_gif_as_jpeg'): if msg.type == MsgType.Sticker or msg.mime == "image/gif": convert_to = "image/jpeg" else: if msg.type == MsgType.Sticker: convert_to = "image/gif" if convert_to == "image/gif": with NamedTemporaryFile(suffix=".gif") as f: try: img = Image.open(file) try: alpha = img.split()[3] mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) except IndexError: mask = Image.eval(img.split()[0], lambda a: 0) img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) img.paste(255, mask) img.save(f, transparency=255) msg.path = f.name self.logger.debug('[%s] Image converted from %s to GIF', msg.uid, msg.mime) file.close() f.seek(0) if os.fstat(f.fileno()).st_size > self.MAX_FILE_SIZE: raise EFBMessageError(self._("Image size is too large. (IS02)")) r = self._bot_send_image(chat, f.name, f) finally: if not file.closed: file.close() elif convert_to == "image/jpeg": with NamedTemporaryFile(suffix=".jpg") as f: try: img = Image.open(file).convert('RGBA') out = Image.new("RGBA", img.size, (255,255,255,255)) out.paste(img, img) out.convert('RGB').save(f) msg.path = f.name self.logger.debug('[%s] Image converted from %s to JPEG', msg.uid, msg.mime) file.close() f.seek(0) if os.fstat(f.fileno()).st_size > self.MAX_FILE_SIZE: raise EFBMessageError(self._("Image size is too large. (IS02)")) r = self._bot_send_image(chat, f.name, f) finally: if not file.closed: file.close() else: try: if os.fstat(file.fileno()).st_size > self.MAX_FILE_SIZE: raise EFBMessageError(self._("Image size is too large. (IS01)")) self.logger.debug("[%s] Sending %s (image) to WeChat.", msg.uid, msg.path) r = self._bot_send_image(chat, msg.path, file) finally: if not file.closed: file.close() if msg.text: self._bot_send_msg(chat, msg.text) elif msg.type in (MsgType.File, MsgType.Audio): self.logger.info("[%s] Sending %s to WeChat\nFileName: %s\nPath: %s\nFilename: %s", msg.uid, msg.type, msg.text, msg.path, msg.filename) r = self._bot_send_file(chat, msg.filename, file=msg.file) if msg.text: self._bot_send_msg(chat, msg.text) msg.file.close() elif msg.type == MsgType.Video: self.logger.info("[%s] Sending video to WeChat\nFileName: %s\nPath: %s", msg.uid, msg.text, msg.path) r = self._bot_send_video(chat, msg.path, file=msg.file) if msg.text: self._bot_send_msg(chat, msg.text) msg.file.close() else: raise EFBMessageTypeNotSupported() msg.uid = ews_utils.generate_message_uid(r) self.logger.debug('WeChat message is assigned with unique ID: %s', msg.uid) return msg
def get_chat_picture(self, chat: EFBChat) -> IO[bytes]: raise EFBOperationNotSupported()
def get_chats(self) -> List[Chat]: raise EFBOperationNotSupported()
def update_group_info(self, bot: telegram.Bot, update: telegram.Update): """ Update the title and profile picture of singly-linked Telegram group according to the linked remote chat. """ if update.effective_chat.id == self.bot.get_me().id: return self.bot.reply_error( update, self. _('Send /update_info in a group where this bot is a group admin ' 'to update group title and profile picture')) if update.effective_message.forward_from_chat and \ update.effective_message.forward_from_chat.type == telegram.Chat.CHANNEL: tg_chat = update.effective_message.forward_from_chat.id else: tg_chat = update.effective_chat.id chats = self.db.get_chat_assoc(master_uid=utils.chat_id_to_str( channel=self.channel, chat_uid=tg_chat)) if len(chats) != 1: return self.bot.reply_error( update, self.ngettext( 'This only works in a group linked with one chat. ' 'Currently {0} chat linked to this group.', 'This only works in a group linked with one chat. ' 'Currently {0} chats linked to this group.', len(chats)).format(len(chats))) picture: Optional[IO] = None pic_resized: Optional[IO] = None try: channel_id, chat_uid = utils.chat_id_str_to_id(chats[0]) channel = coordinator.slaves[channel_id] chat = channel.get_chat(chat_uid) if chat is None: raise EFBChatNotFound() chat = ETMChat(chat=chat, db=self.db) bot.set_chat_title(tg_chat, chat.chat_title) picture = channel.get_chat_picture(chat) if not picture: raise EFBOperationNotSupported() pic_img = Image.open(picture) if pic_img.size[0] < self.TELEGRAM_MIN_PROFILE_PICTURE_SIZE or \ pic_img.size[1] < self.TELEGRAM_MIN_PROFILE_PICTURE_SIZE: # resize scale = self.TELEGRAM_MIN_PROFILE_PICTURE_SIZE / min( pic_img.size) pic_resized = io.BytesIO() pic_img.resize(tuple(map(lambda a: int(scale * a), pic_img.size)), Image.BICUBIC) \ .save(pic_resized, 'PNG') pic_resized.seek(0) picture.seek(0) bot.set_chat_photo(tg_chat, pic_resized or picture) update.message.reply_text(self._('Chat details updated.')) except KeyError: return self.bot.reply_error(update, self._('Channel linked is not found.')) except EFBChatNotFound: self.logger.exception("Chat linked is not found in channel.") return self.bot.reply_error( update, self._('Chat linked is not found in channel.')) except telegram.TelegramError as e: self.logger.exception("Error occurred while update chat details.") return self.bot.reply_error( update, self._('Error occurred while update chat details.\n' '{0}'.format(e.message))) except EFBOperationNotSupported: return self.bot.reply_error( update, self._('No profile picture provided from this chat.')) except Exception as e: self.logger.exception("Unknown error caught when querying chat.") return self.bot.reply_error( update, self._('Error occurred while update chat details. \n' '{0}'.format(e))) finally: if getattr(picture, 'close', None): picture.close() if getattr(pic_resized, 'close', None): pic_resized.close()
def send_message(self, msg: Message) -> Message: """Send a message to WeChat. Supports text, image, sticker, and file. Args: msg (channel.Message): Message Object to be sent. Returns: This method returns nothing. Raises: EFBChatNotFound: Raised when a chat required is not found. EFBMessageTypeNotSupported: Raised when the message type sent is not supported by the channel. EFBOperationNotSupported: Raised when an message edit request is sent, but not supported by the channel. EFBMessageNotFound: Raised when an existing message indicated is not found. E.g.: The message to be edited, the message referred in the :attr:`msg.target <.Message.target>` attribute. EFBMessageError: Raised when other error occurred while sending or editing the message. """ if msg.chat == self.user_auth_chat: raise EFBChatNotFound chat: wxpy.Chat = self.chats.get_wxpy_chat_by_uid(msg.chat.uid) # List of "SentMessage" response for all messages sent r: List[wxpy.SentMessage] = [] self.logger.info("[%s] Sending message to WeChat:\n" "uid: %s\n" "UserName: %s\n" "NickName: %s\n" "Type: %s\n" "Text: %s", msg.uid, msg.chat.uid, chat.user_name, chat.name, msg.type, msg.text) try: chat.mark_as_read() except wxpy.ResponseError as e: self.logger.exception( "[%s] Error occurred while marking chat as read. (%s)", msg.uid, e) send_text_only = False self.logger.debug('[%s] Is edited: %s', msg.uid, msg.edit) if msg.edit and msg.uid: if self.flag('delete_on_edit'): msg_ids = json.loads(msg.uid) if msg.type in self.MEDIA_MSG_TYPES and not msg.edit_media: # Treat message as text message to prevent resend of media msg_ids = msg_ids[1:] send_text_only = True failed = 0 for i in msg_ids: try: ews_utils.message_id_to_dummy_message(i, self).recall() except wxpy.ResponseError as e: self.logger.error( "[%s] Trying to recall message but failed: %s", msg.uid, e) failed += 1 if failed: raise EFBMessageError( self.ngettext('Failed to recall {failed} out of {total} message, edited message was not sent.', 'Failed to recall {failed} out of {total} messages, edited message was not sent.', len(msg_ids)).format( failed=failed, total=len(msg_ids) )) # Not caching message ID as message recall feedback is not needed in edit mode else: raise EFBOperationNotSupported() if send_text_only or msg.type in [MsgType.Text, MsgType.Link]: if isinstance(msg.target, Message): max_length = self.flag("max_quote_length") qt_txt = msg.target.text or msg.target.type.name if max_length > 0: if len(qt_txt) >= max_length: tgt_text = qt_txt[:max_length] tgt_text += "…" else: tgt_text = qt_txt elif max_length < 0: tgt_text = qt_txt else: tgt_text = "" if isinstance(chat, wxpy.Group) and not isinstance(msg.target.author, SelfChatMember): tgt_alias = "@%s\u2005:" % msg.target.author.display_name else: tgt_alias = "" msg.text = f"「{tgt_alias}{tgt_text}」\n- - - - - - - - - - - - - - -\n{msg.text}" r.append(self._bot_send_msg(chat, msg.text)) self.logger.debug( '[%s] Sent as a text message. %s', msg.uid, msg.text) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/GIF/Sticker %s", msg.uid, msg.type) convert_to = None file = msg.file assert file is not None if self.flag('send_stickers_and_gif_as_jpeg'): if msg.type == MsgType.Sticker or msg.mime == "image/gif": convert_to = "image/jpeg" else: if msg.type == MsgType.Sticker: convert_to = "image/gif" if convert_to == "image/gif": with NamedTemporaryFile(suffix=".gif") as f: try: img = Image.open(file) try: alpha = img.split()[3] mask = Image.eval( alpha, lambda a: 255 if a <= 128 else 0) except IndexError: mask = Image.eval(img.split()[0], lambda a: 0) img = img.convert('RGB').convert( 'P', palette=Image.ADAPTIVE, colors=255) img.paste(255, mask) img.save(f, transparency=255) msg.path = Path(f.name) self.logger.debug( '[%s] Image converted from %s to GIF', msg.uid, msg.mime) file.close() if f.seek(0, 2) > self.MAX_FILE_SIZE: raise EFBMessageError( self._("Image size is too large. (IS02)")) f.seek(0) r.append(self._bot_send_image(chat, f.name, f)) finally: if not file.closed: file.close() elif convert_to == "image/jpeg": with NamedTemporaryFile(suffix=".jpg") as f: try: img = Image.open(file).convert('RGBA') out = Image.new("RGBA", img.size, (255, 255, 255, 255)) out.paste(img, img) out.convert('RGB').save(f) msg.path = Path(f.name) self.logger.debug( '[%s] Image converted from %s to JPEG', msg.uid, msg.mime) file.close() if f.seek(0, 2) > self.MAX_FILE_SIZE: raise EFBMessageError( self._("Image size is too large. (IS02)")) f.seek(0) r.append(self._bot_send_image(chat, f.name, f)) finally: if not file.closed: file.close() else: try: if file.seek(0, 2) > self.MAX_FILE_SIZE: raise EFBMessageError( self._("Image size is too large. (IS01)")) file.seek(0) self.logger.debug( "[%s] Sending %s (image) to WeChat.", msg.uid, msg.path) filename = msg.filename or (msg.path and msg.path.name) assert filename r.append(self._bot_send_image(chat, filename, file)) finally: if not file.closed: file.close() if msg.text: r.append(self._bot_send_msg(chat, msg.text)) elif msg.type in (MsgType.File, MsgType.Audio): self.logger.info("[%s] Sending %s to WeChat\nFileName: %s\nPath: %s\nFilename: %s", msg.uid, msg.type, msg.text, msg.path, msg.filename) filename = msg.filename or (msg.path and msg.path.name) assert filename and msg.file r.append(self._bot_send_file(chat, filename, file=msg.file)) if msg.text: self._bot_send_msg(chat, msg.text) if not msg.file.closed: msg.file.close() elif msg.type == MsgType.Video: self.logger.info( "[%s] Sending video to WeChat\nFileName: %s\nPath: %s", msg.uid, msg.text, msg.path) filename = msg.filename or (msg.path and msg.path.name) assert filename and msg.file r.append(self._bot_send_video(chat, filename, file=msg.file)) if msg.text: r.append(self._bot_send_msg(chat, msg.text)) if not msg.file.closed: msg.file.close() else: raise EFBMessageTypeNotSupported() msg.uid = ews_utils.generate_message_uid(r) self.logger.debug( 'WeChat message is assigned with unique ID: %s', msg.uid) return msg
def get_message_by_id(self, chat_uid: ChatID, msg_id: MessageID) -> Optional['EFBMsg']: raise EFBOperationNotSupported()
def message_removal_status(self, status: MessageRemoval): if not self.message_removal_possible: raise EFBOperationNotSupported( "Message removal is not possible by flag.")
def update_group_info(self, update: Update, context: CallbackContext): """ Update the title and profile picture of singly-linked Telegram group according to the linked remote chat. Triggered by ``/update_info`` command. """ if update.effective_chat.type == telegram.Chat.PRIVATE: return self.bot.reply_error( update, self. _('Send /update_info to a group where this bot is a group admin ' 'to update group title, description and profile picture.')) forwarded_from_chat = update.effective_message.forward_from_chat if forwarded_from_chat and forwarded_from_chat.type == telegram.Chat.CHANNEL: tg_chat = forwarded_from_chat.id else: tg_chat = update.effective_chat.id chats = self.db.get_chat_assoc(master_uid=utils.chat_id_to_str( channel=self.channel, chat_uid=tg_chat)) if len(chats) != 1: return self.bot.reply_error( update, self.ngettext( 'This only works in a group linked with one chat. ' 'Currently {0} chat linked to this group.', 'This only works in a group linked with one chat. ' 'Currently {0} chats linked to this group.', len(chats)).format(len(chats))) picture: Optional[IO] = None pic_resized: Optional[IO] = None channel_id, chat_uid, _ = utils.chat_id_str_to_id(chats[0]) if channel_id not in coordinator.slaves: self.logger.exception( f"Channel linked ({channel_id}) is not found.") return self.bot.reply_error( update, self._('Channel linked ({channel}) is not found.').format( channel=channel_id)) channel = coordinator.slaves[channel_id] try: chat = self.chat_manager.update_chat_obj( channel.get_chat(chat_uid), full_update=True) self.bot.set_chat_title( tg_chat, self.truncate_ellipsis(chat.chat_title, self.MAX_LEN_CHAT_TITLE)) # Update remote group members list to Telegram group description if available desc = chat.description if isinstance(chat, ETMGroupChat): names = [ i.long_name for i in chat.members if not isinstance(i, SystemChatMember) ] # TRANSLATORS: Separator between group members in a Telegram group description generated by /update_info members = self._(", ").join(names) if desc: desc += "\n" desc += self.ngettext("{count} group member: {list}", "{count} group members: {list}", len(names)).format(count=len(names), list=members) if desc: try: self.bot.set_chat_description( tg_chat, self.truncate_ellipsis(desc, self.MAX_LEN_CHAT_DESC)) except BadRequest as e: if "Chat description is not modified" in e.message: pass else: self.logger.exception( "Exception occurred while trying to update chat description: %s", e) except TelegramError as e: # description is not updated self.logger.exception( "Exception occurred while trying to update chat description: %s", e) picture = channel.get_chat_picture(chat) if not picture: raise EFBOperationNotSupported() pic_img = Image.open(picture) if pic_img.size[0] < self.TELEGRAM_MIN_PROFILE_PICTURE_SIZE or \ pic_img.size[1] < self.TELEGRAM_MIN_PROFILE_PICTURE_SIZE: # resize scale = self.TELEGRAM_MIN_PROFILE_PICTURE_SIZE / min( pic_img.size) pic_resized = io.BytesIO() pic_img.resize(tuple(map(lambda a: int(scale * a), pic_img.size)), Image.BICUBIC) \ .save(pic_resized, 'PNG') pic_resized.seek(0) picture.seek(0) self.bot.set_chat_photo(tg_chat, pic_resized or picture) update.message.reply_text(self._('Chat details updated.')) except EFBChatNotFound: self.logger.exception( "Chat linked (%s) is not found in the slave channel " "(%s).", channel_id, chat_uid) return self.bot.reply_error( update, self. _("Chat linked ({chat_uid}) is not found in the slave channel " "({channel_name}, {channel_id}).").format( channel_name=channel.channel_name, channel_id=channel_id, chat_uid=chat_uid)) except TelegramError as e: self.logger.exception("Error occurred while update chat details.") return self.bot.reply_error( update, self._('Error occurred while update chat details.\n' '{0}'.format(e.message))) except EFBOperationNotSupported: return self.bot.reply_error( update, self._('No profile picture provided from this chat.')) except Exception as e: self.logger.exception("Unknown error caught when querying chat.") return self.bot.reply_error( update, self._('Error occurred while update chat details. \n' '{0}'.format(e))) finally: if picture and getattr(picture, 'close', None): picture.close() if pic_resized and getattr(pic_resized, 'close', None): pic_resized.close()
def get_message_by_id(self, chat: 'Chat', msg_id: MessageID) -> Optional['Message']: raise EFBOperationNotSupported()