lazybird 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +110 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +339 -0
- data/README.md +74 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/lazybird +7 -0
- data/bin/setup +6 -0
- data/lazybird.gemspec +30 -0
- data/lib/config/tasks.yml +6 -0
- data/lib/lazybird.rb +5 -0
- data/lib/lazybird/cli/command_line.rb +64 -0
- data/lib/lazybird/cli/commands.rb +88 -0
- data/lib/lazybird/config.rb +37 -0
- data/lib/lazybird/db.rb +84 -0
- data/lib/lazybird/lazybird_facade.rb +86 -0
- data/lib/lazybird/tasks/quote.rb +40 -0
- data/lib/lazybird/tasks/retweet_random_task.rb +9 -0
- data/lib/lazybird/tasks/storm_quote_task.rb +12 -0
- data/lib/lazybird/tasks/task.rb +20 -0
- data/lib/lazybird/tasks/task_scheduler.rb +38 -0
- data/lib/lazybird/twitter_client.rb +48 -0
- data/lib/lazybird/utils.rb +17 -0
- data/lib/lazybird/version.rb +7 -0
- metadata +183 -0
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Lazybird (Beta)
|
2
|
+
|
3
|
+
[][gem]
|
4
|
+
|
5
|
+
[gem]: https://rubygems.org/gems/lazybird
|
6
|
+
|
7
|
+
Twitter for busy people.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Register at https://apps.twitter.com/app/new
|
12
|
+
|
13
|
+
Example:
|
14
|
+
|
15
|
+

|
16
|
+
|
17
|
+
Then click on keys and access tokens and generate an access token. You will need this for the setup.
|
18
|
+
|
19
|
+
|
20
|
+
Install lazybird running:
|
21
|
+
|
22
|
+
$ gem install lazybird
|
23
|
+
|
24
|
+
## Setup
|
25
|
+
|
26
|
+
Once lazybird is installed you can run it with:
|
27
|
+
|
28
|
+
`lazybird`
|
29
|
+
|
30
|
+
or
|
31
|
+
|
32
|
+
`bundle exec lazybird`
|
33
|
+
|
34
|
+
The CLI should appear:
|
35
|
+
|
36
|
+

