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