From 7834d345bff7a3b1a95a3ca31d0b45318e5a699c Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sun, 14 Apr 2019 22:22:49 -0700 Subject: [PATCH] Add multi-user and cron support. --- src/joann-pupper-bot.cr | 165 ++++++++++++++++++++------------- src/joann-pupper-bot/reddit.cr | 13 --- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/src/joann-pupper-bot.cr b/src/joann-pupper-bot.cr index 035ae33..99ca654 100644 --- a/src/joann-pupper-bot.cr +++ b/src/joann-pupper-bot.cr @@ -5,70 +5,111 @@ require "time" require "sqlite3" require "cron_scheduler" + # Chat IDs -chatid_joann = 215301902 -chatid_daniel = 220888832 +CHATID_JOANN = 215301902_i64 +CHATID_DANIEL = 220888832_i64 +DATABASE_URL = "sqlite3://./data.sqlite" +BOT_TOKEN = "599474797:AAEmjQNO32uqurI16blS9FT4OoO7GdUZ6h0" +EXTENSIONS = ["png", "jpeg", "jpg"] +LOGGER = Logger.new(STDOUT) -# Configuration -database = "sqlite3://./data.sqlite" -subreddit = "rarepuppers" -chatid = chatid_daniel -delay = 1.hours -active_hours = 7..24 -bot_token = "599474797:AAEmjQNO32uqurI16blS9FT4OoO7GdUZ6h0" +class BotConfiguration + JSON.mapping( + subreddits: Array(String), + send_cron: String, + refresh_cron: String, + recepients: Array(Int64)) -# Setup -completed = [] of String -logger = Logger.new(STDOUT) -bot = Telepathy::Bot.new bot_token + def initialize + @subreddits = [ "rarepuppers" ] + @send_cron = "00 8-21 * * *" + @refresh_cron = "*/15 * * * *" + @recepients = [ CHATID_DANIEL ] + end +end + +class PupperBot + @db : DB::Database + + def initialize(@configuration : BotConfiguration) + @telegram_bot = Telepathy::Bot.new BOT_TOKEN + @db = DB.open DATABASE_URL + initialize_db + update_database + initialize_timers + initialize_telegram + send_broadcast + end + + def initialize + initialize BotConfiguration.new + end + + private def initialize_db + @db.exec "create table if not exists posts(id integer primary key, title text, url text unique)" + @db.exec "create table if not exists recepient_posts(recepient integer, post integer, foreign key(post) references posts(id))" + end + + private def initialize_timers + CronScheduler.define do + at(@configuration.send_cron) { send_broadcast } + at(@configuration.refresh_cron) { update_database } + end + end + + private def initialize_telegram + @telegram_bot.command "ping" do |update, args| + @telegram_bot.send_message(update.message.as(Telepathy::Message).chat.id, "pong") + end + + @telegram_bot.command "pupper" do |update, args| + command_chatid = update.message.as(Telepathy::Message).chat.id + send_single command_chatid + end + + @telegram_bot.poll + end + + def send_single(chatid) + unsent_query = "select id, title, url from posts where not exists (select * from recepient_posts where recepient=? and post=id) limit 1" + + unless to_send = @db.query_one? unsent_query, chatid, as: { Int64, String, String } + LOGGER.info "Unable to find a post to send to #{chatid}." + return + end + + id, title, url = to_send + LOGGER.info "Using URL #{url} for request from #{chatid}" + @db.exec "insert into recepient_posts(recepient, post) values(?, ?)", chatid, id + @telegram_bot.send_photo(chatid, url, title) + end + + def send_broadcast + @configuration.recepients.each do |recepient| + send_single recepient + end + end + + def update_database + unless response = RedditResponse.from_subreddits(@configuration.subreddits) + LOGGER.info "Unable to find more posts for the database" + return + end + + posts = response.data.posts_matching { |post| EXTENSIONS.any? { |it| post.url.ends_with? it } } + posts.each do |post| + LOGGER.info "Trying to save post #{post.title} #{post.url}" + begin + @db.exec "insert into posts(title, url) values(?, ?)", post.title, post.url + rescue e + puts e + end + end + end +end + +botc = PupperBot.new # Commands. -bot.command "ping" do |update, args| - bot.send_message(update.message.as(Telepathy::Message).chat.id, "pong") -end - -# Tasks -def update_database(db) -end - -bot.command "pupper" do |update, args| - url_tuple = get_reddit_post(subreddit, completed) - if url_tuple - url, title = url_tuple - command_chatid = update.message.as(Telepathy::Message).chat.id - logger.info "Using URL #{url} for request from #{command_chatid}" - bot.send_photo(command_chatid, url, title) - else - logger.error "Unable to find a post to send." - end -end - -spawn do - loop do - time = Time.now - url_tuple = get_reddit_post(subreddit, completed) if (active_hours.includes? time.hour) - if url_tuple - url, title = url_tuple - logger.info "Sending regular picture to #{chatid}." - bot.send_photo(chatid.to_i64, url, title) - else - logger.error "Unable to find a post to send. (Or it's quiet hours)" - end - sleep delay - end -end - -# Code to stop the bot on time. -end_channel = Channel(Nil).new(1) - -bot.poll_end do - end_channel.send nil -end - -Signal::INT.trap do - logger.info "Shutting down bot..." - bot.end_poll -end - -bot.poll -end_channel.receive +sleep diff --git a/src/joann-pupper-bot/reddit.cr b/src/joann-pupper-bot/reddit.cr index 5141fc9..374dfb9 100644 --- a/src/joann-pupper-bot/reddit.cr +++ b/src/joann-pupper-bot/reddit.cr @@ -45,16 +45,3 @@ class RedditResponse .select { |it| yield it } end end - -def filter_reddit_json(json, completed, extensions = ["png", "jpeg"]) - json.data.posts_matching do |post| - extensions.any? { |it| post.url.ends_with? it } && !completed.includes? post.url - end -end - -def get_reddit_post(subreddit, completed) - return nil unless json = RedditResponse.from_subreddit subreddit - return nil unless post = filter_reddit_json(json, completed).first? - completed.push(post.name) - return { post.url, post.title } -end