class Adri::Photo
Attributes
location_cache[RW]
dry_run[R]
path_format[R]
prefix[R]
source_path[R]
verbose[R]
Public Class Methods
new(path, options)
click to toggle source
# File bin/adri, line 47 def initialize(path, options) @source_path = File.absolute_path(path) @path_format = options[:path_format].gsub('/', File::SEPARATOR) @verbose = !options[:quiet] @dry_run = !options[:run] @prefix = if options[:prefix].to_s.strip.empty? File.dirname(@source_path) else File.absolute_path(options[:prefix]) end end
Public Instance Methods
date_time()
click to toggle source
# File bin/adri, line 61 def date_time return @date_time if @date_time if exif&.date_time && exif.date_time != '0000:00:00 00:00:00' @date_time = Time.strptime(exif.date_time.sub(' 24:', ' 00:'), '%Y:%m:%d %H:%M:%S') end end
destination_path()
click to toggle source
# File bin/adri, line 100 def destination_path return @destination_path if @destination_path path = date_time.strftime(path_format) if location_in_path_format? path = sprintf(path, location: location) end @destination_path ||= File.join( prefix, path, File.basename(source_path) ) end
latitude()
click to toggle source
# File bin/adri, line 70 def latitude return @latitude if @latitude if exif&.gps_latitude @latitude = geo_float(exif.gps_latitude) end end
location()
click to toggle source
# File bin/adri, line 86 def location return @location if defined?(@location) @location = read_location_from_cache return @location if @location != false @location = location_from_latlng write_location_to_cache @location end
longitude()
click to toggle source
# File bin/adri, line 78 def longitude return @longitude if @longitude if exif&.gps_longitude @longitude = geo_float(exif.gps_longitude) end end
move()
click to toggle source
# File bin/adri, line 116 def move return if skip_move? if verbose puts sprintf( '%s -> %s%s', source_path, destination_path, dry_run ? ' (DRY RUN)' : '' ) end return if dry_run FileUtils.mkdir_p(File.dirname(destination_path)) FileUtils.mv(source_path, destination_path) end
Private Instance Methods
exif()
click to toggle source
# File bin/adri, line 134 def exif begin @exif ||= Exif::Data.new(File.open(source_path)) rescue Exif::NotReadable end end
geo_float(value)
click to toggle source
# File bin/adri, line 239 def geo_float(value) degrees, minutes, seconds = value degrees + minutes / 60.0 + seconds / 3600.0 end
latlng()
click to toggle source
# File bin/adri, line 145 def latlng @latlng ||= [latitude, longitude].compact end
location_cache_key()
click to toggle source
# File bin/adri, line 224 def location_cache_key @location_cache_key ||= [ latitude.truncate(LOCATION_CACHE_SCALE).to_s, longitude.truncate(LOCATION_CACHE_SCALE).to_s ] end
location_from_geocode_result(result)
click to toggle source
# File bin/adri, line 212 def location_from_geocode_result(result) LOCATION_ADDRESS_TYPES.each do |type| entity = result.address_components_of_type(type).first if entity return entity['long_name'] end end nil end
location_from_latlng()
click to toggle source
# File bin/adri, line 180 def location_from_latlng current_delay = 0.1 # 100 ms begin geocode_results = Geocoder.search(latlng) rescue Geocoder::OverQueryLimitError, Geocoder::LookupTimeout => e puts "Got #{e.class.name}" if verbose if current_delay > GEOCODE_MAX_DELAY puts "Exceeded max delay of #{GEOCODE_MAX_DELAY} seconds" if verbose return end puts "Waiting #{current_delay} seconds before retrying..." if verbose sleep(current_delay) current_delay *= 2 # Exponential backoff retry end geocode_results.each do |result| location = location_from_geocode_result(result) if location return location end end nil end
location_in_path_format?()
click to toggle source
# File bin/adri, line 141 def location_in_path_format? path_format['%{location}'] end
read_location_from_cache()
click to toggle source
# File bin/adri, line 235 def read_location_from_cache self.class.location_cache[location_cache_key] end
skip_move?()
click to toggle source
# File bin/adri, line 149 def skip_move? if !File.exist?(source_path) puts "Missing file #{source_path}" if verbose return true end if date_time.nil? puts "No datetime data #{source_path}" if verbose return true end if location_in_path_format? if latlng.empty? puts "No location data #{source_path}" if verbose return true end if location.nil? # Geocoding failed puts "Unknown location #{source_path}" if verbose return true end end if File.exist?(destination_path) puts "Existing file #{destination_path}" if verbose return true end false end
write_location_to_cache()
click to toggle source
# File bin/adri, line 231 def write_location_to_cache self.class.location_cache[location_cache_key] = location end