!/usr/bin/env perl

use Modern::Perl;

use Image::ExifTool;

use Geo::Coder::OSM;

use JSON;

use File::Slurper qw(write_text);

use Getopt::Long;

use Data::Dumper;

binmode(STDOUT, ':utf8'); # force UTF-8 output

my $geocoder = Geo::Coder::OSM->new;

my $exifTool = Image::ExifTool->new;

$exifTool->Options(CoordFormat => q{%+.6f},

DateFormat => "%Y-%m-%d %H:%M:%S");

my %cache = ();

my $usage = <<"EOT";

$0 [--txt|--rename] [--confirm] [--verbose] [FILES...]

Print location data for all the FILES given.

--txt causes it to write a matching text file

--rename show how to rename the files

--confirm in conjunction with --rename actually does it

--verbose uses the display_name instead of the city

EOT

our ($write_text_file, $rename, $confirm, $verbose);

GetOptions("txt" => \$write_text_file,

"rename" => \$rename,

"confirm" => \$confirm,

"verbose" => \$verbose)

or die($usage);

my $i = 0;

for my $file (@ARGV) {

if (not -f $file) { warn "$file is no file"; next }

$exifTool->ExtractInfo("$file");

# Date → just the day

my $date = $exifTool->GetValue('CreateDate', '') || '';

($date) = $1 if $date =~ /^(\d\d\d\d-\d\d-\d\d)/;

# City

my $lat = $exifTool->GetValue('GPSLatitude', '');

my $long = $exifTool->GetValue('GPSLongitude', '');

if (not $lat or not $long) { warn "$file has no location data\n"; next }

my $location = $cache{"$lat, $long"};

if (!$location) {

$location = $cache{"$lat, $long"} = $geocoder->reverse_geocode(lat => $lat, lon => $long);

if (!$location) {

my $json = decode_json($geocoder->response->content);

if ($json->{error}) {

warn $file . " " . $json->{error} . " $lat, $long\n";

} else {

warn "$file unable to geocode, reason unknown\n";

}

next;

}

}

my $place;

if ($verbose) {

$place = $location->{display_name};

} else {

$place = $location->{address}->{city}

|| $location->{address}->{village}

|| $location->{address}->{county};

}

warn "No useful data in " . Dumper($location) unless $place;

my $name = "";

$name .= "$date " if $date;

$name .= "$place " if $place;

$name .= $file;

if ($rename) {

if ($confirm) {

rename($file, $name);

print substr(".oOo", $i++ % 4, 1);

STDOUT->flush();

} else {

say "mv '$file' '$name'";

}

} else {

say $name;

}

if ($write_text_file) {

$file =~ s/(jpg|png)$/txt/i;

write_text($file, $location);

}

}