Skip to content

Instantly share code, notes, and snippets.

@alicraigmile
Created April 18, 2014 18:11
Show Gist options
  • Save alicraigmile/11057122 to your computer and use it in GitHub Desktop.
Save alicraigmile/11057122 to your computer and use it in GitHub Desktop.
Sort a folder of images and movies from your phone or digital camera into an archive folder tree (a folder per year/month)
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Std;
use constant DEFAULT_DEST => '/content/Media/Pictures';
use constant FATAL => 1;
our %opts = (); #eek - nasty hack alert!!!
getopts ('dmfqvh', \%opts);
our $Destination = $ENV{SORTPICS_DEST} || &DEFAULT_DEST;
if ($opts{h}) {
Usage();
exit;
}
if (! $opts{d}) {
Info("******************* DRY RUN *******************\n");
Info("use -d to do the work.\n");
Info("******************* DRY RUN *******************\n");
}
my $Source = shift || '.';
if (! -d $Source) {
Error("Source needs to be a folder\n");
exit -1;
}
local *FOLDER;
opendir FOLDER, $Source or Error("Could not open source folder - $!\n",FATAL);
my @everything = readdir FOLDER;
my @files = sort grep { $_ ne 'Thumbs.db' } grep { -f "$Source/$_" } @everything;
my @folders = sort grep { -d "$Source/$_" && $_ !~ /^\./ } @everything;
closedir FOLDER;
foreach my $selected (@files) {
Info("Looking at '$selected'...\n");
my $year = undef;
my $month = undef;
my $day = undef;
#selected has date in format YYYYMMDD
if (! defined $year) {
($year, $month, $day) = DateFromFilenameYYYYMMDD($selected);
}
#selected has date in format DDMMYYYY
if (! defined $year) {
($year, $month, $day) = DateFromFilenameDDMMYYYY($selected);
}
# FILE MODIFICATION DATE
if (! defined $year) {
eval {
use POSIX 'strftime';
my $file_modification_date = GetFileModificationDate("$Source/$selected");
Debug("file_modification_date='$file_modification_date'\n");
if ($file_modification_date =~ /(\d{4})(\d{2})\d{2}/) {
if ($opts{m}) {
$year = $1;
$month = $2;
} else {
Info("ignoring FILE_MODIFICATION_DATE for this file. Add -m option to use it.\n");
}
}
};
if ($@) {
Error("$@ - $Source/$selected\n");
}
}
#EXIF Photo 'Create Date'
if (! defined $year) {
eval {
my $photo_creation_date = GetPhotoCreationDate("$Source/$selected");
Debug("photo_creation_date='$photo_creation_date'\n");
if ($photo_creation_date =~ /(\d{4})(\d{2})\d{2}/) {
$year = $1;
$month = $2;
}
};
if ($@) {
Error("$@ - $Source/$selected\n");
}
}
#EXIF Video 'Date/Time Original'
if (! defined $year) {
eval {
my $video_creation_date = GetVideoCreationDate("$Source/$selected");
Debug("video_creation_date='$video_creation_date'\n");
if ($video_creation_date =~ /(\d{4})(\d{2})\d{2}/) {
$year = $1;
$month = $2;
}
};
if ($@) {
Error("$@ - $Source/$selected\n");
}
}
if (! defined $year) {
Info("No date was detected from the filename or via the EXIF metadata.\n");
}
if (defined $year) {
if (! -d "$Destination/$year") {
Info("mkdir $Destination/$year\n");
if ($opts{d}) {
mkdir "$Destination/$year" or die $!;
}
}
if (! -d "$Destination/$year/$year-$month") {
Info("mkdir $Destination/$year/$year-$month\n");
if ($opts{d}) {
mkdir "$Destination/$year/$year-$month" or die $!;
}
}
Info("mv $Source/$selected -> $Destination/$year/$year-$month/\n");
if ($opts{d}) {
my $overwrite = -e "$Destination/$year/$year-$month/$selected";
if ((! $overwrite) || ($overwrite && $opts{f})){
`mv "$Source/$selected" "$Destination/$year/$year-$month"`;
}
if ($overwrite && ! $opts{f}) {
Notice("Will not overwite files. Skipping. Use -f to force.\n");
}
}
}
}
#given a filename for a photo, return the creation date
sub GetPhotoCreationDate {
my $filename = shift;
die "Not_A_File\n" if (! -f $filename);
#die "Not_A_JPEG_Photo_File\n" if ($filename !~ /\.jpe?g$/i);
my $file_creation_date = `exiftool -d %Y%m%d -CreateDate "$filename" | cut -d ":" -f 2 | cut -d " " -f 2`;
return $file_creation_date;
}
#given a filename for a video, return the creation date
sub GetVideoCreationDate {
my $filename = shift;
die "Not_A_File\n" if (! -f $filename);
#die "Not_An_AVI_Photo_File\n" if ($filename !~ /\.avi$/i);
my $video_creation_date = `exiftool -d %Y%m%d -DateTimeOriginal "$filename" | cut -d ":" -f 2 | cut -d " " -f 2`;
return $video_creation_date;
}
#given a filename, return the file modification date
sub GetFileModificationDate {
my $filename = shift;
die "Not_A_File" if (! -f $filename);
my $file_modification_date = strftime('%Y%m%d', localtime((stat($filename))[9]));
return $file_modification_date;
}
sub Debug {
my $message = shift;
return unless $opts{v};
print "[DEBUG] $message";
}
sub Info {
my $message = shift;
return if $opts{q};
print "[INFO] $message";
}
sub Error {
my $message = shift;
my $importance = shift;
if ($importance == &FATAL) {
die "[ERROR] $message";
}
# return if $opts{q};
print STDERR "[ERROR] $message";
}
sub Notice {
my $message = shift;
return if $opts{q};
print "[NOTICE] $message";
}
sub DateFromFilenameDDMMYYYY {
my $filename = shift;
my $year = undef;
my $month = undef;
my $day = undef;
if ($filename =~ /(?<!\d)(\d{2})([-_]?)(\d{2})\2((19|20)\d{2})(?!\d)/) {
$year = $4;
$month = $3;
$day = $1;
Debug("DDMMYYYY found in filename='$filename' year='$year' month='$month' day='$day'.\n");
return ($year, $month, $day);
}
return undef;
}
sub DateFromFilenameYYYYMMDD {
my $filename = shift;
my $year = undef;
my $month = undef;
my $day = undef;
if ($filename =~ /(?<!\d)((19|20)\d{2})([-_]?)(\d{2})\3(\d{2})(?!\d)/) {
$year = $1;
$month = $4;
$day = $5;
Debug("YYYYMMDD found in filename='$filename' year='$year' month='$month' day='$day'.\n");
return ($year, $month, $day);
}
return undef;
}
sub Usage
{
print "\n";
print "Destination is '$Destination'.\n(Set via \$ENV{SORTPICS_DEST}).\n";
print "\n";
print "usage:\n";
print "\t-d : do it!\n";
print "\t-f : force (overwrites files)\n";
print "\t-h : show this message\n";
print "\t-m : use modification date (rather than detecting date)\n";
print "\t-q : quiet mode (hide messages)\n";
print "\t-v : verbose (show debugging messages)\n";
print "\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment