twitter_backup 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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +30 -0
- data/Rakefile +2 -0
- data/bin/twitter_backup +49 -0
- data/lib/twitter_backup.rb +47 -0
- data/lib/twitter_backup/config.rb +138 -0
- data/lib/twitter_backup/error.rb +7 -0
- data/lib/twitter_backup/tweet.rb +116 -0
- data/lib/twitter_backup/ui.rb +89 -0
- data/lib/twitter_backup/version.rb +3 -0
- data/twitter_backup.gemspec +25 -0
- metadata +156 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 il.zoff
|
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,30 @@
|
|
1
|
+
# TwitterBackup
|
2
|
+
|
3
|
+
This gem will download your tweets from Twitter and save them to sqlite3 database and plaintext (yaml) archive file.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install twitter_backup
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
First of all, you need to create an app at https://dev.twitter.com/apps
|
12
|
+
Your app will be assigned a 'consumer key'/'consumer secret' pair and you as a user will be assigned an 'access token'/'acces token secret' OAuth pair for that application.
|
13
|
+
Without these credentials you won't be able to use TwitterBackup.
|
14
|
+
|
15
|
+
Now, all you have to do is to run
|
16
|
+
|
17
|
+
$ twitter_backup
|
18
|
+
|
19
|
+
If you want to know, what's happening during your backup process, use verbose mode with `-v`.
|
20
|
+
|
21
|
+
$ twitter_backup -h
|
22
|
+
-v, --verbose Enable verbose mode
|
23
|
+
-f, --force Try to download tweets, even if it seems useless
|
24
|
+
-s, --seed Try to download tweets older than the oldest one you have
|
25
|
+
-c, --config Config file. Default: ~/.config/twitter_backup/config.yml
|
26
|
+
-h, --help Display this help message.
|
27
|
+
|
28
|
+
## TODO
|
29
|
+
|
30
|
+
- Automate adding this script to cron?
|
data/Rakefile
ADDED
data/bin/twitter_backup
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
# require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib twitter_backup]))
|
5
|
+
require "twitter_backup"
|
6
|
+
require "twitter_backup/ui"
|
7
|
+
|
8
|
+
include TwitterBackup
|
9
|
+
|
10
|
+
if TBConfig.passed_opts.help?
|
11
|
+
TBConfig.passed_opts.help
|
12
|
+
exit 0
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
|
17
|
+
say ".... checking existance of credentials" if TBConfig.passed_opts.verbose?
|
18
|
+
UI.ask_credentials if TBConfig.credentials_missing?
|
19
|
+
|
20
|
+
UI.define_path_to_backup unless TBConfig.path_to_backup_defined?
|
21
|
+
|
22
|
+
TBConfig.configure
|
23
|
+
|
24
|
+
UI.greet_user
|
25
|
+
|
26
|
+
Tweet.update_tweets
|
27
|
+
Tweet.update_tweets(:from => :earliest) if TBConfig.passed_opts.seed?
|
28
|
+
|
29
|
+
Tweet.dump_to_backup_file
|
30
|
+
|
31
|
+
rescue Error::MissingCredentials => error
|
32
|
+
UI.missing_credentials_exit
|
33
|
+
|
34
|
+
rescue Twitter::Error::Unauthorized => error
|
35
|
+
TBConfig.empty_credentials
|
36
|
+
UI.wrong_credentials_exit
|
37
|
+
|
38
|
+
rescue Twitter::Error::TooManyRequests => error
|
39
|
+
UI.too_many_requests_exit
|
40
|
+
|
41
|
+
rescue Error::InvalidBackupFile => error
|
42
|
+
UI.failed_backup_path_exit( error.message )
|
43
|
+
|
44
|
+
rescue Error::InvalidPath => error
|
45
|
+
say %[<%= color("#{error.message}", :red) %>]
|
46
|
+
exit 1
|
47
|
+
ensure
|
48
|
+
UI.exit_screen
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "slop"
|
2
|
+
require "yaml"
|
3
|
+
require "fileutils"
|
4
|
+
require "highline/import"
|
5
|
+
require 'active_support/core_ext/string'
|
6
|
+
require "active_record"
|
7
|
+
require "twitter"
|
8
|
+
require_relative "twitter_backup/version"
|
9
|
+
require_relative "twitter_backup/error"
|
10
|
+
require_relative "twitter_backup/config"
|
11
|
+
require_relative "twitter_backup/tweet"
|
12
|
+
|
13
|
+
module TwitterBackup
|
14
|
+
def self.prepare_file file
|
15
|
+
file = File.expand_path file
|
16
|
+
dir = File.dirname file
|
17
|
+
FileUtils.mkdir_p dir unless File.exist? dir
|
18
|
+
FileUtils.touch file unless File.exist? file
|
19
|
+
raise( Error::InvalidPath, "Can't create file: #{file}" ) unless File.exist?( file )
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
unless Kernel.respond_to?(:require_relative)
|
24
|
+
module Kernel
|
25
|
+
def require_relative(path)
|
26
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class File
|
31
|
+
def tail(n)
|
32
|
+
buffer = 1024
|
33
|
+
idx = (size - buffer).abs
|
34
|
+
chunks = []
|
35
|
+
lines = 0
|
36
|
+
begin
|
37
|
+
seek(idx)
|
38
|
+
chunk = read(buffer)
|
39
|
+
lines += chunk ? chunk.count("\n") : 0
|
40
|
+
chunks.unshift chunk
|
41
|
+
idx -= buffer
|
42
|
+
end while lines < ( n + 1 ) && pos != 0
|
43
|
+
tail_of_file = chunks.join('')
|
44
|
+
ary = tail_of_file.split(/\n/)
|
45
|
+
lines_to_return = ary[ ary.size - n, ary.size - 1 ] || []
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
|
2
|
+
CONFIG_DIR = File.expand_path(File.join("~/", ".config", "twitter_backup"))
|
3
|
+
CONFIG_FILE = File.join(CONFIG_DIR, "config.yml")
|
4
|
+
|
5
|
+
CONFIG_DEFAULTS = {
|
6
|
+
:credentials => {
|
7
|
+
:consumer_key => "",
|
8
|
+
:consumer_secret => "",
|
9
|
+
:oauth_token => "",
|
10
|
+
:oauth_token_secret => "",
|
11
|
+
},
|
12
|
+
:db => {
|
13
|
+
:adapter => "sqlite3",
|
14
|
+
:database => File.join(CONFIG_DIR, "tweets.sqlite3"),
|
15
|
+
:pool => 5,
|
16
|
+
:timeout => 5000
|
17
|
+
},
|
18
|
+
:backup_file => ""
|
19
|
+
}
|
20
|
+
|
21
|
+
module TwitterBackup
|
22
|
+
class TBConfig
|
23
|
+
class << self
|
24
|
+
def load
|
25
|
+
TwitterBackup.prepare_file config_file
|
26
|
+
yaml = YAML::load_file( config_file )
|
27
|
+
@@options = if yaml.is_a? Hash
|
28
|
+
CONFIG_DEFAULTS.merge(yaml)
|
29
|
+
else
|
30
|
+
CONFIG_DEFAULTS
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def save options
|
35
|
+
@@options = options
|
36
|
+
TwitterBackup.prepare_file config_file
|
37
|
+
File.open( config_file, "w" ){|f| YAML::dump( options, f )}
|
38
|
+
end
|
39
|
+
|
40
|
+
def options
|
41
|
+
@@options ||= load
|
42
|
+
end
|
43
|
+
|
44
|
+
def credentials_missing?
|
45
|
+
options[:credentials].values.map(&:strip).include? ""
|
46
|
+
end
|
47
|
+
|
48
|
+
def path_to_backup_defined?
|
49
|
+
options[:backup_file].present?
|
50
|
+
end
|
51
|
+
|
52
|
+
def save_backup_file file
|
53
|
+
options[:backup_file] = file
|
54
|
+
save options
|
55
|
+
end
|
56
|
+
|
57
|
+
def save_credentials new_credentials
|
58
|
+
options[:credentials] = options[:credentials].merge(new_credentials)
|
59
|
+
save options
|
60
|
+
end
|
61
|
+
|
62
|
+
def empty_credentials
|
63
|
+
new_credentials = { :consumer_key => "",
|
64
|
+
:consumer_secret => "",
|
65
|
+
:oauth_token => "",
|
66
|
+
:oauth_token_secret => ""}
|
67
|
+
save_credentials new_credentials
|
68
|
+
end
|
69
|
+
|
70
|
+
def configure_database
|
71
|
+
ActiveRecord::Base.establish_connection(options[:db])
|
72
|
+
unless ActiveRecord::Base.connection.tables.include?("tweets")
|
73
|
+
ActiveRecord::Migration.create_table :tweets do |t|
|
74
|
+
t.text :status
|
75
|
+
t.integer :status_id
|
76
|
+
t.timestamp :created_at
|
77
|
+
t.text :raw
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def configure_twitter_gem
|
83
|
+
raise MissingCredentials if credentials_missing?
|
84
|
+
Twitter.configure do |config|
|
85
|
+
config.consumer_key = options[:credentials][:consumer_key]
|
86
|
+
config.consumer_secret = options[:credentials][:consumer_secret]
|
87
|
+
config.oauth_token = options[:credentials][:oauth_token]
|
88
|
+
config.oauth_token_secret = options[:credentials][:oauth_token_secret]
|
89
|
+
end
|
90
|
+
@@twitter_gem_configured = true
|
91
|
+
end
|
92
|
+
|
93
|
+
def check_backup_file
|
94
|
+
begin
|
95
|
+
backup_file = File.expand_path(options[:backup_file])
|
96
|
+
TwitterBackup.prepare_file( backup_file ) unless File.exist?( backup_file )
|
97
|
+
rescue Exception => e
|
98
|
+
raise Error::InvalidBackupFile, e.message
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def configure
|
103
|
+
say ".... configuring database" if passed_opts.verbose?
|
104
|
+
configure_database
|
105
|
+
|
106
|
+
say ".... configuring twitter gem" if passed_opts.verbose?
|
107
|
+
configure_twitter_gem
|
108
|
+
|
109
|
+
say ".... checking backup file: #{options[:backup_file]}" if passed_opts.verbose?
|
110
|
+
check_backup_file
|
111
|
+
end
|
112
|
+
|
113
|
+
def verify_credentials
|
114
|
+
say ".... checking validity of credentials" if passed_opts.verbose?
|
115
|
+
configure_twitter_gem unless @@twitter_gem_configured
|
116
|
+
@@user = Twitter.verify_credentials(:skip_status => true, :include_entities => false)
|
117
|
+
end
|
118
|
+
|
119
|
+
def user
|
120
|
+
@@user ||= verify_credentials
|
121
|
+
end
|
122
|
+
|
123
|
+
def config_file
|
124
|
+
passed_opts[:config] || CONFIG_FILE
|
125
|
+
end
|
126
|
+
|
127
|
+
def passed_opts
|
128
|
+
@@opts ||= Slop.parse(:help => true) do
|
129
|
+
on :v, :verbose, 'Enable verbose mode'
|
130
|
+
on :f, :force, "Try to download tweets, even it seems useless"
|
131
|
+
on :s, :seed, "Try to download tweets older then the oldest one you have"
|
132
|
+
on :c, :config, "Config file. Default: #{CONFIG_FILE}", :argument => true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module TwitterBackup
|
2
|
+
class Tweet < ActiveRecord::Base
|
3
|
+
|
4
|
+
serialize :raw
|
5
|
+
|
6
|
+
scope :slim, select([:id, :created_at, :status, :status_id])
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def update_tweets(args={})
|
11
|
+
args = {
|
12
|
+
:from => nil,
|
13
|
+
:to => latest.try(:status_id)
|
14
|
+
}.merge(args)
|
15
|
+
if args[:from] == :earliest
|
16
|
+
args[:from] = earliest.try(:status_id)
|
17
|
+
args[:to] = nil if args[:to] == latest.try(:status_id)
|
18
|
+
end
|
19
|
+
if !synced? || TBConfig.passed_opts.force?
|
20
|
+
say ".... Updating tweets from #{args[:from] || 'the youngest one'} to #{args[:to] || 'the oldest one'}" if TBConfig.passed_opts.verbose?
|
21
|
+
download(:from => args[:from], :to => args[:to]).each do |tweet|
|
22
|
+
if absent_tweet = find_by_status_id(tweet.id)
|
23
|
+
next
|
24
|
+
else
|
25
|
+
say %[<%= color(".", YELLOW) %> ] if TBConfig.passed_opts.verbose?
|
26
|
+
tweet_text = if tweet.retweet?
|
27
|
+
"RT @#{tweet.retweeted_status.user.screen_name}: #{tweet.retweeted_status.text}"
|
28
|
+
else
|
29
|
+
tweet.text
|
30
|
+
end
|
31
|
+
create(
|
32
|
+
:status_id => tweet.id,
|
33
|
+
:status => tweet_text,
|
34
|
+
:created_at => tweet.created_at,
|
35
|
+
:raw => tweet
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
say "!"
|
40
|
+
say ".... Updating succeeded" if TBConfig.passed_opts.verbose?
|
41
|
+
else
|
42
|
+
say ".... Seems like there is nothing we can update" if TBConfig.passed_opts.verbose?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def latest
|
47
|
+
self.slim.order("created_at DESC").first
|
48
|
+
end
|
49
|
+
def earliest
|
50
|
+
self.slim.order("created_at DESC").last
|
51
|
+
end
|
52
|
+
|
53
|
+
def download(args={})
|
54
|
+
args = {
|
55
|
+
:from => nil,
|
56
|
+
:to => nil
|
57
|
+
}.merge(args)
|
58
|
+
args[:from], args[:to] = [args[:from], args[:to]].sort.reverse unless [args[:from], args[:to]].include? nil
|
59
|
+
|
60
|
+
needed_tweets = []
|
61
|
+
|
62
|
+
if args[:from].blank?
|
63
|
+
say ".... user_timeline API request" if TBConfig.passed_opts.verbose?
|
64
|
+
received_tweets = Twitter.user_timeline(:count => 200)
|
65
|
+
else
|
66
|
+
say ".... user_timeline API request" if TBConfig.passed_opts.verbose?
|
67
|
+
received_tweets = Twitter.user_timeline(:count => 200, :max_id => args[:from])
|
68
|
+
end
|
69
|
+
|
70
|
+
if args[:to].blank?
|
71
|
+
id_of_the_earliest_received_tweet = nil
|
72
|
+
until id_of_the_earliest_received_tweet == received_tweets.last.id
|
73
|
+
id_of_the_earliest_received_tweet = received_tweets.last.id
|
74
|
+
say ".... user_timeline API request" if TBConfig.passed_opts.verbose?
|
75
|
+
received_tweets.concat(
|
76
|
+
Twitter.user_timeline(:count => 200, :max_id => received_tweets.last.id)
|
77
|
+
)
|
78
|
+
end
|
79
|
+
received_tweets
|
80
|
+
else args[:to]
|
81
|
+
id_of_the_earliest_needed_tweet = args[:to]
|
82
|
+
until received_tweets.map(&:id).include? id_of_the_earliest_needed_tweet
|
83
|
+
say ".... user_timeline API request" if TBConfig.passed_opts.verbose?
|
84
|
+
received_tweets.concat(
|
85
|
+
Twitter.user_timeline(:count => 200, :max_id => received_tweets.last.id)
|
86
|
+
)
|
87
|
+
end
|
88
|
+
index_of_earliest_needed_tweet = received_tweets.rindex{|tweet| tweet.id == id_of_the_earliest_needed_tweet}
|
89
|
+
received_tweets[0..index_of_earliest_needed_tweet]
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def synced?
|
95
|
+
self.count == TBConfig.user.statuses_count
|
96
|
+
end
|
97
|
+
|
98
|
+
def dump_to_backup_file
|
99
|
+
if TBConfig.passed_opts.verbose?
|
100
|
+
say ".... Saving tweets to: #{TBConfig.options[:backup_file]}"
|
101
|
+
end
|
102
|
+
tweets = slim.order("created_at DESC").map{ |tweet| {
|
103
|
+
:id => tweet.status_id,
|
104
|
+
:text => tweet.status,
|
105
|
+
:created_at => tweet.created_at,
|
106
|
+
:link => tweet.public_link } }
|
107
|
+
File.open( TBConfig.options[:backup_file], "w" ) { |f| YAML::dump( tweets, f ) }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def public_link
|
112
|
+
"https://twitter.com/#{TBConfig.user.screen_name}/status/#{self.status_id}"
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module TwitterBackup
|
2
|
+
module UI
|
3
|
+
class << self
|
4
|
+
def ask_credentials
|
5
|
+
say "You need to give us necessary credentials"
|
6
|
+
say "Get them at https://dev.twitter.com/apps"
|
7
|
+
|
8
|
+
existing_credentials = TBConfig.options[:credentials]
|
9
|
+
new_credentials = {}
|
10
|
+
|
11
|
+
new_credentials[:consumer_key] = ask("Consumer key? ").to_s if existing_credentials[:consumer_key].blank?
|
12
|
+
new_credentials[:consumer_secret] = ask("Consumer secret? ").to_s if existing_credentials[:consumer_secret].blank?
|
13
|
+
new_credentials[:oauth_token] = ask("Access token? ").to_s if existing_credentials[:oauth_token].blank?
|
14
|
+
new_credentials[:oauth_token_secret] = ask("Access token secret? ").to_s if existing_credentials[:oauth_token_secret].blank?
|
15
|
+
|
16
|
+
TBConfig.save_credentials new_credentials
|
17
|
+
raise MissingCredentials if TBConfig.credentials_missing?
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_path_to_backup
|
21
|
+
default_path = File.join(CONFIG_DIR, "tweets.yml")
|
22
|
+
say "We are going to save your tweets to #{TBConfig.options[:db][:database]}"
|
23
|
+
say "And also as plain text to #{default_path}"
|
24
|
+
if agree ("Dou you want to define another directory for text copy? ")
|
25
|
+
backup_dir = ask("Enter a path to your direcory: ") do |q|
|
26
|
+
q.validate = lambda { |file| File.exist?(File.dirname(File.expand_path(file))) }
|
27
|
+
q.responses[:not_valid] = "You can't save files there"
|
28
|
+
q.confirm = true
|
29
|
+
end
|
30
|
+
backup_file = File.expand_path(File.join(backup_dir, "tweets.yml"))
|
31
|
+
else
|
32
|
+
backup_file = default_path
|
33
|
+
end
|
34
|
+
|
35
|
+
TBConfig.save_backup_file backup_file
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def greet_user
|
40
|
+
say %[.... <%= color("Tweets for: #{TBConfig.user.name}", GREEN) %>!]
|
41
|
+
say %[.... Your tweets at twitter.com: #{TBConfig.user.statuses_count}]
|
42
|
+
end
|
43
|
+
|
44
|
+
def exit_screen
|
45
|
+
if ActiveRecord::Base.connected?
|
46
|
+
say %[.... Your tweets in this backup: #{Tweet.count}]
|
47
|
+
if Tweet.earliest.present?
|
48
|
+
say %[.... Your earliest tweet:]
|
49
|
+
say %[.... <%= color("#{Tweet.earliest.try(:status)}", YELLOW) %>]
|
50
|
+
end
|
51
|
+
if Tweet.latest.present?
|
52
|
+
say %[.... Your latest tweet:]
|
53
|
+
say %[.... <%= color("#{Tweet.latest.try(:status)}", GREEN) %>]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def missing_credentials_exit
|
59
|
+
say %[.... <%= color("We can't work without credentials. Sorry.", RED) %>]
|
60
|
+
say ".... Go get them at https://dev.twitter.com/apps"
|
61
|
+
say ".... And run this script again"
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
def wrong_credentials_exit
|
66
|
+
say %[.... <%= color("Your credentials are somehow wrong.", RED) %>]
|
67
|
+
say ".... Go get the right ones at https://dev.twitter.com/apps"
|
68
|
+
say ".... And run this script again"
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def failed_backup_path_exit message
|
73
|
+
say %[.... <%= color("We've failed to create #{TBConfig.options[:backup_file]} for you.", RED) %>]
|
74
|
+
say %[.... #{message}]
|
75
|
+
TBConfig.save_backup_file("")
|
76
|
+
say ".... Run this script again and chose another place to store your backup"
|
77
|
+
say ".... Or edit it manually at #{TBConfig.config_file}"
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
|
81
|
+
def too_many_requests_exit
|
82
|
+
say %[.... <%= color("You've exceeded your request limit", RED) %>]
|
83
|
+
say ".... Try again tomorrow =)"
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/twitter_backup/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["il.zoff"]
|
6
|
+
gem.email = ["il.zoff@gmail.com"]
|
7
|
+
gem.description = %q{This gem will download your tweets from Twitter and save them to sqlite3 database and plaintext (yaml) archive file.}
|
8
|
+
gem.summary = %q{Twitter archiver}
|
9
|
+
gem.homepage = "http://github.com/ilzoff/twitter_backup"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "twitter_backup"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = TwitterBackup::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency("highline")
|
19
|
+
gem.add_dependency("activesupport")
|
20
|
+
gem.add_dependency("activerecord")
|
21
|
+
gem.add_dependency("sqlite3")
|
22
|
+
gem.add_dependency("twitter")
|
23
|
+
gem.add_dependency("slop")
|
24
|
+
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twitter_backup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- il.zoff
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: highline
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: twitter
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: slop
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: This gem will download your tweets from Twitter and save them to sqlite3
|
111
|
+
database and plaintext (yaml) archive file.
|
112
|
+
email:
|
113
|
+
- il.zoff@gmail.com
|
114
|
+
executables:
|
115
|
+
- twitter_backup
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- Gemfile
|
121
|
+
- LICENSE
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- bin/twitter_backup
|
125
|
+
- lib/twitter_backup.rb
|
126
|
+
- lib/twitter_backup/config.rb
|
127
|
+
- lib/twitter_backup/error.rb
|
128
|
+
- lib/twitter_backup/tweet.rb
|
129
|
+
- lib/twitter_backup/ui.rb
|
130
|
+
- lib/twitter_backup/version.rb
|
131
|
+
- twitter_backup.gemspec
|
132
|
+
homepage: http://github.com/ilzoff/twitter_backup
|
133
|
+
licenses: []
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 1.8.24
|
153
|
+
signing_key:
|
154
|
+
specification_version: 3
|
155
|
+
summary: Twitter archiver
|
156
|
+
test_files: []
|