tweetlr 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,3 @@
1
+ # Include plugins
2
+ require 'autotest/fsevent'
3
+ require 'autotest/growl'
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ *.swp
2
+ *.log
3
+ pkg
4
+ *.pid
5
+ config
6
+ *.output
7
+ .rvmrc
8
+ Gemfile.lock
9
+ tweetlr.tid
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Rakefile CHANGED
@@ -1,43 +1,21 @@
1
- require 'rubygems'
2
- require 'rake'
3
- require 'rake/clean'
4
- require 'rubygems/package_task'
5
- require 'rdoc/task'
6
- require 'rake/testtask'
7
-
8
- spec = Gem::Specification.new do |s|
9
- s.name = 'tweetlr'
10
- s.version = '0.1.2'
11
- s.has_rdoc = true
12
- s.extra_rdoc_files = ['README.md', 'LICENSE']
13
- s.summary = %{tweetlr crawls twitter for a given term, extracts photos out of the collected tweets' short urls and posts the images to tumblr.}
14
- s.description = s.summary
15
- s.author = 'Sven Kraeuter'
16
- s.email = 'mail@svenkraeuter.com'
17
- s.homepage = "http://github.com/5v3n/#{s.name}"
18
- s.files = %w(LICENSE README.md Rakefile) + Dir.glob("{bin,lib}/**/*")
19
- s.require_path = "lib"
20
- s.executables = ['tweetlr']
21
- s.add_dependency('daemons')
22
- s.add_dependency('eventmachine')
23
- s.add_dependency('curb')
24
- end
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
25
3
 
26
- Gem::PackageTask.new(spec) do |p|
27
- p.gem_spec = spec
28
- p.need_tar = true
29
- p.need_zip = true
30
- end
4
+ require 'rdoc/task'
5
+ require 'rspec/core/rake_task'
31
6
 
32
7
  RDoc::Task.new do |rdoc|
33
- files =['README.md', 'LICENSE', 'lib/**/*.rb']
8
+ files = ['README.md', 'LICENSE', 'lib/**/*.rb']
34
9
  rdoc.rdoc_files.add(files)
35
- rdoc.main = "README.md" # page to start on
36
- rdoc.title = "tweetlr Docs" # <--- enter name manually!
37
- rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
10
+ rdoc.main = "README.md" # page to start on
11
+ rdoc.title = "tweetlr Docs" # <--- enter name manually!
12
+ rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
38
13
  rdoc.options << '--line-numbers'
39
14
  end
40
15
 
41
- Rake::TestTask.new do |t|
42
- t.test_files = FileList['test/**/*.rb']
16
+ RSpec::Core::RakeTask.new do |t|
17
+ t.rspec_opts = %w(-c)
43
18
  end
19
+
20
+ task :default => :spec
21
+ task :test => :spec
data/bin/tweetlr CHANGED
@@ -4,15 +4,25 @@ require 'daemons'
4
4
  require 'eventmachine'
5
5
  require 'logger'
6
6
  require 'yaml'
7
- require_relative '../lib/tweetlr.rb'
7
+ require 'tweetlr'
8
8
 
9
9
  begin
10
10
  config_file = File.join( Dir.pwd, 'config', 'tweetlr.yml')
11
+ tid_file = File.join( Dir.pwd ,"tweetlr.tid")
12
+ start_at_tweet_id = lambda {
13
+ begin
14
+ File.open(tid_file, "r") { |io| io.gets.to_i }
15
+ rescue Errno::ENOENT => e
16
+ $stderr.puts "#{e} - we use the value from the configuration file"
17
+ nil
18
+ end
19
+ }.call
11
20
  CONFIG = YAML.load_file(config_file)
21
+ CONFIG['start_at_tweet_id'] = start_at_tweet_id || CONFIG['start_at_tweet_id'] || CONFIG['twitter_timestamp'] #check the latter for backwards compability
12
22
  TERM = CONFIG['search_term']
13
23
  USER = CONFIG['tumblr_username']
14
24
  PW = CONFIG['tumblr_password']
15
- TIMESTAMP = CONFIG['twitter_timestamp']
25
+ TIMESTAMP = start_at_tweet_id || CONFIG['start_at_tweet_id']
16
26
  UPDATE_PERIOD = CONFIG['update_period']
17
27
  LOGLEVEL = CONFIG['loglevel'] || Logger::INFO
18
28
  @tweetlr = Tweetlr.new(USER, PW, config_file, {:since_id => TIMESTAMP, :terms => TERM, :loglevel => LOGLEVEL})
@@ -37,20 +47,18 @@ Daemons.run_proc('tweetlr', :dir_mode => :script, :dir => './', :backtrace => tr
37
47
  if tumblr_post.nil? || tumblr_post[:source].nil?
38
48
  @log.warn "could not get image source: tweet: #{tweet} --- tumblr post: #{tumblr_post.inspect}"
39
49
  else
40
- #@log.debug tumblr_post
41
- #@log.debug @tweetlr.post_to_tumblr tumblr_post
42
- #puts "tumblr post: #{tumblr_post}"
50
+ @log.debug "tumblr post: #{tumblr_post}"
43
51
  res = @tweetlr.post_to_tumblr tumblr_post
44
52
  @log.warn "tumblr response: #{res.header_str} #{res.body_str}" unless res.response_code == 201
45
53
  end
54
+ # save the last received tweet id to tweetlr.tid
55
+ File.open(tid_file, "w+") { |io| io.write(tweets.last['id']) }
46
56
  end
47
57
  end
48
58
  else
49
- @log.error "twitter serach returned no response. hail the failwhale!"
59
+ @log.error "twitter search returned no response. hail the failwhale!"
50
60
  end
51
61
  @log.info "finished tweetlr crawl."
52
62
  }
53
63
  }
