aboutsummaryrefslogtreecommitdiffstats
path: root/botmanager.py
blob: 8cfe94933808ea22ebcce1e8b4f62e3da93edee5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# -*- coding: utf-8 -*-

import random
import sys
import telepot
import traceback
import time
import logging

from jsonfactory import JSONFactory
from shoutboxapicommunicator import ShoutboxCommunicator
from telegramapicommunicator import TelegramCommunicator

class BotManager(object):
    """Manager class for the process"""

    # Make a dict of ( message id : timestamp ) pairs to
    # keep track of sent messages.
    # Messages older than 2 * update interval will be forgotten.
    last_message_timestamps = {}

    def __init__(self, token):
        """
        Attempt to create a bot with telepot

        If not possible, crash gracefully
        """
        TelegramCommunicator.token = token
        try:
            logging.info("Creating bot listener with token {}...".format(token))
            TelegramCommunicator.spawn_bot(token)
            logging.info("Bot succesfully created.")
        except:
            traceback.print_exc()
            logging.error("Error creating bot listener. radiodiodibot will now exit...")
            sys.exit(1)

    def set_parameters(self, shoutbox_api_url, telegram_chat_id, api_call_interval):
        """Store parameters in the manager instance"""
        ShoutboxCommunicator.url = shoutbox_api_url
        TelegramCommunicator.chat_id = telegram_chat_id
        ShoutboxCommunicator.interval = api_call_interval

    def start(self):
        """Try fetching bot information from Telegram to check connection"""
        TelegramCommunicator.start_listening(self.handle)

        while True:
            # Forward all new messages to the Telegram chat
            # and add them to the message dict
            self.forward_to_telegram(ShoutboxCommunicator.fetch())

            # Wait for the update interval
            time.sleep(ShoutboxCommunicator.interval)

            # Remove obsolete messages from the dict to prevent it
            # from bloating
            self.clean_up_message_dict()

    def clean_up_message_dict(self):
        """Purge all obsolete messages from the message dict"""
        new_message_dict = {}
        for msg_id in self.last_message_timestamps:

            # if the message is older than 2 * call interval,
            # pop it from the buffer because there is no way
            # it can be a duplicate anymore
            timestamp = round(float(self.last_message_timestamps[msg_id]))
            if not round(time.time()) - timestamp < 2 * ShoutboxCommunicator.interval:
                new_message_dict[msg_id] = self.last_message_timestamps[msg_id]
            else:
                logging.info("Popped message from buffer.")
        self.last_message_timestamps = new_message_dict

    def forward_to_telegram(self, messages):
        """Send all messages in the messages list to the Telegram chat"""
        try:
            for message in messages:
                # Do not send messages that have already been sent
                # This check is in place because of possible artifacts in API calls
                if message["id"] not in self.last_message_timestamps:
                    TelegramCommunicator.send(message)
                    self.last_message_timestamps[message["id"]] = message["timestamp"]

        except:
            logging.warning("Failed to send message to Telegram!")

    songs = ["Ace of Spades", "Mökkitie", "Alpha Russian XXL Night Mixtape", "teekkarihymni"]

    def action_now_playing(self, msg):
        """Placeholder action for testing commands"""
        TelegramCommunicator.send_raw("Radiossa soi {}!".format(random.choice(BotManager.songs)))

    def action_not_supported(self, msg):
        """Notify the user that the given command is not supported"""
        TelegramCommunicator.send_raw("Tätä toimintoa ei ole tuettu.")

    def parse_message(self, msg):
        """Determine which action to take for an incoming Telegram text message"""
        t = msg["text"]
        content_type, chat_type, chat_id = telepot.glance(msg)
        if "/nowplaying" in t:
            self.action_now_playing(msg)
        elif "/start" in t:
            self.action_not_supported(msg)
        elif "/stop" in t:
            self.action_not_supported(msg)
        elif str(chat_id) == TelegramCommunicator.chat_id.strip():
            self.action_send_to_shoutbox(msg)
        else:
            logging.info("Got non-forwarded message from chat_id: {}".format(chat_id))

    def action_send_to_shoutbox(self, msg):
        """Forward a Telegram message to shoutbox"""
        try:
            user_name = msg["from"]["first_name"]
            text = msg["text"]
            date = msg["date"]
        except KeyError:
            logging.warning("Malformed message from Telegram! Details:\n{}".format(msg))
            logging.warning("Skipped sending message to shoutbox.")
            return

        data = JSONFactory.make_object(text, user_name, date, "null")
        logging.info("Created JSON packet:\n{}".format(data))
        ShoutboxCommunicator.send(data)

    def handle(self, msg):
        """Start parsing the incoming message if it is a text message"""
        content_type, chat_type, chat_id = telepot.glance(msg)

        if content_type == 'text':
            self.parse_message(msg)