retrobot 0.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1f45da0e3a0e9809a79c0989c34e46a3d830fbbc
4
+ data.tar.gz: 8a8395194a7dc0399e061d1e9246def6dc1df8ce
5
+ SHA512:
6
+ metadata.gz: f8bd439b243ac2f7c2c750331aa804cf18ed5391367c84b6ce1b78c91b9cd5fb2ef26aa37a3f3338d07f22fec34d21bf953ac52d043ef2b56c7ddfb051da095a
7
+ data.tar.gz: e940b57b01287d7a92c07bc9e28ad838604e4ad70cac0e285d2b77eaf3585ec63d47bb2c85177407db3431768a6f76c8fb82bd58e64703f757603273cf28c56e
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ tweets/
2
+ *.env
3
+ log/
4
+ tmp/
5
+ .bundle
6
+ retrobot.yml
data/ChangeLog.md ADDED
@@ -0,0 +1,7 @@
1
+ # ChangeLog
2
+ ## 0.2.0
3
+ - Gemify, and YAML style configuration (Thanks @sorah)
4
+ - Remove .env
5
+
6
+ ## 0.0.1
7
+ - First release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,65 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ retrobot (0.0.1)
5
+ activesupport (~> 4.0)
6
+ daemons
7
+ get-twitter-oauth-token
8
+ retryable
9
+ twitter (~> 4.8.1)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ activesupport (4.0.4)
15
+ i18n (~> 0.6, >= 0.6.9)
16
+ minitest (~> 4.2)
17
+ multi_json (~> 1.3)
18
+ thread_safe (~> 0.1)
19
+ tzinfo (~> 0.3.37)
20
+ atomic (1.1.16)
21
+ awesome_print (1.2.0)
22
+ daemons (1.1.9)
23
+ diff-lcs (1.2.5)
24
+ faraday (0.9.0)
25
+ multipart-post (>= 1.2, < 3)
26
+ get-twitter-oauth-token (1.1.0)
27
+ oauth
28
+ i18n (0.6.9)
29
+ json (1.8.1)
30
+ minitest (4.7.5)
31
+ multi_json (1.9.2)
32
+ multipart-post (2.0.0)
33
+ oauth (0.4.7)
34
+ rack (1.5.2)
35
+ rack-test (0.6.2)
36
+ rack (>= 1.0)
37
+ retryable (1.3.4)
38
+ rspec (2.13.0)
39
+ rspec-core (~> 2.13.0)
40
+ rspec-expectations (~> 2.13.0)
41
+ rspec-mocks (~> 2.13.0)
42
+ rspec-core (2.13.1)
43
+ rspec-expectations (2.13.0)
44
+ diff-lcs (>= 1.1.3, < 2.0)
45
+ rspec-json_matcher (0.0.6)
46
+ awesome_print
47
+ json
48
+ rspec-mocks (2.13.1)
49
+ simple_oauth (0.2.0)
50
+ thread_safe (0.3.1)
51
+ atomic (>= 1.1.7, < 2)
52
+ twitter (4.8.1)
53
+ faraday (~> 0.8, < 0.10)
54
+ multi_json (~> 1.0)
55
+ simple_oauth (~> 0.2)
56
+ tzinfo (0.3.39)
57
+
58
+ PLATFORMS
59
+ ruby
60
+
61
+ DEPENDENCIES
62
+ rack-test (~> 0.6.2)
63
+ retrobot!
64
+ rspec (~> 2.13.0)
65
+ rspec-json_matcher (~> 0.0.4)
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Issei Naruta
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ retrobot
2
+ =============
3
+ Retrobot is a twitter-bot engine that working at [mirakui_retro](https://twitter.com/mirakui_retro).
4
+
5
+ Retrobot tweets a word that you've tweeted just 1 year ago!
6
+
7
+ ## Requirements
8
+
9
+ - Ruby 1.9+
10
+ - Your [tweets.zip](https://blog.twitter.com/2012/your-twitter-archive)
11
+
12
+ ## Installation
13
+
14
+ ### Rubygems command
15
+
16
+ ```
17
+ $ git clone https://github.com/mirakui/retrobot.git
18
+ $ cd retrobot
19
+ $ bundle install
20
+ ```
21
+
22
+ ### Using bundler
23
+
24
+ This way may be useful for deploying using capistrano or heroku.
25
+
26
+ (This way separates repository by your deployment and application itself)
27
+
28
+ ```
29
+ $ bundle init
30
+ $ echo 'gem "retrobot"' >> Gemfile
31
+ $ bundle install
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ ```
37
+ $ bundle exec get-twitter-oauth-token
38
+ (follow shown instruction to earn required credentials)
39
+
40
+ $ unzip ~/tweets.zip -d tweets
41
+ $ cp retrobot.example.yml retrobot.yml
42
+ $ vi retrobot.yml
43
+ (write your oauth credentials)
44
+ ```
45
+
46
+ ### Detail
47
+
48
+ Config file is set to `./retrobot.yml` from `Dir.pwd` in default.
49
+ You can give another file by using `--config` command line option.
50
+
51
+ - `consumer_key`, `consumer_secret`: Your OAuth consumer key/secret given from Twitter.
52
+ - `access_token`, `access_secret`: Your OAuth access key/secret of your Twitter account where you want to run retrobot.
53
+ - `tweets_csv`: Path to your tweets.csv (default to `./tweets/tweets.csv` in pwd)
54
+
55
+ ## Running retrobot
56
+
57
+ ```
58
+ $ bin/retrobot
59
+ (or, )
60
+ $ bin/retrobot -c /path/to/retrobot.yml
61
+ ```
62
+
63
+ or you can run it as a daemon as follows:
64
+
65
+ ```
66
+ $ bin/retrobotctl [start|stop]
67
+ ```
68
+
69
+ ## License
70
+ Copyright (c) 2013 Issei Naruta. Retrobot is released under the MIT License.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/retrobot ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ retried = false
3
+ begin
4
+ require 'retrobot'
5
+ rescue LoadError
6
+ raise if retried
7
+ retried = true
8
+ $:.unshift "#{__dir__}/../lib"
9
+ retry
10
+ end
11
+
12
+ Retrobot.new(ARGV).main
data/bin/retrobotctl ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup'
3
+ require 'daemons'
4
+ require 'pathname'
5
+
6
+ base_dir = Pathname('../../').expand_path(__FILE__)
7
+ Daemons.run(
8
+ base_dir.join('bin/retrobot'),
9
+ app_name: 'retrobot',
10
+ dir_mode: :normal,
11
+ dir: base_dir.join('tmp'),
12
+ log_dir: base_dir.join('log'),
13
+ log_output: true
14
+ )
data/lib/retrobot.rb ADDED
@@ -0,0 +1,154 @@
1
+ require 'retrobot/version'
2
+ require 'retrobot/config'
3
+
4
+ require 'active_support/core_ext'
5
+ require 'twitter'
6
+ require 'retryable'
7
+ require 'logger'
8
+ require 'csv'
9
+ require 'pathname'
10
+ require 'time'
11
+ require 'optparse'
12
+ require 'cgi'
13
+
14
+ class Retrobot
15
+
16
+ GEM_ROOT = Pathname.new('..').expand_path(__dir__)
17
+
18
+ def initialize(argv)
19
+ @argv = argv
20
+ end
21
+
22
+ def client
23
+ @client ||= Twitter::Client.new(
24
+ consumer_key: @config.consumer_key,
25
+ consumer_secret: @config.consumer_secret,
26
+ oauth_token: @config.access_token,
27
+ oauth_token_secret: @config.access_secret
28
+ )
29
+ end
30
+
31
+ def logger
32
+ @logger ||= begin
33
+ l = Logger.new($stdout)
34
+ l.level = @config.debug ? Logger::DEBUG : Logger::INFO
35
+ l
36
+ end
37
+ end
38
+
39
+ def csv
40
+ @csv ||= begin
41
+ tweets_csv = file_from_candidates(
42
+ @config.tweets_csv,
43
+ GEM_ROOT.join('tweets', 'tweets.csv'),
44
+ )
45
+ CSV.parse File.read(tweets_csv)
46
+ end
47
+ end
48
+
49
+ def init_csv
50
+ csv.slice! 0
51
+ last_index = nil
52
+ csv.each_with_index.each do |line, i|
53
+ time = Time.parse line[3]
54
+ if time < @config.retro_days.ago
55
+ last_index = i
56
+ break;
57
+ end
58
+ end
59
+ csv.slice! last_index..-1
60
+ logger.info "Next update: \"#{csv.last[5]}\" at #{@config.retro_days.since(Time.parse(csv.last[3]))}"
61
+ end
62
+
63
+ def tweet_loop
64
+ logger.info 'start'
65
+ loop do
66
+ line = csv.last
67
+ if process_line(line)
68
+ csv.pop
69
+ end
70
+ sleep @config.loop_interval
71
+ logger.debug '.'
72
+ end
73
+ end
74
+
75
+ def process_line(line)
76
+ tweet_id, in_reply_to_status_id, in_reply_to_user_id,
77
+ timestamp, source, text,
78
+ retweeted_status_id, retweeted_status_user_id, retweeted_status_timestamp,
79
+ *expanded_urls = line
80
+
81
+ timestamp = Time.parse(timestamp).localtime
82
+ return false if timestamp > @config.retro_days.ago
83
+
84
+ if retweeted_status_id.present?
85
+ retweet retweeted_status_id.to_i, text
86
+ return true
87
+ end
88
+
89
+ tweet CGI.unescape_html(text.gsub('@', ''))
90
+ true
91
+ rescue Twitter::Error
92
+ logger.error "#{$!} (#{$!.class})\n #{$@.join("\n ")}"
93
+ true
94
+ end
95
+
96
+ def retweet(status_id, text=nil)
97
+ logger.info "retweet: #{status_id} \"#{text}\""
98
+ return if @config.dryrun
99
+ retryable(tries: @config.retry_count, sleep: @config.retry_interval) do
100
+ client.retweet status_id
101
+ end
102
+ end
103
+
104
+ def tweet(text)
105
+ logger.info "tweet: #{text}"
106
+ return if @config.dryrun
107
+ retryable(tries: @config.retry_count, sleep: @config.retry_interval) do
108
+ client.update text
109
+ end
110
+ end
111
+
112
+ def init_configuration
113
+ options = parse_options()
114
+ @config = Config.new
115
+
116
+ config_yml = file_from_candidates(
117
+ options[:config], './retrobot.yml',
118
+ GEM_ROOT.join('retrobot.yml')
119
+ )
120
+ @config.load_yaml_file!(config_yml) if config_yml
121
+
122
+ @config.merge!(options)
123
+
124
+ client.current_user # for faster fail (e.g. wrong credentials given)
125
+ end
126
+
127
+ def parse_options
128
+ options = {}
129
+
130
+ opt = OptionParser.new @argv
131
+ opt.banner = "Usage: #{$0} [OPTIONS]"
132
+ opt.on('--debug') { options[:debug] = true }
133
+ opt.on('--dryrun') { options[:dryrun] = true }
134
+ opt.on('--config file') {|v| options[:config] = v }
135
+ opt.on('--retro-days days') {|v| options[:retro_days] = v }
136
+ opt.on('--tweets-csv path') {|v| options[:tweets_csv] = v }
137
+ opt.parse!
138
+
139
+ options
140
+ end
141
+
142
+ def main
143
+ init_configuration
144
+ init_csv
145
+ tweet_loop
146
+ end
147
+
148
+ private
149
+
150
+ def file_from_candidates(*candidates)
151
+ path = candidates.find { |f| f && File.exists?(f.to_s) }
152
+ path && path.to_s
153
+ end
154
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_support/core_ext'
2
+ require 'psych'
3
+
4
+ class Retrobot
5
+ class Config
6
+ KEYS = %i(
7
+ tweets_csv
8
+ consumer_key
9
+ consumer_secret
10
+ access_token
11
+ access_secret
12
+ retro_days
13
+ debug
14
+ dryrun
15
+ loop_interval
16
+ retry_interval
17
+ retry_count
18
+ )
19
+
20
+ DEFAULTS = {
21
+ tweets_csv: './tweets/tweets.csv',
22
+ retro_days: 365,
23
+ debug: false,
24
+ dryrun: false,
25
+ loop_interval: 3,
26
+ retry_interval: 3,
27
+ retry_count: 5
28
+ }
29
+
30
+ def initialize(options={})
31
+ @options = DEFAULTS.merge(options.symbolize_keys)
32
+ end
33
+
34
+ def merge!(hash)
35
+ @options.merge!(hash)
36
+ end
37
+
38
+ KEYS.each do |k|
39
+ define_method(k) { @options[k] }
40
+ end
41
+
42
+ def retro_days
43
+ @options[:retro_days].to_i.days
44
+ end
45
+
46
+ def tweets_csv
47
+ Pathname.new(@options[:tweets_csv])
48
+ end
49
+
50
+ def loop_interval; @options[:loop_interval].to_i; end
51
+ def retry_interval; @options[:retry_interval].to_i; end
52
+ def retry_count; @options[:retry_count].to_i; end
53
+
54
+ def load_yaml_file!(path)
55
+ @options.merge! Psych.load_file(path.to_s).symbolize_keys
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ class Retrobot
2
+ VERSION = '0.2.0'
3
+ end
@@ -0,0 +1,8 @@
1
+ # tweets_csv: tweets/tweets.csv (default)
2
+ consumer_key: your_consumer_key
3
+ consumer_secret: your_consumer_secret
4
+ access_token: your_access_token
5
+ access_secret: your_access_secret
6
+ # retro_days: 365 (default=365 / how days long ago do you want to see? / in N days ago)
7
+ # debug: false (default)
8
+ # dryrun: false (default)
data/retrobot.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'retrobot/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "retrobot"
8
+ gem.version = Retrobot::VERSION
9
+ gem.authors = ["Issei Naruta"]
10
+ gem.email = ["mimitako@gmail.com"]
11
+ gem.description = %q{Bot for twitter, which tweets a word that you've tweeted just 1 year ago}
12
+ gem.summary = %q{Retrobot tweets a word that you've tweeted just 1 year ago. (example: @mirakui_retro)}
13
+ gem.homepage = "https://github.com/mirakui/retrobot"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'twitter', '~> 4.8.1'
21
+ gem.add_dependency 'activesupport', '~> 4.0'
22
+ gem.add_dependency 'retryable'
23
+ gem.add_dependency 'daemons'
24
+
25
+ gem.add_runtime_dependency 'get-twitter-oauth-token'
26
+
27
+ gem.add_development_dependency "rspec", "~> 2.13.0"
28
+ gem.add_development_dependency "rspec-json_matcher", "~> 0.0.4"
29
+ gem.add_development_dependency "rack-test", "~> 0.6.2"
30
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: retrobot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Issei Naruta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: twitter
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.8.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.8.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: retryable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: daemons
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: get-twitter-oauth-token
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.13.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.13.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-json_matcher
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.0.4
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.0.4
111
+ - !ruby/object:Gem::Dependency
112
+ name: rack-test
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.6.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.6.2
125
+ description: Bot for twitter, which tweets a word that you've tweeted just 1 year
126
+ ago
127
+ email:
128
+ - mimitako@gmail.com
129
+ executables:
130
+ - retrobot
131
+ - retrobotctl
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - ".gitignore"
136
+ - ChangeLog.md
137
+ - Gemfile
138
+ - Gemfile.lock
139
+ - LICENSE.txt
140
+ - README.md
141
+ - Rakefile
142
+ - bin/retrobot
143
+ - bin/retrobotctl
144
+ - lib/retrobot.rb
145
+ - lib/retrobot/config.rb
146
+ - lib/retrobot/version.rb
147
+ - log/.keep
148
+ - retrobot.example.yml
149
+ - retrobot.gemspec
150
+ - tmp/.keep
151
+ homepage: https://github.com/mirakui/retrobot
152
+ licenses: []
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.2.2
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: 'Retrobot tweets a word that you''ve tweeted just 1 year ago. (example: @mirakui_retro)'
174
+ test_files: []