picasa-downloader 0.0.1

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.
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'require_all'
3
+ require 'fileutils'
4
+ require_all 'lib'
5
+ require 'gdata'
6
+ require 'nokogiri'
7
+ require 'net/http'
8
+ require 'uri'
@@ -0,0 +1,10 @@
1
+ module PicasaDownloader
2
+ class Album
3
+ attr_reader :title, :id
4
+
5
+ def initialize(title, id)
6
+ @title = title
7
+ @id = id
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ module PicasaDownloader
2
+ class AlbumPersister
3
+ def initialize(client, album, download_directory_root)
4
+ @client = client
5
+ @album = album
6
+ @download_directory_root = download_directory_root
7
+ FileUtils.mkdir_p(get_album_dir)
8
+ end
9
+
10
+ def download
11
+ @client.list_photos(@album.id).each { |photo|
12
+ photo_data = @client.download_photo(photo)
13
+ if photo_data
14
+ File.open(get_album_dir + photo.name, 'wb') { |file|
15
+ file.write(photo_data)
16
+ }
17
+ end
18
+ }
19
+ end
20
+
21
+ private
22
+
23
+ def get_album_dir
24
+ @download_directory_root + "/#{@album.title}/"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ module PicasaDownloader
2
+ class Client
3
+ def initialize(credentials)
4
+ @gd = GData::Client::Photos.new
5
+ @gd.clientlogin(credentials.username, credentials.password)
6
+ end
7
+
8
+ def list_albums
9
+ doc = to_xml('https://picasaweb.google.com/data/feed/api/user/default')
10
+ doc.css('entry').map { |e|
11
+ id = e.xpath("id/text()").
12
+ select { |x| x.to_s.match(/^\d+$/) }.
13
+ map { |x| x.inner_text }.first
14
+ Album.new(e.css('title').first.inner_text, id)
15
+ }
16
+ end
17
+
18
+ def list_photos(album_id)
19
+ doc = to_xml(
20
+ "https://picasaweb.google.com/data/feed/api/user/default/albumid/#{album_id}?imgmax=d")
21
+ doc.css("entry").map { |e|
22
+ Photo.new(
23
+ e.xpath("group/content/@url").to_s,
24
+ # Google includes the milliseconds in the timestamp:
25
+ e.css("tags time").inner_text.to_i / 1000,
26
+ e.css("size").inner_text.to_i,
27
+ e.css("title").inner_text)
28
+ }
29
+ end
30
+
31
+ def download_photo(photo)
32
+ unless photo.url.include?"googlevideo"
33
+ uri = URI.parse(photo.url)
34
+ http = Net::HTTP.new(uri.host, uri.port)
35
+ request = Net::HTTP::Get.new(uri.request_uri)
36
+ http.use_ssl = true
37
+ response = http.request(request)
38
+ raise "Response not ok, was #{response.code}" unless
39
+ response.code.to_i.between? 200, 299
40
+ response.body
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def to_xml(gdata_url)
47
+ response = @gd.get(gdata_url)
48
+ xml = response.to_xml.to_s
49
+ doc = Nokogiri::XML(xml)
50
+ doc.remove_namespaces!
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ module PicasaDownloader
2
+ class EnvCredentials
3
+ attr_reader :username, :password
4
+
5
+ def initialize
6
+ @username = ENV['PICASA_USERNAME']
7
+ @password = ENV['PICASA_PASSWORD']
8
+ end
9
+
10
+ def is_configured?
11
+ ENV['PICASA_USERNAME'].to_s != '' &&
12
+ ENV['PICASA_PASSWORD'].to_s != ''
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module PicasaDownloader
2
+ class PicasaDownloaderError < StandardError
3
+ end
4
+
5
+ class EnvironmentalCredentialsNotSet < PicasaDownloaderError
6
+ def initialize(message = 'Cannot authenticate - environmental settings missing. Please set the environmental values PICASA_USERNAME and PICASA_PASSWORD')
7
+ super(message)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module PicasaDownloader
2
+ class Photo
3
+ attr_reader :url, :created_date, :size, :name
4
+
5
+ def initialize(url, created_date_since_epoch, size, name)
6
+ @url = url
7
+ @created_date = Time.at(created_date_since_epoch)
8
+ @size = size
9
+ @name = name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'picasa-downloader'
3
+ s.version = '0.0.1'
4
+ s.license = 'MIT'
5
+ s.summary = 'Download your Google Picasa photo albums'
6
+ s.description =
7
+ 'This Gem makes it convenient to download Picasa albums via command-line interface'
8
+ s.authors = ['Lauri Lehmijoki']
9
+ s.email = 'lauri.lehmijoki@iki.fi'
10
+ s.files = `git ls-files`.split("\n")
11
+ s.require_paths = ['lib']
12
+ s.executables << 'picasa-downloader'
13
+ s.homepage = 'https://github.com/laurilehmijoki/picasa-downloader'
14
+
15
+ s.add_dependency 'require_all'
16
+ if RUBY_VERSION < "1.9"
17
+ s.add_dependency 'gdata'
18
+ else
19
+ s.add_dependency 'gdata_19'
20
+ end
21
+ s.add_dependency 'require_relative'
22
+ s.add_dependency 'nokogiri'
23
+ s.add_dependency 'gli'
24
+ s.add_dependency 'rake'
25
+
26
+ s.add_development_dependency 'rspec'
27
+ s.add_development_dependency 'vcr'
28
+ s.add_development_dependency 'webmock'
29
+ end
@@ -0,0 +1,38 @@
1
+ require 'vcr'
2
+ require 'test_helper'
3
+ require_relative '../lib/picasa-downloader'
4
+
5
+ module PicasaDownloader
6
+ describe AlbumPersister do
7
+ before :each do
8
+ VCR.use_cassette("google-login") do
9
+ @client = Client.new(EnvCredentials.new)
10
+ tempdir = ENV['TMPDIR']
11
+ tempdir = '' unless tempdir
12
+ @dir = tempdir + 'picasa-downloader-test'
13
+ end
14
+ end
15
+
16
+ after :each do
17
+ FileUtils.rm_r(@dir)
18
+ end
19
+
20
+ it "creates a directory for each album" do
21
+ with_cassettes {
22
+ @albums = @client.list_albums
23
+ AlbumPersister.new(@client, @albums.first, @dir).download
24
+ File.exists?(@dir + "/#{@albums.first.title}")
25
+ }
26
+ end
27
+
28
+ it "saves each photo into the album" do
29
+ with_cassettes {
30
+ @albums = @client.list_albums
31
+ AlbumPersister.new(@client, @albums.first, @dir).download
32
+ Dir.entries(@dir + "/#{@albums.first.title}/").any? { |file|
33
+ file.downcase.match(/jp(e)?g/)
34
+ }.should be true
35
+ }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ require 'vcr'
2
+ require_relative 'test_helper'
3
+ require_relative '../lib/picasa-downloader'
4
+
5
+ module PicasaDownloader
6
+ describe Client do
7
+ before :each do
8
+ VCR.use_cassette("google-login") do
9
+ @client = Client.new(EnvCredentials.new())
10
+ end
11
+ end
12
+
13
+ it "loads the album ids" do
14
+ VCR.use_cassette("picasa-albums") do
15
+ albums = @client.list_albums
16
+ albums.length.should be > 0
17
+ albums.first.id =~ /^\d+$/
18
+ albums.first.title.length.should be > 0
19
+ end
20
+ end
21
+
22
+ it "lists photos for an album" do
23
+ VCR.use_cassette("picasa-albums") do
24
+ @albums = @client.list_albums
25
+ end
26
+ VCR.use_cassette("picasa-album") do
27
+ photos = @client.list_photos(@albums.first.id)
28
+ photos.length.should be > 0
29
+ photos.first.url =~ /^https/
30
+ photos.first.created_date.should be < Time.new
31
+ photos.first.created_date.should be > Time.at(0)
32
+ photos.first.size.should be > 0
33
+ photos.first.name.length.should be > 0
34
+ end
35
+ end
36
+
37
+ it "downloads photos photos of an album" do
38
+ with_cassettes {
39
+ @albums = @client.list_albums
40
+ @photos = @client.list_photos(@albums.first.id)
41
+ def jpeg?(data)
42
+ # See http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html
43
+ return data[0, 4] == "\xff\xd8\xff\xe0"
44
+ end
45
+ bytes = @client.download_photo(@photos.first)
46
+ jpeg?(bytes).should be true
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+ require_relative '../lib/picasa-downloader'
3
+
4
+ module PicasaDownloader
5
+ describe EnvCredentials do
6
+ it "knows when the credentials are not set" do
7
+ ENV['PICASA_USERNAME'] = ''
8
+ ENV['PICASA_PASSWORD'] = ''
9
+ creds = EnvCredentials.new
10
+ creds.is_configured?.should be false
11
+ end
12
+
13
+ it "knows when the credentials are set" do
14
+ ENV['PICASA_USERNAME'] = 'uzer'
15
+ ENV['PICASA_PASSWORD'] = 'pazz'
16
+ creds = EnvCredentials.new
17
+ creds.is_configured?.should be true
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require 'require_relative'
2
+
3
+ VCR.configure do |config|
4
+ config.cassette_library_dir = "fixtures/cassettes"
5
+ config.hook_into :webmock
6
+ end
7
+
8
+ def with_cassettes
9
+ photo_matcher = lambda do |req_1, req_2|
10
+ [req_1, req_2].all? { |req|
11
+ req.uri.include?"googleusercontent"
12
+ }
13
+ end
14
+ VCR.use_cassette("picasa-albums") do
15
+ VCR.use_cassette("picasa-album") do
16
+ VCR.use_cassette("picasa-photo",
17
+ :match_requests_on => [photo_matcher],
18
+ :allow_playback_repeats => true) do
19
+ yield
20
+ end
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,211 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: picasa-downloader
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Lauri Lehmijoki
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-07-18 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: require_all
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: gdata
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: require_relative
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: nokogiri
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :runtime
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: gli
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ type: :runtime
89
+ version_requirements: *id005
90
+ - !ruby/object:Gem::Dependency
91
+ name: rake
92
+ prerelease: false
93
+ requirement: &id006 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ type: :runtime
103
+ version_requirements: *id006
104
+ - !ruby/object:Gem::Dependency
105
+ name: rspec
106
+ prerelease: false
107
+ requirement: &id007 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ type: :development
117
+ version_requirements: *id007
118
+ - !ruby/object:Gem::Dependency
119
+ name: vcr
120
+ prerelease: false
121
+ requirement: &id008 !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: 3
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ type: :development
131
+ version_requirements: *id008
132
+ - !ruby/object:Gem::Dependency
133
+ name: webmock
134
+ prerelease: false
135
+ requirement: &id009 !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ type: :development
145
+ version_requirements: *id009
146
+ description: This Gem makes it convenient to download Picasa albums via command-line interface
147
+ email: lauri.lehmijoki@iki.fi
148
+ executables:
149
+ - picasa-downloader
150
+ extensions: []
151
+
152
+ extra_rdoc_files: []
153
+
154
+ files:
155
+ - .gitignore
156
+ - .travis.yml
157
+ - Gemfile
158
+ - Rakefile
159
+ - TODO.md
160
+ - bin/picasa-downloader
161
+ - fixtures/cassettes/google-login.yml
162
+ - fixtures/cassettes/picasa-album.yml
163
+ - fixtures/cassettes/picasa-albums.yml
164
+ - fixtures/cassettes/picasa-photo.yml
165
+ - lib/picasa-downloader.rb
166
+ - lib/picasa-downloader/album.rb
167
+ - lib/picasa-downloader/album_persister.rb
168
+ - lib/picasa-downloader/client.rb
169
+ - lib/picasa-downloader/env_credentials.rb
170
+ - lib/picasa-downloader/errors.rb
171
+ - lib/picasa-downloader/photo.rb
172
+ - picasa-downloader.gemspec
173
+ - spec/album_persister_spec.rb
174
+ - spec/client_spec.rb
175
+ - spec/env_credentials_spec.rb
176
+ - spec/test_helper.rb
177
+ homepage: https://github.com/laurilehmijoki/picasa-downloader
178
+ licenses:
179
+ - MIT
180
+ post_install_message:
181
+ rdoc_options: []
182
+
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ none: false
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ hash: 3
191
+ segments:
192
+ - 0
193
+ version: "0"
194
+ required_rubygems_version: !ruby/object:Gem::Requirement
195
+ none: false
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ hash: 3
200
+ segments:
201
+ - 0
202
+ version: "0"
203
+ requirements: []
204
+
205
+ rubyforge_project:
206
+ rubygems_version: 1.8.13
207
+ signing_key:
208
+ specification_version: 3
209
+ summary: Download your Google Picasa photo albums
210
+ test_files: []
211
+