flickrup 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/flickrup +6 -0
- data/lib/flickrup/logging.rb +5 -0
- data/lib/flickrup/processor.rb +31 -0
- data/lib/flickrup/quick_listener.rb +52 -0
- data/lib/flickrup/slow_listener.rb +69 -0
- data/lib/flickrup/tagged_image.rb +36 -0
- data/lib/flickrup/uploader.rb +56 -0
- data/lib/flickrup.rb +43 -0
- metadata +167 -0
data/bin/flickrup
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "flickrup/tagged_image"
|
2
|
+
require "flickrup/uploader"
|
3
|
+
require "flickrup/logging"
|
4
|
+
|
5
|
+
class Processor
|
6
|
+
include Logging
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(files = Dir["#{@config['watch_dir']}/*.{jpg,JPG,jpeg,JPEG}"])
|
13
|
+
|
14
|
+
logger.debug("Processing #{files.length} files")
|
15
|
+
|
16
|
+
images = files.map { |x| TaggedImage.new(x) }
|
17
|
+
|
18
|
+
tagged = images.select { |x| !(x.tags.nil? || x.tags.empty?) }
|
19
|
+
|
20
|
+
uploader = Uploader.new(@config["api_key"], @config["shared_secret"])
|
21
|
+
|
22
|
+
tagged.each { |x|
|
23
|
+
x.doUpload(uploader)
|
24
|
+
x.archive(@config["archive_dir"])
|
25
|
+
}
|
26
|
+
|
27
|
+
logger.debug("Processed #{tagged.length} valid files")
|
28
|
+
|
29
|
+
tagged.length
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'atomic'
|
2
|
+
require "thread"
|
3
|
+
require "listen"
|
4
|
+
|
5
|
+
class QuickListener
|
6
|
+
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@changes = Atomic.new 0
|
10
|
+
@mutex = Mutex.new
|
11
|
+
@sync = ConditionVariable.new
|
12
|
+
@flickup = Flickrup.new(config)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
Thread.new { run_loop }
|
17
|
+
Listen.to(@config['watch_dir']) do |modified, added, removed|
|
18
|
+
unless modified.empty? && added.empty?
|
19
|
+
on_change
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def run_loop
|
26
|
+
|
27
|
+
@mutex.synchronize do
|
28
|
+
while 1 do
|
29
|
+
reloop = @changes.swap 0
|
30
|
+
|
31
|
+
while reloop > 0 do
|
32
|
+
execute
|
33
|
+
reloop = @changes.swap 0
|
34
|
+
end
|
35
|
+
|
36
|
+
@sync.wait(@mutex)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_change
|
43
|
+
@mutex.synchronize do
|
44
|
+
@changes.set 1
|
45
|
+
@sync.signal
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def execute
|
50
|
+
@flickup.run
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rufus/scheduler'
|
3
|
+
require "flickrup/logging"
|
4
|
+
|
5
|
+
#modification ->
|
6
|
+
# schedule upload for 5 mins time
|
7
|
+
#
|
8
|
+
#upload run ->
|
9
|
+
# for files modified > 5 mins ago
|
10
|
+
# -> do upload
|
11
|
+
# if there are files modified < 5 mins ago
|
12
|
+
# -> schedule upload for minimum time
|
13
|
+
#
|
14
|
+
#When scheduling upload, remove all but the nearest
|
15
|
+
#When paused, upload run should be a no-op
|
16
|
+
|
17
|
+
class SlowListener
|
18
|
+
include Logging
|
19
|
+
|
20
|
+
WAIT = 5#*60 #5 min
|
21
|
+
|
22
|
+
def initialize(config)
|
23
|
+
@config = config
|
24
|
+
@scheduler = Rufus::Scheduler.start_new
|
25
|
+
@processor = Processor.new(config)
|
26
|
+
end
|
27
|
+
|
28
|
+
def run
|
29
|
+
logger.debug("Watching #{@config['watch_dir']}...")
|
30
|
+
Listen.to(@config['watch_dir']) do |modified, added, removed|
|
31
|
+
unless modified.empty? && added.empty?
|
32
|
+
on_change
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def do_upload
|
38
|
+
logger.debug("Checking files for upload")
|
39
|
+
files = Dir["#{@config['watch_dir']}/*.{jpg,JPG,jpeg,JPEG}"]
|
40
|
+
|
41
|
+
old, new = files.partition { |x| Time.now > File.mtime(x) + WAIT }
|
42
|
+
|
43
|
+
unless old.empty?
|
44
|
+
logger.debug("Found #{old.length} stable files")
|
45
|
+
@processor.run(old)
|
46
|
+
end
|
47
|
+
|
48
|
+
unless new.empty?
|
49
|
+
logger.debug("Found #{new.length} new files")
|
50
|
+
#todo: schedule for latest
|
51
|
+
schedule
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def on_change
|
56
|
+
logger.debug("Change detected")
|
57
|
+
schedule
|
58
|
+
end
|
59
|
+
|
60
|
+
def schedule
|
61
|
+
if @scheduler.jobs.empty?
|
62
|
+
logger.debug("Scheduling processing for #{WAIT} sec")
|
63
|
+
@scheduler.in WAIT do
|
64
|
+
do_upload
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'mini_exiftool'
|
2
|
+
require 'ftools'
|
3
|
+
require 'fileutils'
|
4
|
+
require "flickrup/logging"
|
5
|
+
|
6
|
+
class TaggedImage
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
attr_reader :file
|
10
|
+
|
11
|
+
def initialize(file)
|
12
|
+
@file = file
|
13
|
+
@parsed = MiniExiftool.new @file
|
14
|
+
end
|
15
|
+
|
16
|
+
def tags
|
17
|
+
@parsed.keywords.to_a
|
18
|
+
end
|
19
|
+
|
20
|
+
def doUpload(uploader)
|
21
|
+
uploader.upload(file, tags)
|
22
|
+
end
|
23
|
+
|
24
|
+
def archive(to_dir)
|
25
|
+
date_taken = @parsed.date_time_original
|
26
|
+
target_dir = File.join(
|
27
|
+
to_dir,
|
28
|
+
date_taken.strftime("%y"),
|
29
|
+
date_taken.strftime("%m")
|
30
|
+
)
|
31
|
+
|
32
|
+
File.makedirs(target_dir)
|
33
|
+
FileUtils.mv(@file, File.join(target_dir, File.basename(@file)))
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require 'rubygems'
|
3
|
+
require "flickraw"
|
4
|
+
require "flickrup/logging"
|
5
|
+
|
6
|
+
class Uploader
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
def initialize(api_key, shared_secret)
|
10
|
+
FlickRaw.api_key= api_key
|
11
|
+
FlickRaw.shared_secret=shared_secret
|
12
|
+
|
13
|
+
@token_file = File.join(ENV['HOME'], ".flickrup")
|
14
|
+
@flickr = FlickRaw::Flickr.new
|
15
|
+
|
16
|
+
if File.exist?(@token_file)
|
17
|
+
token = YAML.load_file(@token_file)
|
18
|
+
@flickr.access_token = token["access"]
|
19
|
+
@flickr.access_secret = token["secret"]
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
login = @flickr.test.login
|
24
|
+
rescue FlickRaw::OAuthClient::FailedResponse => e
|
25
|
+
get_token
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
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}")
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/flickrup.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "rubygems"
|
3
|
+
require "trollop"
|
4
|
+
require "logger"
|
5
|
+
require "flickrup/quick_listener"
|
6
|
+
require "flickrup/slow_listener"
|
7
|
+
require "flickrup/tagged_image"
|
8
|
+
require "flickrup/uploader"
|
9
|
+
require "flickrup/processor"
|
10
|
+
require "flickrup/logging"
|
11
|
+
|
12
|
+
|
13
|
+
module Flickrup
|
14
|
+
|
15
|
+
def self.run_cmd(args = ARGV)
|
16
|
+
Runner.new.run(args)
|
17
|
+
end
|
18
|
+
|
19
|
+
class Runner
|
20
|
+
include Logging
|
21
|
+
|
22
|
+
def run(args = ARGV)
|
23
|
+
opts = Trollop::options do
|
24
|
+
opt :once, "Run single pass" # flag --once, default false
|
25
|
+
opt :nowait, "Upload immediately on change, no delay"
|
26
|
+
opt :loglevel, "Logging level", :type => :string, :default => "INFO"
|
27
|
+
opt :config, "Configuration file", :type => :string, :default => './flickrup.yml'
|
28
|
+
end
|
29
|
+
|
30
|
+
logger.level = Logger::Severity.const_get(opts.loglevel)
|
31
|
+
|
32
|
+
config = YAML::load(File.open(opts.config, "r"))
|
33
|
+
|
34
|
+
if opts.once
|
35
|
+
Processor.new(config).run
|
36
|
+
elsif opts.nowait
|
37
|
+
QuickListener.new(config).run
|
38
|
+
else
|
39
|
+
SlowListener.new(config).run
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: flickrup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jonathan Gilbert
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-12-21 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: atomic
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 23
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
- 0
|
33
|
+
version: 1.0.0
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: listen
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 7
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
- 6
|
48
|
+
- 0
|
49
|
+
version: 0.6.0
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: rufus-scheduler
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 15
|
61
|
+
segments:
|
62
|
+
- 2
|
63
|
+
- 0
|
64
|
+
- 0
|
65
|
+
version: 2.0.0
|
66
|
+
type: :runtime
|
67
|
+
version_requirements: *id003
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: mini_exiftool
|
70
|
+
prerelease: false
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 15
|
77
|
+
segments:
|
78
|
+
- 1
|
79
|
+
- 6
|
80
|
+
- 0
|
81
|
+
version: 1.6.0
|
82
|
+
type: :runtime
|
83
|
+
version_requirements: *id004
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: flickraw
|
86
|
+
prerelease: false
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 55
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
- 9
|
96
|
+
- 6
|
97
|
+
version: 0.9.6
|
98
|
+
type: :runtime
|
99
|
+
version_requirements: *id005
|
100
|
+
- !ruby/object:Gem::Dependency
|
101
|
+
name: trollop
|
102
|
+
prerelease: false
|
103
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
hash: 15
|
109
|
+
segments:
|
110
|
+
- 2
|
111
|
+
- 0
|
112
|
+
- 0
|
113
|
+
version: 2.0.0
|
114
|
+
type: :runtime
|
115
|
+
version_requirements: *id006
|
116
|
+
description: Flickr auto uploading script
|
117
|
+
email: bb..jgilbert@xoxy.net
|
118
|
+
executables:
|
119
|
+
- flickrup
|
120
|
+
extensions: []
|
121
|
+
|
122
|
+
extra_rdoc_files: []
|
123
|
+
|
124
|
+
files:
|
125
|
+
- lib/flickrup/logging.rb
|
126
|
+
- lib/flickrup/processor.rb
|
127
|
+
- lib/flickrup/quick_listener.rb
|
128
|
+
- lib/flickrup/slow_listener.rb
|
129
|
+
- lib/flickrup/tagged_image.rb
|
130
|
+
- lib/flickrup/uploader.rb
|
131
|
+
- lib/flickrup.rb
|
132
|
+
- bin/flickrup
|
133
|
+
homepage: http://bitbucket.org/jgilbert/flickrup
|
134
|
+
licenses: []
|
135
|
+
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
hash: 3
|
147
|
+
segments:
|
148
|
+
- 0
|
149
|
+
version: "0"
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
hash: 3
|
156
|
+
segments:
|
157
|
+
- 0
|
158
|
+
version: "0"
|
159
|
+
requirements: []
|
160
|
+
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 1.8.24
|
163
|
+
signing_key:
|
164
|
+
specification_version: 3
|
165
|
+
summary: Flickr Uploader!
|
166
|
+
test_files: []
|
167
|
+
|