class GetMessages:
    def __init__(self, print_fn=print, loop=None):
        self._print_fn = print_fn
        self._driver = Whalesong(driver=WhalesongDriver(profile=path.join(
            path.dirname(__file__), 'profile-chromium'),
                                                        headless=True,
                                                        loop=loop),
                                 loop=loop)

        try:
            mkdir(OUTPUT_DIR)
        except FileExistsError:
            pass

    @property
    def loop(self):
        return self._driver.loop

    def echo(self, txt):
        self._print_fn(txt)

    async def check_stream(self):
        stream = await self._driver.stream.get_model()
        self.echo("Stream: {}".format(stream.stream))
        self.echo("State: {}".format(stream.state))

    async def monitor_stream(self):
        self.echo('Monitor stream')
        messages_it = None
        new_message_monitor = None
        message_ack_monitor = None

        async for evt in self._driver.stream.monitor_field('stream'):
            self.echo('Stream value: {}'.format(evt['value']))

            if evt['value'] == Stream.Stream.CONNECTED:
                if messages_it is None:
                    messages_it = self._driver.messages.get_items()
                    ensure_future(self.list_messages(messages_it))

                if new_message_monitor is None:
                    new_message_monitor = self._driver.messages.monitor_new()
                    ensure_future(
                        self.monitor_new_messages(new_message_monitor))

                if message_ack_monitor is None:
                    message_ack_monitor = self._driver.messages.monitor_field(
                        'ack')
                    ensure_future(
                        self.monitor_message_acks(message_ack_monitor))
            else:
                if messages_it is not None:
                    messages_it = None
                    await self._driver.cancel_iterators()

                if new_message_monitor is not None:
                    self._driver.stop_monitor(new_message_monitor)
                    new_message_monitor = None

                if message_ack_monitor is not None:
                    self._driver.stop_monitor(message_ack_monitor)
                    message_ack_monitor = None

    async def list_messages(self, it):
        self.echo('List messages')
        async for message in it:
            self.echo('Message: {}'.format(message))

            if isinstance(message, MediaMixin):
                await self.download_media(message)
            elif isinstance(message, LocationMessage):
                await self.store_thumbnail(message.id, message.body)
            elif isinstance(message, TextMessage) and message.thumbnail:
                await self.store_thumbnail(message.id, message.thumbnail)

        self.echo('List messages finished')

    async def monitor_new_messages(self, it):
        self.echo('Monitor new messages')
        async for message in it:
            self.echo('New message: {}'.format(message))

            if isinstance(message, MediaMixin):
                await self.download_media(message)
            elif isinstance(message, LocationMessage):
                await self.store_thumbnail(message.id, message.body)
            elif isinstance(message, TextMessage) and message.thumbnail:
                await self.store_thumbnail(message.id, message.thumbnail)

        self.echo('Stop new messages bot')

    async def monitor_message_acks(self, it):
        self.echo('Monitor message ack')
        async for ack in it:
            self.echo('ACK: {}'.format(ack))

        self.echo('Stop message acks bot')

    async def start(self):
        await self._driver.start()

        ensure_future(self.check_stream()),
        ensure_future(self.monitor_stream())

        await self._driver.wait_until_stop()

    async def download_media(self, message):
        if isinstance(message, MediaFrameMixin) and not isinstance(
                message, StickerMessage):
            await self.store_thumbnail(message.id, message.body)

        media_data = await self._driver.messages.download_media(message)

        mimetype = message.mimetype

        if ';' in mimetype:
            mimetype, _ = mimetype.split(';', 1)

        ext = mimetypes.guess_extension(mimetype, strict=False)

        await self._store_media('{}{}'.format(message.id, ext or '.bin'),
                                media_data.read())

    async def store_thumbnail(self, message_id, image_data):
        await self._store_media('{}_thumb.jpg'.format(message_id), image_data)

    async def _store_media(self, filename, filedata):
        filepath = path.join(OUTPUT_DIR, filename)

        self.echo('Storing file {}'.format(filepath))

        with open(filepath, 'wb') as f:
            f.write(filedata)