54
-
55
- end
56
-
64
+ end
@@ -0,0 +1,14 @@
1
+ results_per_page: 100
2
+ result_type: recent
3
+ search_term: 'cat+dog+unicorn' #find tweets containing any of these terms
4
+ start_at_tweet_id: 61847783463854082 # the tweet id to start searching at
5
+ api_endpoint_twitter: 'http://search.twitter.com/search.json'
6
+ api_endpoint_tumblr: 'http://www.tumblr.com'
7
+ tumblr_username: YOUR_TUMBLR_EMAIL
8
+ tumblr_password: YOUR_TUMBLR_PW
9
+ update_period: 300 #check for updates every 300 secs = 5 minutes
10
+ shouts: 'says' # will be concatenated after the username, before the message: @mr_x says: awesome things on a photo!
11
+ loglevel: 0 # 0: debug, 1: info (default), 2: warn, 3: error, 5: fatal
12
+ whitelist: #twitter accounts in that list will have their tweets published immediately. post from others will be saved as drafts
13
+ - whitey_mc_whitelist
14
+ - sven_kr
data/lib/tweetlr.rb CHANGED
@@ -5,9 +5,9 @@ require 'json'
5
5
 
6
6
  class Tweetlr
7
7
 
8
- VERSION = '0.1.2'
8
+ VERSION = '0.1.3'
9
9
  GENERATOR = %{tweetlr - http://github.com/5v3n/tweetlr}
10
- USER_AGENT = %{Mozilla/5.0 (compatible; tweetlr/#{VERSION};)}
10
+ USER_AGENT = %{Mozilla/5.0 (compatible; tweetlr/#{VERSION}; +http://github.com/5v3n/tweetlr/wiki)}
11
11
  LOCATION_START_INDICATOR = 'Location: '
12
12
  LOCATION_STOP_INDICATOR = "\r\n"
13
13
 
@@ -144,14 +144,20 @@ class Tweetlr
144
144
  url = image_url_tco link if link.index 't.co'
145
145
  url = image_url_lockerz link if link.index 'lockerz.com'
146
146
  url = image_url_foursquare link if link.index '4sq.com'
147
+ url = image_url_embedly link if url.nil? #just try embed.ly for anything else. could do all image url processing w/ embedly, but there's probably some kind of rate limit invovled.
147
148
  end
148
149
  url
149
150
  end
150
- #find the image's url for a foursquare link
151
- def image_url_foursquare(link_url)
151
+
152
+ #find the image's url via embed.ly
153
+ def image_url_embedly(link_url)
152
154
  response = http_get "http://api.embed.ly/1/oembed?url=#{link_url}"
153
155
  response['url'] if response
154
156
  end
157
+ #find the image's url for a foursquare link
158
+ def image_url_foursquare(link_url)
159
+ image_url_embedly link_url
160
+ end
155
161
  #find the image's url for a lockerz link
156
162
  def image_url_lockerz(link_url)
157
163
  response = http_get "http://api.plixi.com/api/tpapi.svc/json/metadatafromurl?details=false&url=#{link_url}"
@@ -239,7 +245,12 @@ class Tweetlr
239
245
  curl = Curl::Easy.new request
240
246
  curl.useragent = USER_AGENT
241
247
  curl.perform
242
- JSON.parse curl.body_str
248
+ begin
249
+ JSON.parse curl.body_str
250
+ rescue JSON::ParserError => err
251
+ @log.warn "#{err}: Could not parse response for #{request} - this is probably not a json response: #{curl.body_str}"
252
+ return nil
253
+ end
243
254
  rescue Curl::Err::ConnectionFailedError => err
244
255
  @log.error "Connection failed: #{err}"
245
256
  tries -= 1
@@ -267,6 +278,6 @@ class Tweetlr
267
278
  else
268
279
  nil
269
280
  end
270
- end
281
+ end
271
282
  end
272
283
  end
@@ -0,0 +1,2 @@
1
+ require "bundler"
2
+ Bundler.require :default, :development
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tweetlr do
4
+
5
+ config_file = File.join( Dir.pwd, 'config', 'tweetlr.yml')
6
+ config = YAML.load_file(config_file)
7
+ USER = config['tumblr_username']
8
+ PW = config['tumblr_password']
9
+ TIMESTAMP = config['twitter_timestamp']
10
+
11
+ before :each do
12
+ @credentials = {:email => USER, :password => PW}
13
+ @cookie = "tmgioct=as3u4KJr9COyJA9j4nwr6ZAn"
14
+ @searchterm = 'fail'
15
+ @twitter_response = {"from_user_id_str"=>"1915714", "profile_image_url"=>"http://a0.twimg.com/profile_images/386000279/2_normal.jpg", "created_at"=>"Sun, 17 Apr 2011 16:48:42 +0000", "from_user"=>"whitey_Mc_whIteLIst", "id_str"=>"59659561224765440", "metadata"=>{"result_type"=>"recent"}, "to_user_id"=>nil, "text"=>"Rigaer #wirsounterwegs @ Augenarzt Dr. Lierow http://instagr.am/p/DzCWn/", "id"=>59659561224765440, "from_user_id"=>1915714, "geo"=>{"type"=>"Point", "coordinates"=>[52.5182, 13.454]}, "iso_language_code"=>"de", "place"=>{"id"=>"3078869807f9dd36", "type"=>"city", "full_name"=>"Berlin, Berlin"}, "to_user_id_str"=>nil, "source"=>"&lt;a href=&quot;http://instagr.am&quot; rel=&quot;nofollow&quot;&gt;instagram&lt;/a&gt;"}
16
+ @non_whitelist_tweet = @twitter_response.merge 'from_user' => 'nonwhitelist user'
17
+ @retweet = @twitter_response.merge "text" => "bla bla RT @fgd: tueddelkram"
18
+ @new_style_retweet = @twitter_response.merge "text" => "and it scales! \u201c@moeffju: http://t.co/8gUSPKu #hktbl1 #origami success! :)\u201d"
19
+ @links = {
20
+ :instagram => "http://instagr.am/p/DzCWn/",
21
+ :twitpic => "http://twitpic.com/449o2x",
22
+ :yfrog => "http://yfrog.com/h4vlfp",
23
+ :picplz => "http://picplz.com/2hWv",
24
+ :imgly => "http://img.ly/3M1o",
25
+ :tco => 'http://t.co/MUGNayA',
26
+ :lockerz => 'http://lockerz.com/s/100269159',
27
+ :foursquare => 'http://4sq.com/mLKDdF',
28
+ :embedly => 'http://flic.kr/p/973hTv' #if no service matches, just try embedly
29
+ }
30
+ @pic_regexp = /(.*?)\.(jpg|jpeg|png|gif)$/i
31
+ @config_file = File.join( Dir.pwd, 'config', 'tweetlr.yml')
32
+ @tweetlr = Tweetlr.new(USER, PW, @config_file, {:since_id => TIMESTAMP, :terms => @searchterm, :loglevel => 4, :cookie => @cookie})
33
+ end
34
+ # it "should post to tumblr" do
35
+ # tweetlr = Tweetlr.new @credentials[:email], @credentials[:password], @cookie, nil, @searchterm, @config_file
36
+ # tumblr_post = tweetlr.generate_tumblr_photo_post @twitter_response
37
+ # tumblr_post[:date] = Time.now.to_s
38
+ # response = tweetlr.post_to_tumblr tumblr_post
39
+ # response.should be
40
+ # response.response_code.should be 201
41
+ # end
42
+ it "should search twitter for a given term" do
43
+ tweetlr = @tweetlr
44
+ response = tweetlr.search_twitter
45
+ tweets = response['results']
46
+ tweets.should be
47
+ tweets.should_not be_empty
48
+ end
49
+ it "should mark whitelist users' tweets as published" do
50
+ post = @tweetlr.generate_tumblr_photo_post @twitter_response
51
+ post[:state].should == 'published'
52
+ end
53
+ it "should mark non whitelist users' tweets as drafts" do
54
+ post = @tweetlr.generate_tumblr_photo_post @non_whitelist_tweet
55
+ post[:state].should == 'draft'
56
+ end
57
+ it "should not use retweets which would produce double blog posts" do
58
+ post = @tweetlr.generate_tumblr_photo_post @retweet
59
+ post.should_not be
60
+ end
61
+ it "should not use new style retweets which would produce double blog posts" do
62
+ post = @tweetlr.generate_tumblr_photo_post @new_style_retweet
63
+ post.should_not be
64
+ end
65
+ describe "image url processing" do
66
+ it "should find a picture's url from the supported services" do
67
+ @links.each do |key,value|
68
+ url = @tweetlr.find_image_url value
69
+ url.should be, "service #{key} not working!"
70
+ check_pic_url_extraction key if [:instagram,:picplz,:yfrog,:tco,:foursquare, :not_listed].index key
71
+ end
72
+ end
73
+ it "should not crash if embedly fallback won't find a link" do
74
+ url = @tweetlr.find_image_url "http://mopskopf"
75
+ end
76
+ end
77
+ describe "tweet api response processing" do
78
+ it "should extract links" do
79
+ tweetlr = @tweetlr
80
+ link = tweetlr.extract_link @twitter_response
81
+ link.should == @links[:instagram]
82
+ link = tweetlr.extract_link @twitter_response.merge 'text' => @links[:instagram].chop #check if it works w/o the trailing slash
83
+ link.should == @links[:instagram].chop
84
+ end
85
+ end
86
+ def check_pic_url_extraction(service)
87
+ tweetlr = @tweetlr
88
+ image_url = tweetlr.send "image_url_#{service}".to_sym, @links[service]
89
+ image_url.should =~ @pic_regexp
90
+ end
91
+
92
+ end
93
+
data/tweetlr.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "tweetlr"
3
+ s.version = "0.1.3"
4
+ s.author = "Sven Kraeuter"
5
+ s.email = "mail@svenkraeuter.com"
6
+ s.homepage = "http://github.com/5v3n/#{s.name}"
7
+ s.summary = "tweetlr crawls twitter for a given term, extracts photos out of the collected tweets' short urls and posts the images to tumblr."
8
+ s.description = s.summary
9
+
10
+ s.rubyforge_project = s.name
11
+ s.extra_rdoc_files = %w(README.md LICENSE)
12
+
13
+ s.add_dependency "daemons", "~> 1.1.3"
14
+ s.add_dependency "eventmachine", "~> 0.12.10"
15
+ s.add_dependency "curb", "~> 0.7.15"
16
+ s.add_dependency "json", "~> 1.5.1"
17
+
18
+ s.add_development_dependency "rspec", "~> 2.6.0"
19
+ s.add_development_dependency "autotest", "~> 4.4.6"
20
+ s.add_development_dependency "autotest-growl", "~> 0.2.9"
21
+ s.add_development_dependency "autotest-fsevent", "~> 0.2.5"
22
+ s.add_development_dependency "rdoc"
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tweetlr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,42 +9,108 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-06-06 00:00:00.000000000 +02:00
12
+ date: 2011-06-14 00:00:00.000000000 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: daemons
17
- requirement: &2156428160 !ruby/object:Gem::Requirement
17
+ requirement: &2153694000 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
- - - ! '>='
20
+ - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: '0'
22
+ version: 1.1.3
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2156428160
25
+ version_requirements: *2153694000
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: eventmachine
28
- requirement: &2156427180 !ruby/object:Gem::Requirement
28
+ requirement: &2153693520 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
- - - ! '>='
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.12.10
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *2156427180
36
+ version_requirements: *2153693520
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: curb
39
- requirement: &2156426180 !ruby/object:Gem::Requirement
39
+ requirement: &2153693060 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 0.7.15
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *2153693060
48
+ - !ruby/object:Gem::Dependency
49
+ name: json
50
+ requirement: &2153692600 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 1.5.1
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *2153692600
59
+ - !ruby/object:Gem::Dependency
60
+ name: rspec
61
+ requirement: &2153692140 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 2.6.0
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *2153692140
70
+ - !ruby/object:Gem::Dependency
71
+ name: autotest
72
+ requirement: &2153691680 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 4.4.6
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *2153691680
81
+ - !ruby/object:Gem::Dependency
82
+ name: autotest-growl
83
+ requirement: &2153691220 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: 0.2.9
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: *2153691220
92
+ - !ruby/object:Gem::Dependency
93
+ name: autotest-fsevent
94
+ requirement: &2153713280 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ~>
98
+ - !ruby/object:Gem::Version
99
+ version: 0.2.5
100
+ type: :development
101
+ prerelease: false
102
+ version_requirements: *2153713280
103
+ - !ruby/object:Gem::Dependency
104
+ name: rdoc
105
+ requirement: &2153712900 !ruby/object:Gem::Requirement
40
106
  none: false
41
107
  requirements:
42
108
  - - ! '>='
43
109
  - !ruby/object:Gem::Version
44
110
  version: '0'
45
- type: :runtime
111
+ type: :development
46
112
  prerelease: false
47
- version_requirements: *2156426180
113
+ version_requirements: *2153712900
48
114
  description: tweetlr crawls twitter for a given term, extracts photos out of the collected
49
115
  tweets' short urls and posts the images to tumblr.
50
116
  email: mail@svenkraeuter.com
@@ -55,11 +121,19 @@ extra_rdoc_files:
55
121
  - README.md
56
122
  - LICENSE
57
123
  files:
124
+ - .autotest
125
+ - .gitignore
126
+ - .rspec
127
+ - Gemfile
58
128
  - LICENSE
59
129
  - README.md
60
130
  - Rakefile
61
131
  - bin/tweetlr
132
+ - config/tweetlr.yml
62
133
  - lib/tweetlr.rb
134
+ - spec/spec_helper.rb
135
+ - spec/tweetlr_spec.rb
136
+ - tweetlr.gemspec
63
137
  has_rdoc: true
64
138
  homepage: http://github.com/5v3n/tweetlr
65
139
  licenses: []
@@ -80,10 +154,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
154
  - !ruby/object:Gem::Version
81
155
  version: '0'
82
156
  requirements: []
83
- rubyforge_project:
157
+ rubyforge_project: tweetlr
84
158
  rubygems_version: 1.6.2
85
159
  signing_key:
86
160
  specification_version: 3
87
161
  summary: tweetlr crawls twitter for a given term, extracts photos out of the collected
88
162
  tweets' short urls and posts the images to tumblr.
89
- test_files: []
163
+ test_files:
164
+ - spec/spec_helper.rb
165
+ - spec/tweetlr_spec.rb