ubiquitously 0.0.1.6 → 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.
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