class Minibot:
    def __init__(self, print_fn=print, loop=None):
        self._print_fn = print_fn
        self._driver = Whalesong(driver=WhalesongDriver(profile=path.join(
            path.dirname(__file__), 'profile-chromium'),
                                                        headless=True,
                                                        loop=loop),
                                 loop=loop)

    @property
    def loop(self):
        return self._driver.loop

    def echo(self, txt):
        self._print_fn(txt)

    async def download_url(self, url):
        async with ClientSession() as session:
            async with session.get(url) as resp:
                content_type = resp.headers.get(hdrs.CONTENT_TYPE)
                data = BytesIO(await resp.read())

        if content_type and ';' in content_type:
            content_type = content_type[:content_type.index(';')]

        return content_type, data

    async def monitor_stream(self):
        self.echo('Monitor stream')
        new_message_monitor = None

        async for evt in self._driver.stream.monitor_field('stream'):
            self.echo('Stream value: {}'.format(evt['value']))

            if evt['value'] == Stream.Stream.CONNECTED:
                if new_message_monitor is None:
                    new_message_monitor = self._driver.messages.monitor_new()
                    ensure_future(
                        self.monitor_new_messages(new_message_monitor))
            else:
                if new_message_monitor is not None:
                    self._driver.stop_monitor(new_message_monitor)
                    new_message_monitor = None

    async def monitor_new_messages(self, it):
        self.echo('Monitor new messages')
        async for message in it:
            try:
                if message.type == MessageTypes.CHAT:
                    if message.body.startswith('/echo '):
                        ensure_future(self.make_echo(message))
                    elif message.body.startswith('/contact '):
                        ensure_future(self.make_contact(message))
                    elif message.body.startswith('/download '):
                        ensure_future(self.make_download(message))
                    elif message.body.startswith('/send '):
                        ensure_future(self.make_message(message))
                    elif message.body.startswith('/link '):
                        ensure_future(self.make_link(message))
                    elif message.body.startswith('/exist '):
                        ensure_future(self.make_exists(message))
                    elif message.body.startswith('/sticker '):
                        ensure_future(self.make_sticker(message))
                    elif message.body.startswith('/status '):
                        ensure_future(self.make_status(message))
                    elif message.body.startswith('/pushname '):
                        ensure_future(self.make_pushname(message))

            except Exception as ex:
                self.echo('Ignoring message {} because error : {}'.format(
                    message.id, ex))

        self.echo('Stop new messages bot')

    async def make_echo(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        text = message.body[len('/echo '):].strip()
        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id].send_text(text, message.id)))

    async def make_contact(self, message):
        self._driver.chats[message.chat.id].send_seen()
        contact_id = message.body[len('/contact '):].strip()

        contact = await self._driver.contacts.get_item_by_id(contact_id)

        self.echo('Sent message (by phone): {}'.format(
            await self._driver.chats[message.chat.id].send_contact_phone(
                contact.formatted_name, contact.userid, message.id)))

        self.echo('Sent message (by contact id): {}'.format(
            await self._driver.chats[message.chat.id
                                     ].send_contact(contact_id, message.id)))

    async def make_download(self, message):
        self._driver.chats[message.chat.id].send_seen()
        url = message.body[len('/download '):].strip()

        content_type, data = await self.download_url(url)

        filename = url
        if '?' in filename:
            filename = filename[:filename.index('?')]
        if '#' in filename:
            filename = filename[:filename.index('#')]
        _, filename = filename.rstrip('/').rsplit('/', 1)

        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id].send_media(data, content_type, filename, url,
                                        message.id)))

    async def make_message(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        cmd = message.body[len('/send '):].strip()
        contact_id, text = cmd.split(' ')
        if not contact_id.endswith('@c.us'):
            contact_id = f'{contact_id.strip()}@c.us'

        chat = await self._driver.chats.ensure_chat_with_contact(
            contact_id=contact_id)
        msg = await self._driver.chats[chat.id].send_text(text)
        self.echo('Sent message: {}'.format(msg))

        await self._driver.chats[message.chat.id
                                 ].send_text(f'Message sent to {chat.id}')

    async def make_link(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        text = message.body[len('/link '):].strip()
        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id].send_text(text)))

    async def make_exists(self, message):
        self._driver.chats[message.chat.id].send_seen()

        contact_id = message.body[len('/exist '):].strip()

        if not contact_id.endswith('@c.us'):
            contact_id = f'{contact_id.strip()}@c.us'

        exists = await self._driver.wap.query_exist(contact_id=contact_id)
        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id
        ].send_text('It exists' if exists else 'It does not exist',
                    message.id)))

    async def make_sticker(self, message):
        self._driver.chats[message.chat.id].send_seen()

        sticker_pack_name = message.body[len('/sticker '):].strip()

        if sticker_pack_name == 'list':
            ensure_future(self.make_sticker_pack_list(message))
            return

        await self._driver.sticker_packs.fetch_all_pages()

        try:
            sticker_pack = await self._driver.sticker_packs.get_item_by_name(
                sticker_pack_name)
        except ModuleNotFoundError:
            self.echo('Sent message: {}'.format(await self._driver.chats[
                message.chat.id
            ].send_text(f'Sticker pack "{sticker_pack_name}" does not exist',
                        message.id)))

            return

        await self._driver.sticker_packs[sticker_pack.id].stickers.fetch()

        sticker = choice([
            s async for s in self._driver.sticker_packs[
                sticker_pack.id].stickers.get_items()
        ])

        msg = await self._driver.sticker_packs[sticker_pack.id].stickers[
            sticker.id].send_to_chat(chat_id=message.chat.id,
                                     quoted_msg_id=message.id)

        self.echo(f'Sent message: {msg}')

    async def make_sticker_pack_list(self, message):
        await self._driver.sticker_packs.fetch_all_pages()

        async for sticker_pack in self._driver.sticker_packs.get_items():
            content_type, image = await self.download_url(sticker_pack.url)

            self.echo('Sent message: {}'.format(await self._driver.chats[
                message.chat.id].send_media(image,
                                            content_type,
                                            caption=sticker_pack.name)))

    async def make_status(self, message):
        new_status = message.body[len('/status '):].strip()
        await self._driver.status.set_my_status(new_status=new_status)
        self.echo(f'Set status: {new_status}')

    async def make_pushname(self, message):
        new_pushname = message.body[len('/pushname '):].strip()
        await self._driver.conn.update_pushname(name=new_pushname)
        self.echo(f'Set pushname: {new_pushname}')

    async def start(self):
        await self._driver.start()

        ensure_future(self.monitor_stream())

        await self._driver.wait_until_stop()
