grapi 0.2.0 → 0.3.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.
- data/README.textile +16 -8
- data/Rakefile +0 -3
- data/VERSION +1 -1
- data/grapi.gemspec +1 -9
- data/lib/grapi/reader.rb +34 -23
- metadata +1 -23
- data/example.rb +0 -34
- data/lib/grapi/parser.rb +0 -55
data/README.textile
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
h2. Grapi : Ruby client to access the unofficial Google Reader API
|
2
2
|
|
3
|
-
h3.
|
3
|
+
h3. Install
|
4
4
|
|
5
|
-
|
5
|
+
<pre>
|
6
|
+
gem install grapi
|
7
|
+
</pre>
|
6
8
|
|
7
|
-
h3.
|
9
|
+
h3. Client Dependencies
|
8
10
|
|
9
|
-
* "
|
10
|
-
* "Loofah":http://github.com/flavorjones/loofah (gem install loofah)
|
11
|
+
* "Curb":http://github.com/taf2/curb (gem install curb)
|
11
12
|
|
12
13
|
h3. Synopsis
|
13
14
|
|
@@ -18,20 +19,27 @@ require "grapi"
|
|
18
19
|
reader = Grapi::Reader.new
|
19
20
|
reader.login USERNAME, PASSWORD
|
20
21
|
|
21
|
-
|
22
|
-
list= Grapi::Parser::ReadingList.parse reader.reading_list
|
22
|
+
puts reader.reading_list
|
23
23
|
|
24
24
|
</pre>
|
25
25
|
|
26
26
|
h3. API methods
|
27
27
|
|
28
|
+
Public API:
|
29
|
+
|
28
30
|
* initialize(verbose= false)
|
29
31
|
* login(USERNAME, PASSWORD)
|
30
|
-
* reading_list(continuation
|
32
|
+
* reading_list(:continuation => nil, :dump_data => false, :output => "atom/json")
|
31
33
|
* subscribe(feed_url, label=test)
|
32
34
|
* unsubscribe(feed_url)
|
33
35
|
* mark_as_read(entry_google_id)
|
34
36
|
|
37
|
+
Protected API:
|
38
|
+
|
39
|
+
* get(url)
|
40
|
+
* post(url, params={})
|
41
|
+
* post_with_token(url, params={})
|
42
|
+
|
35
43
|
h3. License: see "MIT-LICENSE":http://github.com/aurelian/grapi/blob/master/MIT-LICENSE
|
36
44
|
|
37
45
|
h3. For: contact - ideas - patches please use github infrastructure
|
data/Rakefile
CHANGED
@@ -11,9 +11,6 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/aurelian/grapi"
|
12
12
|
gem.authors = ["Aurelian Oancea"]
|
13
13
|
gem.add_dependency("curb", ">=0.6.1.0")
|
14
|
-
gem.add_dependency("nokogiri", ">=1.4.1")
|
15
|
-
gem.add_dependency("loofah", ">=0.4.1")
|
16
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
14
|
end
|
18
15
|
Jeweler::GemcutterTasks.new
|
19
16
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/grapi.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{grapi}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aurelian Oancea"]
|
@@ -21,11 +21,9 @@ Gem::Specification.new do |s|
|
|
21
21
|
"README.textile",
|
22
22
|
"Rakefile",
|
23
23
|
"VERSION",
|
24
|
-
"example.rb",
|
25
24
|
"grapi.gemspec",
|
26
25
|
"lib/core_ext/string.rb",
|
27
26
|
"lib/grapi.rb",
|
28
|
-
"lib/grapi/parser.rb",
|
29
27
|
"lib/grapi/reader.rb",
|
30
28
|
"test/helper.rb",
|
31
29
|
"test/test_grapi.rb"
|
@@ -46,17 +44,11 @@ Gem::Specification.new do |s|
|
|
46
44
|
|
47
45
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
48
46
|
s.add_runtime_dependency(%q<curb>, [">= 0.6.1.0"])
|
49
|
-
s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.1"])
|
50
|
-
s.add_runtime_dependency(%q<loofah>, [">= 0.4.1"])
|
51
47
|
else
|
52
48
|
s.add_dependency(%q<curb>, [">= 0.6.1.0"])
|
53
|
-
s.add_dependency(%q<nokogiri>, [">= 1.4.1"])
|
54
|
-
s.add_dependency(%q<loofah>, [">= 0.4.1"])
|
55
49
|
end
|
56
50
|
else
|
57
51
|
s.add_dependency(%q<curb>, [">= 0.6.1.0"])
|
58
|
-
s.add_dependency(%q<nokogiri>, [">= 1.4.1"])
|
59
|
-
s.add_dependency(%q<loofah>, [">= 0.4.1"])
|
60
52
|
end
|
61
53
|
end
|
62
54
|
|
data/lib/grapi/reader.rb
CHANGED
@@ -4,32 +4,19 @@ module Grapi
|
|
4
4
|
|
5
5
|
class Reader
|
6
6
|
|
7
|
+
VERSION = File.read(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "VERSION"))).strip
|
8
|
+
|
7
9
|
def initialize(verbose= false)
|
8
10
|
@client = ::Curl::Easy.new do | easy |
|
9
11
|
easy.headers= {
|
10
|
-
"User-Agent" => "Grapi::Reader
|
12
|
+
"User-Agent" => "Grapi::Reader /#{Grapi::Reader::VERSION} +gzip",
|
11
13
|
"Accept-Encoding" => "gzip, deflate",
|
12
14
|
"GData-Version" => 2
|
13
15
|
}
|
14
16
|
easy.follow_location= true
|
15
17
|
easy.verbose= true if verbose
|
16
18
|
end
|
17
|
-
@token
|
18
|
-
end
|
19
|
-
|
20
|
-
def get(url)
|
21
|
-
make_request(url){|c| c.http_get }
|
22
|
-
end
|
23
|
-
|
24
|
-
def post(url, params)
|
25
|
-
curl_post_params= params.inject([]){|p, e| p << ::Curl::PostField.content(e[0],e[1])}
|
26
|
-
make_request(url){|c| c.http_post(*curl_post_params)}
|
27
|
-
end
|
28
|
-
|
29
|
-
def post_with_token(url, params)
|
30
|
-
request_token if @token.nil?
|
31
|
-
params["T"]= @token
|
32
|
-
post url, params
|
19
|
+
@token= nil
|
33
20
|
end
|
34
21
|
|
35
22
|
def login(username, password)
|
@@ -57,18 +44,42 @@ module Grapi
|
|
57
44
|
post_with_token "http://www.google.com/reader/api/0/edit-tag", {"i" => entry_id, "a" => "user/-/state/com.google/read"}
|
58
45
|
end
|
59
46
|
|
60
|
-
|
61
|
-
|
47
|
+
# options:
|
48
|
+
# :continuation (default: nil) -> continuation string
|
49
|
+
# :dump_data (default: false) -> whether to write the response to a file in /tmp or not
|
50
|
+
# :output (default: atom) -> desired output (atom|json)
|
51
|
+
def reading_list(options={})
|
52
|
+
options= {:continuation => nil, :output => "atom", :dump_data => false}.update(options)
|
53
|
+
if options[:output] == "atom"
|
54
|
+
get "http://www.google.com/reader/atom/user/-/state/com.google/reading-list?xt=user/-/state/com.google/read&ck=#{Time.now.to_i*1000}&n=1000&c=#{options[:continuation]}"
|
55
|
+
else
|
56
|
+
get "http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list?output=#{options[:output]}&xt=user/-/state/com.google/read&ck=#{Time.now.to_i*1000}&n=1000&c=#{options[:continuation]}"
|
57
|
+
end
|
62
58
|
response= @client.body_str.uncompress
|
63
|
-
File.open("/tmp/#{Time.now.to_i}-reading_list
|
59
|
+
File.open("/tmp/#{Time.now.to_i}-reading_list.#{options[:output]}", "w"){|f|f<<response} if options[:dump_data]
|
64
60
|
response
|
65
61
|
end
|
66
62
|
|
67
|
-
|
63
|
+
protected
|
64
|
+
def get(url)
|
65
|
+
make_request(url){|c| c.http_get }
|
66
|
+
end
|
67
|
+
|
68
|
+
def post(url, params)
|
69
|
+
curl_post_params= params.inject([]){|p, e| p << ::Curl::PostField.content(e[0],e[1])}
|
70
|
+
make_request(url){|c| c.http_post(*curl_post_params)}
|
71
|
+
end
|
68
72
|
|
73
|
+
def post_with_token(url, params)
|
74
|
+
request_token if @token.nil?
|
75
|
+
params["T"]= @token
|
76
|
+
post url, params
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
69
80
|
def edit_subscription(feed_url, action, params={})
|
70
81
|
post_with_token "http://www.google.com/reader/api/0/subscription/edit", { "s" => "feed/#{feed_url}", "ac" => action }.update(params)
|
71
|
-
response
|
82
|
+
response= @client.body_str.uncompress
|
72
83
|
unless response == "OK"
|
73
84
|
$stderr<< "WARN: [#{__FILE__}:#{__LINE__}] ~> response is not OK. probably token has expired!\n#{response}\n\n"
|
74
85
|
end
|
@@ -76,7 +87,7 @@ module Grapi
|
|
76
87
|
|
77
88
|
def request_token
|
78
89
|
get "http://www.google.com/reader/api/0/token"
|
79
|
-
@token
|
90
|
+
@token= @client.body_str.uncompress
|
80
91
|
end
|
81
92
|
|
82
93
|
def make_request(url)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aurelian Oancea
|
@@ -22,26 +22,6 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 0.6.1.0
|
24
24
|
version:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: nokogiri
|
27
|
-
type: :runtime
|
28
|
-
version_requirement:
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.4.1
|
34
|
-
version:
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: loofah
|
37
|
-
type: :runtime
|
38
|
-
version_requirement:
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: 0.4.1
|
44
|
-
version:
|
45
25
|
description: Ruby client for unofficial Google Reader API
|
46
26
|
email: oancea@gmail.com
|
47
27
|
executables: []
|
@@ -56,11 +36,9 @@ files:
|
|
56
36
|
- README.textile
|
57
37
|
- Rakefile
|
58
38
|
- VERSION
|
59
|
-
- example.rb
|
60
39
|
- grapi.gemspec
|
61
40
|
- lib/core_ext/string.rb
|
62
41
|
- lib/grapi.rb
|
63
|
-
- lib/grapi/parser.rb
|
64
42
|
- lib/grapi/reader.rb
|
65
43
|
- test/helper.rb
|
66
44
|
- test/test_grapi.rb
|
data/example.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
$LOAD_PATH<< "lib"
|
2
|
-
|
3
|
-
require "rubygems"
|
4
|
-
require "grapi"
|
5
|
-
require "grapi/parser"
|
6
|
-
require "yaml"
|
7
|
-
|
8
|
-
def print_list(list)
|
9
|
-
puts "~> Got: #{list.gid} updated at: #{list.updated_at}\n\t contains: #{list.entries.size} items. continuation: #{list.continuation}"
|
10
|
-
list.entries.each do | entry |
|
11
|
-
puts "~> #{entry.title}"
|
12
|
-
puts "\tpublished at: #{entry.published_at}"
|
13
|
-
puts "\tcategories: \n\t\t#{entry.categories.map{|k| "label= #{k[:label]} | term= #{k[:term]}"}.join("\n\t\t")}"
|
14
|
-
puts "\tsource: #{entry.source[:title]}"
|
15
|
-
puts "\tauthor: #{entry.author}"
|
16
|
-
puts "\turl: #{entry.link}"
|
17
|
-
puts "\tsummary: #{entry.summary}"
|
18
|
-
puts "======================================================================="
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
config= YAML.load_file File.expand_path("~/.gdata.yml")
|
23
|
-
|
24
|
-
reader= Grapi::Reader.new(true)
|
25
|
-
reader.login config["username"], config["password"]
|
26
|
-
|
27
|
-
continuation= nil
|
28
|
-
loop do
|
29
|
-
list= Grapi::Parser::ReadingList.parse(reader.reading_list(continuation))
|
30
|
-
print_list list
|
31
|
-
continuation= list.continuation
|
32
|
-
break if continuation.nil?
|
33
|
-
end
|
34
|
-
|
data/lib/grapi/parser.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require "nokogiri"
|
2
|
-
require "loofah"
|
3
|
-
require "time"
|
4
|
-
|
5
|
-
module Grapi
|
6
|
-
|
7
|
-
module Parser
|
8
|
-
|
9
|
-
class Entry
|
10
|
-
attr_accessor :crawled_at, :summary, :gid, :categories, :published_at, :updated_at, :author, :source, :title, :link
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@categories= []
|
14
|
-
yield self
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class ReadingList
|
19
|
-
attr_accessor :entries, :gid, :updated_at, :continuation
|
20
|
-
|
21
|
-
def initialize
|
22
|
-
@entries= []
|
23
|
-
yield self
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.parse(xml)
|
27
|
-
doc= Nokogiri::XML xml
|
28
|
-
Grapi::Parser::ReadingList.new do | list |
|
29
|
-
list.gid = doc.search("id").first.inner_text
|
30
|
-
list.updated_at = Time.parse(doc.search("updated").first.inner_text)
|
31
|
-
list.continuation = doc.at_xpath("//gr:continuation").inner_text rescue nil
|
32
|
-
doc.search("entry").each do | entry |
|
33
|
-
list.entries << Grapi::Parser::Entry.new do | e |
|
34
|
-
e.gid = entry.search("id").first.inner_text
|
35
|
-
e.title = entry.search("title").first.inner_text
|
36
|
-
e.published_at = Time.parse(entry.search("published").first.inner_text)
|
37
|
-
e.updated_at = Time.parse(entry.search("updated").first.inner_text)
|
38
|
-
e.link = entry.search("link").attr("href").value
|
39
|
-
e.crawled_at = Time.at(entry["crawl-timestamp-msec"].to_i/1000.0).utc
|
40
|
-
e.summary = Loofah.fragment(entry.search("summary").inner_text).scrub!(:strip).text
|
41
|
-
e.author = entry.search("author/name").inner_text
|
42
|
-
e.source = {
|
43
|
-
:id => entry.search("source/id").inner_text,
|
44
|
-
:title => entry.search("source/title").inner_text,
|
45
|
-
:link => entry.search("source/link").attr("href").value
|
46
|
-
}
|
47
|
-
entry.search("category").each { | category | e.categories << {:term=>category.attr("term"), :label=>category.attr("label")} }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|