GoogleReaderApi 0.3.5 → 0.3.6
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.
- 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
|