|
37
|
+
|
38
|
+
|
39
|
+
Typically you want to setup the database first running `setup`
|
40
|
+
|
41
|
+
And run config to enter your twitter settings: `config consumer_key consumer_secret access_token access_token_secret`
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
Run it with `lazybird` - you would need to keep the app running as long as you want to tweet automatically.
|
46
|
+
|
47
|
+
Lazybird contains (at the moment) only two tasks that run at a certain configured time:
|
48
|
+
|
49
|
+
|
50
|
+
_retweet_random_: Retweets a random tweet (latest) from a random friend
|
51
|
+
|
52
|
+
_tweet_storm_: Tweets a random quote from the Storm API http://quotes.stormconsultancy.co.uk
|
53
|
+
|
54
|
+
|
55
|
+
Add them both to your list of tasks (this will store them in an internal DB to resume later)
|
56
|
+
|
57
|
+
`add retweet_random`
|
58
|
+
|
59
|
+
`add tweet_storm`
|
60
|
+
|
61
|
+
Then you want to either randomly tweet something now with `run now` or schedule it to tweet every N minutes/hours/day:s `run 2h` or `run 30m` for example.
|
62
|
+
|
63
|
+
You will need to keep the command line open and you should see an update everytime something random gets tweeted.
|
64
|
+
|
65
|
+
Lazybird stores a DB/config file at ~/.twitter.db - make sure it's safe.
|
66
|
+
|
67
|
+
|
68
|
+
## Contributing
|
69
|
+
|
70
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bluegod/lazybird.
|
71
|
+
|
72
|
+
## License
|
73
|
+
|
74
|
+
GPL v2
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "lazybird"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/lazybird
ADDED
data/bin/setup
ADDED
data/lazybird.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'lazybird/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'lazybird'
|
8
|
+
spec.version = Lazybird::VERSION
|
9
|
+
spec.authors = ['James Lopez']
|
10
|
+
spec.email = ['james@jameslopez.es']
|
11
|
+
spec.license = 'GPL-2.0'
|
12
|
+
|
13
|
+
spec.summary = %q{Twitter for lazy people. Automatically tweets/retweets random stuff. }
|
14
|
+
spec.description = %q{Provides a command line interface to interact with twitter and automatically tweets/retweets some predefined (or API based tweets) at a specified frequency. }
|
15
|
+
spec.homepage = "https://github.com/bluegod/lazybird"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "bin"
|
19
|
+
spec.executables = ['lazybird']
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.3"
|
25
|
+
spec.add_dependency 'twitter', '~> 5.15'
|
26
|
+
spec.add_dependency 'rufus-scheduler', '~> 3.1'
|
27
|
+
spec.add_dependency 'amalgalite', '~> 1.4'
|
28
|
+
spec.add_dependency 'sequel', '~> 4.27'
|
29
|
+
spec.add_dependency 'colorize', '~> 0.7'
|
30
|
+
end
|
data/lib/lazybird.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
require 'lazybird/version'
|
3
|
+
require 'lazybird/lazybird_facade'
|
4
|
+
require 'lazybird/cli/commands'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
module Lazybird
|
8
|
+
module Cli
|
9
|
+
class CommandLine
|
10
|
+
include Lazybird::Cli::Commands
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@facade = Lazybird::LazybirdFacade.new
|
14
|
+
intro.display
|
15
|
+
setup_check
|
16
|
+
run_main_loop
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def setup_check
|
22
|
+
if Lazybird::Config.db_file_exists?
|
23
|
+
@facade.load_default_tasks
|
24
|
+
else
|
25
|
+
puts 'Type: '.bold + "setup \u{23ce}".red.bold + " as this is the first time running the app.\n".bold
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def run_main_loop
|
30
|
+
loop do
|
31
|
+
display_prompt
|
32
|
+
command, *params = gets.chomp.split /\s/
|
33
|
+
process_command(command, params) if command
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def newline
|
38
|
+
puts
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_command(command, params)
|
42
|
+
command.downcase!
|
43
|
+
if respond_to?(command)
|
44
|
+
send(command, params)
|
45
|
+
else
|
46
|
+
puts 'Invalid command'.light_red
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def display_prompt
|
51
|
+
prompt.yellow.display
|
52
|
+
end
|
53
|
+
|
54
|
+
def prompt
|
55
|
+
@_prompt ||=
|
56
|
+
begin
|
57
|
+
os = RbConfig::CONFIG['host_os']
|
58
|
+
icon = os.start_with?('darwin') ? "\u{1F425}" : ')<'
|
59
|
+
"#{icon} Lazybird> "
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Lazybird
|
2
|
+
module Cli
|
3
|
+
module Commands
|
4
|
+
|
5
|
+
def config(params)
|
6
|
+
@facade.config(params)
|
7
|
+
display_done
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup(params)
|
11
|
+
@facade.init
|
12
|
+
display_done
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(params)
|
16
|
+
@facade.add_task params.first
|
17
|
+
display_done
|
18
|
+
end
|
19
|
+
|
20
|
+
def my_tasks(params)
|
21
|
+
@facade.current_tasks.join("\n").green.display
|
22
|
+
newline
|
23
|
+
end
|
24
|
+
|
25
|
+
def rem(params)
|
26
|
+
@facade.rem_task(params.first)
|
27
|
+
display_done
|
28
|
+
end
|
29
|
+
|
30
|
+
def run(params)
|
31
|
+
cursor = -> () do
|
32
|
+
display_prompt
|
33
|
+
end
|
34
|
+
@facade.run_tasks(params, &cursor)
|
35
|
+
end
|
36
|
+
|
37
|
+
def my_run(params)
|
38
|
+
@facade.run_info.green.display
|
39
|
+
newline
|
40
|
+
end
|
41
|
+
|
42
|
+
def exit(params)
|
43
|
+
Kernel.exit(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
def intro
|
47
|
+
"Lazybird v#{Lazybird.version}\n".light_yellow +
|
48
|
+
"by James Lopez <http://jameslopez.net> <https://github.com/bluegod/lazybird>\n".blue +
|
49
|
+
'Type: ' + "help \u{23ce}".bold + " for a list of commands.\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
def help(params)
|
53
|
+
begin
|
54
|
+
"List of available commands: \n".yellow +
|
55
|
+
"config ".bold + "consumer_key consumer_secret access_token access_token_secret".green + " \u{23ce} \n".white +
|
56
|
+
"Configures twitter account (Should be the first step!)\n" +
|
57
|
+
"tasks \u{23ce} \n".bold +
|
58
|
+
"Displays a list of available tasks \n" +
|
59
|
+
"my_tasks".bold + " \u{23ce} \n" +
|
60
|
+
"Displays a list of your selected tasks \n" +
|
61
|
+
"add ".bold + "task".green + " \u{23ce} \n".white +
|
62
|
+
"Adds a task to be randomly tweeted\n" +
|
63
|
+
"rem ".bold + "task".green + " \u{23ce} \n".white +
|
64
|
+
"Removes a task from your list\n" +
|
65
|
+
"run ".bold + "time".green + " \u{23ce} \n".white +
|
66
|
+
"Sets how frequent we tweet (Ex: run 3h or run 1d or run 30m)\n" +
|
67
|
+
"my_run ".bold + " \u{23ce} \n" +
|
68
|
+
"Displays the current frequency of tweets \n" +
|
69
|
+
"setup \u{23ce} \n".bold +
|
70
|
+
"setups the app for the first time \n" +
|
71
|
+
"exit \u{23ce} \n".bold +
|
72
|
+
"Exits the app \n"
|
73
|
+
end.display
|
74
|
+
end
|
75
|
+
|
76
|
+
def tasks(params)
|
77
|
+
@facade.tasks.each do |k, v|
|
78
|
+
puts "#{k}:".bold + " #{v['desc']}".green
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def display_done
|
83
|
+
'done!'.green.display
|
84
|
+
newline
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'twitter'
|
2
|
+
require 'yaml'
|
3
|
+
require 'lazybird/db'
|
4
|
+
|
5
|
+
module Lazybird
|
6
|
+
module Config
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def client
|
10
|
+
@_client ||= Twitter::REST::Client.new do |config|
|
11
|
+
config.consumer_key = db_config[:consumer_key]
|
12
|
+
config.consumer_secret = db_config[:consumer_secret]
|
13
|
+
config.access_token = db_config[:access_token]
|
14
|
+
config.access_token_secret = db_config[:access_token_secret]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def tasks
|
19
|
+
@_tasks ||= YAML::load_file('./lib/config/tasks.yml')
|
20
|
+
end
|
21
|
+
|
22
|
+
def db_file
|
23
|
+
"#{Dir.home}/.twitter.db"
|
24
|
+
end
|
25
|
+
|
26
|
+
def db_file_exists?
|
27
|
+
File.file? db_file
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def db_config
|
33
|
+
#TODO: nice to have - this should go to the DB if a new config is saved.
|
34
|
+
@_config ||= Lazybird::Db.config
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/lazybird/db.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'lazybird/tasks/task'
|
3
|
+
require 'lazybird/utils'
|
4
|
+
require 'lazybird/config'
|
5
|
+
module Lazybird
|
6
|
+
module Db
|
7
|
+
extend self
|
8
|
+
|
9
|
+
#TODO: refactor this. This is a quick & dirty way to create the DB
|
10
|
+
def self.init
|
11
|
+
db.transaction do
|
12
|
+
db.create_table :config do
|
13
|
+
primary_key :id
|
14
|
+
String :name, :unique => true, :null => false
|
15
|
+
String :consumer_key, :null => false
|
16
|
+
String :consumer_secret, :null => false
|
17
|
+
String :access_token, :null => false
|
18
|
+
String :access_token_secret, :null => false
|
19
|
+
end
|
20
|
+
|
21
|
+
db.create_table :tweets do
|
22
|
+
primary_key :id
|
23
|
+
String :text, :unique => true, :null => false
|
24
|
+
DateTime :created_at
|
25
|
+
end
|
26
|
+
|
27
|
+
db.create_table :tasks do
|
28
|
+
primary_key :id
|
29
|
+
String :command, :unique => true, :null => false
|
30
|
+
String :options
|
31
|
+
DateTime :created_at
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_tweet!(text:)
|
37
|
+
db[:tweets].insert(text: text, created_at: DateTime.now)
|
38
|
+
end
|
39
|
+
|
40
|
+
# TODO: Ideally we should have different configs, perhaps per twitter user
|
41
|
+
# for now, let's just delete every time we save a new one.
|
42
|
+
def save_config!(config)
|
43
|
+
db[:config].delete
|
44
|
+
db[:config].insert(config.merge(name: 'default'))
|
45
|
+
end
|
46
|
+
|
47
|
+
def config
|
48
|
+
db[:config].first
|
49
|
+
end
|
50
|
+
|
51
|
+
def save_task!(task)
|
52
|
+
task_hash = {command: task.command,
|
53
|
+
created_at: DateTime.now}
|
54
|
+
task_hash.merge!(options: task.opts) if !task.opts.empty?
|
55
|
+
db[:tasks].insert(Lazybird::Utils::Hash.compact(task_hash))
|
56
|
+
end
|
57
|
+
|
58
|
+
def rem_task!(task_command)
|
59
|
+
db[:tasks].where('command = ?', task_command).delete
|
60
|
+
end
|
61
|
+
|
62
|
+
def list_tasks
|
63
|
+
db[:tasks].select(:command)
|
64
|
+
end
|
65
|
+
|
66
|
+
def tasks
|
67
|
+
db[:tasks].all.map do |task|
|
68
|
+
found = Lazybird::Utils::Hash.find_by_key(Lazybird::Config.tasks, task[:command])
|
69
|
+
unless found.empty?
|
70
|
+
task_found(task[:command], found).new(command: task[:command],
|
71
|
+
options: found[:options])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def task_found(task_name, found)
|
77
|
+
Object.const_get(found[task_name]['class'])
|
78
|
+
end
|
79
|
+
|
80
|
+
def db
|
81
|
+
@_db ||= Sequel.amalgalite(Lazybird::Config.db_file)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'lazybird/config'
|
2
|
+
require 'lazybird/db'
|
3
|
+
require 'lazybird/utils'
|
4
|
+
require 'lazybird/tasks/storm_quote_task'
|
5
|
+
require 'lazybird/tasks/retweet_random_task'
|
6
|
+
require 'lazybird/tasks/task_scheduler'
|
7
|
+
|
8
|
+
module Lazybird
|
9
|
+
#TODO: split this file
|
10
|
+
class LazybirdFacade
|
11
|
+
|
12
|
+
attr_reader :tasks
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@current_tasks = Set.new
|
16
|
+
@tasks = Lazybird::Config.tasks
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_task(task_name)
|
20
|
+
# TODO refactor this method
|
21
|
+
found = Lazybird::Utils::Hash.find_by_key(@tasks, task_name)
|
22
|
+
if found
|
23
|
+
task = Object.const_get(found[task_name]['class']).new(command: task_name)
|
24
|
+
begin
|
25
|
+
Lazybird::Db.save_task!(task)
|
26
|
+
rescue Sequel::UniqueConstraintViolation
|
27
|
+
puts 'Task added already'.light_red
|
28
|
+
end
|
29
|
+
@current_tasks << task
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def rem_task(task_name)
|
34
|
+
Lazybird::Db.rem_task!(task_name)
|
35
|
+
@current_tasks.delete_if { |t| t.command == task_name }
|
36
|
+
end
|
37
|
+
|
38
|
+
def current_tasks
|
39
|
+
@current_tasks.map { |t| t.command }
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_default_tasks
|
43
|
+
@current_tasks.merge(Lazybird::Db.tasks)
|
44
|
+
end
|
45
|
+
|
46
|
+
def init
|
47
|
+
Lazybird::Db.init
|
48
|
+
end
|
49
|
+
|
50
|
+
def config(params)
|
51
|
+
config = Lazybird::Utils::Hash.array_to_hash([:consumer_key,
|
52
|
+
:consumer_secret,
|
53
|
+
:access_token,
|
54
|
+
:access_token_secret], params)
|
55
|
+
Lazybird::Db.save_config! config
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_tasks(params, &block)
|
59
|
+
if params.first == 'now'
|
60
|
+
run_random_task
|
61
|
+
else
|
62
|
+
Lazybird::Tasks::TaskScheduler.schedule(frequency: params.first) do
|
63
|
+
run_random_task(&block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def run_info
|
69
|
+
Lazybird::Tasks::TaskScheduler.job_info
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def run_random_task(&block)
|
75
|
+
puts 'Twitting something random...'.yellow
|
76
|
+
text = @current_tasks.to_a.sample.run
|
77
|
+
if text.nil?
|
78
|
+
puts "Sorry! We couldn't tweet :(".light_red
|
79
|
+
else
|
80
|
+
puts "<<#{text.magenta}>>"
|
81
|
+
end
|
82
|
+
yield if block
|
83
|
+
text
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|