Beispiel #1
0
class ParseBot(object):
    bot = None
    states = None
    oops_handler = None

    def __init__(self):
        self.states = {}

    def init(self):
        self.bot = Bot(api_token=config.TELEGRAM_TOKEN)
        from bot.conversation import init_dialogs
        init_dialogs(self)
        self.bot.default(self.get_default_handler())
        yield_data.add_observer('pbot', self.data_receive_observer)

    async def data_receive_observer(self, tg_id, data):
        log.debug("DATA RECEIVED: to {}, data: {}", tg_id, data)
        chat = self.bot.private(tg_id)
        return chat.send_text('Look what I found!\n{}'.format(data))

    def add_state_handler(self, state, hlr):
        self.states[state] = hlr

    def add_default_state_handler(self, hlr):
        self.oops_handler = hlr

    def add_callback(self, regexp, fn):
        return self.bot.add_callback(regexp, fn)

    def add_command(self, regexp, fn):
        return self.bot.add_command(regexp, fn)

    def add_inline(self, regexp, fn):
        return self.bot.add_inline(regexp, fn)

    def get_default_handler(self):
        @with_user_data
        async def def_handler(chat, message, user_data):
            state = user_data.get('state')
            if state:
                handler = self.states.get(state)
                if handler:
                    return await handler(chat, message, user_data)
            if self.oops_handler:
                return await self.oops_handler(chat, message, user_data)
            return await chat.send_text('Oops! Something went wrong, for now we can start again and see how it goes')
        return def_handler

    def run(self, webhook=config.WEBHOOK_URL):
        if webhook:
            self.bot.run_webhook(webhook)
        else:
            self.bot.run(config.DEBUG)
Beispiel #2
0
class TelegramConnector:
    def __init__(self, name, andrew):
        self.name = name
        self.andrew = andrew
        self.bot = None
        self.callbacks = {}

    def pre_connect(self):
        self.andrew.connections.add_connector(self)

    def connect(self, config):
        proxy = None
        if 'proxy' in config:
            self.andrew.logger.info('{}: connecting through proxy'.format(
                config['token']))
            proxy = config['proxy']

        self.bot = Bot(api_token=config['token'], proxy=proxy)
        self.bot.default_in_groups = True
        self.bot.default(self.handler)
        return self.bot.loop

    def add_handler(self, msg_type, cb):
        async def _handler(chat, message):
            await cb(self, chat, message)

        self.bot.handle(msg_type)(_handler)

    async def handler(self, chat, message):
        msg = Message.build_from_raw(self, message)
        await self.andrew.handle_message(msg)

    async def send_message(self, destination, text, reply_to=None):
        return await self.bot.send_message(destination,
                                           text,
                                           reply_to_message_id=reply_to,
                                           parse_mode='Markdown')
Beispiel #3
0
class TelegramAgent(Agent):
    def __init__(self, name=None):
        super().__init__(name=name)
        self._bot = Bot(api_token=TELEGRAM_BOT_API_TOKEN,
                        name=TELEGRAM_BOT_NAME,
                        api_timeout=10)
        self._bot.default(self.on_incoming_telegram_message)
        self.sent_telegram_messages = {}

    def on_incoming_telegram_message(self, chat, message):
        try:
            text = message['text']
            name = text
            if len(name) > FRAME_NAME_MAX_LENGTH:
                name = name[:FRAME_NAME_MAX_LENGTH - 1] + '…'
            full_name = '{} {}'.format(message['from']['first_name'],
                                       message['from']['last_name'])
            sent_msg = self.message(name,
                                    data={
                                        'text': text,
                                        'message_id': message['message_id'],
                                        'chat_id': message['chat']['id'],
                                        'user_id': message['from']['id'],
                                        'username':
                                        message['from']['username'],
                                        'full_name': full_name,
                                        'session': message['chat']['id'],
                                    })
            self.sent_telegram_messages.update(
                {sent_msg.id: message['chat']['id']})
        except Exception:
            print(traceback.format_exc())
            print(message.name, message.data)

    @on_message('*')
    async def telegram_message_reply(self, message):
        if message.reply_to not in self.sent_telegram_messages:
            return
        text = message.data.text or message.name
        try:
            chat_id = self.sent_telegram_messages[message.reply_to]
            # del self.sent_telegram_messages[message.reply_to]
            await self._bot.send_message(chat_id=chat_id, text=text)
            self.emit('telegram_reply_sent',
                      data={
                          'text': text,
                          'chat_id': chat_id
                      })
        except Exception:
            print(traceback.format_exc())
            print(message.name, message.data)

    @on_event('send_telegram_message')
    async def send_message(self, event):
        text = event.data.text
        chat_id = event.data.session or event.data.chat_id
        if not chat_id:
            self.emit('telegram_message_error',
                      data={'text': 'session or chat_id expected.'})
            return
        try:
            ret_val = await self._bot.send_message(chat_id=chat_id, text=text)
            self.emit('telegram_message_sent',
                      data={
                          'text': text,
                          'chat_id': chat_id,
                          'return': ret_val
                      })
        except Exception:
            print(traceback.format_exc())
            print(event.name, event.data)

    @on_event('*** started')
    def on_started(self, event):
        self.emit('telegram_connecting')
        self.spawn(self._bot.loop())

    @on_event('*** stopping')
    def on_stopping(self, event):
        self._bot.stop()
