Added push_feature for weather
Enables user to get weather information every day at a set time for a set city City and time can be changed and the subscription can be deleted. Formatting can be optimized
This commit is contained in:
parent
172efd7974
commit
d6debf6a46
3 changed files with 283 additions and 2 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -5,6 +5,9 @@
|
|||
token
|
||||
openweathermap_token
|
||||
|
||||
#storage/pickle
|
||||
*.pkl
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
|
32
bot.py
32
bot.py
|
@ -1,11 +1,17 @@
|
|||
import logging
|
||||
import threading
|
||||
import time
|
||||
|
||||
import schedule
|
||||
from telegram.ext import Updater, CommandHandler, InlineQueryHandler, CallbackQueryHandler
|
||||
|
||||
from exceptions import *
|
||||
from vvs import inline_station_search, handle_vvs, handle_multiple_stations_reply
|
||||
from weather_meteomedia import handle_meteomedia
|
||||
from weather_openweathermap import handle_weather, __init__
|
||||
from weather_openweathermap import handle_weather
|
||||
from weather_openweathermap import __init__ as openweathermap_init
|
||||
from push_information import __init__ as push_init
|
||||
|
||||
|
||||
token_file = open("token", "r")
|
||||
updater = Updater(token=token_file.read(), use_context=True)
|
||||
|
@ -16,6 +22,21 @@ dispatcher = updater.dispatcher
|
|||
logging.basicConfig(format='%(acstime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
|
||||
|
||||
|
||||
def send_message(chat_id: int, message: str):
|
||||
dispatcher.bot.send_message(chat_id=chat_id, text=message, disable_notification=True, parse_mode="Markdown")
|
||||
|
||||
|
||||
cease_continuous_run = threading.Event()
|
||||
|
||||
|
||||
class ScheduleThread(threading.Thread):
|
||||
@classmethod
|
||||
def run(cls):
|
||||
while not cease_continuous_run.is_set():
|
||||
schedule.run_pending()
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
def __main__():
|
||||
inline_station_search_handler = InlineQueryHandler(inline_station_search)
|
||||
dispatcher.add_handler(inline_station_search_handler)
|
||||
|
@ -23,14 +44,21 @@ def __main__():
|
|||
dispatcher.add_handler(CommandHandler('meteomedia', handle_meteomedia))
|
||||
dispatcher.add_handler(CommandHandler("weather", handle_weather))
|
||||
|
||||
__init__()
|
||||
openweathermap_init()
|
||||
dispatcher.add_handler(push_init())
|
||||
|
||||
dispatcher.add_error_handler(error_callback)
|
||||
|
||||
dispatcher.add_handler(CallbackQueryHandler(handle_multiple_stations_reply, pattern="^\/vvs"))
|
||||
|
||||
continuous_thread = ScheduleThread()
|
||||
continuous_thread.start()
|
||||
|
||||
updater.start_polling()
|
||||
updater.idle()
|
||||
|
||||
cease_continuous_run.set()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
__main__()
|
||||
|
|
250
push_information.py
Normal file
250
push_information.py
Normal file
|
@ -0,0 +1,250 @@
|
|||
import _pickle as pickle
|
||||
import time
|
||||
|
||||
import schedule
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, CallbackQueryHandler, CallbackContext
|
||||
from telegram.ext.filters import Filters
|
||||
|
||||
from bot import send_message
|
||||
from weather_openweathermap import City, get_city_by_name
|
||||
|
||||
users = {}
|
||||
subs_in_edit = {}
|
||||
|
||||
|
||||
class Subscription(object):
|
||||
time: time
|
||||
city: City
|
||||
chat_id: int
|
||||
|
||||
def __init__(self, chat_id: int, city: City):
|
||||
self.chat_id = chat_id
|
||||
self.city = city
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.city.name} at {time.strftime('%H:%M', self.time)}"
|
||||
|
||||
def edit_time(self, edited_time: time):
|
||||
self.time = edited_time
|
||||
schedule_subscriptions()
|
||||
save_users_to_file()
|
||||
|
||||
def edit_city(self, edited_city: City):
|
||||
self.city = edited_city
|
||||
schedule_subscriptions()
|
||||
save_users_to_file()
|
||||
|
||||
|
||||
class User(object):
|
||||
chat_id: int
|
||||
subs = []
|
||||
|
||||
def __init__(self, chat_id: int):
|
||||
self.chat_id = chat_id
|
||||
global users
|
||||
users[self.chat_id] = self.subs
|
||||
|
||||
def __getstate__(self):
|
||||
attributes = self.__dict__.copy()
|
||||
attributes['subs'] = self.subs
|
||||
for i in range(len(attributes['subs'])):
|
||||
try:
|
||||
del attributes['subs'][i].city.weather
|
||||
except AttributeError:
|
||||
pass
|
||||
return attributes
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.chat_id = state['chat_id']
|
||||
self.subs = state['subs']
|
||||
|
||||
def add_subscription(self, subscription: Subscription):
|
||||
self.subs.append(subscription)
|
||||
global users
|
||||
users[self.chat_id] = self
|
||||
save_users_to_file()
|
||||
schedule_subscriptions()
|
||||
|
||||
def del_subscription(self, idx: int):
|
||||
del self.subs[idx]
|
||||
save_users_to_file()
|
||||
schedule_subscriptions()
|
||||
|
||||
|
||||
def save_users_to_file():
|
||||
global users
|
||||
with open("users.pkl", 'wb') as users_file:
|
||||
pickle.dump(users, users_file)
|
||||
|
||||
|
||||
def load_users_from_file():
|
||||
global users
|
||||
try:
|
||||
with open("users.pkl", 'rb') as users_file:
|
||||
users = pickle.load(users_file)
|
||||
schedule_subscriptions()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except EOFError:
|
||||
pass
|
||||
|
||||
|
||||
def schedule_subscriptions():
|
||||
schedule.default_scheduler.clear()
|
||||
for user in users.values():
|
||||
for sub in user.subs:
|
||||
sub.city.query_weather()
|
||||
schedule.default_scheduler.every().day.at(time.strftime("%H:%M", sub.time)).do(
|
||||
send_message, chat_id=user.chat_id, message=str(sub.city.weather))
|
||||
sub.city.weather.clear()
|
||||
|
||||
|
||||
def push_callback(update: Update, context: CallbackContext):
|
||||
global users
|
||||
if update.effective_chat.id in users:
|
||||
user = users[update.effective_chat.id]
|
||||
else:
|
||||
user = User(update.effective_chat.id)
|
||||
users[update.effective_chat.id] = user
|
||||
string = f"Hello, {update.effective_user.first_name}!\n"
|
||||
string += f"You have {len(user.subs)} subscriptions:\n"
|
||||
|
||||
button_list = []
|
||||
for i, subscription in enumerate(user.subs):
|
||||
button_list.append(
|
||||
InlineKeyboardButton(text=f"{subscription.city.name} at {time.strftime('%H:%M', subscription.time)}",
|
||||
callback_data=f"/push_edit {i}"))
|
||||
button_list.append(InlineKeyboardButton(text="Add", callback_data="/push_add"))
|
||||
reply_markup = InlineKeyboardMarkup.from_column(button_list)
|
||||
update.message.reply_text(string, reply_markup=reply_markup)
|
||||
return "list"
|
||||
|
||||
|
||||
def edit_sub_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
user = users[update.effective_chat.id]
|
||||
sub_idx = int(update.callback_query.data[11:])
|
||||
sub = user.subs[sub_idx]
|
||||
subs_in_edit[update.effective_chat.id] = sub
|
||||
button_list = [[InlineKeyboardButton(text="City", callback_data="/push_edit_city"),
|
||||
InlineKeyboardButton(text="Time", callback_data="/push_edit_time")],
|
||||
[InlineKeyboardButton(text="Delete", callback_data=f"/push_edit_delete {sub_idx}")]]
|
||||
reply_markup = InlineKeyboardMarkup(button_list)
|
||||
update.effective_chat.send_message("Change subscription.\nWhat do you want to change?", reply_markup=reply_markup)
|
||||
return "edit"
|
||||
|
||||
|
||||
def edit_city_callback(update: Update, context: CallbackContext):
|
||||
update.effective_chat.send_message("Tell me the city you want information for:")
|
||||
return "edit_city"
|
||||
|
||||
|
||||
def edited_city_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
user = users[update.effective_chat.id]
|
||||
city_name = update.message.text
|
||||
city = get_city_by_name(city_name)
|
||||
if city.name == "none":
|
||||
update.message.reply_text("This city was not found! Try again")
|
||||
return None
|
||||
else:
|
||||
subs_in_edit[user.chat_id].edit_city(city)
|
||||
update.message.reply_text(f"City changed to {city.name}.")
|
||||
del subs_in_edit[update.effective_chat.id]
|
||||
update.message.reply_text(f"Subscription now is {subs_in_edit[user.chat_id]}")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def edit_time_callback(update: Update, context: CallbackContext):
|
||||
update.effective_chat.send_message("When do you want to receive updates?")
|
||||
return "edit_time"
|
||||
|
||||
|
||||
def edited_time_callback(update: Update, context: CallbackContext):
|
||||
global users
|
||||
user = users[update.effective_chat.id]
|
||||
sub_in_edit = subs_in_edit[user.chat_id]
|
||||
time_string = update.message.text
|
||||
if time_string.find(':') == -1:
|
||||
sub_in_edit.edit_time(time.strptime(time_string, "%H"))
|
||||
else:
|
||||
sub_in_edit.edit_time(time.strptime(time_string, "%H:%M"))
|
||||
del subs_in_edit[user.chat_id]
|
||||
update.message.reply_text(f"Subscription now is {sub_in_edit}")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def delete_subscription_callback(update: Update, context: CallbackContext):
|
||||
global users
|
||||
users[update.effective_chat.id].del_subscription(int(update.callback_query.data[18:]))
|
||||
update.effective_chat.send_message("Deleted")
|
||||
schedule_subscriptions()
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def add_sub_callback(update: Update, context: CallbackContext):
|
||||
update.effective_chat.send_message("Add a new subscription.\nTell me the city you want information for:")
|
||||
return "add_city"
|
||||
|
||||
|
||||
def add_city_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
user = users[update.effective_chat.id]
|
||||
city_name = update.message.text
|
||||
city = get_city_by_name(city_name)
|
||||
if city.name == "none":
|
||||
update.message.reply_text("This city was not found! Try again")
|
||||
return None
|
||||
else:
|
||||
update.message.reply_text(f"I found {city.name}. When do you want to receive updates?")
|
||||
subs_in_edit[user.chat_id] = Subscription(user.chat_id, city)
|
||||
return "time"
|
||||
|
||||
|
||||
def time_callback(update: Update, context: CallbackContext):
|
||||
global users, subs_in_edit
|
||||
user = users[update.effective_chat.id]
|
||||
sub_in_edit = subs_in_edit[update.effective_chat.id]
|
||||
time_string = update.message.text
|
||||
if time_string.find(':') == -1:
|
||||
sub_in_edit.time = time.strptime(time_string, "%H")
|
||||
else:
|
||||
sub_in_edit.time = time.strptime(time_string, "%H:%M")
|
||||
user.add_subscription(sub_in_edit)
|
||||
update.message.reply_text(f"Subscription now is: {str(sub_in_edit)}")
|
||||
del subs_in_edit[update.effective_chat.id]
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def cancel_callback(update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Timeout")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def __init__() -> ConversationHandler:
|
||||
load_users_from_file()
|
||||
|
||||
push_handler = CommandHandler(command="push", callback=push_callback)
|
||||
|
||||
edit_sub_handler = CallbackQueryHandler(callback=edit_sub_callback, pattern="^\/push_edit ")
|
||||
edit_city_handler = CallbackQueryHandler(callback=edit_city_callback, pattern="^\/push_edit_city")
|
||||
edited_city_handler = MessageHandler(callback=edited_city_callback, filters=Filters.text)
|
||||
edit_time_handler = CallbackQueryHandler(callback=edit_time_callback, pattern="^\/push_edit_time")
|
||||
edited_time_handler = MessageHandler(callback=edited_time_callback, filters=Filters.text)
|
||||
delete_subscription_handler = CallbackQueryHandler(callback=delete_subscription_callback,
|
||||
pattern="^\/push_edit_delete")
|
||||
|
||||
add_sub_handler = CallbackQueryHandler(callback=add_sub_callback, pattern="^\/push_add")
|
||||
add_city_handler = MessageHandler(callback=add_city_callback, filters=Filters.text)
|
||||
|
||||
time_handler = MessageHandler(callback=time_callback, filters=Filters.text)
|
||||
|
||||
fallback_handler = CommandHandler(command="cancel", callback=cancel_callback)
|
||||
|
||||
return ConversationHandler(entry_points=[push_handler],
|
||||
states={"list": [edit_sub_handler, add_sub_handler], "add_city": [add_city_handler],
|
||||
"edit": [edit_city_handler, edit_time_handler, delete_subscription_handler],
|
||||
"edit_city": [edited_city_handler], "edit_time": [edited_time_handler],
|
||||
"time": [time_handler]},
|
||||
fallbacks=[fallback_handler], conversation_timeout=10)
|
Loading…
Reference in a new issue