GoogleReaderApi 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/GoogleReaderApi.gemspec +20 -22
- data/VERSION +1 -1
- data/lib/google-reader-api/api.rb +35 -44
- data/lib/google-reader-api/google_login.rb +139 -0
- data/lib/google-reader-api/user.rb +11 -3
- data/lib/google_reader_api.rb +2 -1
- metadata +22 -43
- data/.gitignore +0 -1
data/GoogleReaderApi.gemspec
CHANGED
@@ -1,44 +1,42 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{GoogleReaderApi}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{
|
11
|
+
s.authors = [%q{Toon Willems}]
|
12
|
+
s.date = %q{2011-08-21}
|
13
13
|
s.description = %q{a google reader api (unofficial) written in ruby}
|
14
14
|
s.email = %q{willemstoon@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"README.mdown"
|
17
17
|
]
|
18
18
|
s.files = [
|
19
|
-
".
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
19
|
+
"GoogleReaderApi.gemspec",
|
20
|
+
"License",
|
21
|
+
"README.mdown",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"lib/google-reader-api/api.rb",
|
25
|
+
"lib/google-reader-api/cache.rb",
|
26
|
+
"lib/google-reader-api/entry.rb",
|
27
|
+
"lib/google-reader-api/feed.rb",
|
28
|
+
"lib/google-reader-api/google_login.rb",
|
29
|
+
"lib/google-reader-api/rss_utils.rb",
|
30
|
+
"lib/google-reader-api/subscription_list.rb",
|
31
|
+
"lib/google-reader-api/user.rb",
|
32
|
+
"lib/google_reader_api.rb"
|
33
33
|
]
|
34
34
|
s.homepage = %q{http://github.com/nudded/GoogleReaderAPI}
|
35
|
-
s.
|
36
|
-
s.
|
37
|
-
s.rubygems_version = %q{1.3.7}
|
35
|
+
s.require_paths = [%q{lib}]
|
36
|
+
s.rubygems_version = %q{1.8.8}
|
38
37
|
s.summary = %q{a google reader api (unofficial) written in ruby}
|
39
38
|
|
40
39
|
if s.respond_to? :specification_version then
|
41
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
40
|
s.specification_version = 3
|
43
41
|
|
44
42
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.6
|
@@ -1,41 +1,52 @@
|
|
1
1
|
module GoogleReaderApi
|
2
|
-
|
2
|
+
|
3
3
|
class Api
|
4
|
-
|
4
|
+
|
5
5
|
require "cgi"
|
6
6
|
require "net/https"
|
7
7
|
require "uri"
|
8
|
-
|
8
|
+
|
9
9
|
BASE_URL = "http://www.google.com/reader/"
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
|
11
|
+
# specify either the :email and :password or the :auth token you got in the past
|
12
|
+
#
|
13
|
+
# [:email] the user's email address for login purposes
|
14
|
+
#
|
15
|
+
# [:password] the user's password for login purposes
|
16
|
+
#
|
17
|
+
# [:auth] the auth token you got from a previous authentication request
|
18
|
+
# if you provide this you do not need to provide the email and password
|
19
|
+
def initialize(options)
|
20
|
+
if options[:auth]
|
21
|
+
@auth = options[:auth]
|
22
|
+
else
|
23
|
+
request_auth(options[:email],options[:password])
|
24
|
+
end
|
13
25
|
@cache = GoogleReaderApi::Cache.new(2)
|
14
26
|
end
|
15
|
-
|
27
|
+
|
16
28
|
# do a get request to the link
|
17
29
|
# args is a hash of values that should be used in the request
|
18
30
|
def get_link(link,args={})
|
19
31
|
link = BASE_URL + link
|
20
32
|
get_request(link,args)
|
21
33
|
end
|
22
|
-
|
34
|
+
|
23
35
|
def post_link(link,args={})
|
24
36
|
link = BASE_URL + link
|
25
37
|
post_request(link,args)
|
26
38
|
end
|
27
|
-
|
39
|
+
|
28
40
|
def cached_unread_count
|
29
41
|
@cache['unread-count'] ||= get_link 'api/0/unread-count', :output => :json
|
30
42
|
end
|
31
|
-
|
43
|
+
|
32
44
|
private
|
33
45
|
|
34
46
|
# url as a string
|
35
47
|
# the post data as a hash
|
36
48
|
def post_request(url,args)
|
37
49
|
uri = URI.parse(url)
|
38
|
-
args[:T] = token
|
39
50
|
req = Net::HTTP::Post.new(uri.path)
|
40
51
|
req.set_form_data(args)
|
41
52
|
request(uri,req)
|
@@ -45,24 +56,24 @@ module GoogleReaderApi
|
|
45
56
|
# e.g. :allcomments => true etc...
|
46
57
|
def get_request(url,args)
|
47
58
|
uri = URI.parse url
|
48
|
-
|
59
|
+
|
49
60
|
# ck is the current unix timestamp
|
50
61
|
args[:ck] = Time.now.to_i unless args[:ck]
|
51
|
-
|
62
|
+
|
52
63
|
req = Net::HTTP::Get.new("#{uri.path}?#{argument_string(args)}")
|
53
64
|
request(uri,req)
|
54
65
|
end
|
55
66
|
|
56
67
|
def request(uri,request)
|
57
68
|
# add the cookie to the http header
|
58
|
-
request.add_field('
|
69
|
+
request.add_field('Authorization',"GoogleLogin auth=#{auth}")
|
59
70
|
res = Net::HTTP.start(uri.host,uri.port) do |http|
|
60
71
|
http.request(request)
|
61
72
|
end
|
62
73
|
# TODO: use better exception
|
63
74
|
if res.code != '200'
|
64
75
|
p res.body
|
65
|
-
raise "something went wrong"
|
76
|
+
raise "something went wrong"
|
66
77
|
end
|
67
78
|
res.body
|
68
79
|
end
|
@@ -71,37 +82,17 @@ module GoogleReaderApi
|
|
71
82
|
def argument_string(args)
|
72
83
|
args.to_a.map { |v| v.join '=' }.join('&')
|
73
84
|
end
|
74
|
-
|
75
|
-
def token
|
76
|
-
url = URI.parse "http://www.google.com/reader/api/0/token"
|
77
|
-
res = Net::HTTP.start(url.host,url.port) do |http|
|
78
|
-
http.get(url.path,"Cookie" => user_cookie)
|
79
|
-
end
|
80
|
-
res.body
|
81
|
-
end
|
82
85
|
|
83
|
-
def
|
84
|
-
|
85
|
-
'path' => '/' , 'domain' => '.google.com').to_s
|
86
|
+
def auth
|
87
|
+
@auth
|
86
88
|
end
|
87
89
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
def request_sid(email,password)
|
93
|
-
password = CGI.escape(password)
|
94
|
-
email = CGI.escape(email)
|
95
|
-
url = URI.parse "https://www.google.com/accounts/ClientLogin?service=reader&Email=#{email}&Passwd=#{password}"
|
96
|
-
http = Net::HTTP.new(url.host,url.port)
|
97
|
-
http.use_ssl = true
|
98
|
-
res,data = http.get("#{url.path}?#{url.query}")
|
99
|
-
|
100
|
-
raise "could not authenticate" if res.code != "200"
|
101
|
-
|
102
|
-
@sid = data.match(/SID=(.+?)\n/)[1]
|
90
|
+
def request_auth(email,password)
|
91
|
+
login = GoogleLogin::ClientLogin.new :service => 'reader', :source => 'nudded-greader-0.1'
|
92
|
+
login.authenticate email, password
|
93
|
+
@auth = login.auth
|
103
94
|
end
|
104
|
-
|
95
|
+
|
105
96
|
end
|
106
|
-
|
107
|
-
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module GoogleLogin
|
5
|
+
|
6
|
+
# == ClientLogin
|
7
|
+
#
|
8
|
+
# Use this Class to get an auth-token
|
9
|
+
class ClientLogin
|
10
|
+
|
11
|
+
# Base Exception class
|
12
|
+
LoginError = Class.new Exception
|
13
|
+
|
14
|
+
# All the possible exceptions
|
15
|
+
[
|
16
|
+
"BadAuthentication",
|
17
|
+
"NotVerified",
|
18
|
+
"TermsNotAgreed",
|
19
|
+
"CaptchaRequired",
|
20
|
+
"Unknown",
|
21
|
+
"AccountDeleted",
|
22
|
+
"AccountDisabled",
|
23
|
+
"ServiceDisabled",
|
24
|
+
"ServiceUnavailable",
|
25
|
+
].each do |const|
|
26
|
+
const_set const, Class.new(LoginError)
|
27
|
+
end
|
28
|
+
|
29
|
+
DEFAULTS = {
|
30
|
+
:accountType => 'HOSTED_OR_GOOGLE' ,
|
31
|
+
:source => 'companyName-applicationName-versionID',
|
32
|
+
:service => 'service-identifier'
|
33
|
+
}
|
34
|
+
|
35
|
+
attr_reader :auth, :sid, :lsid, :captcha_url
|
36
|
+
|
37
|
+
# specify the :service, :source and optionally :accountType
|
38
|
+
#
|
39
|
+
# [:service] the service identifier, check the google api documentation.
|
40
|
+
#
|
41
|
+
# [:source] the name of your application. String should be in the form
|
42
|
+
# "companyName-applicationName-versionID".
|
43
|
+
#
|
44
|
+
# [:accountType] one of the following values:
|
45
|
+
# "GOOGLE", "HOSTED", "HOSTED_OR_GOOGLE" (default if none
|
46
|
+
# given)
|
47
|
+
def initialize(arghash = {})
|
48
|
+
@options = DEFAULTS.merge arghash
|
49
|
+
end
|
50
|
+
|
51
|
+
# authenticate a user, which sets the auth, sid and lsid instance_variables
|
52
|
+
# if you provide a block, it will be called with a captcha url if google
|
53
|
+
# forces you to answer the captcha. Make sure you return the anwer in the block.
|
54
|
+
#
|
55
|
+
# if no block is given, this will raise a CaptchaRequired error.
|
56
|
+
# you can rescue them and show the url via the captcha_url method.
|
57
|
+
#
|
58
|
+
# you can then call authenticate and as 3rd parameter you provide the
|
59
|
+
# captcha answer.
|
60
|
+
#
|
61
|
+
# all Exceptions this raises are subclasses of ClientLogin::LoginError.
|
62
|
+
# so make sure you handle them.
|
63
|
+
#
|
64
|
+
# This is a list of all the possible errors and their meaning
|
65
|
+
# Error code:: Description
|
66
|
+
# BadAuthentication:: The login request used a username or password that is not recognized.
|
67
|
+
# NotVerified:: The account email address has not been verified. The user will need to access their Google account directly to resolve the issue before logging in using a non-Google application.
|
68
|
+
# TermsNotAgreed:: The user has not agreed to terms. The user will need to access their Google account directly to resolve the issue before logging in using a non-Google application.
|
69
|
+
# CaptchaRequired:: A CAPTCHA is required. (A response with this error code will also contain an image URL and a CAPTCHA token.)
|
70
|
+
# Unknown:: The error is unknown or unspecified; the request contained invalid input or was malformed.
|
71
|
+
# AccountDeleted:: The user account has been deleted.
|
72
|
+
# AccountDisabled:: The user account has been disabled.
|
73
|
+
# ServiceDisabled:: The user's access to the specified service has been disabled. (The user account may still be valid.)
|
74
|
+
# ServiceUnavailable:: The service is not available; try again later.
|
75
|
+
def authenticate(username, password, captcha_response = nil)
|
76
|
+
@options[:Email], @options[:Passwd] = username, password
|
77
|
+
# set logincaptcha, captchatoken will already be set
|
78
|
+
@options[:logincaptcha] = captcha_response if captcha_response
|
79
|
+
|
80
|
+
parse_response perform_request
|
81
|
+
|
82
|
+
rescue CaptchaRequired
|
83
|
+
if block_given?
|
84
|
+
@options[:logincaptcha] = yield captcha_url
|
85
|
+
retry
|
86
|
+
else
|
87
|
+
raise CaptchaRequired
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def perform_request
|
94
|
+
request = Net::HTTP::Post.new '/accounts/ClientLogin'
|
95
|
+
request.form_data = @options
|
96
|
+
|
97
|
+
https = Net::HTTP.new 'www.google.com', 443
|
98
|
+
https.use_ssl = true
|
99
|
+
|
100
|
+
https.request request
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_body(response_body)
|
104
|
+
response_body.scan(/(\w+)=(.+)\n/).each do |key, value|
|
105
|
+
instance_variable_set "@#{key.downcase}" , value
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_response(response)
|
110
|
+
if response.code_type == Net::HTTPOK
|
111
|
+
parse_body response.body
|
112
|
+
else
|
113
|
+
handle_error response.body
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def handle_error(response_body)
|
119
|
+
error_message = response_body.match(/Error=(\w+)\n/)[1].strip
|
120
|
+
|
121
|
+
if error_message == "CaptchaRequired"
|
122
|
+
@options[:logintoken] = response_body.match(/CaptchaToken=(.+)\n/)[1]
|
123
|
+
self.captcha_url = response_body.match(/CaptchaUrl=(.+)\n/)[1]
|
124
|
+
end
|
125
|
+
|
126
|
+
raise_error_class error_message
|
127
|
+
end
|
128
|
+
|
129
|
+
def raise_error_class(error_message)
|
130
|
+
raise self.class.const_get error_message
|
131
|
+
end
|
132
|
+
|
133
|
+
def captcha_url=(url)
|
134
|
+
@captcha_url = "http://www.google.com/accounts/" << url
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -5,9 +5,17 @@ module GoogleReaderApi
|
|
5
5
|
require "json"
|
6
6
|
# maybe someone would like to access the api for a user
|
7
7
|
attr_reader :api
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
|
9
|
+
# specify either the :email and :password or the :auth token you got in the past
|
10
|
+
#
|
11
|
+
# [:email] the user's email address for login purposes
|
12
|
+
#
|
13
|
+
# [:password] the user's password for login purposes
|
14
|
+
#
|
15
|
+
# [:auth] the auth token you got from a previous authentication request
|
16
|
+
# if you provide this you do not need to provide the email and password
|
17
|
+
def initialize(options)
|
18
|
+
@api = GoogleReaderApi::Api::new options
|
11
19
|
end
|
12
20
|
|
13
21
|
def info
|
data/lib/google_reader_api.rb
CHANGED
metadata
CHANGED
@@ -1,34 +1,23 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: GoogleReaderApi
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 5
|
10
|
-
version: 0.3.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.6
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Toon Willems
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2010-06-22 00:00:00 +02:00
|
19
|
-
default_executable:
|
12
|
+
date: 2011-08-21 00:00:00.000000000Z
|
20
13
|
dependencies: []
|
21
|
-
|
22
14
|
description: a google reader api (unofficial) written in ruby
|
23
15
|
email: willemstoon@gmail.com
|
24
16
|
executables: []
|
25
|
-
|
26
17
|
extensions: []
|
27
|
-
|
28
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
29
19
|
- README.mdown
|
30
|
-
files:
|
31
|
-
- .gitignore
|
20
|
+
files:
|
32
21
|
- GoogleReaderApi.gemspec
|
33
22
|
- License
|
34
23
|
- README.mdown
|
@@ -38,43 +27,33 @@ files:
|
|
38
27
|
- lib/google-reader-api/cache.rb
|
39
28
|
- lib/google-reader-api/entry.rb
|
40
29
|
- lib/google-reader-api/feed.rb
|
30
|
+
- lib/google-reader-api/google_login.rb
|
41
31
|
- lib/google-reader-api/rss_utils.rb
|
42
32
|
- lib/google-reader-api/subscription_list.rb
|
43
33
|
- lib/google-reader-api/user.rb
|
44
34
|
- lib/google_reader_api.rb
|
45
|
-
has_rdoc: true
|
46
35
|
homepage: http://github.com/nudded/GoogleReaderAPI
|
47
36
|
licenses: []
|
48
|
-
|
49
37
|
post_install_message:
|
50
|
-
rdoc_options:
|
51
|
-
|
52
|
-
require_paths:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
53
40
|
- lib
|
54
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
42
|
none: false
|
56
|
-
requirements:
|
57
|
-
- -
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
|
60
|
-
|
61
|
-
- 0
|
62
|
-
version: "0"
|
63
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
48
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
segments:
|
70
|
-
- 0
|
71
|
-
version: "0"
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
72
53
|
requirements: []
|
73
|
-
|
74
54
|
rubyforge_project:
|
75
|
-
rubygems_version: 1.
|
55
|
+
rubygems_version: 1.8.8
|
76
56
|
signing_key:
|
77
57
|
specification_version: 3
|
78
58
|
summary: a google reader api (unofficial) written in ruby
|
79
59
|
test_files: []
|
80
|
-
|
data/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
pkg
|