picasaweb-backup 0.4.0 → 0.5.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -3
- data/bin/picasaweb-backup +16 -8
- data/lib/picasaweb-backup.rb +87 -78
- data/lib/version.rb +1 -1
- data/picasaweb-backup.gemspec +6 -5
- metadata +42 -35
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 65b528a9faea826628aa1501f2eb4fecd1a4859b
|
4
|
+
data.tar.gz: 5cdbe52dd1e524d088415b036ad20e38886f47ba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7b8acd1ddb8fe26302564dfdb8ff1fd269bc693ba238e9caf366e593498587e30b8f50e9d4fe90f39db79a807c75f412ec1f8018c78a4d2616d02c62ee37f5c5
|
7
|
+
data.tar.gz: 15365bbb6f58c8c2b98cb5416e0df10d01ac69f014a4c4057846724018da538b3ed7cafe5733d1f6da93e22afdbd6f53c5febf1fe6072bbae5a74e12bbd4cb84
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/bin/picasaweb-backup
CHANGED
@@ -29,15 +29,23 @@ opt_parser = OptionParser.new('Backing up your Picasaweb photos') do |opt|
|
|
29
29
|
end
|
30
30
|
|
31
31
|
opt_parser.parse!(ARGV)
|
32
|
-
cli = Picasaweb::CLI.new opts
|
33
32
|
|
34
|
-
|
33
|
+
if !File.exists?("client_id.json")
|
34
|
+
puts("No file client_id.json found. \n" \
|
35
|
+
"Please go to https://console.developers.google.com/apis/credentials "\
|
36
|
+
"to generate an OAuth CLI app and download, client_id.json file and "\
|
37
|
+
"place it in the directory where you run picasaweb-backup.")
|
35
38
|
|
36
|
-
|
39
|
+
else
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
41
|
+
begin
|
42
|
+
|
43
|
+
cli = Picasaweb::CLI.new opts
|
44
|
+
cli.start_backup
|
43
45
|
|
46
|
+
rescue => e
|
47
|
+
puts "ERROR: #{e.message}".red
|
48
|
+
puts e.backtrace
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/picasaweb-backup.rb
CHANGED
@@ -8,9 +8,11 @@
|
|
8
8
|
|
9
9
|
require "version"
|
10
10
|
require "yaml"
|
11
|
-
require "rubygems"
|
12
|
-
require "gdata"
|
13
11
|
require "logger"
|
12
|
+
require 'googleauth'
|
13
|
+
require 'googleauth/stores/file_token_store'
|
14
|
+
require 'http'
|
15
|
+
require 'nokogiri'
|
14
16
|
|
15
17
|
#monkey-patch logger formatting
|
16
18
|
class Logger
|
@@ -20,24 +22,93 @@ class Logger
|
|
20
22
|
end
|
21
23
|
|
22
24
|
module Picasaweb
|
25
|
+
class Client
|
26
|
+
|
27
|
+
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
scope = 'https://picasaweb.google.com/data/'
|
31
|
+
client_id = Google::Auth::ClientId.from_file('client_id.json')
|
32
|
+
token_store = Google::Auth::Stores::FileTokenStore.new(:file => 'tokens.yaml')
|
33
|
+
authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store)
|
34
|
+
|
35
|
+
user_id = "picasaweb-backup"
|
36
|
+
|
37
|
+
credentials = authorizer.get_credentials(user_id)
|
38
|
+
|
39
|
+
if credentials.nil?
|
40
|
+
url = authorizer.get_authorization_url(base_url: OOB_URI )
|
41
|
+
puts "Open #{url} in your browser and enter the resulting code:"
|
42
|
+
code = gets
|
43
|
+
@credentials = authorizer.get_and_store_credentials_from_code(
|
44
|
+
user_id: user_id, code: code, base_url: OOB_URI)
|
45
|
+
else
|
46
|
+
puts "Found token #{credentials.access_token}. Refreshing..."
|
47
|
+
credentials.fetch_access_token!
|
48
|
+
@credentials = credentials
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Retrieves all albums for a user.
|
53
|
+
def get_albums
|
54
|
+
uri = "https://picasaweb.google.com/data/feed/api/user/default"
|
55
|
+
feed = get(uri)
|
56
|
+
entries = feed.css("entry")
|
57
|
+
|
58
|
+
entries.map do |entry|
|
59
|
+
{ :id => entry.css('gphoto|id').text,
|
60
|
+
:user => entry.css('gphoto|user').text,
|
61
|
+
:title => entry.css('title').text }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Retrieves all photos from an album.
|
66
|
+
def get_photos(album)
|
67
|
+
uri = "https://picasaweb.google.com/data/feed/api/user/" +
|
68
|
+
"default/albumid/#{album[:id]}?kind=photo&imgmax=d"
|
69
|
+
|
70
|
+
entries = get(uri).css("entry")
|
71
|
+
|
72
|
+
entries.map do |entry|
|
73
|
+
url = entry.css('media|group > media|content[url]').first.attribute("url").value
|
74
|
+
photo = { :id => entry.css('gphoto|id').text,
|
75
|
+
:album_id => entry.css('gphoto|albumid').text,
|
76
|
+
:title => entry.css('title').text,
|
77
|
+
:url => url
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def get(url)
|
84
|
+
res = HTTP[:authorization => "Bearer #{@credentials.access_token}"].get(url)
|
85
|
+
Nokogiri::XML(res.body)
|
86
|
+
end
|
87
|
+
|
88
|
+
def download(photo)
|
89
|
+
response = HTTP.get(photo[:url])
|
90
|
+
File.open(photo[:title], 'w') { |f| f.write response.body }
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
23
95
|
class CLI
|
96
|
+
|
24
97
|
ALBUM_DIR = "Albums"
|
98
|
+
|
25
99
|
def initialize opts
|
26
100
|
@opts = opts
|
101
|
+
@client = Client.new
|
27
102
|
|
28
103
|
if opts[:dir]
|
29
104
|
Dir.chdir opts[:dir]
|
105
|
+
self.print "Changing working directory to #{opts[:dir]}"
|
30
106
|
end
|
31
107
|
|
32
108
|
if @opts[:log]
|
33
109
|
@logger = Logger.new "picasaweb-backup.log", shift_age = "monthly"
|
34
110
|
end
|
35
111
|
|
36
|
-
if opts[:dir]
|
37
|
-
self.print "Changing working directory to #{opts[:dir]}"
|
38
|
-
end
|
39
|
-
|
40
|
-
@account = File.open("account.yml", 'r') { |f| YAML.load f }
|
41
112
|
end
|
42
113
|
|
43
114
|
def print msg
|
@@ -48,67 +119,26 @@ module Picasaweb
|
|
48
119
|
end
|
49
120
|
end
|
50
121
|
|
51
|
-
def
|
52
|
-
if account["username"].nil?
|
53
|
-
raise "Please add your username to account.yml"
|
54
|
-
elsif account["password"].nil?
|
55
|
-
raise "Please add your password to account.yml"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def picasa_client(username, password)
|
60
|
-
client = GData::Client::Photos.new
|
61
|
-
client.clientlogin(username, password)
|
62
|
-
client
|
63
|
-
end
|
64
|
-
|
65
|
-
def ensure_exists dir
|
122
|
+
def ensure_exists(dir)
|
66
123
|
if !File.directory? dir
|
67
124
|
Dir.mkdir dir
|
68
125
|
self.print "Creating directory '#{dir}'"
|
69
126
|
end
|
70
127
|
end
|
71
128
|
|
72
|
-
|
73
|
-
def get_albums(client, user = nil)
|
74
|
-
uri = "http://picasaweb.google.com/data/feed/api/user/#{user || 'default'}"
|
75
|
-
feed = client.get(uri).to_xml
|
76
|
-
albums = []
|
77
|
-
feed.elements.each('entry') do |entry|
|
78
|
-
next unless entry.elements['gphoto:id']
|
79
|
-
albums << { :id => entry.elements['gphoto:id'].text,
|
80
|
-
:user => entry.elements['gphoto:user'].text,
|
81
|
-
:title => entry.elements['title'].text }
|
82
|
-
end
|
83
|
-
albums
|
84
|
-
end
|
85
|
-
|
86
|
-
def download_album client, album
|
129
|
+
def download_album(client, album)
|
87
130
|
Dir.chdir album[:title] do
|
88
131
|
self.print "Checking for new photos in '#{album[:title]}'"
|
89
132
|
photos = nil
|
90
133
|
until photos
|
91
|
-
|
92
|
-
photos = get_photos client, album
|
93
|
-
rescue GData::Client::ServerError
|
94
|
-
"Server error, retrying\n"
|
95
|
-
end
|
134
|
+
photos = client.get_photos(album)
|
96
135
|
end
|
97
136
|
|
98
137
|
downloaded_photos = 0
|
99
138
|
photos.each do |photo|
|
100
139
|
if !File.exists? photo[:title]
|
101
140
|
self.print " ==> #{photo[:title]}"
|
102
|
-
|
103
|
-
until response
|
104
|
-
begin
|
105
|
-
response = client.get photo[:url]
|
106
|
-
rescue GData::Client::ServerError
|
107
|
-
"Server error, retrying\n"
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
File.open(photo[:title], 'w') { |f| f.write response.body }
|
141
|
+
client.download(photo)
|
112
142
|
downloaded_photos += 1
|
113
143
|
end
|
114
144
|
end
|
@@ -118,38 +148,17 @@ module Picasaweb
|
|
118
148
|
end
|
119
149
|
end
|
120
150
|
|
121
|
-
# Retrieves all photos from an album.
|
122
|
-
def get_photos(client, album)
|
123
|
-
uri = "http://picasaweb.google.com/data/feed/api/user/" +
|
124
|
-
"#{album[:user] || 'default'}/albumid/#{album[:id]}?kind=photo&imgmax=d"
|
125
|
-
|
126
|
-
feed = client.get(uri).to_xml
|
127
|
-
photos = []
|
128
|
-
feed.elements.each('entry') do |entry|
|
129
|
-
next unless entry.elements['gphoto:id']
|
130
|
-
next unless entry.elements['media:group']
|
131
|
-
photo = { :id => entry.elements['gphoto:id'].text,
|
132
|
-
:album_id => entry.elements['gphoto:albumid'].text,
|
133
|
-
:title => entry.elements['title'].text }
|
134
|
-
entry.elements['media:group'].elements.each('media:content') do |content|
|
135
|
-
photo[:url] = content.attribute('url').value
|
136
|
-
end
|
137
|
-
photos << photo
|
138
|
-
end
|
139
|
-
photos
|
140
|
-
end
|
141
|
-
|
142
151
|
def start_backup
|
143
|
-
|
144
|
-
|
145
|
-
|
152
|
+
albums = @client.get_albums.select do |album|
|
153
|
+
album[:title].downcase != "auto backup"
|
154
|
+
end
|
146
155
|
|
147
|
-
ensure_exists
|
156
|
+
ensure_exists(ALBUM_DIR)
|
148
157
|
Dir.chdir ALBUM_DIR
|
149
158
|
|
150
159
|
albums.each do |album|
|
151
160
|
ensure_exists album[:title]
|
152
|
-
download_album
|
161
|
+
download_album(@client, album)
|
153
162
|
end
|
154
163
|
|
155
164
|
end
|
data/lib/version.rb
CHANGED
data/picasaweb-backup.gemspec
CHANGED
@@ -3,16 +3,17 @@ require File.expand_path('../lib/version', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Leonard Ehrenfried"]
|
6
|
-
gem.email = ['leonard.ehrenfried@
|
6
|
+
gem.email = ['leonard.ehrenfried@gmail.com']
|
7
7
|
gem.summary = "Picasa Web Albums backup tool"
|
8
8
|
gem.description = %{Backup all your photos from Google's Picasa Web Albums service,
|
9
9
|
can be run repeatedly on the same folder and only downloads new files.}
|
10
10
|
|
11
|
-
gem.homepage = 'http://github.com/
|
11
|
+
gem.homepage = 'http://github.com/leonardehrenfried/picasaweb-backup'
|
12
12
|
|
13
|
-
gem.add_dependency('
|
14
|
-
gem.add_dependency('
|
15
|
-
gem.add_dependency('
|
13
|
+
gem.add_dependency('artii', '~> 2.1')
|
14
|
+
gem.add_dependency('colored', '~> 1.2')
|
15
|
+
gem.add_dependency('googleauth', '~> 0.5.1')
|
16
|
+
gem.add_dependency('http', '~> 2.1')
|
16
17
|
|
17
18
|
gem.files = `git ls-files`.split($\)
|
18
19
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,74 +1,82 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: picasaweb-backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.5.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Leonard Ehrenfried
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-12-01 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
14
|
+
name: artii
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: '2.1'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
26
|
+
version: '2.1'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
28
|
+
name: colored
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version: 2
|
33
|
+
version: '1.2'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
|
-
version: 2
|
40
|
+
version: '1.2'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
42
|
+
name: googleauth
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- - ~>
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
47
|
+
version: 0.5.1
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- - ~>
|
52
|
+
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
|
63
|
-
|
54
|
+
version: 0.5.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: http
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.1'
|
69
|
+
description: |-
|
70
|
+
Backup all your photos from Google's Picasa Web Albums service,
|
71
|
+
can be run repeatedly on the same folder and only downloads new files.
|
64
72
|
email:
|
65
|
-
- leonard.ehrenfried@
|
73
|
+
- leonard.ehrenfried@gmail.com
|
66
74
|
executables:
|
67
75
|
- picasaweb-backup
|
68
76
|
extensions: []
|
69
77
|
extra_rdoc_files: []
|
70
78
|
files:
|
71
|
-
- .gitignore
|
79
|
+
- ".gitignore"
|
72
80
|
- Gemfile
|
73
81
|
- Gemfile.lock
|
74
82
|
- LICENSE
|
@@ -78,28 +86,27 @@ files:
|
|
78
86
|
- lib/picasaweb-backup.rb
|
79
87
|
- lib/version.rb
|
80
88
|
- picasaweb-backup.gemspec
|
81
|
-
homepage: http://github.com/
|
89
|
+
homepage: http://github.com/leonardehrenfried/picasaweb-backup
|
82
90
|
licenses: []
|
91
|
+
metadata: {}
|
83
92
|
post_install_message:
|
84
93
|
rdoc_options: []
|
85
94
|
require_paths:
|
86
95
|
- lib
|
87
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
-
none: false
|
89
97
|
requirements:
|
90
|
-
- -
|
98
|
+
- - ">="
|
91
99
|
- !ruby/object:Gem::Version
|
92
100
|
version: '0'
|
93
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
-
none: false
|
95
102
|
requirements:
|
96
|
-
- -
|
103
|
+
- - ">="
|
97
104
|
- !ruby/object:Gem::Version
|
98
105
|
version: '0'
|
99
106
|
requirements: []
|
100
107
|
rubyforge_project:
|
101
|
-
rubygems_version:
|
108
|
+
rubygems_version: 2.4.5
|
102
109
|
signing_key:
|
103
|
-
specification_version:
|
110
|
+
specification_version: 4
|
104
111
|
summary: Picasa Web Albums backup tool
|
105
112
|
test_files: []
|