ubiquitously 0.0.1.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/README.markdown +224 -19
  2. data/Rakefile +12 -4
  3. data/bin/u.me +4 -0
  4. data/lib/ubiquitously.rb +56 -7
  5. data/lib/ubiquitously/commands/base.rb +118 -0
  6. data/lib/ubiquitously/commands/post.rb +108 -0
  7. data/lib/ubiquitously/commands/user.rb +111 -0
  8. data/lib/ubiquitously/extensions/callbacks.rb +62 -0
  9. data/lib/ubiquitously/extensions/core.rb +88 -0
  10. data/lib/ubiquitously/extensions/mechanize.rb +35 -0
  11. data/lib/ubiquitously/models/base.rb +18 -0
  12. data/lib/ubiquitously/models/page.rb +28 -0
  13. data/lib/ubiquitously/models/post.rb +66 -0
  14. data/lib/ubiquitously/models/service.rb +1 -0
  15. data/lib/ubiquitously/models/service/account.rb +57 -0
  16. data/lib/ubiquitously/models/service/account/authorizable.rb +58 -0
  17. data/lib/ubiquitously/models/service/account/loggable.rb +50 -0
  18. data/lib/ubiquitously/models/service/account/restful.rb +21 -0
  19. data/lib/ubiquitously/models/service/post.rb +59 -0
  20. data/lib/ubiquitously/models/service/post/loggable.rb +64 -0
  21. data/lib/ubiquitously/models/service/post/ownable.rb +31 -0
  22. data/lib/ubiquitously/models/service/post/postable.rb +73 -0
  23. data/lib/ubiquitously/models/service/post/restful.rb +52 -0
  24. data/lib/ubiquitously/models/user.rb +128 -0
  25. data/lib/ubiquitously/services/blogger_den.rb +68 -0
  26. data/lib/ubiquitously/services/chetzit.rb +37 -0
  27. data/lib/ubiquitously/services/code_project.rb +21 -0
  28. data/lib/ubiquitously/services/delicious.rb +54 -0
  29. data/lib/ubiquitously/services/design_bump.rb +41 -0
  30. data/lib/ubiquitously/services/designgizer.rb +21 -0
  31. data/lib/ubiquitously/services/designr_fix.rb +21 -0
  32. data/lib/ubiquitously/services/digg.rb +151 -0
  33. data/lib/ubiquitously/services/digzign.rb +25 -0
  34. data/lib/ubiquitously/services/diigo.rb +68 -0
  35. data/lib/ubiquitously/services/dzone.rb +132 -0
  36. data/lib/ubiquitously/services/dzone_snippets.rb +39 -0
  37. data/lib/ubiquitously/services/facebook.rb +42 -0
  38. data/lib/ubiquitously/services/faves.rb +81 -0
  39. data/lib/ubiquitously/services/favshare.rb +78 -0
  40. data/lib/ubiquitously/services/flikode.rb +38 -0
  41. data/lib/ubiquitously/services/friendfeed.rb +21 -0
  42. data/lib/ubiquitously/services/gist.rb +52 -0
  43. data/lib/ubiquitously/services/google_buzz.rb +15 -0
  44. data/lib/ubiquitously/services/identica.rb +15 -0
  45. data/lib/ubiquitously/services/jump_tags.rb +21 -0
  46. data/lib/ubiquitously/services/kailoon.rb +27 -0
  47. data/lib/ubiquitously/services/meta_filter.rb +26 -0
  48. data/lib/ubiquitously/services/mixx.rb +94 -0
  49. data/lib/ubiquitously/services/mmo.rb +22 -0
  50. data/lib/ubiquitously/services/mvc_forge.rb +37 -0
  51. data/lib/ubiquitously/services/my_space.rb +25 -0
  52. data/lib/ubiquitously/services/nestdev.rb +36 -0
  53. data/lib/ubiquitously/services/newsvine.rb +76 -0
  54. data/lib/ubiquitously/services/pixel_groovy.rb +22 -0
  55. data/lib/ubiquitously/services/posterous.rb +24 -0
  56. data/lib/ubiquitously/services/programmers_heaven.rb +21 -0
  57. data/lib/ubiquitously/{propeller.rb → services/propeller.rb} +17 -26
  58. data/lib/ubiquitously/services/queness.rb +38 -0
  59. data/lib/ubiquitously/services/reddit.rb +62 -0
  60. data/lib/ubiquitously/services/scribd.rb +21 -0
  61. data/lib/ubiquitously/services/script_and_style.rb +23 -0
  62. data/lib/ubiquitously/services/sharebrain.rb +19 -0
  63. data/lib/ubiquitously/services/shoutwire.rb +34 -0
  64. data/lib/ubiquitously/services/slideshare.rb +70 -0
  65. data/lib/ubiquitously/services/smipple.rb +21 -0
  66. data/lib/ubiquitously/services/snipplr.rb +67 -0
  67. data/lib/ubiquitously/services/snipt.rb +49 -0
  68. data/lib/ubiquitously/services/sphinn.rb +24 -0
  69. data/lib/ubiquitously/services/stumble_upon.rb +67 -0
  70. data/lib/ubiquitously/services/stumpedia.rb +13 -0
  71. data/lib/ubiquitously/services/tumblr.rb +28 -0
  72. data/lib/ubiquitously/services/tweako.rb +53 -0
  73. data/lib/ubiquitously/services/twitter.rb +60 -0
  74. data/lib/ubiquitously/services/web_blend.rb +25 -0
  75. data/lib/ubiquitously/services/webdev5.rb +32 -0
  76. data/lib/ubiquitously/services/who_freelance.rb +21 -0
  77. data/lib/ubiquitously/services/wordtaps.rb +36 -0
  78. data/lib/ubiquitously/services/yahoo_buzz.rb +64 -0
  79. data/lib/ubiquitously/services/youblr.rb +15 -0
  80. data/lib/ubiquitously/services/zabox.rb +22 -0
  81. data/lib/ubiquitously/support/active_record.rb +25 -0
  82. data/lib/ubiquitously/support/storage.rb +71 -0
  83. data/test/config/cookies.yml +111 -0
  84. data/test/config/credentials.yml +7 -0
  85. data/test/config/secrets.yml +33 -0
  86. data/test/config/tokens.yml +30 -0
  87. data/test/meta.html +19 -0
  88. data/test/test_delicious.rb +37 -0
  89. data/test/test_digg.rb +57 -0
  90. data/test/test_dzone.rb +23 -18
  91. data/test/test_facebook.rb +40 -0
  92. data/test/test_faves.rb +18 -20
  93. data/test/test_helper.rb +8 -1
  94. data/test/test_newsvine.rb +3 -3
  95. data/test/test_page.rb +21 -0
  96. data/test/test_post.rb +55 -0
  97. data/test/test_propeller.rb +2 -2
  98. data/test/test_reddit.rb +26 -4
  99. data/test/test_stumble_upon.rb +23 -3
  100. data/test/test_twitter.rb +33 -0
  101. data/test/test_user.rb +22 -0
  102. metadata +199 -24
  103. data/lib/ext.rb +0 -37
  104. data/lib/ubiquitously/base.rb +0 -56
  105. data/lib/ubiquitously/dzone.rb +0 -111
  106. data/lib/ubiquitously/faves.rb +0 -43
  107. data/lib/ubiquitously/mister_wong.rb +0 -11
  108. data/lib/ubiquitously/mixins/resourceful.rb +0 -50
  109. data/lib/ubiquitously/mixx.rb +0 -66
  110. data/lib/ubiquitously/newsvine.rb +0 -54
  111. data/lib/ubiquitously/reddit.rb +0 -46
  112. data/lib/ubiquitously/sphinn.rb +0 -11
  113. data/lib/ubiquitously/stumble_upon.rb +0 -61
  114. data/test/config.yml +0 -18