Exemple #3
0
class Minibot:
    def __init__(self, print_fn=print, loop=None):
        self._print_fn = print_fn
        self._driver = Whalesong(profile=path.join(path.dirname(__file__),
                                                   'profile'),
                                 loadstyles=True,
                                 loop=loop)

    @property
    def loop(self):
        return self._driver.loop

    def echo(self, txt):
        self._print_fn(txt)

    async def monitor_stream(self):
        self.echo('Monitor stream')
        new_message_monitor = None

        async for evt in self._driver.stream.monitor_field('stream'):
            self.echo('Stream value: {}'.format(evt['value']))

            if evt['value'] == 'CONNECTED':
                if new_message_monitor is None:
                    new_message_monitor = self._driver.messages.monitor_new()
                    ensure_future(
                        self.monitor_new_messages(new_message_monitor))
            else:
                if new_message_monitor is not None:
                    self._driver.stop_monitor(new_message_monitor)
                    new_message_monitor = None

    async def monitor_new_messages(self, it):
        self.echo('Monitor new messages')
        async for message in it:
            try:
                if message.type == MessageTypes.CHAT:
                    if message.body.startswith('/echo '):
                        ensure_future(self.make_echo(message))
                    elif message.body.startswith('/contact '):
                        ensure_future(self.make_contact(message))
                    elif message.body.startswith('/download '):
                        ensure_future(self.make_download(message))
                    elif message.body.startswith('/send '):
                        ensure_future(self.make_message(message))
                    elif message.body.startswith('/link '):
                        ensure_future(self.make_link(message))
                    elif message.body.startswith('/exist '):
                        ensure_future(self.make_exists(message))
            except Exception as ex:
                self.echo('Ignoring message {} because error : {}'.format(
                    message.id, ex))

        self.echo('Stop new messages bot')

    async def make_echo(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        text = message.body[len('/echo '):].strip()
        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id].send_text(text, message.id)))

    async def make_contact(self, message):
        self._driver.chats[message.chat.id].send_seen()
        contact_id = message.body[len('/contact '):].strip()

        contact = await self._driver.contacts.get_item_by_id(contact_id)

        self.echo('Sent message (by phone): {}'.format(
            await self._driver.chats[message.chat.id].send_contact_phone(
                contact.formatted_name, contact.userid, message.id)))

        self.echo('Sent message (by contact id): {}'.format(
            await self._driver.chats[message.chat.id
                                     ].send_contact(contact_id, message.id)))

    async def make_download(self, message):
        self._driver.chats[message.chat.id].send_seen()
        url = message.body[len('/download '):].strip()

        async with ClientSession() as session:
            async with session.get(url) as resp:
                content_type = resp.headers.get(hdrs.CONTENT_TYPE)
                data = BytesIO(await resp.read())

        if content_type and ';' in content_type:
            content_type = content_type[:content_type.index(';')]

        filename = url
        if '?' in filename:
            filename = filename[:filename.index('?')]
        if '#' in filename:
            filename = filename[:filename.index('#')]
        _, filename = filename.rstrip('/').rsplit('/', 1)

        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id].send_media(data, content_type, filename, url,
                                        message.id)))

    async def make_message(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        cmd = message.body[len('/send '):].strip()
        contact_id, text = cmd.split(' ')
        if not contact_id.endswith('@c.us'):
            contact_id = f'{contact_id.strip()}@c.us'

        chat = await self._driver.chats.ensure_chat_with_contact(
            contact_id=contact_id)
        msg = await self._driver.chats[chat.id].send_text(text)
        self.echo('Sent message: {}'.format(msg))

        await self._driver.chats[message.chat.id
                                 ].send_text(f'Message sent to {chat.id}')

    async def make_link(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        text = message.body[len('/link '):].strip()
        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id].send_text(text)))

    async def make_exists(self, message):
        self._driver.chats[message.chat.id].send_seen()
        self.echo(message.chat.id)
        contact_id = message.body[len('/exist '):].strip()

        if not contact_id.endswith('@c.us'):
            contact_id = f'{contact_id.strip()}@c.us'

        exists = await self._driver.wap.query_exist(contact_id=contact_id)
        self.echo('Sent message: {}'.format(await self._driver.chats[
            message.chat.id
        ].send_text('It exists' if exists else 'It does not exist',
                    message.id)))

    async def start(self):
        await self._driver.start()

        ensure_future(self.monitor_stream())

        await self._driver.wait_until_stop()
