picasa 0.3.3 → 0.4.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/.gitignore +1 -0
- data/.travis.yml +6 -1
- data/Gemfile +6 -0
- data/README.md +16 -24
- data/Rakefile +1 -1
- data/lib/picasa.rb +18 -12
- data/lib/picasa/api/album.rb +45 -0
- data/lib/picasa/client.rb +14 -0
- data/lib/picasa/connection.rb +86 -0
- data/lib/picasa/exceptions.rb +17 -0
- data/lib/picasa/presenter/album.rb +76 -0
- data/lib/picasa/presenter/album_list.rb +60 -0
- data/lib/picasa/presenter/author.rb +15 -0
- data/lib/picasa/presenter/base.rb +29 -0
- data/lib/picasa/presenter/link.rb +19 -0
- data/lib/picasa/presenter/media.rb +27 -0
- data/lib/picasa/presenter/photo.rb +79 -0
- data/lib/picasa/presenter/thumbnail.rb +19 -0
- data/lib/picasa/utils.rb +44 -0
- data/lib/picasa/version.rb +1 -1
- data/picasa.gemspec +4 -15
- data/test/api/album_test.rb +24 -0
- data/test/client_test.rb +14 -0
- data/test/connection_test.rb +71 -0
- data/test/fixtures/album/album-list-with-tag.txt +105 -0
- data/test/fixtures/album/album-list.txt +105 -0
- data/test/fixtures/album/album-show-with-max-results.txt +131 -0
- data/test/fixtures/album/album-show-with-tag-and-many-photos.txt +156 -0
- data/test/fixtures/album/album-show-with-tag-and-one-photo.txt +105 -0
- data/test/fixtures/album/album-show.txt +169 -0
- data/test/fixtures/auth/failure.txt +12 -0
- data/test/fixtures/auth/success.txt +14 -0
- data/test/fixtures/json.txt +435 -0
- data/test/fixtures/photo/photo-list-all-with-q.txt +556 -0
- data/test/fixtures/photo/photo-list-all.txt +623 -0
- data/test/fixtures/photo/photo-list-user.txt +388 -0
- data/test/fixtures/presenters/album_list.xml +88 -0
- data/test/fixtures/presenters/album_show.xml +152 -0
- data/test/fixtures/presenters/album_show_with_one_photo.xml +88 -0
- data/test/fixtures/tag/tag-list-album.txt +77 -0
- data/test/fixtures/tag/tag-list-photo.txt +72 -0
- data/test/fixtures/tag/tag-list.txt +68 -0
- data/test/helper.rb +12 -6
- data/test/presenter/album_list_test.rb +67 -0
- data/test/presenter/album_test.rb +173 -0
- data/test/presenter/author_test.rb +17 -0
- data/test/presenter/base_test.rb +27 -0
- data/test/presenter/link_test.rb +21 -0
- data/test/presenter/media_test.rb +29 -0
- data/test/presenter/photo_test.rb +81 -0
- data/test/presenter/thumbnail_test.rb +24 -0
- data/test/utils_test.rb +84 -0
- metadata +66 -31
- data/lib/picasa/config.rb +0 -15
- data/lib/picasa/web_albums.rb +0 -56
- data/test/fixtures/albums +0 -15
- data/test/fixtures/photos +0 -15
- data/test/test_config.rb +0 -12
- data/test/test_web_albums.rb +0 -44
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Picasa
|
2
2
|
|
3
|
-
|
4
|
-
Only for public albums so far.
|
3
|
+
Ruby library for [Picasa Web Albums Data API](https://developers.google.com/picasa-web/)
|
5
4
|
|
6
5
|
## Installation
|
7
6
|
|
@@ -12,34 +11,27 @@ gem install picasa
|
|
12
11
|
## Usage
|
13
12
|
|
14
13
|
``` ruby
|
15
|
-
Picasa.
|
16
|
-
|
17
|
-
#
|
18
|
-
# {another one} ]
|
19
|
-
|
20
|
-
Picasa.photos(:google_user => 'google_username', :album_id => 'album_id')
|
21
|
-
#=> {:photos => [{ :title, :thumbnail_1, :thumbnail_2, :thumbnail_3, :photo },{}],
|
22
|
-
# :slideshow => "link to picasa slideshow"}
|
23
|
-
```
|
24
|
-
|
25
|
-
or you can set google user for all requests like this:
|
14
|
+
client = Picasa::Client.new(user_id: "username@gmail.com")
|
15
|
+
client.album.list
|
16
|
+
# => Picasa::Presenter::AlbumList
|
26
17
|
|
27
|
-
|
28
|
-
|
29
|
-
c.google_user = 'google.user'
|
30
|
-
end
|
18
|
+
client.album.show("album_id")
|
19
|
+
# => Picasa::Presenter::Album
|
31
20
|
```
|
32
21
|
|
33
|
-
|
34
|
-
|
35
|
-
``` ruby
|
36
|
-
Picasa.albums
|
37
|
-
Picasa.photos(:album_id => 'album_id')
|
38
|
-
```
|
22
|
+
If password is specified, all requests will be authenticated.
|
23
|
+
This affect results to contain private data.
|
39
24
|
|
40
25
|
## Continuous Integration
|
41
26
|
[](http://travis-ci.org/morgoth/picasa)
|
42
27
|
|
28
|
+
## Contributors
|
29
|
+
|
30
|
+
* [Bram Wijnands](https://github.com/BRamBoo)
|
31
|
+
* [Rafael Souza](https://github.com/rafaels)
|
32
|
+
* [jsaak](https://github.com/jsaak)
|
33
|
+
* [Javier Guerra](https://github.com/javierg)
|
34
|
+
|
43
35
|
## Copyright
|
44
36
|
|
45
|
-
Copyright (c)
|
37
|
+
Copyright (c) Wojciech Wnętrzak, released under the MIT license.
|
data/Rakefile
CHANGED
data/lib/picasa.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
1
|
-
require "
|
2
|
-
|
1
|
+
require "multi_xml"
|
2
|
+
|
3
3
|
require "picasa/version"
|
4
|
+
require "picasa/utils"
|
5
|
+
require "picasa/exceptions"
|
6
|
+
require "picasa/connection"
|
7
|
+
require "picasa/client"
|
8
|
+
require "picasa/api/album"
|
4
9
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
require "picasa/presenter/album"
|
11
|
+
require "picasa/presenter/album_list"
|
12
|
+
require "picasa/presenter/author"
|
13
|
+
require "picasa/presenter/link"
|
14
|
+
require "picasa/presenter/media"
|
15
|
+
require "picasa/presenter/photo"
|
16
|
+
require "picasa/presenter/thumbnail"
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
18
|
+
module Picasa
|
19
|
+
API_URL = "https://picasaweb.google.com"
|
20
|
+
API_AUTH_URL = "https://www.google.com"
|
21
|
+
API_VERSION = "2"
|
16
22
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Picasa
|
2
|
+
module API
|
3
|
+
class Album
|
4
|
+
attr_reader :user_id, :credentials
|
5
|
+
|
6
|
+
# @param [Hash] credentials
|
7
|
+
# @option options [String] :user_id google username/email
|
8
|
+
# @option options [String] :password password for given username/email
|
9
|
+
def initialize(credentials)
|
10
|
+
if MultiXml.parser.to_s == "MultiXml::Parsers::Ox"
|
11
|
+
raise StandardError, "MultiXml parser is set to :ox - picasa gem will not work with it currently, use one of: :libxml, :nokogiri, :rexml"
|
12
|
+
end
|
13
|
+
@user_id = credentials.fetch(:user_id)
|
14
|
+
@credentials = credentials
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns album list
|
18
|
+
#
|
19
|
+
# @param [Hash] additional options included in request
|
20
|
+
#
|
21
|
+
# @return [Presenter::AlbumList]
|
22
|
+
def list(options = {})
|
23
|
+
uri = URI.parse("/data/feed/api/user/#{user_id}")
|
24
|
+
parsed_body = Connection.new(credentials).get(uri.path, options)
|
25
|
+
|
26
|
+
Presenter::AlbumList.new(parsed_body["feed"])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns photo list for given album
|
30
|
+
#
|
31
|
+
# @param [String] id of album
|
32
|
+
# @param [Hash] additional options included in request
|
33
|
+
# @option options [String, Integer] :max_results max number of returned results
|
34
|
+
# @option options [String] :tag include photos with given tag only
|
35
|
+
#
|
36
|
+
# @return [Presenter::Album]
|
37
|
+
def show(album_id, options = {})
|
38
|
+
uri = URI.parse("/data/feed/api/user/#{user_id}/albumid/#{album_id}")
|
39
|
+
parsed_body = Connection.new(credentials).get(uri.path, options)
|
40
|
+
|
41
|
+
Presenter::Album.new(parsed_body["feed"])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Picasa
|
2
|
+
class Client
|
3
|
+
attr_reader :credentials
|
4
|
+
|
5
|
+
def initialize(credentials = {})
|
6
|
+
credentials[:user_id] || raise(ArgumentError, "You must specify user_id")
|
7
|
+
@credentials = credentials
|
8
|
+
end
|
9
|
+
|
10
|
+
def album
|
11
|
+
API::Album.new(credentials)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "cgi"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module Picasa
|
6
|
+
class Connection
|
7
|
+
attr_reader :user_id, :password, :response
|
8
|
+
|
9
|
+
def initialize(credentials = {})
|
10
|
+
@user_id = credentials.fetch(:user_id)
|
11
|
+
@password = credentials.fetch(:password, nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
def http(url = API_URL)
|
15
|
+
uri = URI.parse(url)
|
16
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
17
|
+
http.use_ssl = true
|
18
|
+
http
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(path, params = {})
|
22
|
+
authenticate if auth?
|
23
|
+
|
24
|
+
path = path_with_params(path, params)
|
25
|
+
request = Net::HTTP::Get.new(path, headers)
|
26
|
+
@response = http.request(request)
|
27
|
+
parsed_body
|
28
|
+
end
|
29
|
+
|
30
|
+
def parsed_body
|
31
|
+
@parsed_body ||= MultiXml.parse(response.body)
|
32
|
+
end
|
33
|
+
|
34
|
+
def inline_params(params)
|
35
|
+
params.map do |key, value|
|
36
|
+
dasherized = key.to_s.gsub("_", "-")
|
37
|
+
"#{CGI.escape(dasherized)}=#{CGI.escape(value.to_s)}"
|
38
|
+
end.join("&")
|
39
|
+
end
|
40
|
+
|
41
|
+
def path_with_params(path, params = {})
|
42
|
+
path = path + "?" + inline_params(params) unless params.empty?
|
43
|
+
URI.parse(path).to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def headers
|
49
|
+
{"User-Agent" => "ruby-gem-v#{Picasa::VERSION}", "GData-Version" => API_VERSION}.tap do |headers|
|
50
|
+
headers["Authorization"] = "GoogleLogin auth=#{@auth_key}" if @auth_key
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def auth?
|
55
|
+
!password.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_email!
|
59
|
+
unless user_id =~ /[a-z0-9][a-z0-9._%+-]+[a-z0-9]@[a-z0-9][a-z0-9.-][a-z0-9]+\.[a-z]{2,6}/i
|
60
|
+
raise ArgumentError.new("user_id must be a valid E-mail address when authentication is used.")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def authenticate
|
65
|
+
return @auth_key if defined?(@auth_key)
|
66
|
+
validate_email!
|
67
|
+
|
68
|
+
data = inline_params({"accountType" => "HOSTED_OR_GOOGLE",
|
69
|
+
"Email" => user_id,
|
70
|
+
"Passwd" => password,
|
71
|
+
"service" => "lh2",
|
72
|
+
"source" => "ruby-gem-v#{Picasa::VERSION}"})
|
73
|
+
|
74
|
+
response = http(API_AUTH_URL).post("/accounts/ClientLogin", data)
|
75
|
+
raise ResponseError.new(response.body, response) unless response.is_a? Net::HTTPSuccess
|
76
|
+
|
77
|
+
@auth_key = extract_auth_key(response.body)
|
78
|
+
end
|
79
|
+
|
80
|
+
def extract_auth_key(data)
|
81
|
+
response = data.split("\n").map { |v| v.split("=") }
|
82
|
+
params = Hash[response]
|
83
|
+
params["Auth"]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Picasa
|
2
|
+
# All Picasa exceptions can be cought by rescuing:
|
3
|
+
# Picasa::StandardError
|
4
|
+
#
|
5
|
+
class StandardError < StandardError; end
|
6
|
+
|
7
|
+
class ArgumentError < StandardError; end
|
8
|
+
|
9
|
+
class ResponseError < StandardError
|
10
|
+
attr_reader :response
|
11
|
+
|
12
|
+
def initialize(message, response)
|
13
|
+
@response = response
|
14
|
+
super(message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "picasa/presenter/base"
|
2
|
+
|
3
|
+
module Picasa
|
4
|
+
module Presenter
|
5
|
+
class Album < Base
|
6
|
+
def author
|
7
|
+
@author ||= Author.new(safe_retrieve(parsed_body, "author"))
|
8
|
+
end
|
9
|
+
|
10
|
+
def entries
|
11
|
+
@entries ||= array_wrap(safe_retrieve(parsed_body, "entry")).map { |photo| Photo.new(photo) }
|
12
|
+
end
|
13
|
+
alias :photos :entries
|
14
|
+
|
15
|
+
def links
|
16
|
+
@links ||= safe_retrieve(parsed_body, "link").map { |link| Link.new(link) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def media
|
20
|
+
@media ||= Media.new(safe_retrieve(parsed_body, "group"))
|
21
|
+
end
|
22
|
+
|
23
|
+
def published
|
24
|
+
@published ||= map_to_date(safe_retrieve(parsed_body, "published"))
|
25
|
+
end
|
26
|
+
|
27
|
+
def updated
|
28
|
+
@updated ||= map_to_date(safe_retrieve(parsed_body, "updated"))
|
29
|
+
end
|
30
|
+
|
31
|
+
def title
|
32
|
+
@title ||= safe_retrieve(parsed_body, "title")
|
33
|
+
end
|
34
|
+
|
35
|
+
def summary
|
36
|
+
@summary ||= safe_retrieve(parsed_body, "summary")
|
37
|
+
end
|
38
|
+
|
39
|
+
def rights
|
40
|
+
@rights ||= safe_retrieve(parsed_body, "rights")
|
41
|
+
end
|
42
|
+
|
43
|
+
def id
|
44
|
+
@id ||= array_wrap(safe_retrieve(parsed_body, "id"))[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
def name
|
48
|
+
@name ||= safe_retrieve(parsed_body, "name")
|
49
|
+
end
|
50
|
+
|
51
|
+
def location
|
52
|
+
@location ||= safe_retrieve(parsed_body, "location")
|
53
|
+
end
|
54
|
+
|
55
|
+
def access
|
56
|
+
@access ||= safe_retrieve(parsed_body, "access")
|
57
|
+
end
|
58
|
+
|
59
|
+
def timestamp
|
60
|
+
@timestamp ||= safe_retrieve(parsed_body, "timestamp")
|
61
|
+
end
|
62
|
+
|
63
|
+
def numphotos
|
64
|
+
@numphotos ||= map_to_integer(safe_retrieve(parsed_body, "numphotos"))
|
65
|
+
end
|
66
|
+
|
67
|
+
def user
|
68
|
+
@user ||= safe_retrieve(parsed_body, "user")
|
69
|
+
end
|
70
|
+
|
71
|
+
def nickname
|
72
|
+
@nickname ||= safe_retrieve(parsed_body, "nickname")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "picasa/presenter/base"
|
2
|
+
|
3
|
+
module Picasa
|
4
|
+
module Presenter
|
5
|
+
class AlbumList < Base
|
6
|
+
def author
|
7
|
+
@author ||= Author.new(safe_retrieve(parsed_body, "author"))
|
8
|
+
end
|
9
|
+
|
10
|
+
def entries
|
11
|
+
@entries ||= array_wrap(safe_retrieve(parsed_body, "entry")).map { |entry| Album.new(entry) }
|
12
|
+
end
|
13
|
+
alias :albums :entries
|
14
|
+
|
15
|
+
def links
|
16
|
+
@links ||= safe_retrieve(parsed_body, "link").map { |link| Link.new(link) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def title
|
20
|
+
@title ||= safe_retrieve(parsed_body, "title")
|
21
|
+
end
|
22
|
+
|
23
|
+
def updated
|
24
|
+
@updated ||= map_to_date(safe_retrieve(parsed_body, "updated"))
|
25
|
+
end
|
26
|
+
|
27
|
+
def icon
|
28
|
+
@icon ||= safe_retrieve(parsed_body, "icon")
|
29
|
+
end
|
30
|
+
|
31
|
+
def generator
|
32
|
+
@generator ||= safe_retrieve(parsed_body, "generator", "__content__")
|
33
|
+
end
|
34
|
+
|
35
|
+
def total_results
|
36
|
+
@total_results ||= map_to_integer(safe_retrieve(parsed_body, "totalResults"))
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_index
|
40
|
+
@start_index ||= map_to_integer(safe_retrieve(parsed_body, "startIndex"))
|
41
|
+
end
|
42
|
+
|
43
|
+
def items_per_page
|
44
|
+
@items_per_page ||= map_to_integer(safe_retrieve(parsed_body, "itemsPerPage"))
|
45
|
+
end
|
46
|
+
|
47
|
+
def user
|
48
|
+
@user ||= safe_retrieve(parsed_body, "user")
|
49
|
+
end
|
50
|
+
|
51
|
+
def nickname
|
52
|
+
@nickname ||= safe_retrieve(parsed_body, "nickname")
|
53
|
+
end
|
54
|
+
|
55
|
+
def thumbnail
|
56
|
+
@thumbnail ||= safe_retrieve(parsed_body, "thumbnail")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|