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.
Files changed (59) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +6 -1
  3. data/Gemfile +6 -0
  4. data/README.md +16 -24
  5. data/Rakefile +1 -1
  6. data/lib/picasa.rb +18 -12
  7. data/lib/picasa/api/album.rb +45 -0
  8. data/lib/picasa/client.rb +14 -0
  9. data/lib/picasa/connection.rb +86 -0
  10. data/lib/picasa/exceptions.rb +17 -0
  11. data/lib/picasa/presenter/album.rb +76 -0
  12. data/lib/picasa/presenter/album_list.rb +60 -0
  13. data/lib/picasa/presenter/author.rb +15 -0
  14. data/lib/picasa/presenter/base.rb +29 -0
  15. data/lib/picasa/presenter/link.rb +19 -0
  16. data/lib/picasa/presenter/media.rb +27 -0
  17. data/lib/picasa/presenter/photo.rb +79 -0
  18. data/lib/picasa/presenter/thumbnail.rb +19 -0
  19. data/lib/picasa/utils.rb +44 -0
  20. data/lib/picasa/version.rb +1 -1
  21. data/picasa.gemspec +4 -15
  22. data/test/api/album_test.rb +24 -0
  23. data/test/client_test.rb +14 -0
  24. data/test/connection_test.rb +71 -0
  25. data/test/fixtures/album/album-list-with-tag.txt +105 -0
  26. data/test/fixtures/album/album-list.txt +105 -0
  27. data/test/fixtures/album/album-show-with-max-results.txt +131 -0
  28. data/test/fixtures/album/album-show-with-tag-and-many-photos.txt +156 -0
  29. data/test/fixtures/album/album-show-with-tag-and-one-photo.txt +105 -0
  30. data/test/fixtures/album/album-show.txt +169 -0
  31. data/test/fixtures/auth/failure.txt +12 -0
  32. data/test/fixtures/auth/success.txt +14 -0
  33. data/test/fixtures/json.txt +435 -0
  34. data/test/fixtures/photo/photo-list-all-with-q.txt +556 -0
  35. data/test/fixtures/photo/photo-list-all.txt +623 -0
  36. data/test/fixtures/photo/photo-list-user.txt +388 -0
  37. data/test/fixtures/presenters/album_list.xml +88 -0
  38. data/test/fixtures/presenters/album_show.xml +152 -0
  39. data/test/fixtures/presenters/album_show_with_one_photo.xml +88 -0
  40. data/test/fixtures/tag/tag-list-album.txt +77 -0
  41. data/test/fixtures/tag/tag-list-photo.txt +72 -0
  42. data/test/fixtures/tag/tag-list.txt +68 -0
  43. data/test/helper.rb +12 -6
  44. data/test/presenter/album_list_test.rb +67 -0
  45. data/test/presenter/album_test.rb +173 -0
  46. data/test/presenter/author_test.rb +17 -0
  47. data/test/presenter/base_test.rb +27 -0
  48. data/test/presenter/link_test.rb +21 -0
  49. data/test/presenter/media_test.rb +29 -0
  50. data/test/presenter/photo_test.rb +81 -0
  51. data/test/presenter/thumbnail_test.rb +24 -0
  52. data/test/utils_test.rb +84 -0
  53. metadata +66 -31
  54. data/lib/picasa/config.rb +0 -15
  55. data/lib/picasa/web_albums.rb +0 -56
  56. data/test/fixtures/albums +0 -15
  57. data/test/fixtures/photos +0 -15
  58. data/test/test_config.rb +0 -12
  59. data/test/test_web_albums.rb +0 -44
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  *.rbc
3
+ .rvmrc
3
4
  .bundle
4
5
  .config
5
6
  .yardoc
data/.travis.yml CHANGED
@@ -2,5 +2,10 @@ notifications:
2
2
  disabled: true
3
3
  rvm:
4
4
  - 1.8.7
5
- - 1.9.2
6
5
  - 1.9.3
6
+ env:
7
+ - XML_PARSER=rexml
8
+ - XML_PARSER=nokogiri
9
+ - XML_PARSER=libxml
10
+ # does not work yet
11
+ # - XML_PARSER=ox
data/Gemfile CHANGED
@@ -4,3 +4,9 @@ gemspec
4
4
 
5
5
  gem "rake"
6
6
  gem "minitest", :platform => :ruby_18
7
+ gem "debugger", :platform => :ruby_19
8
+
9
+ # xml parsers
10
+ gem "nokogiri"
11
+ gem "libxml-ruby"
12
+ gem "ox"
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Picasa
2
2
 
3
- Simple google picasa managment.
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.albums(:google_user => 'google_username')
16
- # => [ {:id => "666", :title => "satan-album", :photos_count => 6, :photo => "url",
17
- # :thumbnail => "url", :slideshow => "url", :summary => "summary"},
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
- ``` ruby
28
- Picasa.config do |c|
29
- c.google_user = 'google.user'
30
- end
18
+ client.album.show("album_id")
19
+ # => Picasa::Presenter::Album
31
20
  ```
32
21
 
33
- and use it:
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
  [![Build Status](https://secure.travis-ci.org/morgoth/picasa.png)](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) 2011 Wojciech Wnętrzak, released under the MIT license.
37
+ Copyright (c) Wojciech Wnętrzak, released under the MIT license.
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require "bundler/gem_tasks"
4
4
  require "rake/testtask"
5
5
  Rake::TestTask.new(:test) do |test|
6
6
  test.libs << "lib" << "test"
7
- test.pattern = "test/**/test_*.rb"
7
+ test.pattern = "test/**/*_test.rb"
8
8
  test.verbose = true
9
9
  end
10
10
 
data/lib/picasa.rb CHANGED
@@ -1,16 +1,22 @@
1
- require "picasa/web_albums"
2
- require "picasa/config"
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
- module Picasa
6
- def self.albums(options = {})
7
- web_albums = Picasa::WebAlbums.new(options.delete(:google_user))
8
- web_albums.albums(options)
9
- end
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
- def self.photos(options = {})
12
- raise ArgumentError.new("You must specify album_id") unless options[:album_id]
13
- web_albums = Picasa::WebAlbums.new(options.delete(:google_user))
14
- web_albums.photos(options.delete(:album_id), options)
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
@@ -0,0 +1,15 @@
1
+ require "picasa/presenter/base"
2
+
3
+ module Picasa
4
+ module Presenter
5
+ class Author < Base
6
+ def name
7
+ @name ||= safe_retrieve(parsed_body, "name")
8
+ end
9
+
10
+ def uri
11
+ @uri ||= safe_retrieve(parsed_body, "uri")
12
+ end
13
+ end
14
+ end
15
+ end