class GetLiveLocations:
    def __init__(self, print_fn=print, loop=None):
        self._print_fn = print_fn
        self._driver = Whalesong(driver=WhalesongDriver(profile=path.join(
            path.dirname(__file__), 'profile-chromium'),
                                                        headless=True,
                                                        loop=loop),
                                 loop=loop)

    @property
    def loop(self):
        return self._driver.loop

    def echo(self, txt):
        self._print_fn(txt)

    async def check_stream(self):
        stream = await self._driver.stream.get_model()
        self.echo("Stream: {}".format(stream.stream))
        self.echo("State: {}".format(stream.state))

    async def monitor_stream(self):
        self.echo('Monitor stream')
        live_loc_it = None
        new_message_monitor = None
        message_ack_monitor = None

        async for evt in self._driver.stream.monitor_field('stream'):
            self.echo('Stream value: {}'.format(evt['value']))

            if evt['value'] == Stream.Stream.CONNECTED:

                if live_loc_it is None:
                    live_loc_it = self._driver.live_locations.get_items()
                    ensure_future(self.list_live_locations(live_loc_it))

                if new_message_monitor is None:
                    new_live_locations = self._driver.live_locations.monitor_add(
                    )
                    ensure_future(
                        self.monitor_new_live_locations(new_live_locations))

            else:
                if live_loc_it is not None:
                    live_loc_it = None
                    await self._driver.cancel_iterators()

                if new_message_monitor is not None:
                    self._driver.stop_monitor(new_message_monitor)
                    new_message_monitor = None

                if message_ack_monitor is not None:
                    self._driver.stop_monitor(message_ack_monitor)
                    message_ack_monitor = None

    async def list_live_locations(self, it):
        self.echo('List live locations')
        async for live_location in it:
            self.echo('Live location: {}'.format(live_location))
            ensure_future(self.monitor_live_location(live_location))

        self.echo('List messages finished')

    async def monitor_new_live_locations(self, it):
        self.echo('Monitor live locations')
        async for live_location in it:
            self.echo('New live location: {}'.format(live_location))
            ensure_future(self.monitor_live_location(live_location))

    async def monitor_live_location(self, live_location):
        self._driver.live_locations[live_location.id].subscribe()

        for participant in live_location.participants:
            ensure_future(self.monitor_participant(live_location, participant))

        async for participant in self._driver.live_locations[
                live_location.id].participants.monitor_add():
            ensure_future(self.monitor_participant(live_location, participant))

    async def monitor_participant(self, live_location, participant):
        async for new_part in self._driver.live_locations[live_location.id] \
                .participants[participant.id].monitor_model():
            self.echo(
                'Participant at live location `{}` now are in {}@{}'.format(
                    live_location.id, new_part.lat, new_part.lng))

    async def start(self):
        await self._driver.start()

        loop = get_event_loop()
        loop.add_signal_handler(
            SIGINT, lambda *args: ensure_future(self._driver.stop()))
        loop.add_signal_handler(
            SIGTERM, lambda *args: ensure_future(self._driver.stop()))

        ensure_future(self.check_stream()),
        ensure_future(self.monitor_stream())

        await self._driver.wait_until_stop()