def efb_image_wrapper(file: IO, filename: str = None, text: str = None) -> Message: """ A EFB message wrapper for images. :param file: The file handle :param filename: The actual filename :param text: The attached text :return: EFB Message """ efb_msg = Message() efb_msg.file = file mime = magic.from_file(file.name, mime=True) if isinstance(mime, bytes): mime = mime.decode() if "gif" in mime: efb_msg.type = MsgType.Animation else: efb_msg.type = MsgType.Image if filename: efb_msg.filename = filename else: efb_msg.filename = file.name efb_msg.filename += '.' + str(mime).split('/')[ 1] # Add extension suffix if text: efb_msg.text = text efb_msg.path = efb_msg.file.name efb_msg.mime = mime return efb_msg
def efb_text_simple_wrapper( text: str, ats: Union[Mapping[Tuple[int, int], Union[Chat, ChatMember]], None] = None ) -> Message: """ A simple EFB message wrapper for plain text. Emojis are presented as is (plain text). :param text: The content of the message :param ats: The substitutions of at messages, must follow the Substitution format when not None [[begin_index, end_index], {Chat or ChatMember}] :return: EFB Message """ efb_msg = Message(type=MsgType.Text, text=text) if ats: efb_msg.substitutions = Substitutions(ats) return efb_msg
async def handle_new_telegram_message(self, event: NewMessage): msg: TgMsg = event.message chat_id = get_chat_id(msg.peer_id) chat = await self.async_get_chat(chat_id) self.logger.debug(msg) file = None path = None filename = None mime = None msg_type = MsgType.Text tempfile_suffix = '' if getattr(msg, 'media', None): media = msg.media tempfile_suffix = get_extension(media) if isinstance(media, MessageMediaPhoto): msg_type = MsgType.Image if isinstance(media, MessageMediaDocument): document = media.document mime = document.mime_type msg_type = MsgType.File for attr in document.attributes: if isinstance(attr, DocumentAttributeFilename): tempfile_suffix = attr.file_name filename = attr.file_name if isinstance(attr, DocumentAttributeSticker): msg_type = MsgType.Sticker if isinstance(attr, DocumentAttributeVideo): msg_type = MsgType.Video if isinstance(attr, DocumentAttributeAudio): msg_type = MsgType.Audio if msg_type != MsgType.Text: file = tempfile.NamedTemporaryFile(suffix=tempfile_suffix) path = file.name await self.client.download_media(msg, file) msg_peer = await self.client.get_entity( get_chat_id(msg.from_id or msg.peer_id)) self.logger.debug(msg_peer) chat_member = ChatMember( chat=chat, name=format_entity_name(msg_peer), uid=str(chat_id), ) efb_msg = Message( deliver_to=coordinator.master, author=chat_member, chat=chat, text=msg.message, type=msg_type, uid=f'{chat_id}_{msg.id}', file=file, filename=filename, mime=mime, path=path, ) coordinator.send_message(efb_msg)
def efb_unsupported_wrapper(text: str) -> Message: """ A simple EFB message wrapper for unsupported message :param text: The content of the message :return: EFB Message """ efb_msg = Message(type=MsgType.Unsupported, text=text) return efb_msg
def send_message(self, msg: Message) -> Message: if msg.type == MsgType.Text: coordinator.send_message(Message( uid=MessageID(f'echo_{uuid4()}'), type=MsgType.Text, chat=self.chat, author=self.chat.other, deliver_to=coordinator.master, text=msg.text, )) return msg
def efb_file_wrapper(file: IO, filename: str = None, text: str = None) -> Message: efb_msg = Message() efb_msg.type = MsgType.File efb_msg.file = file mime = magic.from_file(efb_msg.file.name, mime=True) if isinstance(mime, bytes): mime = mime.decode() if filename: efb_msg.filename = filename else: efb_msg.filename = file.name efb_msg.filename += '.' + str(mime).split('/')[ 1] # Add extension suffix efb_msg.path = efb_msg.file.name efb_msg.mime = mime if text: efb_msg.text = text return efb_msg
def build_efb_msg(self, mid: str, thread_id: str, author_id: str, message_object: Message, nested: bool = False) -> EFBMessage: efb_msg = EFBMessage( uid=MessageID(mid), text=message_object.text, type=MsgType.Text, deliver_to=coordinator.master, ) # Authors efb_msg.chat = self.chat_manager.get_thread(thread_id) efb_msg.author = efb_msg.chat.get_member(ChatID(author_id)) if not nested and message_object.replied_to: efb_msg.target = self.build_efb_msg(message_object.reply_to_id, thread_id=thread_id, author_id=message_object.author, message_object=message_object.replied_to, nested=True) if message_object.mentions: mentions: Dict[Tuple[int, int], ChatMember] = dict() for i in message_object.mentions: mentions[(i.offset, i.offset + i.length)] = efb_msg.chat.get_member(i.thread_id) efb_msg.substitutions = Substitutions(mentions) if message_object.emoji_size: efb_msg.text += " (%s)" % message_object.emoji_size.name[0] # " (S)", " (M)", " (L)" if message_object.reactions: reactions: DefaultDict[ReactionName, List[ChatMember]] = defaultdict(list) for user_id, reaction in message_object.reactions.items(): reactions[ReactionName(reaction.value)].append( efb_msg.chat.get_member(user_id)) efb_msg.reactions = reactions return efb_msg
def send_message(self, msg: EFBMessage) -> Message: self.logger.debug("Received message from master: %s", msg) try: target_msg_offset = 0 prefix = "" mentions = [] # Send message reaction # if msg.target and msg.text.startswith('r`') and \ # msg.target.uid.startswith("mid.$"): # self.logger.debug("[%s] Message is a reaction to another message: %s", msg.uid, msg.text) # msg_id = ".".join(msg.target.uid.split(".", 2)[:2]) # if getattr(MessageReaction, msg.text[2:], None): # self.client.reactToMessage(msg_id, getattr(MessageReaction, msg.text[2:])) # else: # self.client.reactToMessage(msg_id, self.CustomReaction(msg.text[2:])) # msg.uid = "__reaction__" # return msg # Message substitutions if msg.substitutions: self.logger.debug("[%s] Message has substitutions: %s", msg.uid, msg.substitutions) for i in msg.substitutions: mentions.append(Mention(msg.substitutions[i].id, target_msg_offset + i[0], i[1] - i[0])) self.logger.debug("[%s] Translated to mentions: %s", msg.uid, mentions) fb_msg = Message(text=prefix + msg.text, mentions=mentions) thread: Thread = self.client.fetchThreadInfo(msg.chat.uid)[str(msg.chat.uid)] if msg.target and msg.target.uid: fb_msg.reply_to_id = msg.target.uid if msg.type in (MsgType.Text, MsgType.Unsupported): # Remove variation selector-16 (force colored emoji) for # matching. emoji_compare = msg.text.replace("\uFE0F", "") if emoji_compare == "👍": fb_msg.sticker = Sticker(uid=EmojiSize.SMALL.value) if not prefix: fb_msg.text = None elif emoji_compare[:-1] == "👍" and emoji_compare[-1] in 'SML': if emoji_compare[-1] == 'S': fb_msg.sticker = Sticker(uid=EmojiSize.SMALL.value) elif emoji_compare[-1] == 'M': fb_msg.sticker = Sticker(uid=EmojiSize.MEDIUM.value) elif emoji_compare[-1] == 'L': fb_msg.sticker = Sticker(uid=EmojiSize.LARGE.value) if not prefix: fb_msg.text = None elif emoji_compare[:-1] in emoji.UNICODE_EMOJI and emoji_compare[-1] in 'SML': # type: ignore self.logger.debug("[%s] Message is an Emoji message: %s", msg.uid, emoji_compare) if emoji_compare[-1] == 'S': fb_msg.emoji_size = EmojiSize.SMALL elif emoji_compare[-1] == 'M': fb_msg.emoji_size = EmojiSize.MEDIUM elif emoji_compare[-1] == 'L': fb_msg.emoji_size = EmojiSize.LARGE fb_msg.text = emoji_compare[:-1] msg.uid = self.client.send(fb_msg, thread_id=thread.uid, thread_type=thread.type) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): msg_uid = self.client.send_image_file(msg.filename, msg.file, msg.mime, message=fb_msg, thread_id=thread.uid, thread_type=thread.type) if msg_uid.startswith('mid.$'): self.client.sent_messages.add(msg_uid) self.logger.debug("Sent message with ID %s", msg_uid) msg.uid = msg_uid elif msg.type == MsgType.Voice: files = self.upload_file(msg, voice_clip=True) msg_uid = self.client._sendFiles(files=files, message=fb_msg, thread_id=thread.uid, thread_type=thread.type) if msg_uid.startswith('mid.$'): self.client.sent_messages.add(msg_uid) self.logger.debug("Sent message with ID %s", msg_uid) msg.uid = msg_uid elif msg.type in (MsgType.File, MsgType.Video): files = self.upload_file(msg) msg_uid = self.client._sendFiles(files=files, message=fb_msg, thread_id=thread.uid, thread_type=thread.type) if msg_uid.startswith('mid.$'): self.client.sent_messages.add(msg_uid) self.logger.debug("Sent message with ID %s", msg_uid) msg.uid = msg_uid elif msg.type == MsgType.Status: assert (isinstance(msg.attributes, StatusAttribute)) status: StatusAttribute = msg.attributes if status.status_type in (StatusAttribute.Types.TYPING, StatusAttribute.Types.UPLOADING_VOICE, StatusAttribute.Types.UPLOADING_VIDEO, StatusAttribute.Types.UPLOADING_IMAGE, StatusAttribute.Types.UPLOADING_FILE): self.client.setTypingStatus(TypingStatus.TYPING, thread_id=thread.uid, thread_type=thread.type) threading.Timer(status.timeout / 1000, self.stop_typing, args=(thread.uid, thread.type)).start() elif msg.type == MsgType.Link: assert (isinstance(msg.attributes, LinkAttribute)) link: LinkAttribute = msg.attributes if self.flag('send_link_with_description'): info: Tuple[str, ...] = (link.title,) if link.description: info += (link.description,) info += (link.url,) text = "\n".join(info) else: text = link.url if fb_msg.text: text = fb_msg.text + "\n" + text fb_msg.text = text msg.uid = self.client.send(fb_msg, thread_id=thread.uid, thread_type=thread.type) elif msg.type == MsgType.Location: assert (isinstance(msg.attributes, LocationAttribute)) location_attr: LocationAttribute = msg.attributes location = LocationAttachment(latitude=location_attr.latitude, longitude=location_attr.longitude) self.client.sendPinnedLocation(location, fb_msg, thread_id=thread.uid, thread_type=thread.type) else: raise EFBMessageTypeNotSupported() return msg finally: if msg.file and not msg.file.closed: msg.file.close() self.client.markAsSeen() self.client.markAsRead(msg.chat.uid)