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,81 @@
1
+ module Ubiquitously
2
+ module Faves
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://secure.faves.com/signIn")
6
+ form = page.forms.detect {|form| form.form_node["id"] == "signInBox"}
7
+ form["rUsername"] = username
8
+ form["rPassword"] = password
9
+ form["action"] = "Sign In"
10
+ page = form.submit
11
+
12
+ authorize!(page.title !~ /Sign In/i)
13
+ end
14
+ end
15
+
16
+ class Post < Ubiquitously::Service::Post
17
+ def create
18
+ page = agent.get("http://faves.com/createdot.aspx")
19
+ form = page.form_with(:name => "createDotForm")
20
+ form["noteText"] = description
21
+ form["urlText"] = url
22
+ form["subjectText"] = title
23
+ form["tagsText"] = tags.join(", ")
24
+ form.field_with(:name => "rateSelect").options.each do |option|
25
+ option.select if option.value.to_s == "5"
26
+ end
27
+ form.field_with(:name => "shareSelect").options.each do |option|
28
+ option.select if option.value.to_s.downcase == "public"
29
+ end
30
+ # hidden fields they fill out with javascript
31
+ # form["imageUrl"] = "http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png"
32
+ # form["imageWidth"] = "149"
33
+ # form["imageHeight"] = "149"
34
+ # just before you submit the form they append the current time, so they have a range.
35
+ # mimic the range of time :)
36
+ form["authoringExpiry"] = form["authoringExpiry"] + "loadedtime=#{1.minute.ago.to_i * 1000}publishedtime=#{Time.now.to_i * 1000}"
37
+ headers = {
38
+ "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
39
+ "Keep-Alive" => "115",
40
+ "Accept-Encoding" => "gzip,deflate"
41
+ }
42
+
43
+ unless debug?
44
+ page = form.submit(nil, headers)
45
+ end
46
+
47
+ self
48
+ end
49
+
50
+ class << self
51
+ def find(options = {})
52
+ result = []
53
+ user = options[:user]
54
+ user_url = "http://faves.com/users/#{user.username_for(self)}"
55
+ html = Nokogiri::HTML(open(user_url).read)
56
+
57
+ html.css(".userDotList li").each do |node|
58
+ next if node["id"].blank?
59
+ url = node.css(".note > a").first["href"]
60
+ title = node.css(".note > p").first.text
61
+ tags = []
62
+ node.xpath("a").each do |tag|
63
+ tags << tag.text if tag["class"].blank?
64
+ end
65
+ record = new(
66
+ :title => title,
67
+ :url => url,
68
+ :tags => tags
69
+ )
70
+ if options[:url] && options[:url] == record.url
71
+ return record
72
+ end
73
+ result << record
74
+ end
75
+
76
+ options[:url] ? nil : result
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,78 @@
1
+ module Ubiquitously
2
+ module Favshare
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://favshare.net/login.php")
6
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
7
+ form["username"] = username
8
+ form["password"] = password
9
+ form["persistent"] = "persistent"
10
+ form["processlogin"] = "1"
11
+ page = form.submit
12
+
13
+ end
14
+ end
15
+
16
+ # see your posts here: http://favshare.net/user/history/viatropos/
17
+ class Post < Ubiquitously::Service::Post
18
+
19
+ # max tags == 40 chars
20
+ def tokenize
21
+ super.merge(:tags => tags.taggify(" ", ", ", 40))
22
+ end
23
+
24
+ def create
25
+ page = agent.get("http://favshare.net/submit.php")
26
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
27
+
28
+ form["url"] = url
29
+
30
+ page = form.submit
31
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
32
+
33
+ form["title"] = title
34
+ form["bodytext"] = description # 350 chars max
35
+ form["summarytext"] = description
36
+ # MALFORMATTED HTML: select box is outside of the form
37
+ #form.fields_with(:name => "category").first.options.each do |option|
38
+ # option.select if option.value.to_s == "3"
39
+ #end
40
+ # b/c of malformedness...
41
+ form["category"] = "3"
42
+ form["url"] = url
43
+ form["phase"] = "2"
44
+ form["randkey"] = page.parser.css("input[@name='randkey']").first["value"]
45
+ form["id"] = page.parser.css("input[@name='id']").first["value"]
46
+
47
+ form["tags"] = token[:tags] # comma separated with space
48
+
49
+ iframe_url = page.parser.css("noscript iframe").first["src"]
50
+ params = iframe_url.split("?").last
51
+ captcha_iframe = agent.click(page.iframes.first)
52
+ captcha_form = captcha_iframe.forms.first
53
+ captcha_image = captcha_iframe.parser.css("img").first["src"]
54
+ # open browser with captcha image
55
+ system("open", "http://api.recaptcha.net/#{captcha_image}")
56
+ # enter captcha response in terminal
57
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
58
+ captcha_form["recaptcha_response_field"] = captcha_says
59
+ # submit captcha
60
+ captcha_form.action = "http://www.google.com/recaptcha/api/noscript?#{params}"
61
+ captcha_response = captcha_form.submit
62
+ # grab secret
63
+ captcha_response = captcha_response.parser.css("textarea").first.text
64
+
65
+ form["recaptcha_challenge_field"] = captcha_response
66
+ form["recaptcha_response_field"] = "manual_challenge"
67
+ page = form.submit
68
+
69
+ unless debug?
70
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
71
+ page = form.submit
72
+ end
73
+
74
+ true
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ module Ubiquitously
2
+ module Flikode
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://flikode.com/login")
6
+ form = page.form_with(:name => "login")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "http://flikode.com/login")
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://flikode.com/snippet")
18
+ form = page.form_with(:name => "snippet")
19
+
20
+ form["title"] = token[:title]
21
+ form["description"] = token[:description]
22
+ form["tags"] = token[:tags]
23
+
24
+ form.field_with(:name => "language").options.each do |option|
25
+ option.select if option.text.to_s.strip.downcase =~ /#{format}/
26
+ end
27
+
28
+ form.radiobuttons_with(:name => "choose").last.check
29
+
30
+ form["snippet"] = token[:body]
31
+
32
+ page = form.submit
33
+
34
+ true
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module Friendfeed
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://service.com/login")
6
+ form = page.form_with(:name => "loginform")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Some title/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+ module Ubiquitously
2
+ module Gist
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://gist.github.com/login")
6
+ form = page.form_with(:action => "/session")
7
+ form["login"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "https://gist.github.com/session")
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ validates_presence_of :format, :extension
17
+
18
+ def tokenize
19
+ super.merge(
20
+ # make sure we have the extension
21
+ :title => self.title.gsub(/(?:\.#{self.extension})?$/, ".#{self.extension}")
22
+ )
23
+ end
24
+
25
+ def create
26
+ page = agent.get("http://gist.github.com/")
27
+ form = page.form_with(:action => "/gists")
28
+
29
+ form.field_with(:name => "file_ext[gistfile1]").options.each do |option|
30
+ if format == extension || format == option.text.to_s.downcase.strip
31
+ option.select
32
+ break
33
+ end
34
+ end
35
+
36
+ form["file_name[gistfile1]"] = token[:title]
37
+ form["file_contents[gistfile1]"] = token[:description]
38
+
39
+ if public?
40
+ button = form.buttons.last
41
+ else
42
+ form["action_button"] = "private"
43
+ button = form.buttons.first
44
+ end
45
+
46
+ page = form.submit(button)
47
+
48
+ true
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module Ubiquitously
2
+ module GoogleBuzz
3
+ class Account < Ubiquitously::Service::Account
4
+ end
5
+
6
+ class Post < Ubiquitously::Service::Post
7
+ validates_presence_of :url, :title, :description, :tags
8
+
9
+ def save(options = {})
10
+ return false unless valid?
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Ubiquitously
2
+ module Identica
3
+ class Account < Ubiquitously::Service::Account
4
+ end
5
+
6
+ class Post < Ubiquitously::Service::Post
7
+ validates_presence_of :url, :title, :description, :tags
8
+
9
+ def save(options = {})
10
+ return false unless valid?
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module JumpTags
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://service.com/login")
6
+ form = page.form_with(:name => "loginform")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Some title/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ module Ubiquitously
2
+ module Kailoon
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ return true
6
+ end
7
+ end
8
+
9
+ class Post < Ubiquitously::Service::Post
10
+ def create
11
+ page = agent.get("http://kailoon.com/web-design-news/")
12
+ form = page.forms.detect { |form| form.form_node["id"] == "commentform" }
13
+
14
+ # weird, but this is how they're doing it
15
+ form["author"] = title
16
+ form["url"] = url
17
+ form["email"] = user.email
18
+ # 200 word max
19
+ form["comment"] = description
20
+
21
+ page = form.submit
22
+
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module Ubiquitously
2
+ module MetaFilter
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://login.metafilter.com/")
6
+ form = page.forms.first
7
+ form["user_name"] = username
8
+ form["user_pass"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "https://login.metafilter.com/logging-in.mefi")
12
+ end
13
+ end
14
+
15
+ # You cannot post to the front page at this time.
16
+ # This can be due to one of several things.
17
+ # You may not have been a member long enough (1 week),
18
+ # you may not have posted enough comments (at least 3),
19
+ # or you may have already posted a link in the past 24 hours.
20
+ class Post < Ubiquitously::Service::Post
21
+ def create
22
+ page = agent.get("http://www.metafilter.com/")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,94 @@
1
+ module Ubiquitously
2
+ module Mixx
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://www.mixx.com/")
6
+ form = page.form_with(:action => "https://www.mixx.com/save_login")
7
+ form["user[loginid]"] = username
8
+ form["user[password]"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.body !~ /login was unsuccessful/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://www.mixx.com/submit")
18
+ form = page.form_with(:action => "http://www.mixx.com/submit/step2")
19
+ form["thingy[page_url]"] = token[:url]
20
+ page = form.submit
21
+
22
+ already_submitted = page.parser.css(".flash.notice").first.text rescue ""
23
+ if (already_submitted =~ /already submitted/i)
24
+ form = page.forms.detect { |form| form.form_node["class"] =~ /vote-for/ }
25
+ form.submit
26
+
27
+ form = page.forms.detect { |form| form.form_node["id"] == "thingy_comment_form" }
28
+ form["comment[body]"] = token[:description]
29
+ form.submit
30
+ else
31
+ # last page
32
+ form = page.form_with(:action => "http://www.mixx.com/submit/save")
33
+
34
+ # captcha
35
+ iframe_url = page.parser.css("li.captcha iframe").first["src"]
36
+ params = iframe_url.split("?").last
37
+ captcha_iframe = agent.click(page.iframes.first)
38
+ captcha_form = captcha_iframe.forms.first
39
+ captcha_image = captcha_iframe.parser.css("img").first["src"]
40
+ # open browser with captcha image
41
+ system("open", "http://api.recaptcha.net/#{captcha_image}")
42
+ # enter captcha response in terminal
43
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
44
+ captcha_form["recaptcha_response_field"] = captcha_says
45
+ # submit captcha
46
+ captcha_form.action = "http://www.google.com/recaptcha/api/noscript?#{params}"
47
+ captcha_response = captcha_form.submit
48
+ # grab secret
49
+ captcha_response = captcha_response.parser.css("textarea").first.text
50
+
51
+ # submit post
52
+ form = page.form_with(:action => "http://www.mixx.com/submit/save")
53
+ form["thingy[title]"] = token[:title]
54
+ form["thingy[description]"] = token[:description]
55
+ form["thingy[new_tags]"] = token[:tags]
56
+ form["recaptcha_challenge_field"] = captcha_response
57
+ form["recaptcha_response_field"] = captcha_says
58
+
59
+ form.submit
60
+ end
61
+
62
+ true
63
+ end
64
+
65
+ class << self
66
+ def find(options = {})
67
+ records = []
68
+ user = options[:user]
69
+ user_url = "http://www.mixx.com/feeds/users/#{user.username_for(self)}"
70
+ xml = Nokogiri::XML(open(user_url).read)
71
+ urls = url_permutations(options[:url])
72
+
73
+ xml.css("item").each do |node|
74
+ title = node.css("title").first.text
75
+ url = node.xpath("mixx:source", {"mixx" => "http://www.mixx.com/mixxrss/"}).first.text
76
+ description = node.css("description").first.text
77
+ service_url = node.css("link").first.text
78
+ record = new(
79
+ :title => title,
80
+ :url => url,
81
+ :description => description,
82
+ :service_url => service_url,
83
+ :user => user
84
+ )
85
+ return record if urls.include?(record.url)
86
+ records << record
87
+ end
88
+
89
+ options[:url] ? nil : records
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end