Created
April 18, 2014 18:11
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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