picasa 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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