flickrup 0.0.6 → 0.0.8
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.
- data/lib/flickrup/ext/machine_tags.rb +23 -0
- data/lib/flickrup/ext/prefixed_extension.rb +19 -0
- data/lib/flickrup/ext/replacement_tags.rb +23 -0
- data/lib/flickrup/ext/tag_sets.rb +19 -0
- data/lib/flickrup/ext/visibility.rb +42 -0
- data/lib/flickrup/flickr_client.rb +79 -0
- data/lib/flickrup/processor.rb +30 -5
- data/lib/flickrup/slow_listener.rb +2 -2
- data/lib/flickrup/tagged_image.rb +28 -2
- data/lib/flickrup/uploader.rb +20 -41
- data/lib/flickrup.rb +2 -1
- metadata +9 -3
@@ -0,0 +1,23 @@
|
|
1
|
+
class MachineTags
|
2
|
+
def initialize(config, context)
|
3
|
+
@config = config
|
4
|
+
end
|
5
|
+
|
6
|
+
def preupload(image, meta, config)
|
7
|
+
|
8
|
+
tags = config[:tags].split(" ")
|
9
|
+
|
10
|
+
remapped = tags.map do |x|
|
11
|
+
x.sub(/^([^:]+):([^:]+)::/,"\\1:\\2=")
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
unless tags == remapped #write back to file
|
16
|
+
meta['Keywords'] = remapped
|
17
|
+
meta['Subject'] = remapped #also write Subject XMP tag
|
18
|
+
end
|
19
|
+
|
20
|
+
config.merge({:tags => remapped.join(" ")})
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class PrefixedExtension
|
2
|
+
def initialize(config)
|
3
|
+
@config = config
|
4
|
+
end
|
5
|
+
|
6
|
+
def values(prefix_key, config)
|
7
|
+
all_tags = config[:tags].split(" ")
|
8
|
+
|
9
|
+
prefix = @config[prefix_key]
|
10
|
+
|
11
|
+
(selected_tags, tags) = all_tags.partition do |x|
|
12
|
+
x.start_with?("#{prefix}")
|
13
|
+
end
|
14
|
+
|
15
|
+
selected_tags.map do |x|
|
16
|
+
x[(prefix.length)..x.length]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class ReplacementTags
|
2
|
+
def initialize(config)
|
3
|
+
@config = config
|
4
|
+
end
|
5
|
+
|
6
|
+
def preupload(image, meta, config)
|
7
|
+
|
8
|
+
replacements = @config[:tag_replacements]
|
9
|
+
|
10
|
+
if replacements != nil
|
11
|
+
replacements.each do |tag_name, tag_value_replacements|
|
12
|
+
existing = meta[tag_name]
|
13
|
+
|
14
|
+
tag_value_replacements.each do |key, value|
|
15
|
+
if existing == key
|
16
|
+
meta[tag_name] = value
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "flickrup/ext/prefixed_extension"
|
2
|
+
|
3
|
+
class TagSets < PrefixedExtension
|
4
|
+
def initialize(config, delegate, context)
|
5
|
+
super(config)
|
6
|
+
@delegate = delegate
|
7
|
+
@flickr = context[:flickr_client]
|
8
|
+
end
|
9
|
+
|
10
|
+
def upload(image, meta, config)
|
11
|
+
sets = values(:tagsetprefix, config)
|
12
|
+
|
13
|
+
uploaded = @delegate.upload(image, meta, config)
|
14
|
+
|
15
|
+
sets.each do |set|
|
16
|
+
@flickr.add_to_set(uploaded, set)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "flickrup/logging"
|
2
|
+
|
3
|
+
class Visibility < PrefixedExtension
|
4
|
+
include Logging
|
5
|
+
|
6
|
+
def initialize(config, delegate, context)
|
7
|
+
super(config)
|
8
|
+
@delegate = delegate
|
9
|
+
end
|
10
|
+
|
11
|
+
def upload(image, meta, config)
|
12
|
+
visibility = values(:visibilityprefix, config)
|
13
|
+
|
14
|
+
config_override = if visibility.length == 0
|
15
|
+
logger.debug("No visibility specified for #{image}.")
|
16
|
+
{}
|
17
|
+
elsif visibility.length == 1
|
18
|
+
config_for_visibility(visibility[0])
|
19
|
+
else #multiple visibilities
|
20
|
+
logger.warn("Multiple visibilities specified. Using the first encountered: #{visibility[0]}.")
|
21
|
+
config_for_visibility(visibility[0])
|
22
|
+
end
|
23
|
+
|
24
|
+
@delegate.upload(image, meta, config.merge(config_override))
|
25
|
+
end
|
26
|
+
|
27
|
+
def config_for_visibility(visibility)
|
28
|
+
if visibility == "offline"
|
29
|
+
logger.debug("Offline Visibility specified. Disabling upload.")
|
30
|
+
{UploaderConstants::NO_UPLOAD => true}
|
31
|
+
elsif visibility == "private"
|
32
|
+
logger.debug("Private visibility specified.")
|
33
|
+
{"is_public" => "0", "is_friend" => "0", "is_family" => "0"}
|
34
|
+
elsif visibility == "friends"
|
35
|
+
logger.debug("Friends visibility specified.")
|
36
|
+
{"is_public" => "0", "is_friend" => "1", "is_family" => "1"}
|
37
|
+
else
|
38
|
+
logger.warn("Unknown visibility #{visibility}. Ignoring.")
|
39
|
+
{}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "flickraw"
|
2
|
+
|
3
|
+
class FlickrClient
|
4
|
+
|
5
|
+
def initialize(api_key, shared_secret)
|
6
|
+
@set_name_to_id = {}
|
7
|
+
FlickRaw.api_key= api_key
|
8
|
+
FlickRaw.shared_secret=shared_secret
|
9
|
+
|
10
|
+
@token_file = File.join(ENV['HOME'], ".flickrup")
|
11
|
+
set_client(FlickRaw::Flickr.new)
|
12
|
+
|
13
|
+
if File.exist?(@token_file)
|
14
|
+
token = YAML.load_file(@token_file)
|
15
|
+
client.access_token = token["access"]
|
16
|
+
client.access_secret = token["secret"]
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
login = client.test.login
|
21
|
+
rescue FlickRaw::OAuthClient::FailedResponse => e
|
22
|
+
get_token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def client
|
27
|
+
@client
|
28
|
+
end
|
29
|
+
|
30
|
+
def upload_photo(image, config)
|
31
|
+
client.upload_photo(image, config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_to_set(photo_id, set_name)
|
35
|
+
set_id = get_set_id(set_name, photo_id)
|
36
|
+
client.photosets.addPhoto(:photoset_id => set_id, :photo_id => photo_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_set_id(set_name, for_photo_id)
|
40
|
+
unless @set_name_to_id.include? set_name
|
41
|
+
sets_response = client.photosets.getList #if we don't have it, refresh
|
42
|
+
@set_name_to_id = Hash[*sets_response.to_a.map{ |set|
|
43
|
+
[set['title'], set['id']]
|
44
|
+
}.flatten]
|
45
|
+
unless @set_name_to_id.include? set_name #if we still don't, create it
|
46
|
+
created = client.photosets.create(:title => set_name, :primary_photo_id => for_photo_id)
|
47
|
+
@set_name_to_id = @set_name_to_id.merge({set_name => created.id})
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@set_name_to_id[set_name]
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_token
|
55
|
+
token = client.get_request_token
|
56
|
+
auth_url = client.get_authorize_url(token['oauth_token'], :perms => 'write')
|
57
|
+
|
58
|
+
puts "Open this url in your process to complete the authentication process : #{auth_url}"
|
59
|
+
puts "Copy here the number given when you complete the process."
|
60
|
+
verify = gets.strip
|
61
|
+
|
62
|
+
begin
|
63
|
+
client.get_access_token(token['oauth_token'], token['oauth_token_secret'], verify)
|
64
|
+
token = {"access" => client.access_token, "secret" => client.access_secret}
|
65
|
+
login = client.test.login
|
66
|
+
puts "You are now authenticated as #{login.username}"
|
67
|
+
File.open(@token_file, 'w') { |f| f.write(token.to_yaml) }
|
68
|
+
rescue FlickRaw::OAuthClient::FailedResponse => e
|
69
|
+
puts "Authentication failed : #{e.msg}"
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def set_client(client)
|
76
|
+
@client = client
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/lib/flickrup/processor.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require "flickrup/tagged_image"
|
2
2
|
require "flickrup/uploader"
|
3
3
|
require "flickrup/logging"
|
4
|
+
require "flickrup/ext/tag_sets"
|
5
|
+
require "flickrup/ext/replacement_tags"
|
6
|
+
require "flickrup/ext/machine_tags"
|
7
|
+
require "flickrup/ext/visibility"
|
4
8
|
|
5
9
|
class Processor
|
6
10
|
include Logging
|
@@ -10,10 +14,10 @@ class Processor
|
|
10
14
|
end
|
11
15
|
|
12
16
|
def paused
|
13
|
-
Dir["#{@config[
|
17
|
+
Dir["#{@config[:watch_dir]}/paused"].length > 0
|
14
18
|
end
|
15
19
|
|
16
|
-
def run(files = Dir["#{@config[
|
20
|
+
def run(files = Dir["#{@config[:watch_dir]}/*.{jpg,JPG,jpeg,JPEG}"])
|
17
21
|
|
18
22
|
logger.debug("Processing #{files.length} files")
|
19
23
|
|
@@ -26,15 +30,15 @@ class Processor
|
|
26
30
|
|
27
31
|
tagged = images.select { |x| !(x.tags.nil? || x.tags.empty?) }
|
28
32
|
|
29
|
-
uploader =
|
33
|
+
uploader = get_uploader
|
30
34
|
|
31
35
|
if @config[:dryrun]
|
32
36
|
logger.info("Would now upload & move #{tagged.length} files, pausing for 5 secs instead")
|
33
37
|
sleep 5
|
34
38
|
else
|
35
39
|
tagged.each { |x|
|
36
|
-
x.doUpload(uploader)
|
37
|
-
x.archive(@config[
|
40
|
+
x.doUpload(get_preupload_handlers, uploader)
|
41
|
+
x.archive(@config[:archive_dir])
|
38
42
|
}
|
39
43
|
end
|
40
44
|
|
@@ -42,4 +46,25 @@ class Processor
|
|
42
46
|
|
43
47
|
tagged.length
|
44
48
|
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def get_uploader
|
52
|
+
flickr_client = FlickrClient.new(@config[:api_key], @config[:shared_secret])
|
53
|
+
|
54
|
+
context = {:flickr_client => flickr_client}
|
55
|
+
|
56
|
+
uploader = Uploader.new(flickr_client)
|
57
|
+
|
58
|
+
upload_handlers.reduce(uploader) do |result, clazz|
|
59
|
+
clazz.new(@config, result, context)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_preupload_handlers
|
64
|
+
[MachineTags.new(@config, {}), ReplacementTags.new(@config)]
|
65
|
+
end
|
66
|
+
|
67
|
+
def upload_handlers() [TagSets, Visibility] end
|
68
|
+
|
45
69
|
end
|
70
|
+
|
@@ -33,7 +33,7 @@ class SlowListener
|
|
33
33
|
|
34
34
|
def run
|
35
35
|
logger.debug("Watching #{@config['watch_dir']}...")
|
36
|
-
Listen.to(@config[
|
36
|
+
Listen.to(@config[:watch_dir]) do |modified, added, _|
|
37
37
|
unless modified.empty? && added.empty?
|
38
38
|
on_change
|
39
39
|
end
|
@@ -45,7 +45,7 @@ class SlowListener
|
|
45
45
|
|
46
46
|
@processing.set PROCESSING
|
47
47
|
|
48
|
-
files = Dir["#{@config[
|
48
|
+
files = Dir["#{@config[:watch_dir]}/*.{jpg,JPG,jpeg,JPEG}"]
|
49
49
|
|
50
50
|
old, new = files.partition { |x| Time.now > File.mtime(x) + @wait }
|
51
51
|
|
@@ -17,8 +17,23 @@ class TaggedImage
|
|
17
17
|
@parsed.keywords.to_a
|
18
18
|
end
|
19
19
|
|
20
|
-
def doUpload(uploader)
|
21
|
-
|
20
|
+
def doUpload(preupload_handlers, uploader)
|
21
|
+
|
22
|
+
config = preupload_handlers.reduce({:tags => tags.join(" ")}) do |config, handler|
|
23
|
+
handler.preupload(file, self, config)
|
24
|
+
end
|
25
|
+
|
26
|
+
#maybe save afterwards
|
27
|
+
if @parsed.changed?
|
28
|
+
@parsed.save!
|
29
|
+
end
|
30
|
+
|
31
|
+
uploader.upload(file, self, config)
|
32
|
+
|
33
|
+
#maybe save afterwards
|
34
|
+
if @parsed.changed?
|
35
|
+
@parsed.save!
|
36
|
+
end
|
22
37
|
end
|
23
38
|
|
24
39
|
def archive(to_dir)
|
@@ -32,6 +47,17 @@ class TaggedImage
|
|
32
47
|
|
33
48
|
File.makedirs(target_dir)
|
34
49
|
FileUtils.mv(@file, File.join(target_dir, File.basename(@file)))
|
50
|
+
logger.info("Archived #{File.basename(@file)} to #{target_dir}")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the value of a tag.
|
54
|
+
def [] tag
|
55
|
+
@parsed[tag]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Set the value of a tag.
|
59
|
+
def []=(tag, val)
|
60
|
+
@parsed[tag] = val
|
35
61
|
end
|
36
62
|
|
37
63
|
end
|
data/lib/flickrup/uploader.rb
CHANGED
@@ -1,56 +1,35 @@
|
|
1
1
|
require "yaml"
|
2
2
|
require 'rubygems'
|
3
|
-
require "flickraw"
|
4
3
|
require "flickrup/logging"
|
4
|
+
require "flickrup/flickr_client"
|
5
|
+
|
6
|
+
module UploaderConstants
|
7
|
+
NO_UPLOAD = :no_upload
|
8
|
+
end
|
5
9
|
|
6
10
|
class Uploader
|
7
11
|
include Logging
|
8
12
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
13
|
+
def initialize(flickr_client)
|
14
|
+
@flickr = flickr_client
|
15
|
+
end
|
12
16
|
|
13
|
-
|
14
|
-
@flickr = FlickRaw::Flickr.new
|
17
|
+
def upload(image, meta, config)
|
15
18
|
|
16
|
-
if
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
19
|
+
if config[UploaderConstants::NO_UPLOAD]
|
20
|
+
logger.info("Skipping upload of #{image} as marked as NO_UPLOAD")
|
21
|
+
else
|
22
|
+
logger.debug("Uploading #{image} with tags #{config[:tags]}")
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
begin
|
25
|
+
rv = @flickr.upload_photo(image, config)
|
26
|
+
logger.debug("Uploaded #{image}")
|
27
|
+
rescue StandardError => err
|
28
|
+
logger.error("Failed to upload #{image}: #{err}")
|
29
|
+
end
|
26
30
|
end
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
def get_token
|
31
|
-
token = @flickr.get_request_token
|
32
|
-
auth_url = @flickr.get_authorize_url(token['oauth_token'], :perms => 'write')
|
33
|
-
|
34
|
-
puts "Open this url in your process to complete the authentication process : #{auth_url}"
|
35
|
-
puts "Copy here the number given when you complete the process."
|
36
|
-
verify = gets.strip
|
37
|
-
|
38
|
-
begin
|
39
|
-
@flickr.get_access_token(token['oauth_token'], token['oauth_token_secret'], verify)
|
40
|
-
token = {"access" => @flickr.access_token, "secret" => @flickr.access_secret}
|
41
|
-
login = @flickr.test.login
|
42
|
-
puts "You are now authenticated as #{login.username}"
|
43
|
-
File.open(@token_file, 'w') { |f| f.write(token.to_yaml) }
|
44
|
-
rescue FlickRaw::OAuthClient::FailedResponse => e
|
45
|
-
puts "Authentication failed : #{e.msg}"
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
def upload(image, tags)
|
51
|
-
logger.debug("Uploading #{image} with tags #{tags.join(",")}")
|
52
|
-
@flickr.upload_photo(image, :tags => tags.join(" "))
|
53
|
-
logger.debug("Uploaded #{image}")
|
32
|
+
rv
|
54
33
|
end
|
55
34
|
|
56
35
|
end
|
data/lib/flickrup.rb
CHANGED
@@ -31,7 +31,8 @@ module Flickrup
|
|
31
31
|
|
32
32
|
logger.level = Logger::Severity.const_get(opts.loglevel)
|
33
33
|
|
34
|
-
|
34
|
+
#load config, symbolise, merge with command line config
|
35
|
+
config = YAML::load(File.open(opts.config, "r")).inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}.merge opts
|
35
36
|
|
36
37
|
if opts.once
|
37
38
|
Processor.new(config).run
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flickrup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 8
|
10
|
+
version: 0.0.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jonathan Gilbert
|
@@ -138,6 +138,12 @@ extensions: []
|
|
138
138
|
extra_rdoc_files: []
|
139
139
|
|
140
140
|
files:
|
141
|
+
- lib/flickrup/ext/machine_tags.rb
|
142
|
+
- lib/flickrup/ext/prefixed_extension.rb
|
143
|
+
- lib/flickrup/ext/replacement_tags.rb
|
144
|
+
- lib/flickrup/ext/tag_sets.rb
|
145
|
+
- lib/flickrup/ext/visibility.rb
|
146
|
+
- lib/flickrup/flickr_client.rb
|
141
147
|
- lib/flickrup/logging.rb
|
142
148
|
- lib/flickrup/processor.rb
|
143
149
|
- lib/flickrup/quick_listener.rb
|