bye-flickr 1.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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +101 -0
- data/bin/bye-flickr +44 -0
- data/lib/bye_flickr.rb +6 -0
- data/lib/bye_flickr/app.rb +133 -0
- data/lib/bye_flickr/auth.rb +42 -0
- data/lib/bye_flickr/photo_downloader.rb +101 -0
- data/lib/bye_flickr/response_to_json.rb +39 -0
- data/lib/bye_flickr/version.rb +3 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 80703e70104c8f9222c918040e506979ae025819ad6cd1192687c8f9555a67cc
|
4
|
+
data.tar.gz: c207aee6f4ca65c80e839b24622d18c7d1eaf2b512920b3f70de850cb1074882
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f5ff0ed9afc666b67a859f6ca3772c523b154da300bd7dd710e017cfe8516520933adb94db1f2a85cbd842f6ad67c2905db09b242a97acd366b5d6c7c742879c
|
7
|
+
data.tar.gz: c32483cfd81b38ab3e883472fa74c838c0ddf1140c6a83004b5297f86afff50d58ac0b3be1a56ce9801b9e31857e9d666ddc785a4e4fbe3c86b25142bd27cd93
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 Jens Krämer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
Bye, Flickr!
|
2
|
+
============
|
3
|
+
|
4
|
+
Simple app to download everything from your flickr account. Your photos will be
|
5
|
+
put into a directory structure reflecting Flickr collections and sets. Metadata
|
6
|
+
for collections, sets and photos will be stored as JSON files, as well as
|
7
|
+
contacts and groups data.
|
8
|
+
|
9
|
+
Installation
|
10
|
+
------------
|
11
|
+
|
12
|
+
You need Ruby. I used it with Ruby 2.5, 2.4 should be ok as well. Install the
|
13
|
+
gem, run `bye-flickr -h` for usage info.
|
14
|
+
|
15
|
+
~~~~
|
16
|
+
|
17
|
+
$ gem install bye-flickr
|
18
|
+
Successfully installed bye-flickr-0.1.0
|
19
|
+
1 gem installed
|
20
|
+
|
21
|
+
$ bye-flickr -h
|
22
|
+
usage: /home/jk/.gem/ruby/2.5.1/bin/bye-flickr [options]
|
23
|
+
Required arguments (create API key and secret in the Flickr web interface):
|
24
|
+
-d, --dir directory to store data
|
25
|
+
-k, --key API key
|
26
|
+
-s, --secret API secret
|
27
|
+
|
28
|
+
Optional arguments, if you already have authorized the app:
|
29
|
+
--at Access token
|
30
|
+
--as Access token secret
|
31
|
+
|
32
|
+
Other commands:
|
33
|
+
--version print the version
|
34
|
+
-h, --help
|
35
|
+
|
36
|
+
~~~~
|
37
|
+
|
38
|
+
Usage
|
39
|
+
-----
|
40
|
+
|
41
|
+
First of all, head to your [Flickr
|
42
|
+
account](https://www.flickr.com/services/apps/create/apply/) and create an API
|
43
|
+
key. Choose non-commercial and pick any name you like for your 'App'. In the
|
44
|
+
end you will get a key and a secret which are what you need for the `-k` and
|
45
|
+
`-s` options. Pick a directory in a location with enough disk space and there you go:
|
46
|
+
|
47
|
+
~~~~
|
48
|
+
|
49
|
+
$ bye-flickr -d /space/photos -k lengthyAPIkey -s notsolongsecret
|
50
|
+
token_rejected
|
51
|
+
Open this url in your browser to complete the authentication process:
|
52
|
+
https://api.flickr.com/services/oauth/authorize?oauth_token=some-token&perms=read
|
53
|
+
Copy here the number given when you complete the process.
|
54
|
+
|
55
|
+
~~~~
|
56
|
+
|
57
|
+
Do as you're told and go to the URL, authorize the app, copy/paste the nine
|
58
|
+
digit number and hit Enter.
|
59
|
+
|
60
|
+
~~~~
|
61
|
+
179-386-583
|
62
|
+
You are now authenticated as flickrUserName with token some-other-token and secret yetanothersecret.
|
63
|
+
~~~~
|
64
|
+
|
65
|
+
For subsequent runs you can take note of the access token and secret you just
|
66
|
+
got and use them as values for the `--at` and `--as` command line options. This
|
67
|
+
will save you from having to authorize the app through the web interface over
|
68
|
+
and over again.
|
69
|
+
|
70
|
+
To show it's working the app prints out a `.` for every photo downloaded, and
|
71
|
+
also prints the name of the directory (collection/set) it's currently working
|
72
|
+
on. Photos not belonging to any set are, surprise, put into a directory named
|
73
|
+
`not in any set`.
|
74
|
+
|
75
|
+
Depending on the size of your Flickr account and your bandwidth this may take a
|
76
|
+
long time. Downloading 26GB from my personal account took a couple of hours on
|
77
|
+
my Hetzner server.
|
78
|
+
|
79
|
+
|
80
|
+
Caveats
|
81
|
+
-------
|
82
|
+
|
83
|
+
I built this because I wanted to download my photos, so naturally I cut some
|
84
|
+
corners where I could. Two things that I'm aware of which might need improvement are:
|
85
|
+
|
86
|
+
- Support Flickr's pagination. If you have sets with more than 500 photos in it
|
87
|
+
(or more than 500 Photos that are not in any set) you will need that because
|
88
|
+
500 is the maximum number of photos you can get with a single API request. My
|
89
|
+
sets aren't that large so I skipped this.
|
90
|
+
- There is no support for resuming an unfinished download, the app always
|
91
|
+
starts from scratch.
|
92
|
+
|
93
|
+
Pull Requests welcome :)
|
94
|
+
|
95
|
+
|
96
|
+
License
|
97
|
+
-------
|
98
|
+
|
99
|
+
MIT. See LICENSE for the text.
|
100
|
+
|
101
|
+
|
data/bin/bye-flickr
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bye_flickr'
|
4
|
+
require 'slop'
|
5
|
+
|
6
|
+
o = Slop::Options.new
|
7
|
+
|
8
|
+
o.separator 'Required arguments (create API key and secret in the Flickr web interface):'
|
9
|
+
o.string '-d', '--dir', 'directory to store data', required: true
|
10
|
+
o.string '-k', '--key', 'API key', required: true
|
11
|
+
o.string '-s', '--secret', 'API secret', required: true
|
12
|
+
|
13
|
+
o.separator ''
|
14
|
+
o.separator 'Optional arguments, if you already have authorized the app:'
|
15
|
+
o.string '--at', 'Access token'
|
16
|
+
o.string '--as', 'Access token secret'
|
17
|
+
|
18
|
+
o.separator ''
|
19
|
+
o.separator 'Other commands:'
|
20
|
+
o.on '--version', 'print the version' do
|
21
|
+
puts ByeFlickr::VERSION
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
o.on '-h', '--help' do
|
25
|
+
puts o
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
opts = Slop::Parser.new(o).parse ARGV
|
31
|
+
rescue Slop::Error
|
32
|
+
puts $!
|
33
|
+
puts o
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
FlickRaw.api_key = opts[:key]
|
38
|
+
FlickRaw.shared_secret = opts[:secret]
|
39
|
+
|
40
|
+
flickr.access_token = opts[:at] if opts[:at]
|
41
|
+
flickr.access_secret = opts[:as] if opts[:as]
|
42
|
+
|
43
|
+
ByeFlickr::App.new(dir: opts[:dir]).run
|
44
|
+
|
data/lib/bye_flickr.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'json'
|
3
|
+
require 'pathname'
|
4
|
+
require 'bye_flickr/auth'
|
5
|
+
require 'bye_flickr/photo_downloader'
|
6
|
+
require 'bye_flickr/response_to_json'
|
7
|
+
|
8
|
+
module ByeFlickr
|
9
|
+
class App
|
10
|
+
def initialize(dir: '.')
|
11
|
+
@basedir = Pathname(dir)
|
12
|
+
FileUtils.mkdir_p @basedir
|
13
|
+
|
14
|
+
@downloader = ByeFlickr::PhotoDownloader.new(@basedir)
|
15
|
+
end
|
16
|
+
|
17
|
+
# This code does not take into account pagination. 500 photos per set (the
|
18
|
+
# maximum supported per_page value) is enough for my purposes.
|
19
|
+
def run
|
20
|
+
user = Auth.call
|
21
|
+
@username = user[:username]
|
22
|
+
@id = user[:id]
|
23
|
+
exit if @username.nil? || @id.nil?
|
24
|
+
|
25
|
+
# Download photos that are not in any set
|
26
|
+
download_not_in_set
|
27
|
+
|
28
|
+
# Get collection info
|
29
|
+
@collections = flickr.collections.getTree
|
30
|
+
write_info(
|
31
|
+
@collections, path('collections.json')
|
32
|
+
)
|
33
|
+
|
34
|
+
# Get sets info
|
35
|
+
@sets = Hash[
|
36
|
+
flickr.photosets.getList(per_page: 500).photoset.map{|s|[s.id, s]}
|
37
|
+
]
|
38
|
+
|
39
|
+
# Download collections and their included sets, removing downloaded sets
|
40
|
+
# from the @sets list
|
41
|
+
@collections.collection.each do |collection|
|
42
|
+
download_collection collection
|
43
|
+
end
|
44
|
+
|
45
|
+
# download the remaining sets, which aren't in any collection
|
46
|
+
@sets.values.each do |set|
|
47
|
+
download_set set, @basedir
|
48
|
+
end
|
49
|
+
|
50
|
+
# Fetch contacts and groups meta data
|
51
|
+
write_info(
|
52
|
+
flickr.contacts.getList, path('contacts.json')
|
53
|
+
)
|
54
|
+
write_info(
|
55
|
+
flickr.people.getGroups(user_id: @id), path('groups.json')
|
56
|
+
)
|
57
|
+
|
58
|
+
# wait for photo downloads to finish
|
59
|
+
@downloader.wait
|
60
|
+
end
|
61
|
+
|
62
|
+
def path(name, base = @basedir)
|
63
|
+
base.join(name.gsub(%r{/}, '_'))
|
64
|
+
end
|
65
|
+
|
66
|
+
def subdir(name, base = @basedir)
|
67
|
+
path(name, base).tap do |dir|
|
68
|
+
FileUtils.mkdir_p dir
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def download_not_in_set
|
73
|
+
dir = subdir 'not in any set'
|
74
|
+
download_photos_to_dir(
|
75
|
+
flickr.photos.getNotInSet(extras: 'url_o', per_page: 500),
|
76
|
+
dir
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
# can collections be nested? If so, this code ignores them.
|
81
|
+
def download_collection(collection)
|
82
|
+
dir = subdir collection.title
|
83
|
+
FileUtils.mkdir_p dir
|
84
|
+
write_info collection, path("#{collection.title}.json")
|
85
|
+
collection.set.each do |set|
|
86
|
+
download_set set, dir
|
87
|
+
@sets.delete set.id # remove this set from the lists of sets to download
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def download_set(set, basedir)
|
92
|
+
dir = subdir set.title, basedir
|
93
|
+
|
94
|
+
download_photos_to_dir(
|
95
|
+
flickr.photosets.getPhotos(photoset_id: set.id,
|
96
|
+
per_page: 500,
|
97
|
+
user_id: @id,
|
98
|
+
extras: 'url_o').photo,
|
99
|
+
dir
|
100
|
+
)
|
101
|
+
|
102
|
+
write_info(
|
103
|
+
flickr.photosets.getInfo(photoset_id: set.id),
|
104
|
+
path("#{set.title}.json", basedir)
|
105
|
+
)
|
106
|
+
rescue Net::OpenTimeout
|
107
|
+
puts "#{$!} - retrying to download Set #{set.title}"
|
108
|
+
retry
|
109
|
+
end
|
110
|
+
|
111
|
+
def write_info(info, path)
|
112
|
+
(File.open(path, 'wb') << ResponseToJson.(info)).close
|
113
|
+
end
|
114
|
+
|
115
|
+
def download_photos_to_dir(photos, dir)
|
116
|
+
puts dir
|
117
|
+
photos.each do |photo|
|
118
|
+
name = photo.title
|
119
|
+
name = name + '.jpg' unless name =~ /\.jpg$/i
|
120
|
+
name = "#{photo.id}.jpg"
|
121
|
+
@downloader.add_image photo.url_o, path(name, dir).to_s
|
122
|
+
end
|
123
|
+
|
124
|
+
photos.each do |photo|
|
125
|
+
write_info(
|
126
|
+
flickr.photos.getInfo(photo_id: photo.id),
|
127
|
+
path("#{photo.id}.json", dir)
|
128
|
+
)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ByeFlickr
|
2
|
+
class Auth
|
3
|
+
def self.call
|
4
|
+
new.call
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
unless test_login
|
9
|
+
request_auth
|
10
|
+
end
|
11
|
+
{ username: @username, id: @id}
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_login
|
15
|
+
login = flickr.test.login
|
16
|
+
@username = login.username
|
17
|
+
@id = login.id
|
18
|
+
true
|
19
|
+
rescue
|
20
|
+
puts $!
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def request_auth
|
25
|
+
token = flickr.get_request_token
|
26
|
+
auth_url = flickr.get_authorize_url(token['oauth_token'], perms: 'read')
|
27
|
+
|
28
|
+
puts "Open this url in your browser to complete the authentication process:\n#{auth_url}"
|
29
|
+
puts "Copy here the number given when you complete the process."
|
30
|
+
|
31
|
+
verify = $stdin.gets.strip
|
32
|
+
flickr.get_access_token(token['oauth_token'], token['oauth_token_secret'], verify)
|
33
|
+
|
34
|
+
if test_login
|
35
|
+
puts "You are now authenticated as #{@username} with token #{flickr.access_token} and secret #{flickr.access_secret}"
|
36
|
+
else
|
37
|
+
puts "Login failed."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'net/http/persistent'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'thread'
|
6
|
+
|
7
|
+
module ByeFlickr
|
8
|
+
class PhotoDownloader
|
9
|
+
|
10
|
+
Download = Struct.new(:url, :path, :tries)
|
11
|
+
|
12
|
+
attr_reader :errors
|
13
|
+
|
14
|
+
def initialize(dir, workers: 2)
|
15
|
+
@basedir = dir
|
16
|
+
@lock = Mutex.new
|
17
|
+
@http = Net::HTTP::Persistent.new
|
18
|
+
|
19
|
+
@images = Concurrent::Array.new
|
20
|
+
@errors = Concurrent::Array.new
|
21
|
+
|
22
|
+
@tempdir = @basedir.join 'tmp'
|
23
|
+
FileUtils.mkdir_p @tempdir
|
24
|
+
@running = true
|
25
|
+
@workers = 1.upto(workers).map do |i|
|
26
|
+
Thread.new{ Worker.new(self).run }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def wait
|
31
|
+
@running = false
|
32
|
+
@workers.each{|t|t.join}
|
33
|
+
if @errors.any?
|
34
|
+
(File.open(@basedir.join('errors.json'), 'wb') << @errors.to_json).close
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_image(url, path)
|
39
|
+
@images << Download.new(url, path, 0)
|
40
|
+
end
|
41
|
+
|
42
|
+
def running?
|
43
|
+
!!@running
|
44
|
+
end
|
45
|
+
|
46
|
+
def next
|
47
|
+
@images.shift
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_failure(dl)
|
51
|
+
@errors << dl
|
52
|
+
end
|
53
|
+
|
54
|
+
def download(dl)
|
55
|
+
response = @http.request dl.url
|
56
|
+
f = Tempfile.create('bye-flickr-download', @tempdir)
|
57
|
+
f << response.body
|
58
|
+
f.close
|
59
|
+
|
60
|
+
@lock.synchronize do
|
61
|
+
i = 0
|
62
|
+
path = dl.path
|
63
|
+
while File.readable?(path)
|
64
|
+
i = i+1
|
65
|
+
path = "#{dl.path.sub(/\.jpg$/i, '')}_#{i}.jpg"
|
66
|
+
end
|
67
|
+
FileUtils.mv f, path
|
68
|
+
end
|
69
|
+
|
70
|
+
rescue
|
71
|
+
puts "#{$!}:\n#{dl.url} => #{dl.path}"
|
72
|
+
dl.tries += 1
|
73
|
+
if dl.tries > 2
|
74
|
+
puts "giving up on this one"
|
75
|
+
add_failure dl
|
76
|
+
else
|
77
|
+
@images << dl
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
class Worker
|
83
|
+
def initialize(downloader)
|
84
|
+
@downloader = downloader
|
85
|
+
end
|
86
|
+
|
87
|
+
def run
|
88
|
+
while file = @downloader.next or @downloader.running? do
|
89
|
+
if file
|
90
|
+
@downloader.download(file)
|
91
|
+
print '.'
|
92
|
+
else
|
93
|
+
# queue is empty but we're still running, wait a bit and try again
|
94
|
+
sleep 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ByeFlickr
|
2
|
+
|
3
|
+
class ResponseToJson
|
4
|
+
def initialize(r)
|
5
|
+
@r = r
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.call(r)
|
9
|
+
new(r).serialize.to_json
|
10
|
+
end
|
11
|
+
|
12
|
+
def serialize(o = @r)
|
13
|
+
case o
|
14
|
+
when FlickRaw::Response
|
15
|
+
serialize_response o
|
16
|
+
when FlickRaw::ResponseList, Enumerable
|
17
|
+
serialize_response_list o
|
18
|
+
else
|
19
|
+
o
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def serialize_response_list(list)
|
27
|
+
list.to_a.map{|o|serialize(o)}
|
28
|
+
end
|
29
|
+
|
30
|
+
def serialize_response(r)
|
31
|
+
Hash.new.tap do |hsh|
|
32
|
+
r.to_hash.each do |key, value|
|
33
|
+
hsh[key] = serialize value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bye-flickr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jens Krämer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: flickraw
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: net-http-persistent
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: concurrent-ruby
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: slop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.16'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.16'
|
83
|
+
description: This gem will download all photos and as much metadata as possible from
|
84
|
+
your Flickr account. Metadata is stored in json files, one file per photo. Collection
|
85
|
+
/ Set metadata and your group subscriptions and contacts are stored as JSON files,
|
86
|
+
as well.
|
87
|
+
email:
|
88
|
+
- jk@jkraemer.net
|
89
|
+
executables:
|
90
|
+
- bye-flickr
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
96
|
+
- bin/bye-flickr
|
97
|
+
- lib/bye_flickr.rb
|
98
|
+
- lib/bye_flickr/app.rb
|
99
|
+
- lib/bye_flickr/auth.rb
|
100
|
+
- lib/bye_flickr/photo_downloader.rb
|
101
|
+
- lib/bye_flickr/response_to_json.rb
|
102
|
+
- lib/bye_flickr/version.rb
|
103
|
+
homepage: http://github.com/jkraemer/bye_flickr
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '2.0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project: bye-flickr
|
123
|
+
rubygems_version: 2.7.6
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Download all photos and metadata from your Flickr account.
|
127
|
+
test_files: []
|