async def _print_comic(bot, event, num=None): info = await _get_comic(bot, num) image_id = info['image_id'] context = { "parser": False, } msg1 = [ ChatMessageSegment("xkcd #%s: " % info['num']), ChatMessageSegment(info["title"], is_bold=True), ] msg2 = [ ChatMessageSegment(info["alt"]), ] + ChatMessageSegment.from_str( '\n- <i><a href="https://xkcd.com/%s">CC-BY-SA xkcd</a></i>' % info['num']) if "link" in info and info["link"]: msg2.extend( ChatMessageSegment.from_str("\n* see also %s" % info["link"])) await bot.coro_send_message(event.conv.id_, msg1, context) await bot.coro_send_message( event.conv.id_, msg2, context, image_id=image_id ) # image appears above text, so order is [msg1, image, msg2]
async def _async_send_message(self, message, targets): conversations = [] for target in targets: conversation = None if 'id' in target: conversation = self._conversation_list.get(target['id']) elif 'name' in target: conversation = self._resolve_conversation_name(target['name']) if conversation is not None: conversations.append(conversation) if not conversations: return False from hangups import ChatMessageSegment, hangouts_pb2 messages = [] for segment in message: if 'parse_str' in segment and segment['parse_str']: messages.extend(ChatMessageSegment.from_str(segment['text'])) else: if 'parse_str' in segment: del segment['parse_str'] messages.append(ChatMessageSegment(**segment)) messages.append(ChatMessageSegment('', segment_type=hangouts_pb2. SEGMENT_TYPE_LINE_BREAK)) if not messages: return False for conv in conversations: await conv.send_message(messages)
async def _async_send_message(self, message, targets, data): conversations = [] for target in targets: conversation = None if CONF_CONVERSATION_ID in target: conversation = self._conversation_list.get(target[CONF_CONVERSATION_ID]) elif CONF_CONVERSATION_NAME in target: conversation = self._resolve_conversation_name( target[CONF_CONVERSATION_NAME] ) if conversation is not None: conversations.append(conversation) if not conversations: return False from hangups import ChatMessageSegment, hangouts_pb2 messages = [] for segment in message: if messages: messages.append( ChatMessageSegment( "", segment_type=hangouts_pb2.SEGMENT_TYPE_LINE_BREAK ) ) if "parse_str" in segment and segment["parse_str"]: messages.extend(ChatMessageSegment.from_str(segment["text"])) else: if "parse_str" in segment: del segment["parse_str"] messages.append(ChatMessageSegment(**segment)) image_file = None if data: if data.get("image_url"): uri = data.get("image_url") try: websession = async_get_clientsession(self.hass) async with websession.get(uri, timeout=5) as response: if response.status != 200: _LOGGER.error( "Fetch image failed, %s, %s", response.status, response ) image_file = None else: image_data = await response.read() image_file = io.BytesIO(image_data) image_file.name = "image.png" except (asyncio.TimeoutError, aiohttp.ClientError) as error: _LOGGER.error("Failed to fetch image, %s", type(error)) image_file = None elif data.get("image_file"): uri = data.get("image_file") if self.hass.config.is_allowed_path(uri): try: image_file = open(uri, "rb") except OSError as error: _LOGGER.error( "Image file I/O error(%s): %s", error.errno, error.strerror ) else: _LOGGER.error('Path "%s" not allowed', uri) if not messages: return False for conv in conversations: await conv.send_message(messages, image_file)
def convert(self, source, slack): if isinstance(source, str): # Parse, then convert reparser.Segment to hangups.ChatMessageSegment. segments = [ ChatMessageSegment(seg.text, **seg.params) for seg in self.parse(source) ] else: # We'll assume it's already a ChatMessageSegment list. segments = source formatted = "" current = [] for seg in segments: if seg.type_ == hangouts_pb2.SEGMENT_TYPE_LINE_BREAK: # Insert closing tags for all current formatting, in reverse order. for chars in reversed(current): formatted += chars # Start a new line. formatted += "\n" # Now reinsert the current formatting. for chars in current: formatted += chars continue if self.from_slack: text = seg.text.replace(">", ">").replace("<", "<").replace( "&", "&") if seg.link_target: if seg.link_target[0] == "@": # User link, just replace with the plain username. user = seg.link_target[1:] if user in slack.users: user = slack.users[user]["name"] text = "@{}".format(user) elif seg.link_target[0] == "#": # Channel link, just replace with the plain channel name. channel = seg.link_target[1:] if channel in slack.channels: channel = slack.channels[channel]["name"] text = "#{}".format(channel) else: # Markdown link: [label](target) text = "[{}]({})".format( text, message_parser.url_complete(seg.link_target)) else: text = seg.text.replace("&", "&").replace(">", ">").replace( "<", "<") if seg.link_target: if text == seg.link_target: # Slack implicit link: <target> text = "<{}>".format(seg.link_target) else: # Slack link with label: <target|label> text = "<{}|{}>".format(seg.link_target, text) # Compare formatting of the previous segment to the current one. formatting = { self.bold: seg.is_bold, self.italic: seg.is_italic, self.strike: seg.is_strikethrough } # Insert closing tags for any formatting that ends here. # Apply in reverse order to opened tags. for chars in reversed(current): if not formatting[chars]: formatted += chars current.remove(chars) # Insert opening tags for any formatting that starts here. for chars, condition in formatting.items(): if condition and chars not in current: formatted += chars current.append(chars) # XXX: May generate tags closed in the wrong order: *bold _bold+italic* italic_ # Testing suggests both Slack and Hangouts can cope with this though. formatted += text # Close any remaining format tags. formatted += "".join(reversed(current)) return formatted