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
134
135
|
# -*- coding: utf-8 -*-
import logging
import random
import sys
import time
import traceback
import telepot
from project.jsonfactory import JSONFactory
from project.shoutboxapicommunicator import ShoutboxCommunicator
from project.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. src 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)
|