flickru 0.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.
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ #flickru_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ #$LOAD_PATH.unshift(flickru_dir) unless $LOAD_PATH.include?(flickru_dir)
4
+
5
+ require 'flickru'
6
+
7
+ photo_dir = ARGV[0]
8
+
9
+ if ARGV.length > 1
10
+ Flickru.usage
11
+ Flickru.die __LINE__, "wrong number of arguments: #{ARGV[1,ARGV.length]}"
12
+ elsif photo_dir.nil? or photo_dir.empty?
13
+ Flickru.usage
14
+ Flickru.die __LINE__, "missing photo directory"
15
+ end
16
+
17
+ Flickru.flickru photo_dir
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+
3
+ APP_NAME=`basename $0`
4
+
5
+ function error {
6
+ echo -e "\E[31m$APP_NAME: $1: $2$(tput sgr0)" 1>&2
7
+ }
8
+
9
+ if [ $# -ne 1 ]; then
10
+ echo "$APP_NAME - find coordinates of a place described by Wikipedia"
11
+ echo "usage: $APP_NAME <place Wikipedia page>"
12
+ echo "example: $APP_NAME 'Mille-Isles, Quebec'"
13
+ error $LINENO "wrong number of arguments"
14
+ exit 1
15
+ fi
16
+
17
+ PAGE=`echo "$1" | tr ' ' '_'`
18
+
19
+ # temporal file management
20
+ if [ -d /tmp ]; then
21
+ TMP="/tmp/$PAGE.tmp.$$.$RANDOM.html"
22
+ else
23
+ TMP="$PAGE.tmp.html"
24
+ fi
25
+ function clean_up {
26
+ rm -f "$TMP"
27
+ exit $1
28
+ }
29
+ trap clean_up SIGHUP SIGINT SIGTERM
30
+
31
+ curl "http://en.wikipedia.org/wiki/$PAGE" > "$TMP" 2> /dev/null
32
+
33
+ if [ $? -ne 0 ]; then
34
+ error $LINENO "Wikipedia page '$PAGE' not found"
35
+ clean_up 1
36
+ fi
37
+
38
+ URL=`cat "$TMP" | tr '"' '\n' | grep geohack | head -n 1 | sed -e 's|&amp;|\&|'`
39
+
40
+ if [ -z "$URL" ]; then
41
+ error $LINENO "location not found in Wikipedia page '$PAGE'"
42
+ clean_up 1
43
+ fi
44
+
45
+ curl "$URL" > "$TMP" 2> /dev/null
46
+
47
+ if [ $? -ne 0 ]; then
48
+ error $LINENO "GeoHack URL '$URL' not found"
49
+ clean_up 1
50
+ fi
51
+
52
+ cat "$TMP" | grep '<span class="geo"' | sed -e 's|^.*"Latitude">\([^<]*\)</span>, .*"Longitude">\([^<]*\)</span>.*$|\1, \2|'
53
+
54
+ clean_up
@@ -0,0 +1,112 @@
1
+ # ruby
2
+ require 'etc'
3
+ require 'set'
4
+ # gems
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ # flickru
8
+ require 'flickru/file'
9
+ require 'flickru/flickr'
10
+ require 'flickru/journey'
11
+ require 'flickru/printer'
12
+
13
+ FlickRaw.api_key = "aaf7253e0f88f03aa59f9d3074bf2d4b"
14
+ FlickRaw.shared_secret = "138ee268f76cd780"
15
+
16
+ module Flickru
17
+
18
+ def Flickru.usage
19
+ filename = File.basename __FILE__
20
+ Printer.show "#{filename} -- command-line Flickr upload automator\n"
21
+ Printer.show "usage: #{filename} <photo directory>\n"
22
+ Printer.show "example: #{filename} my_photos\n"
23
+ Printer.show "\n#{IO.read('README')}\n"
24
+ end
25
+
26
+ def Flickru.die code, message
27
+ Printer.error "error:#{code}: #{message}"
28
+ exit 1
29
+ end
30
+
31
+ def Flickru.config_filename
32
+ File.join Etc.getpwuid.dir, "." + File.basename(__FILE__, File.extname(__FILE__)) + "rc"
33
+ end
34
+
35
+ def self.read_config
36
+ file = File.open config_filename, "r"
37
+ token, secret = file.readlines.map { |line| line.sub(/\#.*$/, '').strip } # remove line comments
38
+ file.close
39
+ Flickr.access token, secret
40
+ rescue
41
+ raise RuntimeError, "unable to open configuration file #{config_filename}"
42
+ end
43
+
44
+ def Flickru.write_config token, secret
45
+ Printer.show "writing configuration file #{config_filename}... "
46
+ if File.exists? config_filename
47
+ file = File.new config_filename, "w"
48
+ else
49
+ file = File.open config_filename, "w"
50
+ end
51
+ file.puts "#{token} \# access token"
52
+ file.puts "#{secret} \# access secret"
53
+ file.close
54
+ Printer.success
55
+ rescue
56
+ raise RuntimeError, "unable to write configuration file #{config_filename}"
57
+ end
58
+
59
+ def self.flickru photo_dir
60
+ begin
61
+ Flickru.read_config
62
+ rescue RuntimeError
63
+ token, secret = Flickr.login
64
+ write_config token, secret
65
+ end
66
+
67
+ # upload and classify
68
+ photos = File.find(photo_dir) {|f| File.image? f or File.video? f }
69
+ total_size = photos.reduce(0) {|t,p| t + File.size(p)}
70
+ Printer.info "#{File.human_readable_size total_size} to upload"
71
+ journey = Journey.new total_size
72
+ photoset_ids = Set.new
73
+ photos.each do |photo|
74
+ Printer.info "file '#{File.join File.basename(File.dirname(photo)), File.basename(photo)}' under process"
75
+ begin
76
+ photo_id = Flickr.upload_photo photo
77
+ photoset_ids << Flickr.classify(photo, photo_id)
78
+ rescue ArgumentError || Errno::ENOENT || Errno::EAGAIN || FlickRaw::FailedResponse
79
+ Printer.failure "#{photo}: #{$!}"
80
+ end
81
+ journey.take File.size(photo)
82
+ Printer.info "#{File.human_readable_size journey.progress} uploaded, " +
83
+ "#{File.human_readable_size journey.distance} remaining. " +
84
+ "ETA: #{Printer.human_readable_seconds journey.eta}" if journey.eta > 0
85
+ end
86
+
87
+ photoset_ids.each do |set_id|
88
+ Flickr.arrangePhotos set_id
89
+ end
90
+
91
+ Printer.ask "Please, review whether: any of your photos need to be rotated,\n" +
92
+ " better primary photos for your sets have been uploaded,\n" +
93
+ " and better collection mosaics can be randomised."
94
+ rescue
95
+ die __LINE__, $!
96
+ end
97
+
98
+ end # module Flickru
99
+
100
+ if __FILE__ == $0
101
+ photo_dir = ARGV[0]
102
+
103
+ if ARGV.length > 1
104
+ Flickru.usage
105
+ Flickru.die __LINE__, "wrong number of arguments: #{ARGV[1,ARGV.length]}"
106
+ elsif not photo_dir or photo_dir.empty?
107
+ Flickru.usage
108
+ Flickru.die __LINE__, "missing photo directory"
109
+ end
110
+
111
+ Flickru.flickru photo_dir
112
+ end
@@ -0,0 +1,64 @@
1
+ # ruby
2
+ require 'escape'
3
+ require 'find'
4
+
5
+ class File
6
+
7
+ def File.find dir
8
+ found = Array.new
9
+ Find.find dir do |file|
10
+ if File.directory? file
11
+ if File.basename(file)[0] == ?.
12
+ Find.prune # don't look any further into this directory
13
+ else
14
+ next
15
+ end
16
+ else
17
+ if yield file
18
+ found << file
19
+ end
20
+ end
21
+ end
22
+ found
23
+ end
24
+
25
+ def File.image? file
26
+ IMAGE_EXTENSIONS.include? File.extname(file).downcase
27
+ end
28
+
29
+ def File.video? file
30
+ VIDEO_EXTENSIONS.include? File.extname(file).downcase
31
+ end
32
+
33
+ def File.duration video
34
+ s = `#{Escape.shell_command ["ffmpeg", "-i", video]} 2>&1`
35
+ if s =~ /Duration: ([\d][\d]):([\d][\d]):([\d][\d]).([\d]+)/
36
+ hours = $1.to_i
37
+ mins = $2.to_i
38
+ seconds = $3.to_i
39
+ # fractions = ("." + $4).to_f
40
+
41
+ hours * 60 * 60 + mins * 60 + seconds
42
+ else
43
+ 0
44
+ end
45
+ end
46
+
47
+ def File.human_readable_size file_size
48
+ if file_size < 1000
49
+ file_size.to_s + " bytes"
50
+ elsif file_size < 1000000
51
+ (file_size / 1000).to_s + "KB"
52
+ elsif file_size < 1000000000
53
+ (file_size / 1000000).to_s + "MB"
54
+ else
55
+ (file_size / 1000000000).to_s + "GB"
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ IMAGE_EXTENSIONS = [".gif", ".jpg", ".jpeg", ".png"] # lowercase
62
+ VIDEO_EXTENSIONS = [".mpeg", ".mpg", ".avi"] # lowercase
63
+
64
+ end
@@ -0,0 +1,150 @@
1
+ # gems
2
+ require 'flickraw'
3
+ require 'unicode_utils'
4
+ # flickru
5
+ require 'flickru/file'
6
+ require 'flickru/location'
7
+ require 'flickru/printer'
8
+ require 'flickru/ruby'
9
+
10
+ module Flickr
11
+
12
+ def self.access token, secret
13
+ flickr.access_token = token
14
+ flickr.access_secret = secret
15
+ end
16
+
17
+ def self.login
18
+ token = flickr.get_request_token
19
+ auth_url = flickr.get_authorize_url token['oauth_token'], :perms => 'write' # read, delete
20
+ Printer.ask "Open this URL in your process to complete the authentication process:\n#{auth_url}\n"
21
+ Printer.enter "Copy the number given when you complete the process here"
22
+
23
+ verify = STDIN.gets.strip
24
+ flickr.get_access_token token['oauth_token'], token['oauth_token_secret'], verify
25
+
26
+ login = flickr.test.login
27
+ Printer.show "you are now authenticated as #{login.username} " +
28
+ "with token #{flickr.access_token} and secret #{flickr.access_secret}\n"
29
+ [flickr.access_token, flickr.access_secret]
30
+ end
31
+
32
+ def self.size_limit_exceeded? file
33
+ if File.image? file
34
+ File.size(file).to_i > 20000000 # 20MB
35
+ elsif File.video? file
36
+ File.size(file).to_i > 500000000 # 500MB
37
+ else
38
+ raise ArgumentError, "#{file}: not an image nor a video"
39
+ end
40
+ end
41
+
42
+ def self.upload_photo photo
43
+ Ruby.assert("not Flickr.size_limit_exceeded?(photo)") \
44
+ { not Flickr.size_limit_exceeded?(photo) }
45
+
46
+ if File.duration(photo) > 90 # seconds
47
+ description = "video duration (#{File.duration photo} sec) exceeds Flickr's duration limit (90 sec)."
48
+ Printer.warn description
49
+ description = "This " + description + "\nDownload original file to play full video."
50
+ end
51
+
52
+ date = File.mtime(photo).strftime("%y-%m-%d %H:%M:%S")
53
+ loc = Location.new photo
54
+ Printer.show "uploading as " +
55
+ (loc.nil? ? "\"#{loc.name.black}\" (no location given)" : loc.to_s.black) +
56
+ " taken on #{date}... "
57
+ begin
58
+ id = flickr.upload_photo photo, :title => UnicodeUtils.nfkc(loc.name), :is_public => 0,
59
+ :description => description, :tags => UPLOADING_TAG,
60
+ :is_friend => 1, :is_family => 1, :safety_level => 1, # Safe,
61
+ :content_type => 1, :hidden => 2 # Photo/Video
62
+ # TODO visibility MAY be configurable
63
+ req = flickr.photos.getNotInSet(:extras => 'tags').to_hash["photo"][-1]
64
+ rescue Timeout::Error
65
+ Flickru.read_config
66
+ req = flickr.photos.getNotInSet(:extras => 'tags').to_hash["photo"][-1]
67
+ if req.nil?
68
+ raise RuntimeError, "unrecoverable timeout due to large file size"
69
+ else
70
+ if req.to_hash["tags"] != UPLOADING_TAG
71
+ raise RuntimeError, "unrecoverable timeout due to large file size"
72
+ end
73
+ id = req.to_hash["id"]
74
+ end
75
+ end
76
+ flickr.photos.setTags :photo_id => id, :tags => ''
77
+
78
+ flickr.photos.setDates :photo_id => id, :date_taken => date
79
+ flickr.photos.setPerms :photo_id => id, :perm_comment => 1, :perm_addmeta => 0
80
+ # TODO permission MAY be configurable
81
+ if not loc.nil?
82
+ flickr.photos.geo.setLocation :photo_id => id, :lat => loc.latitude,
83
+ :lon => loc.longitude, :accuracy => loc.accuracy
84
+ end
85
+
86
+ Printer.success
87
+
88
+ return id
89
+ end
90
+
91
+ # TODO face tagging (http://developers.face.com http://github.com/rociiu/face) MAY be available
92
+
93
+ def self.classify photo_path, photo_id
94
+ set_title = File.basename(File.dirname(File.dirname(photo_path)))
95
+ set_id = Flickr.photoset_id set_title
96
+ photo_name = File.basename(photo_path, File.extname(photo_path))
97
+ if set_id
98
+ Printer.show "classifying #{photo_name.black} under set #{set_title}... "
99
+ flickr.photosets.addPhoto :photoset_id => set_id, :photo_id => photo_id
100
+ Printer.success
101
+ else
102
+ Printer.show "creating photoset #{set_title.black} with primary photo #{photo_name}... "
103
+ response = flickr.photosets.create :title => set_title, :primary_photo_id => photo_id
104
+ set_id = response.to_hash["id"]
105
+ Printer.success
106
+
107
+ # TODO new photosets MAY be included in some collection. Unfortunately, collections cannot be yet modified by the Flickr API.
108
+ # TODO photosets MAY be ordered alphabetically (flickr.photosets.orderSets API function)
109
+ Printer.ask "Please, choose yourself a better primary photo for this photoset,\n" +
110
+ " order your photosets for positioning this new addition,\n" +
111
+ " and include the new photoset in some collection."
112
+ end
113
+
114
+ return set_id
115
+ end
116
+
117
+ def self.arrangePhotos set_id
118
+ set_title = flickr.photosets.getInfo(:photoset_id => set_id).to_hash["title"]
119
+
120
+ Printer.show "arranging photos in photoset #{set_title.black} by date taken (older first)... "
121
+ response = flickr.photosets.getPhotos(:photoset_id => set_id, :extras => "date_taken").to_hash
122
+ if response["pages"] == 1
123
+ photos = response["photo"].sort! { |a,b| a["datetaken"] <=> b["datetaken"] } # older first
124
+ photo_ids = photos.map { |photo| photo["id"].to_s }
125
+ if not photo_ids.empty?
126
+ photo_ids = photo_ids[1,photo_ids.length].reduce photo_ids[1] do |s,i| s + ',' + i end
127
+ flickr.photosets.reorderPhotos :photoset_id => set_id, :photo_ids => photo_ids
128
+ end
129
+ Printer.success
130
+ else
131
+ Printer.failure "photoset #{set_title} has more than #{response['perpage']} photos."
132
+ Printer.ask "Please, arrange by date taken (older first) within Flickr Organizr."
133
+ end
134
+ end
135
+
136
+ def self.photoset_id set_title
137
+ flickr.photosets.getList.each do |photoset|
138
+ if photoset["title"] == set_title
139
+ return photoset["id"]
140
+ end
141
+ end
142
+
143
+ return nil
144
+ end
145
+
146
+ private
147
+
148
+ UPLOADING_TAG = "uploading"
149
+
150
+ end
@@ -0,0 +1,38 @@
1
+ # flickru
2
+ require 'flickru/ruby'
3
+
4
+ class Journey
5
+
6
+ def initialize destination
7
+ Ruby.assert("destination >= 0") { destination >= 0 }
8
+
9
+ @distance = destination
10
+ @destination = destination
11
+ @beginning = Time.now
12
+ @current = Time.now
13
+ end
14
+
15
+ def take step
16
+ Ruby.assert("@distance >= step") { @distance >= step }
17
+
18
+ @distance -= step
19
+ @current = Time.now
20
+ end
21
+
22
+ def progress
23
+ @destination - @distance
24
+ end
25
+
26
+ def distance
27
+ @distance
28
+ end
29
+
30
+ def elapsed
31
+ @current - @beginning
32
+ end
33
+
34
+ def eta # seconds
35
+ @distance * elapsed / progress
36
+ end
37
+
38
+ end
@@ -0,0 +1,96 @@
1
+ # gems
2
+ require 'escape'
3
+ # flickru
4
+ require 'flickru/ruby'
5
+ require 'flickru/string'
6
+
7
+ class Location
8
+
9
+ GEOWIKI = File.expand_path(File.join File.dirname(__FILE__), '..', '..', 'bin', 'geowiki')
10
+ DEFAULT_ACCURACY = "street"
11
+ COORD_PATTERN = "-?[0-9]+\.?[0-9]*"
12
+
13
+ attr_accessor :name, :place, :latitude, :longitude, :accuracy
14
+
15
+ def initialize photo
16
+ dir = File.basename File.dirname(photo)
17
+ name, place, accuracy = Location.parse dir
18
+ raise RuntimeError, "unnamed location #{dir}" if name.nil?
19
+ @name = name
20
+ begin
21
+ @place = place.nil? ? name : place
22
+ @latitude, @longitude = Location.locate @place
23
+ @accuracy = Location.s_to_accuracy(accuracy ? accuracy : DEFAULT_ACCURACY)
24
+ rescue RuntimeError
25
+ raise if place
26
+ raise RuntimeError, "location #{name} not found" if accuracy
27
+ @place, @latitude, @longitude, @accuracy = nil # no location
28
+ end
29
+ end
30
+
31
+ def nil?
32
+ Ruby.assert("@accuracy.nil? implies @latitude.nil? and @longitude.nil?") {
33
+ @accuracy.nil? or not (@latitude.nil? and @longitude.nil?)
34
+ }
35
+
36
+ @accuracy.nil?
37
+ end
38
+
39
+ def to_s
40
+ place = @place.nil? ? "an undefined place" : @place
41
+ "\"#{@name}\" at #{place} (~#{accuracy_to_s}) " +
42
+ "on lat: #{@latitude}, lon: #{@longitude}"
43
+ end
44
+
45
+ private
46
+
47
+ def self.parse location
48
+ # TODO special characters MAY be escaped
49
+ idx_accuracy = location.index('#') ? location.index('#') : location.length
50
+ idx_place = location.index('@') ? location.index('@') : idx_accuracy
51
+
52
+ name = location.sub(/[@#].*$/, '').strip | nil
53
+ place = location.index('@') ? location.sub(/^.*@/, '').sub(/\#.*$/, '').strip : nil
54
+ accuracy = location.index('#') ? location.sub(/^.*#/, '').strip : nil
55
+
56
+ [name, place, accuracy]
57
+ end
58
+
59
+ def self.locate place
60
+ the_place = place # needed for RuntimeError reporting
61
+ begin
62
+ place = `#{Escape.shell_command [GEOWIKI, place]} 2> /dev/null`[0..-2] \
63
+ if place !~ /^#{COORD_PATTERN}, *#{COORD_PATTERN}$/
64
+ if place =~ /^#{COORD_PATTERN}, *#{COORD_PATTERN}$/
65
+ # latitude, longitude
66
+ [place.sub(/, *#{COORD_PATTERN}$/, ''), place.sub(/^#{COORD_PATTERN}, */, '')]
67
+ else
68
+ raise RuntimeError
69
+ end
70
+ rescue
71
+ raise RuntimeError, "location #{the_place} not found"
72
+ end
73
+ end
74
+
75
+ def Location.s_to_accuracy str
76
+ case str.downcase
77
+ when "world" then 1
78
+ when "country" then 3
79
+ when "region" then 6
80
+ when "city" then 11
81
+ when "street" then 16
82
+ else raise ArgumentError, "unknown accuracy label '#{str}'"
83
+ end
84
+ end
85
+
86
+ def accuracy_to_s
87
+ case @accuracy
88
+ when 1 then "world"
89
+ when 3 then "country"
90
+ when 6 then "region"
91
+ when 11 then "city"
92
+ when 16 then "street"
93
+ else @accuracy
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,52 @@
1
+ # gems
2
+ require 'colorize'
3
+ # flickru
4
+ require 'flickru/ruby'
5
+
6
+ module Printer
7
+
8
+ def self.human_readable_seconds seconds
9
+ Ruby.assert("seconds >= 0") { seconds >= 0 }
10
+
11
+ return "%.1f" % seconds + " seconds" if seconds < 60
12
+ minutes = seconds / 60
13
+ return "%.1f" % minutes + " minutes" if minutes < 60
14
+ hours = minutes / 60
15
+ return "%.1f" % hours + " hours" if hours < 24
16
+ days = hours / 24
17
+ return "%.1f" % days + " days"
18
+ end
19
+
20
+ def self.show msg
21
+ print msg
22
+ end
23
+
24
+ def self.info msg
25
+ puts msg.cyan
26
+ end
27
+
28
+ def self.warn msg
29
+ puts ("warning: " + msg).magenta
30
+ end
31
+
32
+ def self.error msg
33
+ STDERR.puts msg.red
34
+ end
35
+
36
+ def self.enter msg
37
+ print (">>> " + msg + ": ").black
38
+ end
39
+
40
+ def self.ask msg
41
+ puts ("*** " + msg + " ***").light_blue
42
+ end
43
+
44
+ def self.success
45
+ puts "done".green
46
+ end
47
+
48
+ def self.failure msg=nil
49
+ puts ("fail" + (msg.nil? ? "" : ": " + msg)).red
50
+ end
51
+
52
+ end
@@ -0,0 +1,24 @@
1
+ module Ruby
2
+
3
+ def self.assert msg=nil
4
+ if $DEBUG
5
+ raise ArgumentError, msg || "assertion failed" unless yield
6
+ end
7
+ end
8
+
9
+ def self.caller_method_name
10
+ parse_caller(caller(2).first).last
11
+ end
12
+
13
+ private
14
+
15
+ def self.parse_caller at
16
+ if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
17
+ file = Regexp.last_match[1]
18
+ line = Regexp.last_match[2].to_i
19
+ method = Regexp.last_match[3]
20
+ [file, line, method]
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def | what
3
+ self.strip.empty? ? what : self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Flickru
2
+ unless defined? VERSION
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ # gems
2
+ require 'colorize'
3
+ require 'simplecov'
4
+ SimpleCov.coverage_dir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'var', 'cov')))
5
+ SimpleCov.start # should be before loading flickru code!
6
+ # flickru
7
+ require 'flickru'
8
+
9
+ describe Flickru do
10
+ it "accents work" do
11
+ Flickru.flickru "var/ts/tc_accents"
12
+ end
13
+
14
+ it "different accuracies work case-insensitively" do
15
+ Flickru.flickru "var/ts/tc_accuracies"
16
+ end
17
+
18
+ it "several collections, several sizes" do
19
+ Flickru.flickru "var/ts/tc_collections"
20
+ end
21
+
22
+ it "various filetypes available, skipping garbage" do
23
+ Flickru.flickru "var/ts/tc_filetypes"
24
+ end
25
+
26
+ it "large files work" do
27
+ Flickru.flickru "var/ts/tc_large_files"
28
+ end
29
+
30
+ it "locations can be specified in many ways" do
31
+ Flickru.flickru "var/ts/tc_locations"
32
+ end
33
+
34
+ it "leading and trailing whitespaces are removed" do
35
+ Flickru.flickru "var/ts/tc_whitespaces"
36
+ end
37
+
38
+ after(:all) do
39
+ puts "\nRemember to delete the testing files that have been just uploaded to your Flickr's collection 'Testing Collection*'.".red
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flickru
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - "Jes\xC3\xBAs Pardillo"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-12-18 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: colorize
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 0.5.8
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: escape
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 0.0.4
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: flickraw
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.4
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: rubygems-update
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 1.8.11
57
+ type: :runtime
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: simplecov
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 0.5.4
68
+ type: :runtime
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: unicode_utils
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 1.1.2
79
+ type: :runtime
80
+ version_requirements: *id006
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ prerelease: false
84
+ requirement: &id007 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 2.7.0
90
+ type: :development
91
+ version_requirements: *id007
92
+ description: |
93
+ Command-line tool 'flickru' automatises photos/videos uploads to Flickr.
94
+
95
+ Entering 'flickru <directory>' in your command line, any photos under 'directory' (and subdirs)
96
+ are uploaded to your Flickr account (interactively entered at the first time you start flickru).
97
+
98
+ Photos are identified by case-insensitive extensions: GIF, JPEG, JPG, and PNG.
99
+ Videos are identified by case-insensitive extensions: AVI, MPEG, and MPG.
100
+
101
+ The following Flickr metadata for photos (as well as videos) is set:
102
+ - date-taken from the file (last) modification time
103
+ - private, visible by friends & family, hidden for public searches
104
+ - safety level to safe
105
+ - permission for friends & family to add comments to the photo and it's notes
106
+ - permission for nobody to add notes and tags to the photo
107
+ - for videos larger than the Flickr's longer than 90s (but shorter than 500MB,
108
+ Flickr's maximum permisible size), the description will contain an annotation
109
+ about its large duration.
110
+ - title, geolocation, and accuracy from the owner directory's name.
111
+ Owner directory name format is given by the format 'TITLE[@LOCATION[#PRECISION]]',
112
+ where:
113
+ - TITLE is the desired title for the photos directly stored in the directory
114
+ - LOCATION is the location of the stored photos specified as either:
115
+ - the Wikipedia page name (whitespaces allowed) of the location (if exists) or
116
+ - its coordinates LATITUDE,LONGITUDE
117
+ - PRECISION is the Flickr geolocation precision given by one of the following
118
+ case insentitive literals: street, city, region, country, world.
119
+
120
+ Photos are classified into a photoset (existing or not) entitled with the
121
+ second-level directory name containing the photo. The photoset is arranged by
122
+ date taken (older first).
123
+
124
+ To see some examples on the directory structure recognised by flickru, please
125
+ explore the subdirectories under var/ts.
126
+
127
+ email:
128
+ - dev@jesuspardillo.com
129
+ executables:
130
+ - flickru
131
+ extensions: []
132
+
133
+ extra_rdoc_files: []
134
+
135
+ files:
136
+ - bin/flickru
137
+ - bin/geowiki
138
+ - lib/flickru.rb
139
+ - lib/flickru/file.rb
140
+ - lib/flickru/flickr.rb
141
+ - lib/flickru/journey.rb
142
+ - lib/flickru/location.rb
143
+ - lib/flickru/printer.rb
144
+ - lib/flickru/ruby.rb
145
+ - lib/flickru/string.rb
146
+ - lib/flickru/version.rb
147
+ - spec/flickru_spec.rb
148
+ homepage: http://rubygems.org/gems/flickru
149
+ licenses: []
150
+
151
+ post_install_message:
152
+ rdoc_options: []
153
+
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: "0"
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: "0"
168
+ requirements: []
169
+
170
+ rubyforge_project:
171
+ rubygems_version: 1.8.11
172
+ signing_key:
173
+ specification_version: 3
174
+ summary: Command-line Flickr Upload Automator
175
+ test_files:
176
+ - spec/flickru_spec.rb