@@ -0,0 +1,151 @@
1
+ # digg now uses oauth, so switch when we have oauth through terminal
2
+ module Ubiquitously
3
+ module Digg
4
+ class Account < Ubiquitously::Service::Account
5
+ def login
6
+ page = agent.get("http://digg.com/login")
7
+ form = page.form_with(:action => "/login/prepare/digg")
8
+ form["username"] = username
9
+ form["password"] = password
10
+ page = form.submit
11
+
12
+ authorize!(page.title =~ /The Latest News/i)
13
+ end
14
+ end
15
+
16
+ class Post < Ubiquitously::Service::Post
17
+ submit_to "http://digg.com/submit?phase=2&url=:url&title=:title&bodytext=:description&topic=26"
18
+
19
+ def create
20
+ # url
21
+ page = agent.get("http://digg.com/submit/")
22
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
23
+
24
+ form["url"] = url
25
+ form.radiobuttons_with(:name => "type").each do |checkbox|
26
+ checkbox.check if checkbox.value.to_s == "0"
27
+ end
28
+
29
+ page = form.submit
30
+
31
+ key = page.parser.css("input#key").first["value"]
32
+
33
+ # http://digg.com/submit/processing?key=171a6601a6690e7105122a4f02242dd6&type=Crawl
34
+ # redirects you to "http://digg.com/submit/details?key=#{key}"
35
+ page = agent.get("http://digg.com/submit/dupes?key=#{key}", [], "http://digg.com/submit/processing?key=#{key}type=Crawl")
36
+
37
+ form["title"] = title
38
+ form["body"] = description # 350 chars max
39
+ form["topic"] = "26"
40
+
41
+ captcha_image = page.parser.css("img.captcha").first["src"]
42
+ captcha_id = page.parser.css("input#captchaid").first["value"]
43
+ # open browser with captcha image
44
+ # need to pass cookies
45
+ image = agent.get("http://digg.com#{captcha_image}")
46
+ image_path = "digg-image-#{key}.jpg"
47
+
48
+ # instead of writing it, you could do a trick to
49
+ # post a url with javascript that adds the cookie information, and then
50
+ # redirects you to the image url:
51
+ # path = http://some-site.com/?code="<script>document.cookie = #{agent.cookies}</script>"
52
+ # system("open", path)
53
+ File.open(image_path, "w+") { |f| f.puts image.body }
54
+ system("open", image_path)
55
+
56
+ # enter captcha response in terminal
57
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
58
+ File.delete(image_path) if File.exists?(image_path)
59
+
60
+ form["captchaid"] = captcha_id
61
+ form["captchatext"] = captcha_says
62
+ form["thumbnail"] = image if image
63
+
64
+ unless debug?
65
+ form.action = "http://digg.com/submit/details?key=#{key}"
66
+ page = form.submit
67
+ end
68
+ # has captcha, not done with this
69
+ true
70
+ end
71
+
72
+ def update
73
+ key = nil
74
+ page = agent.get(remote.service_url)
75
+ page.parser.css("script").each do |script|
76
+ if script["src"] =~ /http:\/\/digg\.com\/dynjs\/loader/
77
+ key = agent.get(script["src"]).body.match(/tokens\.digg\.perform\s+=\s+"([^"]+)"/)[1]
78
+ end
79
+ end
80
+ location = page.body.match(/D\.meta\.page\.type\s+=\s+"([^"]+)"/)[1]
81
+ headers = {
82
+ "X-Requested-With" => "XMLHttpRequest",
83
+ "Accept" => "application/json, text/javascript",
84
+ "Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8",
85
+ "Pragma" => "no-cache",
86
+ "Cache-Control" => "no-cache",
87
+ "Accept-Encoding" => "gzip,deflate",
88
+ "Referer" => self.remote.service_url
89
+ }
90
+ params = {
91
+ "location" => location,
92
+ "token" => key,
93
+ "itemid" => remote.service_id
94
+ }
95
+
96
+ begin
97
+ page = agent.post("http://digg.com/ajax/digg/perform", params, headers)
98
+ rescue Exception => e
99
+ puts e.page.body
100
+ end
101
+
102
+ true
103
+ end
104
+
105
+ class << self
106
+ def find(options = {})
107
+ url = options[:url]
108
+ raise ArgumentError.new("Please give #{service} a url") if url.blank?
109
+ urls = url_permutations(options[:url])
110
+ user = options[:user]
111
+ records = []
112
+ # search = "http://services.digg.com/1.0/endpoint?method=search.stories&query=#{url}"
113
+ link = "http://services.digg.com/1.0/endpoint?method=story.getAll&link=#{url}"
114
+
115
+ xml = Nokogiri::XML(user.agent.get(link).body)
116
+
117
+ xml.css("story").each do |node|
118
+ service_url = node["href"]
119
+ service_id = node["id"]
120
+ url = node["link"]
121
+ votes = node["diggs"].to_i
122
+ title = node.css("title").first.text
123
+ description = node.css("description").first.text
124
+ categories = [node.css("container").first["name"]] rescue []
125
+ categories << node.css("topic").first["name"] rescue nil
126
+ categories.flatten!
127
+ record = new(
128
+ :title => title,
129
+ :url => url,
130
+ :description => description,
131
+ :categories => categories,
132
+ :service_url => service_url,
133
+ :service_id => service_id,
134
+ :upvotes => votes,
135
+ :user => user
136
+ )
137
+ records << record if urls.include?(record.url)
138
+ end
139
+
140
+ records.sort! { |a, b| b.upvotes <=> a.upvotes }
141
+
142
+ if options[:url]
143
+ records.first
144
+ else
145
+ records
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,25 @@
1
+ module Ubiquitously
2
+ module Digzign
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ return true if logged_in?
6
+
7
+ page = agent.get("http://digzign.com/login")
8
+ form = page.form_with(:name => "loginform")
9
+ form["username"] = username
10
+ form["password"] = password
11
+ page = form.submit
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def save(options = {})
17
+ return false if !valid?
18
+
19
+ authorize
20
+
21
+ page = agent.get("")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,68 @@
1
+ module Ubiquitously
2
+ module Diigo
3
+ class Account < Ubiquitously::Service::Account
4
+
5
+ def login
6
+ page = agent.get("https://secure.diigo.com/sign-in")
7
+ form = page.form_with(:name => "loginForm")
8
+ form["username"] = username
9
+ form["password"] = password
10
+ page = form.submit
11
+
12
+ authorize!(page.title !~ /Sign in/i)
13
+ end
14
+
15
+ end
16
+
17
+ class Post < Ubiquitously::Service::Post
18
+ validates_presence_of :url, :title, :description, :tags
19
+ submit_to "http://www.diigo.com/post?b_mode=0&c_mode=0&url=:url&title=:title&comments=:description&tag=:tags"
20
+
21
+ # tags are space separated. Use " " for tag with multiple words.
22
+ def tokenize
23
+ super.merge(:tags => tags.taggify(" ", " "))
24
+ end
25
+
26
+ def create
27
+ page = agent.get("https://secure.diigo.com/item/new/bookmark")
28
+ form = page.forms.detect { |form| form.form_node["id"] == "newBookmarkForm" }
29
+ form["url"] = token[:url]
30
+ form["title"] = token[:title]
31
+ form["description"] = token[:description]
32
+ # tags are space separated. Use " " for tag with multiple words.
33
+ form["tags"] = token[:tags]
34
+
35
+ unless debug?
36
+ page = form.submit
37
+ end
38
+ end
39
+
40
+ class << self
41
+ def find(options = {})
42
+ records = []
43
+ user = options[:user]
44
+ user_url = "http://secure.diigo.com/rss/user/#{user.username_for(self)}"
45
+ xml = Nokogiri::XML(open(user_url).read)
46
+
47
+ urls = url_permutations(options[:url])
48
+
49
+ xml.css("item").each do |node|
50
+ title = node.css("title").first.text
51
+ url = node.css("link").first.text
52
+ description = node.css("description").first.text
53
+ record = new(
54
+ :title => title,
55
+ :url => url,
56
+ :description => description,
57
+ :user => user
58
+ )
59
+ return record if urls.include?(record.url)
60
+ records << record
61
+ end
62
+
63
+ options[:url] ? nil : records
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,132 @@
1
+ module Ubiquitously
2
+ module Dzone
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://www.dzone.com/links/loginLightbox.html")
6
+ form = page.form_with(:action => "/links/j_acegi_security_check")
7
+ form["j_username"] = username
8
+ form["j_password"] = password
9
+ form["_acegi_security_remember_me"] = "on"
10
+ page = form.submit
11
+
12
+ authorize!(page.body !~ /Invalid username or password/i)
13
+ end
14
+ end
15
+
16
+ class Post < Ubiquitously::Service::Post
17
+ submit_to "http://www.dzone.com/links/add.html?url=:url&title=:url&description=:description"
18
+
19
+ def create
20
+ # url
21
+ page = agent.get("http://www.dzone.com/links/add.html")
22
+ form = page.form_with(:action => "/links/add.html")
23
+
24
+ accepted_tags = []
25
+
26
+ form.checkboxes_with(:name => "tags").each do |tag|
27
+ accepted_tags << tag.value.to_s
28
+ end
29
+
30
+ unaccepted_tags = token[:categories].select { |tag| !accepted_tags.include?(tag) }
31
+
32
+ if unaccepted_tags.length > 0
33
+ raise ArgumentError.new("DZone doesn't accept these tags: #{unaccepted_tags.inspect}, they want these:\n#{accepted_tags.inspect}")
34
+ end
35
+
36
+ form["title"] = title
37
+ form["url"] = url
38
+ form["description"] = description
39
+
40
+ form.checkboxes_with(:name => "tags").each do |checkbox|
41
+ checkbox.check if token[:categories].include?(checkbox.value)
42
+ end
43
+
44
+ unless debug?
45
+ page = form.submit
46
+ end
47
+
48
+ true
49
+ end
50
+
51
+ def update
52
+ page = agent.get(remote.service_url)
53
+ params = "\ncallCount=1\n"
54
+ params << "c0-scriptName=LinkManager\n"
55
+ params << "c0-methodName=incrementVoteCount\n"
56
+ # var random = Math.floor(Math.random() * 10001);
57
+ # var id = (random + "_" + new Date().getTime()).toString();
58
+ # => 9031_1281646074042
59
+ js_time = (Time.now.utc - Time.utc(1970, 1, 1)).floor * 1000
60
+ params << "c0-id=#{rand(10001).to_s}_#{js_time.to_s}\n"
61
+ params << "c0-param0=number:#{remote.service_id}\n"
62
+ params << "c0-param1=number:1\n"
63
+ params << "c0-param2=boolean:false\n"
64
+ params << "xml=true\n"
65
+ headers = {
66
+ "Content-Type" => "text/plain; charset=UTF-8",
67
+ "Referer" => remote.service_url,
68
+ "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
69
+ "Accept-Encoding" => "gzip,deflate",
70
+ "X-Requested-With" => "XMLHttpRequest",
71
+ "Pragma" => "no-cache",
72
+ "Cache-Control" => "no-cache"
73
+ }
74
+ result = agent.post("http://www.dzone.com/links/dwr/exec/LinkManager.incrementVoteCount.dwr", params, headers)
75
+
76
+ # now add comment
77
+ form = page.form_with(:name => "addlinkform")
78
+ form["body"] = description
79
+
80
+ form.submit
81
+
82
+ true
83
+ end
84
+
85
+ class << self
86
+
87
+ def find(options = {})
88
+ url = options[:url]
89
+ user = options[:user]
90
+ urls = url_permutations(url)
91
+ records = []
92
+
93
+ for page in 1..10
94
+ search = "http://dzone.com/links/search.html?query=#{URI.parse(url).host}&type=html&p=#{page}"
95
+ html = user.agent.get(search).parser
96
+
97
+ html.css(".linkblock").each do |node|
98
+ service_id = node["id"].match(/(\d+)/)[1]
99
+ link = node.css(".thumb a").first["href"]
100
+ header = node.css(".details h3 a").first
101
+ title = header.text
102
+ upvotes = node.css(".vwidget .upcount").first.text.to_i
103
+ downvotes = node.css(".vwidget .downcount").first.text.to_i
104
+ service_url = "http://www.dzone.com#{header["href"]}"
105
+ record = new(
106
+ :url => link,
107
+ :title => title,
108
+ :upvotes => upvotes,
109
+ :downvotes => downvotes,
110
+ :service_url => service_url,
111
+ :service_id => service_id,
112
+ :user => user
113
+ )
114
+ if urls.include?(record.url)
115
+ records << record
116
+ break
117
+ end
118
+ end
119
+
120
+ break if records.length > 0
121
+ end
122
+
123
+ if options[:url]
124
+ records.first
125
+ else
126
+ records
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,39 @@
1
+ module Ubiquitously
2
+ module DzoneSnippets
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://snippets.dzone.com/account/login")
6
+ form = page.form_with(:action => "/account/login")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ form["commit"] = "Log In"
10
+ page = form.submit
11
+
12
+ authorize!(page.uri != "http://snippets.dzone.com/account/login")
13
+ end
14
+ end
15
+
16
+ class Post < Ubiquitously::Service::Post
17
+
18
+ def tokenize
19
+ super.merge(
20
+ :description => "<code>#{self.description}</code>",
21
+ :tags => tags.taggify("-", " ", 40)
22
+ )
23
+ end
24
+
25
+ def create
26
+ page = agent.get("http://snippets.dzone.com/")
27
+ form = page.form_with(:action => "/posts/create")
28
+
29
+ form["post[title]"] = token[:title]
30
+ form["post[content]"] = token[:description]
31
+ form["post[tag_list]"] = token[:tags]
32
+ form["post[private]"] = 1 if private?
33
+ page = form.submit
34
+
35
+ true
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ module Ubiquitously
2
+ module Facebook
3
+ class Account < Ubiquitously::Service::Account
4
+ uses :oauth
5
+
6
+ def login
7
+ had_cookies = cookies?
8
+ url = "http://localhost:4567/"
9
+ authorize_url = FacebookToken.authorize(url)
10
+ page = agent.get(authorize_url, [], url)
11
+
12
+ # only login if we don't have cookies
13
+ unless had_cookies
14
+ form = page.forms.detect { |form| form.form_node["id"] == "login_form" }
15
+ form["email"] = username
16
+ form["pass"] = password
17
+ begin
18
+ page = form.submit
19
+ rescue Exception => e
20
+ puts e.inspect
21
+ end
22
+ end
23
+
24
+ location = URI.parse(page.response.to_hash["location"].to_a.first)
25
+ code = Rack::Utils.parse_query(location.query)["code"]
26
+
27
+ # do something with the oauth token, save it in the cookie?
28
+ self.credentials = FacebookToken.access(:secret => code, :callback_url => url)
29
+
30
+ authorize!(page.uri !~ /http:\/\/login\.facebook\.com\/login\.php/i)
31
+ end
32
+ end
33
+
34
+ class Post < Ubiquitously::Service::Post
35
+ def create
36
+ access_token.post("https://graph.facebook.com/me/feed", {
37
+ "message" => token[:description]
38
+ })
39
+ end
40
+ end
41
+ end
42
+ end