tweetlr 0.0.4

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.
Files changed (6) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +35 -0
  3. data/Rakefile +44 -0
  4. data/bin/tweetlr +48 -0
  5. data/lib/tweetlr.rb +157 -0
  6. metadata +91 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ == tweetlr
2
+
3
+ Copyright (c) 2011 Sven Kraeuter sven.kraeuter@gmx.net
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # tweetlr
2
+
3
+ tweetlr crawls twitter for a given term, extracts photos out of the collected tweets' short urls and posts the images to tumblr.
4
+
5
+ ## Installation
6
+
7
+ Use `gem install tweetlr` if you're using *rubygems* or add the line `gem 'tweetlr'` to your `Gemfile` if you're using *bundler*.
8
+
9
+ ## Configuration
10
+
11
+ It's essential that you have a directory called `config` in the directory you are starting tweetlr in, which has to contain the configuration file `tweetlr.yml`:
12
+
13
+ results_per_page: 100
14
+ result_type: recent
15
+ search_term: <the term you want to search for>
16
+ twitter_timestamp: 61847783463854082 # the timestamp you want to start searching at
17
+ api_endpoint_twitter: 'http://search.twitter.com/search.json'
18
+ api_endpoint_tumblr: 'http://www.tumblr.com'
19
+ tumblr_username: <your tumblr username / e-mail address>
20
+ tumblr_password: <your tumblr password>
21
+ update_period: 300 #check for updates every 300 secs = 5 minutes
22
+ shouts: 'says' # will be concatenated after the username, before the message: @mr_x <shouts>: awesome things on a photo!
23
+ whitelist: #twitter accounts in that list will have their tweets published immediately. post from others will be saved as drafts
24
+ - whitey_mc_whitelist
25
+ - sven_kr
26
+
27
+
28
+ ## Usage
29
+
30
+ Make sure you put the configuration file in it's proper place as mentiones above, then:
31
+
32
+ start/stop tweetlr using `tweetlr start`/`tweetlr stop`. Run `tweetlr` without arguments for a list of options concerning the daemon's options.
33
+
34
+ enjoy!
35
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+
8
+ spec = Gem::Specification.new do |s|
9
+ s.name = 'tweetlr'
10
+ s.version = '0.0.4'
11
+ s.has_rdoc = true
12
+ s.extra_rdoc_files = ['README.md', 'LICENSE']
13
+ s.summary = 'an unholy alliance between twitter and 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.executables = ['your_executable_here']
19
+ s.files = %w(LICENSE README.md Rakefile) + Dir.glob("{bin,lib}/**/*")
20
+ s.require_path = "lib"
21
+ s.executables = ['tweetlr']
22
+ s.add_dependency('daemons')
23
+ s.add_dependency('eventmachine')
24
+ s.add_dependency('httparty')
25
+ end
26
+
27
+ Rake::GemPackageTask.new(spec) do |p|
28
+ p.gem_spec = spec
29
+ p.need_tar = true
30
+ p.need_zip = true
31
+ end
32
+
33
+ Rake::RDocTask.new do |rdoc|
34
+ files =['README.md', 'LICENSE', 'lib/**/*.rb']
35
+ rdoc.rdoc_files.add(files)
36
+ rdoc.main = "README.md" # page to start on
37
+ rdoc.title = "tweetlr Docs" # <--- enter name manually!
38
+ rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
39
+ rdoc.options << '--line-numbers'
40
+ end
41
+
42
+ Rake::TestTask.new do |t|
43
+ t.test_files = FileList['test/**/*.rb']
44
+ end
data/bin/tweetlr ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'daemons'
4
+ require 'eventmachine'
5
+ require 'logger'
6
+ require 'yaml'
7
+ require_relative '../lib/tweetlr.rb'
8
+
9
+ begin
10
+ config_file = File.join( Dir.pwd, 'config', 'tweetlr.yml')
11
+ CONFIG = YAML.load_file(config_file)
12
+ TERM = CONFIG['search_term']
13
+ USER = CONFIG['tumblr_username']
14
+ PW = CONFIG['tumblr_password']
15
+ TIMESTAMP = CONFIG['twitter_timestamp']
16
+ UPDATE_PERIOD = CONFIG['update_period']
17
+ rescue SystemCallError
18
+ $stderr.puts "Ooops - looks like there is no ./config/tweetlr.yml found. I'm affraid tweetlr won't work properly until you introduced that configuration file."
19
+ exit(1)
20
+ end
21
+
22
+ Daemons.run_proc('tweetlr') do
23
+ @log = Logger.new('tweetlr.log')
24
+ @log.info('starting tweetlr daemon...')
25
+ @log.info "createing a new tweetlr instance using this config: #{CONFIG.inspect}"
26
+ EventMachine::run {
27
+ tweetlr = Tweetlr.new(USER, PW, nil, TIMESTAMP, TERM, config_file)
28
+ EventMachine::add_periodic_timer( UPDATE_PERIOD ) {
29
+ @log.info('starting tweetlr crawl...')
30
+ response = tweetlr.lazy_search_twitter
31
+ tweets = response.parsed_response['results']
32
+ if tweets
33
+ tweets.each do |tweet|
34
+ tumblr_post = tweetlr.generate_tumblr_photo_post tweet
35
+ if tumblr_post.nil? || tumblr_post[:source].nil?
36
+ @log.error "could not get image source: #{tumblr_post.inspect}"
37
+ else
38
+ @log.debug tumblr_post
39
+ @log.debug tweetlr.post_to_tumblr tumblr_post
40
+ end
41
+ end
42
+ end
43
+ @log.info('finished tweetlr crawl.')
44
+ }
45
+ }
46
+
47
+ end
48
+
data/lib/tweetlr.rb ADDED
@@ -0,0 +1,157 @@
1
+ require 'httparty'
2
+ require 'logger'
3
+ require 'yaml'
4
+
5
+
6
+ class Tweetlr
7
+
8
+ GENERATOR = %{tweetlr - http://github.com/5v3n/tweetlr}
9
+
10
+ def initialize(email, password, cookie=nil, since_id=nil, term=nil, config_file) #TODO use a hash or sth more elegant here...
11
+ @log = Logger.new('tweetlr.log')
12
+ config = YAML.load_file(config_file)
13
+ @results_per_page = config['results_per_page']
14
+ @result_type = config['result_type']
15
+ @api_endpoint_twitter = config['api_endpoint_twitter']
16
+ @api_endpoint_tumblr = config['api_endpoint_tumblr']
17
+ @whitelist = config['whitelist']
18
+ @shouts = config['shouts']
19
+ @since_id = since_id
20
+ @search_term = term
21
+ @whitelist.each {|entry| entry.downcase!}
22
+ @email = email
23
+ @password = password
24
+ @term = term
25
+ @refresh_url = "#{@api_endpoint_twitter}?q=#{term}&since_id=#{since_id}" if (since_id && term)
26
+ if !cookie
27
+ response = HTTParty.post(
28
+ "#{@api_endpoint_tumblr}/login",
29
+ :body => {
30
+ :email => @email,
31
+ :password => password
32
+ }
33
+ )
34
+ @log.debug("initial login response: #{response}")
35
+ @cookie = response.headers['Set-Cookie']
36
+ @log.debug("--------login cookie via new login: #{@cookie.inspect}")
37
+ else
38
+ @cookie = cookie
39
+ @log.debug("--------login cookie via argument: #{@cookie.inspect}")
40
+ end
41
+
42
+ end
43
+
44
+ def post_to_tumblr(options={})
45
+ options[:generator] = GENERATOR
46
+ options[:email] = @email #TODO get cookie auth working!
47
+ options[:password] = @password
48
+ #options[:headers] = {'Cookie' => @cookie}
49
+ #arguments=options.collect { |key, value| "#{key}=#{value}" }.join('&')
50
+ @log.debug("------------********** post_to_tumblr options: #{options.inspect}")
51
+ @log.debug("------------********** post_to_tumblr options: #{{'Cookie' => @cookie}.inspect}")
52
+ response = HTTParty.post("#{@api_endpoint_tumblr}/api/write", :body => options, :headers => {'Cookie' => @cookie})
53
+ @log.debug("------------********** post_to_tumblr response: #{response.inspect}" )
54
+ response
55
+ end
56
+
57
+ #fire a new search
58
+ def search_twitter()
59
+ search_call = "#{@api_endpoint_twitter}?q=#{@search_term}&result_type=#{@result_type}&rpp=#{@results_per_page}"
60
+ @response = HTTParty.get(search_call)
61
+ end
62
+ # lazy update - search for a term or refresh the search if a response is available already
63
+ def lazy_search_twitter()
64
+ @refresh_url = "#{@api_endpoint_twitter}#{@response['refresh_url']}" unless (@response.nil? || @response['refresh_url'].nil? || @response['refresh_url'].empty?)
65
+ if @refresh_url
66
+ #FIXME persist the refresh url - server restart would be a pain elsewise
67
+ @log.info "lazy search using '#{@refresh_url}'"
68
+ @response = HTTParty.get(@refresh_url)
69
+ else
70
+ @log.debug "regular search using '#{term}'"
71
+ @response = search_twitter()
72
+ end
73
+ end
74
+
75
+ #extract the linked image file's url
76
+ def extract_image_url(tweet)
77
+ link = extract_link tweet
78
+ url = nil
79
+ if link
80
+ url = image_url_instagram link if (link.index('instagr.am') || link.index('instagram.com'))
81
+ url = image_url_picplz link if link.index 'picplz'
82
+ url = image_url_twitpic link if link.index 'twitpic'
83
+ url = image_url_yfrog link if link.index 'yfrog'
84
+ end
85
+ url
86
+ end
87
+
88
+ #find the image's url for an instagram link
89
+ def image_url_instagram(link_url)
90
+ link_url['instagram.com'] = 'instagr.am' if link_url.index 'instagram.com' #instagram's oembed does not work for .com links
91
+ response = HTTParty.get "http://api.instagram.com/oembed?url=#{link_url}"
92
+ response.parsed_response['url']
93
+ end
94
+
95
+ #find the image's url for a picplz short/longlink
96
+ def image_url_picplz(link_url)
97
+ id = extract_id link_url
98
+ #try short url
99
+ response = HTTParty.get "http://picplz.com/api/v2/pic.json?shorturl_ids=#{id}"
100
+ #if short url fails, try long url
101
+ #response = HTTParty.get "http://picplz.com/api/v2/pic.json?longurl_ids=#{id}"
102
+ #extract url
103
+ response['value']['pics'].first['pic_files']['640r']['img_url']
104
+ end
105
+ #find the image's url for a twitpic link
106
+ def image_url_twitpic(link_url)
107
+ "http://twitpic.com/show/full/#{extract_id link_url}"
108
+ end
109
+ #find the image'S url for a yfrog link
110
+ def image_url_yfrog(link_url)
111
+ response = HTTParty.get("http://www.yfrog.com/api/oembed?url=#{link_url}")
112
+ response.parsed_response['url']
113
+ end
114
+
115
+ #extract the pic id from a given <code>link</code>
116
+ def extract_id(link)
117
+ link.split('/').last if link.split('/')
118
+ end
119
+
120
+ #extract the link from a given tweet
121
+ def extract_link(tweet)
122
+ if tweet
123
+ text = tweet['text']
124
+ start = text.index('http') if text
125
+ if start
126
+ stop = text.index(' ', start) || 0
127
+ text[start..stop-1]
128
+ end
129
+ end
130
+ end
131
+
132
+ def generate_tumblr_photo_post tweet
133
+ tumblr_post = nil
134
+ message = tweet['text']
135
+ if message && !message.index('RT @') #discard retweets
136
+ @log.debug "tweet: #{tweet}"
137
+ tumblr_post = {}
138
+ tumblr_post[:type] = 'photo'
139
+ tumblr_post[:date] = tweet['created_at']
140
+ tumblr_post[:source] = extract_image_url tweet
141
+ user = tweet['from_user']
142
+ if @whitelist.member? user.downcase
143
+ state = 'published'
144
+ else
145
+ state = 'draft'
146
+ end
147
+ tumblr_post[:state] = state
148
+ tumblr_post[:caption] = %?@#{user} #{@shouts}: #{tweet['text']}? #TODO make this a bigger matter of yml configuration
149
+ end
150
+ tumblr_post
151
+ end
152
+
153
+ end
154
+
155
+
156
+
157
+
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tweetlr
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.4
6
+ platform: ruby
7
+ authors:
8
+ - Sven Kraeuter
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-23 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: daemons
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: eventmachine
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: httparty
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ description: an unholy alliance between twitter and tumblr
49
+ email: mail@svenkraeuter.com
50
+ executables:
51
+ - tweetlr
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - README.md
56
+ - LICENSE
57
+ files:
58
+ - LICENSE
59
+ - README.md
60
+ - Rakefile
61
+ - bin/tweetlr
62
+ - lib/tweetlr.rb
63
+ homepage: http://github.com/5v3n/tweetlr
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.7.2
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: an unholy alliance between twitter and tumblr
90
+ test_files: []
91
+