Dockerized and fixed errors
This commit is contained in:
2
app/bot/commands/__init__.py
Normal file
2
app/bot/commands/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Placeholder
|
||||
from . import clock, help, weather, status, zvv, lists, alias, plaintext, reddit, search
|
64
app/bot/commands/alias.py
Normal file
64
app/bot/commands/alias.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from .template import *
|
||||
|
||||
FIRST = range(1)
|
||||
class Alias(BotFunc):
|
||||
"""create a new command for command-paths you often use"""
|
||||
|
||||
def __init__(self, dispatcher, db):
|
||||
super().__init__(db)
|
||||
self.dispatcher = dispatcher
|
||||
# do not interact with him yet!
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('alias', self.entry_point)],
|
||||
states={
|
||||
FIRST: [
|
||||
CallbackQueryHandler(self.print_all, pattern="^all$"),
|
||||
CallbackQueryHandler(self.create_alias, pattern="^new$"),
|
||||
CallbackQueryHandler(self.delete_alias, pattern='^delete$'),
|
||||
]
|
||||
},
|
||||
fallbacks=[CommandHandler('alias', self.entry_point)],
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
test = self.dispatcher
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("All aliases", callback_data="all")],
|
||||
[InlineKeyboardButton("Create new alias", callback_data="new")],
|
||||
[InlineKeyboardButton("Delete alias", callback_data="delete")],
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
super().log_activity(receive=True, execute=False, send=True)
|
||||
update.message.reply_text("What exactly do you want?", reply_markup=reply_markup)
|
||||
return FIRST
|
||||
|
||||
|
||||
def print_all(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
all_alias = ""
|
||||
for k in self.persistence["bot"]["aliases"]:
|
||||
all_alias += k + " - " + self.persistence["bot"]["aliases"] +"\n"
|
||||
|
||||
query.edit_message_text(text="List of all commands:\n" + all_alias)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def create_alias(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
all_alias = ""
|
||||
for k in self.persistence["bot"]["aliases"]:
|
||||
all_alias += k + " - " + self.persistence["bot"]["aliases"] +"\n"
|
||||
|
||||
query.edit_message_text(text="List of all commands:\n" + all_alias)
|
||||
return ConversationHandler.END
|
||||
|
||||
def delete_alias(self, update: Update, context: CallbackContext) -> None:
|
||||
return ConversationHandler.END
|
206
app/bot/commands/clock.py
Normal file
206
app/bot/commands/clock.py
Normal file
@@ -0,0 +1,206 @@
|
||||
from .template import *
|
||||
import time
|
||||
import numpy
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
CHOOSE, ADDARG = range(2)
|
||||
MESSAGE, WAKE, ALARM, IMAGE, ART = range(3,8)
|
||||
|
||||
class Clock(BotFunc):
|
||||
"""pass on commands to clock-module"""
|
||||
def __init__(self, db_utils, clock_module, art_api):
|
||||
super().__init__(db_utils)
|
||||
self.clock = clock_module
|
||||
self.art_api = art_api
|
||||
|
||||
def create_handler(self):
|
||||
handler = ConversationHandler(
|
||||
entry_points=[CommandHandler("clock", self.entry_point)],
|
||||
states={
|
||||
CHOOSE : [
|
||||
CallbackQueryHandler(self.wake_light, pattern="^wake$"),
|
||||
CallbackQueryHandler(self.alarm_blink, pattern="^alarm$"),
|
||||
CallbackQueryHandler(self.show_message, pattern="^message$"),
|
||||
CallbackQueryHandler(self.show_image, pattern="^image$"),
|
||||
CallbackQueryHandler(self.art_gallery, pattern="^gallery$"),
|
||||
],
|
||||
ADDARG : [MessageHandler(Filters.text, callback=self.get_arg1)],
|
||||
MESSAGE: [MessageHandler(Filters.text, callback=self.exec_show_message)],
|
||||
WAKE : [MessageHandler(Filters.text, callback=self.exec_wake_light)],
|
||||
ALARM : [MessageHandler(Filters.text, callback=self.exec_alarm_blink)],
|
||||
IMAGE : [MessageHandler(Filters.photo, callback=self.exec_show_image)],
|
||||
ART : [MessageHandler(Filters.text, callback=self.exec_art_gallery)],
|
||||
},
|
||||
fallbacks=[CommandHandler('clock', self.entry_point)],
|
||||
)
|
||||
return handler
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("Make a wake-light", callback_data="wake")],
|
||||
[InlineKeyboardButton("Blink as alarm", callback_data="alarm")],
|
||||
[InlineKeyboardButton("Show a message", callback_data="message")],
|
||||
[InlineKeyboardButton("Show an image", callback_data="image")],
|
||||
[InlineKeyboardButton("Art gallery!", callback_data="gallery")],
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
update.message.reply_text("What exactly do you want?", reply_markup=reply_markup)
|
||||
return CHOOSE
|
||||
|
||||
|
||||
def wake_light(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
query.edit_message_text("Ok. How long should the color cycle last? (In seconds)")
|
||||
return WAKE
|
||||
|
||||
def alarm_blink(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
query.edit_message_text("Ok. How long should it blink? (In seconds)")
|
||||
self.next_state = {ALARM : "What frequency (Hertz)"}
|
||||
return ADDARG
|
||||
|
||||
def show_message(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
query.edit_message_text("Ok. What message will I show?")
|
||||
return MESSAGE
|
||||
|
||||
def show_image(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
query.edit_message_text("How long (in minutes) should the image be displayed?")
|
||||
self.next_state = {IMAGE : "Please send me the photo to display."}
|
||||
return ADDARG
|
||||
|
||||
def art_gallery(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
query.edit_message_text("Ok. How long should we display art? (in hours")
|
||||
self.next_state = {ART : "And how many artworks would you like to see during that time?"}
|
||||
return ADDARG
|
||||
|
||||
def get_arg1(self, update: Update, context: CallbackContext) -> None:
|
||||
a = update.message.text
|
||||
self.additional_argument = a
|
||||
update.message.reply_text("Furthermore: "+ list(self.next_state.values())[0])
|
||||
return list(self.next_state.keys())[0]
|
||||
|
||||
|
||||
|
||||
|
||||
###### actually running clock actions
|
||||
def exec_wake_light(self, update: Update, context: CallbackContext) -> None:
|
||||
duration = update.message.text
|
||||
|
||||
matrices = []
|
||||
start_color = numpy.array([153, 0, 51])
|
||||
end_color = numpy.array([255, 255, 0])
|
||||
col_show = numpy.zeros((*self.clock.MOP.shape, 3))
|
||||
col_show[:,:,...] = start_color
|
||||
|
||||
gradient = end_color - start_color
|
||||
# steps are shown at a frequency of ?? frames / second =>
|
||||
for i in range(duration * 2): # / 0.5
|
||||
ct = i/20 * gradient
|
||||
col_show[:,:,...] = [int(x) for x in ct+start_color]
|
||||
matrices.append(col_show)
|
||||
|
||||
self.clock.out.queue.append({"matrices" : matrices})
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def exec_alarm_blink(self, update: Update, context: CallbackContext) -> None:
|
||||
duration = self.additional_argument
|
||||
|
||||
matrices = []
|
||||
duration = int(duration * 2)
|
||||
empty = numpy.zeros((*self.clock.MOP.shape,3))
|
||||
red = numpy.ones_like(empty) * 255
|
||||
|
||||
for _ in range(int(duration / 2)):
|
||||
matrices.append(red)
|
||||
matrices.append(empty)
|
||||
|
||||
self.clock.out.queue.append({"matrices": matrices})
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
|
||||
def exec_show_image(self, update: Update, context: CallbackContext) -> None:
|
||||
duration = self.additional_argument
|
||||
i = update.message.photo
|
||||
img = update.message.photo[0]
|
||||
bot = img.bot
|
||||
id = img.file_id
|
||||
|
||||
file = bot.getFile(id).download_as_bytearray()
|
||||
width = self.clock.shape[1]
|
||||
height = self.clock.shape[0]
|
||||
|
||||
img = Image.open(io.BytesIO(file))
|
||||
im_height = img.height
|
||||
im_width = img.width
|
||||
|
||||
scalex = im_width // width
|
||||
scaley = im_height // height
|
||||
scale = min(scalex, scaley)
|
||||
|
||||
t = img.resize((width, height),box=(0,0,width*scale,height*scale))
|
||||
a = numpy.asarray(t)
|
||||
|
||||
matrices = [a for _ in range(2*60*duration)]
|
||||
|
||||
self.clock.out.queue.append({"matrices": matrices})
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def exec_show_message(self, update: Update, context: CallbackContext) -> None:
|
||||
message_str = update.message.text
|
||||
update.message.reply_text("Now showing: " + message_str)
|
||||
self.clock.run(self.clock.text_scroll,(message_str,))
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def exec_art_gallery(self, update: Update, context: CallbackContext) -> None:
|
||||
duration = float(self.additional_argument)
|
||||
number = int(update.message.text)
|
||||
|
||||
def output(number, duration):
|
||||
for i in range(number):
|
||||
img = self.art_api.get_random_art() # returns an PIL.Image object
|
||||
im_height = img.height
|
||||
im_width = img.width
|
||||
|
||||
width = self.clock.shape[1]
|
||||
height = self.clock.shape[0]
|
||||
|
||||
scalex = im_width // width
|
||||
scaley = im_height // height
|
||||
scale = min(scalex, scaley)
|
||||
|
||||
t = img.resize((width, height),box=(0,0,width*scale,height*scale))
|
||||
a = numpy.asarray(t)
|
||||
self.clock.IO.put(a)
|
||||
|
||||
time.sleep(duration*3600 / number)
|
||||
|
||||
|
||||
update.message.reply_text("Ok. Showing art for the next "+ str(duration) + " hours.")
|
||||
self.clock.run(output,(number, duration))
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# TODO FIx this to work with the new backend
|
128
app/bot/commands/help.py
Normal file
128
app/bot/commands/help.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from .template import *
|
||||
|
||||
FIRST, EXECUTE = range(2)
|
||||
|
||||
|
||||
class Help(BotFunc):
|
||||
"""Shows the functions and their usage"""
|
||||
|
||||
def __init__(self, db):
|
||||
super().__init__(db)
|
||||
self.available_commands = {}
|
||||
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('help', self.entry_point)],
|
||||
states={
|
||||
FIRST: [
|
||||
CallbackQueryHandler(self.print_all, pattern="^all$"),
|
||||
CallbackQueryHandler(self.choose_specific, pattern="^specific$"),
|
||||
CallbackQueryHandler(self.print_one, pattern='func-'),
|
||||
],
|
||||
EXECUTE :[CallbackQueryHandler(self.execute_now)],
|
||||
# ConversationHandler.TIMEOUT : [
|
||||
# CallbackQueryHandler(self.timeout)
|
||||
# ]
|
||||
},
|
||||
fallbacks=[CommandHandler('help', self.entry_point)],
|
||||
conversation_timeout=15,
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
def add_commands(self, commands):
|
||||
# commands is a dict {"name": class}
|
||||
for k in commands:
|
||||
if k != "plaintext":
|
||||
self.available_commands[k] = commands[k].__doc__
|
||||
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("All commands", callback_data="all"),
|
||||
InlineKeyboardButton("Just one", callback_data="specific"),
|
||||
]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
super().log_activity(read=True, execute=True, send=True) # at this point every step has been fulfilled
|
||||
if update.message:
|
||||
update.message.reply_text("What exactly do you want?", reply_markup=reply_markup)
|
||||
else:
|
||||
update._effective_chat.send_message("What exactly do you want?", reply_markup=reply_markup)
|
||||
return FIRST
|
||||
|
||||
|
||||
def print_all(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
all_cmd = ""
|
||||
for h in self.available_commands:
|
||||
all_cmd += "{} - `{}`\n".format(h, self.available_commands[h])
|
||||
|
||||
query.edit_message_text(text="List of all commands:\n" + all_cmd, parse_mode = ParseMode.MARKDOWN)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def choose_specific(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
|
||||
keyboard = [[InlineKeyboardButton(k, callback_data="func-" + k)] for k in self.available_commands]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
query.edit_message_text(
|
||||
text="What command should be printed?", reply_markup=reply_markup
|
||||
)
|
||||
return FIRST
|
||||
|
||||
|
||||
def print_one(self, update: Update, context: CallbackContext) -> None:
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
name = query.data.replace("func-", "")
|
||||
query.answer()
|
||||
|
||||
message = name + ": `" + self.available_commands[name] + "`"
|
||||
|
||||
keyboard = [[InlineKeyboardButton("Call " + name + " now", callback_data=name),]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
query.edit_message_text(
|
||||
text= message,
|
||||
reply_markup = reply_markup,
|
||||
parse_mode = ParseMode.MARKDOWN_V2
|
||||
)
|
||||
return EXECUTE
|
||||
|
||||
|
||||
def execute_now(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
name = query.data
|
||||
query.answer()
|
||||
funcs = context.dispatcher.handlers[0]
|
||||
for func in funcs:
|
||||
if name == func.entry_points[0].command[0]:
|
||||
break
|
||||
callback = func.entry_points[0].handle_update
|
||||
callback(update, context.dispatcher, check_result=True, context=context)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def timeout(self, update: Update, context: CallbackContext) -> None:
|
||||
"""For dying conversation. Currently unused."""
|
||||
|
||||
query = update.callback_query
|
||||
name = query.data.replace("func-", "")
|
||||
query.answer()
|
||||
|
||||
message = name + ": `" + self.available_commands[name] + "`"
|
||||
query.edit_message_text(
|
||||
text= "Timed out...",
|
||||
parse_mode = ParseMode.MARKDOWN_V2
|
||||
)
|
||||
return ConversationHandler.END
|
184
app/bot/commands/lists.py
Normal file
184
app/bot/commands/lists.py
Normal file
@@ -0,0 +1,184 @@
|
||||
from .template import *
|
||||
|
||||
NAME, NEW, ACTION, ITEMADD, ITEMREMOVE = range(5)
|
||||
|
||||
|
||||
class Lists(BotFunc):
|
||||
"""Create and edit lists"""
|
||||
|
||||
def __init__(self, db_utils):
|
||||
super().__init__(db_utils)
|
||||
self.current_name = ""
|
||||
# self.db_utils set through super()
|
||||
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('list', self.entry_point)],
|
||||
states={
|
||||
NAME: [
|
||||
CallbackQueryHandler(self.choose_list, pattern="^list-"),
|
||||
CallbackQueryHandler(self.new_list, pattern="^new$"),
|
||||
],
|
||||
NEW : [MessageHandler(Filters.text, callback=self.new_listname)],
|
||||
ACTION: [
|
||||
CallbackQueryHandler(self.list_add, pattern="^add$"),
|
||||
CallbackQueryHandler(self.list_remove, pattern="^remove$"),
|
||||
CallbackQueryHandler(self.list_clear, pattern="^clear$"),
|
||||
CallbackQueryHandler(self.list_delete, pattern="^delete$"),
|
||||
CallbackQueryHandler(self.list_print, pattern="^print$"),
|
||||
CallbackQueryHandler(self.list_menu, pattern="^overview$"),
|
||||
],
|
||||
ITEMADD : [MessageHandler(Filters.text, callback=self.list_add_item)],
|
||||
ITEMREMOVE : [CallbackQueryHandler(self.list_remove_index)]
|
||||
},
|
||||
fallbacks=[CommandHandler('list', self.entry_point)],
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
lists = self.db_utils.list_get()
|
||||
keyboard = [[InlineKeyboardButton(k, callback_data="list-"+k)] for k in lists] + [[InlineKeyboardButton("New list", callback_data="new")]]
|
||||
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
super().log_activity(read=True, execute=False, send=True)
|
||||
update.message.reply_text(text="Here are the existing lists. You can also create a new one:", reply_markup=reply_markup)
|
||||
return NAME
|
||||
|
||||
|
||||
def choose_list(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
data = query.data
|
||||
name = data.replace("list-","")
|
||||
query.answer()
|
||||
self.current_name = name
|
||||
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("Add item", callback_data="add")],
|
||||
[InlineKeyboardButton("Remove item", callback_data="remove")],
|
||||
[InlineKeyboardButton("Clear list", callback_data="clear")],
|
||||
[InlineKeyboardButton("Print list", callback_data="print")],
|
||||
[InlineKeyboardButton("Delete list", callback_data="delete")],
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
query.edit_message_text("Very well. For " + name + " the following actions are available:", reply_markup=reply_markup)
|
||||
return ACTION
|
||||
|
||||
|
||||
def list_menu(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("Add item", callback_data="add")],
|
||||
[InlineKeyboardButton("Remove item", callback_data="remove")],
|
||||
[InlineKeyboardButton("Clear list", callback_data="clear")],
|
||||
[InlineKeyboardButton("Print list", callback_data="print")],
|
||||
[InlineKeyboardButton("Delete list", callback_data="delete")],
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
query.edit_message_text("Very well. For " + self.current_name + " the following actions are available:", reply_markup=reply_markup)
|
||||
return ACTION
|
||||
|
||||
|
||||
def new_list(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
query.edit_message_text("What's the name of the new list?")
|
||||
return NEW
|
||||
|
||||
|
||||
def new_listname(self, update: Update, context: CallbackContext) -> None:
|
||||
name = update.message.text
|
||||
try:
|
||||
self.db_utils.list_create(name)
|
||||
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("To the menu!", callback_data="overview")]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
self.current_name = name
|
||||
update.message.reply_text("Thanks. List " + name + " was successfully created.", reply_markup=reply_markup)
|
||||
super().log_activity(read=False, execute=True, send=True)
|
||||
return ACTION
|
||||
except Exception as e:
|
||||
update.message.reply_text("Oh no! Encountered exception: {}".format(e))
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def list_add(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
query.edit_message_text("What would you like to add?")
|
||||
return ITEMADD
|
||||
|
||||
|
||||
def list_remove(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
sl = self.db_utils.list_get(self.current_name)
|
||||
|
||||
keyboard = [[InlineKeyboardButton(k, callback_data=i)] for i,k in enumerate(sl)]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
query.edit_message_text("Which item would you like to remove?", reply_markup = reply_markup)
|
||||
return ITEMREMOVE
|
||||
|
||||
|
||||
def list_clear(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
self.db_utils.list_update(self.current_name, replace=[])
|
||||
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
query.edit_message_text("List " + self.current_name + " cleared", reply_markup=reply_markup)
|
||||
return ACTION
|
||||
|
||||
|
||||
def list_delete(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
self.db_utils.list_delete(self.current_name)
|
||||
query.edit_message_text("List " + self.current_name + " deleted")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def list_print(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
it = self.db_utils.list_get(self.current_name)
|
||||
if it:
|
||||
content = "\n".join(it)
|
||||
else:
|
||||
content = "List empty"
|
||||
|
||||
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
query.edit_message_text("Content of " + self.current_name + ":\n" + content, reply_markup=reply_markup)
|
||||
return ACTION
|
||||
|
||||
|
||||
def list_add_item(self, update: Update, context: CallbackContext) -> None:
|
||||
item = update.message.text
|
||||
self.db_utils.list_update(self.current_name, append=item)
|
||||
keyboard = [[InlineKeyboardButton("Add some more", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
update.message.reply_text("Added " + item, reply_markup=reply_markup)
|
||||
return ACTION
|
||||
|
||||
|
||||
def list_remove_index(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
ind = int(query.data)
|
||||
query.answer()
|
||||
|
||||
old = self.db_utils.list_get(self.current_name)
|
||||
name = old.pop(ind)
|
||||
self.db_utils.list_update(self.current_name, replace=old)
|
||||
|
||||
keyboard = [[InlineKeyboardButton("Remove another", callback_data="remove"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
query.edit_message_text("Removed " + name, reply_markup=reply_markup)
|
||||
return ACTION
|
19
app/bot/commands/plaintext.py
Normal file
19
app/bot/commands/plaintext.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from .template import *
|
||||
|
||||
|
||||
class Plain(BotFunc):
|
||||
"""Not a command: just keeps logs and usage_data"""
|
||||
def __init__(self, db_utils):
|
||||
super().__init__(db_utils)
|
||||
|
||||
def create_handler(self):
|
||||
h = MessageHandler(Filters.text, callback=self.add_to_log)
|
||||
return h
|
||||
|
||||
def add_to_log(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
super().log_activity(
|
||||
read = True,
|
||||
send = False,
|
||||
execute = False
|
||||
)
|
179
app/bot/commands/reddit.py
Normal file
179
app/bot/commands/reddit.py
Normal file
@@ -0,0 +1,179 @@
|
||||
from re import U
|
||||
from .template import *
|
||||
|
||||
|
||||
CHOOSE_NUM = 1
|
||||
class Joke(BotFunc):
|
||||
"""Tells a joke from reddit."""
|
||||
|
||||
def __init__(self, api, db):
|
||||
super().__init__(db)
|
||||
self.available_commands = {}
|
||||
self.api = api
|
||||
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('joke', self.entry_point)],
|
||||
states={
|
||||
CHOOSE_NUM: [CallbackQueryHandler(self.get_jokes),],
|
||||
},
|
||||
fallbacks=[CommandHandler('joke', self.entry_point)],
|
||||
# conversation_timeout=5,
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
keyboard = [[InlineKeyboardButton(str(i), callback_data=str(i)) for i in range(1,11)]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
super().log_activity(read=True, execute=True, send=True) # at this point every step has been fulfilled
|
||||
update.message.reply_text("How many jokes?", reply_markup=reply_markup)
|
||||
return CHOOSE_NUM
|
||||
|
||||
|
||||
def get_jokes(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
number = int(query.data)
|
||||
query.answer()
|
||||
jokes = self.api.get_random_rising("jokes", number, "text")
|
||||
# formating
|
||||
message = ""
|
||||
for j in jokes:
|
||||
message += "<b>" + j["title"] + "</b> \n" + j["content"] + "\n\n"
|
||||
if message == "":
|
||||
message += "Could not fetch jokes."
|
||||
query.edit_message_text(text = message, parse_mode = ParseMode.HTML)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
|
||||
|
||||
CHOOSE_TOPIC = 0
|
||||
class Meme(BotFunc):
|
||||
"""Gets the latest memes from reddit"""
|
||||
|
||||
def __init__(self, api, db):
|
||||
super().__init__(db)
|
||||
self.available_commands = {}
|
||||
self.api = api
|
||||
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('meme', self.entry_point)],
|
||||
states={
|
||||
CHOOSE_TOPIC: [CallbackQueryHandler(self.choose_topic)],
|
||||
CHOOSE_NUM :[CallbackQueryHandler(self.get_memes)],
|
||||
},
|
||||
fallbacks=[CommandHandler('meme', self.entry_point)],
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("General", callback_data="memes"),],
|
||||
[InlineKeyboardButton("Dank memes", callback_data="dankmemes"),],
|
||||
[InlineKeyboardButton("Maths", callback_data="mathmemes"),],
|
||||
[InlineKeyboardButton("Physics", callback_data="physicsmemes"),],
|
||||
[InlineKeyboardButton("Biology", callback_data="biologymemes"),],
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
super().log_activity(read=True, execute=True, send=True) # at this point every step has been fulfilled
|
||||
update.message.reply_text("What kind of memes?", reply_markup=reply_markup)
|
||||
return CHOOSE_TOPIC
|
||||
|
||||
|
||||
def choose_topic(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
d = query.data
|
||||
query.answer()
|
||||
|
||||
keyboard = [[InlineKeyboardButton(str(i), callback_data=d + "-" + str(i)) for i in range(1,11)]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
query.edit_message_text("How many memes?", reply_markup=reply_markup)
|
||||
return CHOOSE_NUM
|
||||
|
||||
|
||||
def get_memes(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
data = query.data.split("-")
|
||||
query.answer()
|
||||
|
||||
memes = self.api.get_random_rising(data[0], int(data[1]), "photo")
|
||||
if len(memes) != 0:
|
||||
for m in memes:
|
||||
super().log_activity(read=False, execute=False, send=True) # we just sent an additional message
|
||||
update.effective_chat.send_photo(photo = m["image"],caption = m["caption"])
|
||||
else:
|
||||
update.effective_chat.send_message("Sorry, the meme won't yeet.")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
|
||||
|
||||
# class News(BotFunc):
|
||||
# """Gets the latest news from reddit"""
|
||||
|
||||
# def __init__(self, api, prst):
|
||||
# super().__init__(prst)
|
||||
# self.available_commands = {}
|
||||
# self.api = api
|
||||
|
||||
|
||||
# def create_handler(self):
|
||||
# conv_handler = ConversationHandler(
|
||||
# entry_points=[CommandHandler('news', self.entry_point)],
|
||||
# states={
|
||||
# CHOOSE_TOPIC: [CallbackQueryHandler(self.choose_topic)],
|
||||
# CHOOSE_NUM :[CallbackQueryHandler(self.get_news)],
|
||||
# },
|
||||
# fallbacks=[CommandHandler('news', self.entry_point)],
|
||||
# )
|
||||
# return conv_handler
|
||||
|
||||
|
||||
# def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
# super().entry_point()
|
||||
|
||||
# keyboard = [
|
||||
# [InlineKeyboardButton("World", callback_data="worldnews"),],
|
||||
# [InlineKeyboardButton("Germany", callback_data="germannews"),],
|
||||
# [InlineKeyboardButton("France", callback_data="francenews"),],
|
||||
# [InlineKeyboardButton("Europe", callback_data="eunews"),],
|
||||
# [InlineKeyboardButton("USA", callback_data="usanews"),],
|
||||
# ]
|
||||
# reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
# update.message.reply_text("What kind of news?", reply_markup=reply_markup)
|
||||
# return CHOOSE_TOPIC
|
||||
|
||||
|
||||
# def choose_topic(self, update: Update, context: CallbackContext) -> None:
|
||||
# super().entry_point()
|
||||
# query = update.callback_query
|
||||
# d = query.data
|
||||
# query.answer()
|
||||
|
||||
# keyboard = [[InlineKeyboardButton(str(i), callback_data=d + "-" + str(i)) for i in range(1,11)]]
|
||||
# reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
# query.edit_message_text("How many entries?", reply_markup=reply_markup)
|
||||
# return CHOOSE_NUM
|
||||
|
||||
|
||||
# def get_news(self, update: Update, context: CallbackContext) -> None:
|
||||
# query = update.callback_query
|
||||
# data = query.data.split("-")
|
||||
# query.answer()
|
||||
# #try:
|
||||
# news = self.api.get_top(data[0], data[1], "text")
|
||||
# # formating
|
||||
# message = ""
|
||||
# for j in news:
|
||||
# message += "<b>" + j["title"] + "</b> \n" + j["content"] + "\n\n"
|
||||
# if message == "":
|
||||
# message += "Could not fetch news."
|
||||
# query.edit_message_text(news, paresemode=ParseMode.HTML)
|
||||
# return ConversationHandler.END
|
61
app/bot/commands/search.py
Normal file
61
app/bot/commands/search.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from .template import *
|
||||
|
||||
|
||||
SEARCH, MORE = range(2)
|
||||
class Search(BotFunc):
|
||||
"""Browse the web for a topic."""
|
||||
|
||||
def __init__(self, api, db):
|
||||
super().__init__(db)
|
||||
self.available_commands = {}
|
||||
self.api = api
|
||||
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('search', self.entry_point)],
|
||||
states={
|
||||
SEARCH: [MessageHandler(Filters.text, self.get_results),],
|
||||
MORE: [CallbackQueryHandler(self.show_more, pattern="^more$"),],
|
||||
},
|
||||
fallbacks=[CommandHandler('search', self.entry_point)],
|
||||
conversation_timeout=20,
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
update.message.reply_text("What are we searching?")
|
||||
return SEARCH
|
||||
|
||||
|
||||
def get_results(self, update: Update, context: CallbackContext) -> None:
|
||||
search = update.message.text
|
||||
results = self.api.get_result(search)
|
||||
keyboard = [[InlineKeyboardButton("More!", callback_data="more")]]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
# formating
|
||||
self.results = results
|
||||
if results:
|
||||
first = results[0]
|
||||
message = first["text"] + "\n(" + first["url"] + ")\n\n"
|
||||
else:
|
||||
message = "No results for search query."
|
||||
update.message.reply_text(text = message, reply_markup=reply_markup)
|
||||
super().log_activity(read = True, execute = True, send = True)
|
||||
return MORE
|
||||
|
||||
|
||||
def show_more(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
|
||||
message = ""
|
||||
for r in self.results:
|
||||
message += r["text"] + "\n(" + r["url"] + ")\n\n"
|
||||
|
||||
query.edit_message_text(message)
|
||||
super().log_activity(read = False, execute = False, send = True)
|
||||
return ConversationHandler.END
|
103
app/bot/commands/status.py
Normal file
103
app/bot/commands/status.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from .template import *
|
||||
|
||||
import datetime
|
||||
import requests
|
||||
import socket
|
||||
import json
|
||||
|
||||
|
||||
FIRST = 1
|
||||
|
||||
class Status(BotFunc):
|
||||
"""Shows a short status of the program."""
|
||||
|
||||
def __init__(self, name, version, db_utils):
|
||||
super().__init__(db_utils)
|
||||
self.start_time = datetime.datetime.now()
|
||||
self.name = name
|
||||
self.version = version
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('status', self.entry_point)],
|
||||
states={
|
||||
FIRST: [
|
||||
CallbackQueryHandler(self.send_log, pattern="^full$"),
|
||||
]
|
||||
},
|
||||
fallbacks=[CommandHandler('status', self.entry_point)],
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("And the log?", callback_data="full"),
|
||||
]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
delta = str(datetime.datetime.now() - self.start_time)
|
||||
message = "BeebBop, this is " + self.name + " (V." + self.version + ")\n"
|
||||
|
||||
try:
|
||||
ip = requests.get('https://api.ipify.org').text
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
||||
s.connect(('8.8.8.8', 80))
|
||||
(addr, port) = s.getsockname()
|
||||
local_ips = addr
|
||||
except:
|
||||
ip = "not fetchable"
|
||||
local_ips = "not fetchable"
|
||||
|
||||
message += "Status: Running 🟢\n"
|
||||
message += "Uptime: `" + delta[:delta.rfind(".")] + "`\n"
|
||||
# message += "Reboots: `" + str(self.persistence["global"]["reboots"]) + "`\n"
|
||||
message += "IP (public): `" + ip + "`\n"
|
||||
message += "IP (private): `" + str(local_ips) + "`\n"
|
||||
u = str(self.get_ngrok_url())
|
||||
message += "URL: [" + u + "](" + u + ")\n"
|
||||
|
||||
# TODO new DB
|
||||
tot_r = self.db_utils.chat_count("read")
|
||||
message += "Total messages read: `{}`\n".format(tot_r)
|
||||
|
||||
tot_s = self.db_utils.chat_count("send")
|
||||
message += "Total messages sent: `{}`\n".format(tot_s)
|
||||
|
||||
tot_e = self.db_utils.chat_count("execute")
|
||||
message += "Total commands executed: `{}`\n".format(tot_e)
|
||||
|
||||
if update.message:
|
||||
update.message.reply_text(message, reply_markup=reply_markup, parse_mode=ParseMode.MARKDOWN)
|
||||
else:
|
||||
update._effective_chat.send_message(message, reply_markup=reply_markup, parse_mode=ParseMode.MARKDOWN)
|
||||
|
||||
super().log_activity(read = True, execute = True, send = True)
|
||||
return FIRST
|
||||
|
||||
|
||||
def send_log(self, update: Update, context: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
wanted = query.data.replace("status-","")
|
||||
query.answer()
|
||||
with open("persistence/server.log") as l:
|
||||
query.message.reply_document(l)
|
||||
|
||||
super().log_activity(read = False, execute = False, send = True)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def get_ngrok_url(self):
|
||||
try:
|
||||
url = "http://localhost:4040/api/tunnels/"
|
||||
res = requests.get(url)
|
||||
res_unicode = res.content.decode("utf-8")
|
||||
res_json = json.loads(res_unicode)
|
||||
for i in res_json["tunnels"]:
|
||||
if i['name'] == 'command_line':
|
||||
return i['public_url']
|
||||
except:
|
||||
return "Not available"
|
31
app/bot/commands/template.py
Normal file
31
app/bot/commands/template.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import logging
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ParseMode
|
||||
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext, MessageHandler, Filters
|
||||
from telegram.ext import (
|
||||
Updater,
|
||||
CommandHandler,
|
||||
CallbackQueryHandler,
|
||||
ConversationHandler,
|
||||
CallbackContext,
|
||||
)
|
||||
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
class BotFunc():
|
||||
"""Base class for a specific bot-functionality"""
|
||||
def __init__(self, db_utils):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.db_utils = db_utils
|
||||
|
||||
def log_activity(self, **kwargs):
|
||||
# mark that a new command has been executed
|
||||
self.db_utils.sensor_log(**kwargs)
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
if update.message.text:
|
||||
self.logger.info("Chat said: {}".format(update.message.text))
|
||||
else:
|
||||
self.logger.info("Chat said: {}".format(update.message))
|
||||
|
117
app/bot/commands/weather.py
Normal file
117
app/bot/commands/weather.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from .template import *
|
||||
|
||||
import datetime
|
||||
|
||||
FIRST = 1
|
||||
|
||||
class Weather(BotFunc):
|
||||
"""Shows a weatherforecast for a given location"""
|
||||
def __init__(self, api, db):
|
||||
"""initialize api and persistence"""
|
||||
super().__init__(db)
|
||||
self.api = api
|
||||
self.city = ""
|
||||
|
||||
|
||||
def create_handler(self):
|
||||
"""returns the handlers with button-logic"""
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('weather', self.entry_point)],
|
||||
states={
|
||||
FIRST: [
|
||||
CallbackQueryHandler(self.choose_city, pattern="^city-"),
|
||||
CallbackQueryHandler(self.choose_time, pattern="^time-"),
|
||||
]
|
||||
},
|
||||
fallbacks=[CommandHandler('weather', self.entry_point)],
|
||||
)
|
||||
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
"""Reacts the call of the command. Prints the first buttons"""
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("Zürich", callback_data="city-zurich"),
|
||||
InlineKeyboardButton("Freiburg", callback_data="city-freiburg"),
|
||||
InlineKeyboardButton("Mulhouse", callback_data="city-mulhouse"),
|
||||
]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
if update.message:
|
||||
update.message.reply_text("Which city?", reply_markup=reply_markup)
|
||||
else:
|
||||
update.callback_query.edit_message_text("Which city", reply_markup=reply_markup)
|
||||
return FIRST
|
||||
|
||||
|
||||
def choose_city(self, update: Update, context: CallbackContext) -> None:
|
||||
"""Prompt same text & keyboard as `start` does but not as new message"""
|
||||
# Get CallbackQuery from Update
|
||||
query = update.callback_query
|
||||
data = query.data
|
||||
self.city = data.replace("city-","")
|
||||
query.answer()
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("Now", callback_data="time-now"),
|
||||
InlineKeyboardButton("Tomorrow", callback_data="time-tomorrow"),
|
||||
InlineKeyboardButton("7 days", callback_data="time-7"),
|
||||
]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
query.edit_message_text(
|
||||
text = "Which time?", reply_markup=reply_markup
|
||||
)
|
||||
return FIRST
|
||||
|
||||
|
||||
def choose_time(self, update: Update, context: CallbackContext) -> None:
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
forecast_time = query.data.replace("time-","")
|
||||
weather = self.get_weather(self.city, forecast_time)
|
||||
query.edit_message_text(
|
||||
text = "Broadcast for {}: \n\n{}".format(self.city, weather),
|
||||
parse_mode = ParseMode.HTML
|
||||
)
|
||||
super().log_activity(read = True, execute = True, send = True)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def get_weather(self, city, forecast_time) -> None:
|
||||
"""get the weather that matches the given params"""
|
||||
locations = {"freiburg": [47.9990, 7.8421], "zurich": [47.3769, 8.5417], "mulhouse": [47.7508, 7.3359]}
|
||||
|
||||
city = locations[city]
|
||||
|
||||
categories = {"Clouds": "☁", "Rain": "🌧", "Thunderstorm": "🌩", "Drizzle": ":droplet:", "Snow": "❄", "Clear": "☀", "Mist": "🌫", "Smoke": "Smoke", "Haze": "Haze", "Dust": "Dust", "Fog": "Fog", "Sand": "Sand", "Dust": "Dust", "Ash": "Ash", "Squall": "Squall", "Tornado": "Tornado",}
|
||||
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
||||
today = datetime.datetime.today().weekday()
|
||||
weather = self.api.show_weather(city)
|
||||
message = ""
|
||||
if forecast_time == "now" or forecast_time == "7":
|
||||
now = weather.pop(0)
|
||||
message += "<b>Now:</b> " + categories[now["short"]] + "\n"
|
||||
message += "🌡" + str(now["temps"][0]) + "°\n\n"
|
||||
tod = weather.pop(0)
|
||||
message += "<b>" + "Today" + ":</b> " + categories[tod["short"]] + "\n"
|
||||
message += "🌡 ❄ " + str(tod["temps"][0]) + "° , 🌡 🔥 " + str(tod["temps"][1]) + "°\n\n"
|
||||
|
||||
if forecast_time == "tomorrow" or forecast_time == "7":
|
||||
if forecast_time == "tomorrow": # previous statement was not executed: tomorrow is at weather[2]
|
||||
tom = weather.pop(2)
|
||||
else:
|
||||
tom = weather.pop(0)
|
||||
message += "<b>" + "Tomorrow" + ":</b> " + categories[tom["short"]] + "\n"
|
||||
message += "🌡 ❄ " + str(tom["temps"][0]) + "° , 🌡 🔥 " + str(tom["temps"][1]) + "°\n\n"
|
||||
|
||||
if forecast_time == "7":
|
||||
for i, day in enumerate(weather):
|
||||
message += "<b>" + days[(today + i + 2) % 7] + ":</b> " + categories[day["short"]] + "\n"
|
||||
message += "🌡 ❄ " + str(day["temps"][0]) + "° , 🌡 🔥 " + str(day["temps"][1]) + "°\n\n"
|
||||
|
||||
return message
|
87
app/bot/commands/zvv.py
Normal file
87
app/bot/commands/zvv.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from .template import *
|
||||
|
||||
import datetime
|
||||
import requests
|
||||
|
||||
START, DEST = range(2)
|
||||
|
||||
class Zvv(BotFunc):
|
||||
"""Connects to the swiss travel-api to get public transport routes"""
|
||||
|
||||
def __init__(self, db):
|
||||
super().__init__(db)
|
||||
self.start = ""
|
||||
self.dest = ""
|
||||
pass
|
||||
|
||||
def create_handler(self):
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('zvv', self.entry_point)],
|
||||
states={
|
||||
START: [MessageHandler(Filters.text, callback=self.get_start)],
|
||||
DEST: [MessageHandler(Filters.text, callback=self.get_dest)]
|
||||
},
|
||||
fallbacks=[CommandHandler('zvv', self.entry_point)],
|
||||
)
|
||||
return conv_handler
|
||||
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
update.message.reply_text("What is the start point?")
|
||||
return START
|
||||
|
||||
|
||||
def get_start(self, update: Update, context: CallbackContext) -> None:
|
||||
loc = update.message.text
|
||||
self.start = loc
|
||||
update.message.reply_text("Ok. Going from " + loc + ", what is the destination?")
|
||||
return DEST
|
||||
|
||||
|
||||
def get_dest(self, update: Update, context: CallbackContext) -> None:
|
||||
loc = update.message.text
|
||||
self.dest = loc
|
||||
route = self.get_result()
|
||||
update.message.reply_text("Here are the routes I've got:\n" + route)
|
||||
super().log_activity(read=True, execute=True, send=True)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def get_result(self):
|
||||
url = "http://transport.opendata.ch/v1/connections"
|
||||
|
||||
start = self.start
|
||||
dest = self.dest
|
||||
|
||||
data = {"from" : start, "to" : dest, "limit" : 2}
|
||||
try:
|
||||
routes = requests.get(url, params=data).json()
|
||||
result = routes["connections"]
|
||||
text = result[0]["from"]["station"]["name"] + " ⏩ " + result[0]["to"]["station"]["name"] + "\n\n"
|
||||
for con in result:
|
||||
text += "Start: " + datetime.datetime.fromtimestamp(int(con["from"]["departureTimestamp"])).strftime("%d/%m - %H:%M") + "\n"
|
||||
text += "🏁 " + datetime.datetime.fromtimestamp(int(con["to"]["arrivalTimestamp"])).strftime("%d/%m - %H:%M") + "\n"
|
||||
text += "⏳ " + con["duration"] + "\n"
|
||||
text += "🗺️ Route:\n"
|
||||
|
||||
for step in con["sections"]:
|
||||
if step["journey"] != None:
|
||||
text += step["journey"]["passList"][0]["station"]["name"] + " (" + datetime.datetime.fromtimestamp(int(step["journey"]["passList"][0]["departureTimestamp"])).strftime("%H:%M") + ")\n"
|
||||
|
||||
text += "➡️ Linie " + self.number_to_emoji(step["journey"]["number"]) + "\n"
|
||||
|
||||
text += step["journey"]["passList"][-1]["station"]["name"] + " (" + datetime.datetime.fromtimestamp(int(step["journey"]["passList"][-1]["arrivalTimestamp"])).strftime("%H:%M") +")\n"
|
||||
else:
|
||||
text += "Walk."
|
||||
text += "\n"
|
||||
return text
|
||||
except:
|
||||
return "Invalid api call."
|
||||
|
||||
def number_to_emoji(self, number):
|
||||
out = ""
|
||||
numbers = ["0️⃣","1️⃣","2️⃣","3️⃣","4️⃣","5️⃣","6️⃣","7️⃣","8️⃣","9️⃣"]
|
||||
for i in str(number):
|
||||
out += numbers[int(i)]
|
||||
return str(out)
|
Reference in New Issue
Block a user