diff --git a/README.md b/README.md index ed5506c..bf4c4e0 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,13 @@ [![Build Status](https://travis-ci.org/mispy/twitter_ebooks.svg)](https://travis-ci.org/mispy/twitter_ebooks) [![Dependency Status](https://gemnasium.com/mispy/twitter_ebooks.svg)](https://gemnasium.com/mispy/twitter_ebooks) +A framework for building interactive twitterbots which respond to mentions/DMs. twitter_ebooks tries to be a good friendly bot citizen by avoiding infinite conversations and spamming people, so you only have to write the interesting parts. -Rewrite of my twitter\_ebooks code. While the original was solely a tweeting Markov generator, this framework helps you build any kind of interactive twitterbot which responds to mentions/DMs. See [ebooks\_example](https://github.com/mispy/ebooks_example) for an example of a full bot. +## New in 3.0 + +- Bots now run in their own threads (no eventmachine), and startup is parallelized +- Replies are slightly rate-limited by default to prevent infinite bot convos +- Non-participating users in a mention chain will be dropped after a few tweets ## Installation @@ -65,9 +70,9 @@ Ebooks::Bot.new("abby_ebooks") do |bot| end ``` -Bots defined like this can be spawned by executing `run.rb` in the same directory, and will operate together in a single eventmachine loop. The easiest way to run bots in a semi-permanent fashion is with [Heroku](https://www.heroku.com); just make an app, push the bot repository to it, enable a worker process in the web interface and it ought to chug along merrily forever. +'ebooks start' will run all defined bots in their own threads. The easiest way to run bots in a semi-permanent fashion is with [Heroku](https://www.heroku.com); just make an app, push the bot repository to it, enable a worker process in the web interface and it ought to chug along merrily forever. -The underlying [tweetstream](https://github.com/tweetstream/tweetstream) and [twitter gem](https://github.com/sferik/twitter) client objects can be accessed at `bot.stream` and `bot.twitter` respectively. +The underlying streaming and REST clients from the [twitter gem](https://github.com/sferik/twitter) can be accessed at `bot.stream` and `bot.twitter` respectively. ## Archiving accounts diff --git a/bin/ebooks b/bin/ebooks index 1864380..fab9105 100755 --- a/bin/ebooks +++ b/bin/ebooks @@ -6,7 +6,7 @@ require 'csv' $debug = true -module Ebooks +module Ebooks::CLI APP_PATH = Dir.pwd # XXX do some recursive thing instead def self.new(reponame) @@ -163,11 +163,84 @@ STR bot.tweet(statement) end + def self.auth + consumer_key, consumer_secret = find_consumer + require 'oauth' + + consumer = OAuth::Consumer.new( + consumer_key, + consumer_secret, + site: 'https://twitter.com/', + scheme: :header + ) + + request_token = consumer.get_request_token + auth_url = request_token.authorize_url() + + pin = nil + loop do + log auth_url + + log "Go to the above url and follow the prompts, then enter the PIN code here." + print "> " + + pin = STDIN.gets.chomp + + break unless pin.empty? + end + + access_token = request_token.get_access_token(oauth_verifier: pin) + + log "Account authorized successfully.\n" + + " access token: #{access_token.token}\n" + + " access token secret: #{access_token.secret}" + end + def self.c - load 'bots.rb' + load_bots require 'pry'; pry end + # Non-command methods + + def self.find_consumer + if ENV['CONSUMER_KEY'] && ENV['CONSUMER_SECRET'] + log "Using consumer details from environment variables:\n" + + " consumer key: #{ENV['CONSUMER_KEY']}\n" + + " consumer secret: #{ENV['CONSUMER_SECRET']}" + return [ENV['CONSUMER_KEY'], ENV['CONSUMER_SECRET']] + end + + load_bots + consumer_key = nil + consumer_secret = nil + Ebooks::Bot.all.each do |bot| + if bot.consumer_key && bot.consumer_secret + consumer_key = bot.consumer_key + consumer_secret = bot.consumer_secret + log "Using consumer details from @#{bot.username}:\n" + + " consumer key: #{bot.consumer_key}\n" + + " consumer secret: #{bot.consumer_secret}\n" + return consumer_key, consumer_secret + end + end + + if consumer_key.nil? || consumer_secret.nil? + log "Couldn't find any consumer details to auth an account with.\n" + + "Please either configure a bot with consumer_key and consumer_secret\n" + + "or provide the CONSUMER_KEY and CONSUMER_SECRET environment variables." + exit + end + end + + def self.load_bots + load 'bots.rb' + + if Ebooks::Bot.all.empty? + puts "Couldn't find any bots! Please make sure bots.rb instantiates at least one bot." + end + end + def self.command(args) usage = <