Beispiel #4
0
class TeleGate(object):
    def __init__(self):
        self.ids = PickleDict('ids')
        self.members = PickleDict('members')
        self.ignored = PickleDict('ignored')
        self.cooldown = defaultdict(lambda: 0)
        self.dialogs = {}
        self.tripmap = {}
        self.bot = Bot(api_token=config.token, default_in_groups=True)
        for content_type in ['photo', 'video', 'audio', 'voice', 'document', 'sticker']:
            self.bot.handle(content_type)(self.handle_chat)
        self.bot.default(self.handle_chat)
        # self.bot.command(r'/set(icon|name|region|cooldown) (.+)')(self.set_user_prefs)
        # self.bot.command('help')(self.help)
        self.bot.command('setup')(self.setup)
        self.bot.command('start')(self.setup)
        self.bot.callback(r"setup-(\w+)")(self.setup_button_clicked)

    async def get_trip_flags(self):
        async with self.bot.session.get(f'https://{config.url}/js/tripflags.js') as s:
            data = await s.text()
            for l in data.splitlines():
                if l.startswith('flags_hover_strings'):
                    self.tripmap[l.split('"')[1]] = l.split('"')[3]

    async def post(self, body, name="Anonymous", convo="General", trip="", file="", country=None):
        if trip:
            name = '{}#{}'.format(name, trip)
        data = {
            'chat': config.board,
            'name': name,
            'trip': trip or '',
            'body': body,
            'convo': convo,
        }
        if country:
            data['country'] = country
        if file:
            data['image'] = open(file, 'rb')
        await self.bot.session.post(
                f'https://{config.url}/chat/{config.board}',
                data=data, cookies={'password_livechan': config.password_livechan}
            )

    async def get_posts(self, last_count=0, limit=30):
        params = {'count': last_count, 'limit': limit}
        async with self.bot.session.get(f'https://{config.url}/last/{config.board}', params=params) as s:
            data = await s.json()
            data.reverse()
            return data

    def send_gif(self, chat, animation, caption="", **options):
        return self.bot.api_call(
            "sendAnimation",
            chat_id=str(chat.id),
            animation=animation,
            caption=caption,
            **options
        )

    def get_member(self, chat):
        default = Member(chat.message['from']['first_name'], config.default_trip, None, config.default_cooldown)
        return Member(*self.members.get(chat.message['from']['id'], default))

    async def updater(self):
        last_count = 0
        post_data = {'count': 0}
        while True:
            try:
                await asyncio.sleep(config.poll_interval)
                group = self.bot.group(config.group_id)
                data = await self.get_posts(last_count)
                for post_data in data:
                    if post_data['identifier'] in self.ignored:
                        continue
                    if post_data['convo'] == 'General' and post_data['count'] not in self.ids:
                        res = None
                        country2 = emoji_flags.get_flag(post_data['country'].split('-')[0])
                        if '-' in post_data['country']:
                            country2 = '{}-{}'.format(country2, post_data['country'].split('-')[1])
                        body = '{} {} {} {}:\n{}'.format(post_data['count'], post_data['name'],
                                                         self.tripmap.get(post_data.get('trip'), ''), country2,
                                                         post_data['body'])
                        image = post_data.get('image')
                        reply_to = self.ids.get(int(post_data['body'].lstrip('>').split()[0]) if post_data['body'].startswith('>>') else None)
                        reply_to = {'reply_to_message_id':str(reply_to)} if reply_to else {}
                        if image:
                            image = 'https://{}{}'.format(config.url, image.split('public', 1)[1])
                            filename = image.split('/')[-1]
                            body = body[:1024]
                            async with self.bot.session.get(image) as f:
                                if f.status == 200:
                                    data = await f.read()
                                    with open('tmp/{}'.format(filename), 'wb') as f:
                                        f.write(data)
                                else:
                                    data = None
                            if data:
                                with open('tmp/{}'.format(filename), 'rb') as f:
                                    ext = os.path.splitext(image)[1]
                                    if ext in ['.png', '.jpg']:
                                        res = await group.send_photo(f, caption=body, **reply_to)
                                    elif ext in ['.gif']:
                                        res = await self.send_gif(group, f, caption=body, **reply_to)

                                    elif ext in ['.mp4']:
                                        res = await group.send_video(f, caption=body, **reply_to)
                                    elif ext in ['.mp3', '.ogg']:
                                        res = await group.send_audio(f, caption=body)
                                    elif ext == '.webm':
                                        body += f'\nhttps://{config.url}/tmp/uploads/' + filename
                                        res = await group.send_text(body, **reply_to)
                                os.unlink('tmp/{}'.format(filename))
                            else:
                                res = await group.send_text(body, **reply_to)
                        elif post_data['body']:
                            res = await group.send_text(body, **reply_to)

                        for st in re.findall(r'\[st\]([\w\d\-\.]+)\[\/st\]', body):
                            path = 'stickers/{}.png'.format(st)
                            if not os.path.exists(path):
                                async with self.bot.session.get(f'https://{config.url}/images/stickers/{st}.png') as f:
                                    if f.status == 200:
                                        data = await f.read()
                                        with open(path, 'wb') as f:
                                            f.write(data)
                                        with open(path, 'rb') as f:
                                            res2 = await group.send_photo(f)
                                            if not res:
                                                res = res2
                        if res:
                            self.ids[post_data['count']] = res['result']['message_id']
                            self.ids[res['result']['message_id']] = post_data['count']
            except Exception as e:
                traceback.print_exc()
            last_count = post_data['count']

    async def handle_chat(self, chat, image):
        if not chat.is_group():
            if chat.message['from']['id'] in self.dialogs:
                await self.setup(chat, image)
            return
        else:
            if chat.message['from']['id'] not in self.members:
                await self.setup(chat, image)
        if type(image) == list:
            image = image[-1]
        if 'file_id' in image:
            cq = chat.message
            text = chat.message.get('caption', '')
        else:
            cq = image
            text = cq['text']
        if 'reply_to_message' in cq:
            id = cq['reply_to_message']['message_id']
            if id in self.ids:
                text = '>>{}\n{}'.format(self.ids[id], text)
        id = image.get('file_id')
        if id:
            info = await self.bot.get_file(id)

            path = 'tmp/{}'.format(info['file_path'].split('/')[-1])
            if path.endswith('.oga'): path = path.replace('.oga', '.ogg')
            async with self.bot.download_file(info['file_path']) as res:
                data = await res.read()
                open(path, 'wb').write(data)
            if path.endswith('.webp'):
                newpath = path.replace('.webp', '.png')
                os.system('convert {} {}'.format(path, newpath)) # requires imagemagick
                path = newpath
            elif path.endswith('.tgs'):
                newpath = 'stickers/{}.gif'.format(image['file_id'])
                if not os.path.exists(newpath):
                    import tgs
                    from tgs.exporters import gif
                    a=tgs.parsers.tgs.parse_tgs(path)

                    with open(newpath, 'wb') as f:
                        gif.export_gif(a, f)
                os.unlink(path)
                path = newpath
        else:
            path = None
        member = self.get_member(chat)
        if not (time() > self.cooldown[cq['from']['id']] + member.cooldown_limit):
            return
        self.cooldown[cq['from']['id']] = time()
        await self.post(text, name=member.name, trip=member.trip, country=member.country, file=path)
        if path and path.startswith('tmp/'):
            os.unlink(path)
        await chat.delete_message(cq['message_id'])

    async def setup(self, chat, match):
        member = self.get_member(chat)
        id = chat.message['from']['id']
        if chat.is_group():
            chat = self.bot.private(chat.message['from']['id'])
        if id in self.dialogs:
            setattr(member, {'name': 'name', 'icon': 'trip', 'region': 'country'}[self.dialogs[id]], chat.message['text'])
            if member.trip == 'none':
                member.trip = None
            self.members[chat.message['from']['id']] = member
            del self.dialogs[id]

        buttons = []
        for button in ['name', 'icon', 'region']:
            buttons.append({
                "type": "InlineKeyboardButton",
                "text": "Set {}".format(button),
                "callback_data": "setup-{}".format(button),
            })
        markup = {
            "type": "InlineKeyboardMarkup",
            "inline_keyboard": [buttons]
        }
        chat.send_text(f"Name: {member.name}\nIcon: {member.trip}\nRegion: {member.country}", reply_markup=json.dumps(markup))

    def setup_button_clicked(self, chat, cq, match):
        if chat.is_group():
            chat = self.bot.private(chat.message['from']['id'])
        id = chat.message['chat']['id']
        param = match.group(1)
        self.dialogs[id] = param
        example = {
            'name': 'Kot',
            'icon': 'plkot; none for no icon',
            'region': 'PL-77 or RU-47',
        }[param]
        chat.send_text('Send your {}(for example: {})'.format(param, example))

    def run(self):
        loop = asyncio.get_event_loop()
        loop.create_task(self.updater())
        loop.create_task(self.get_trip_flags())
        self.bot.run()