summaryrefslogtreecommitdiff
path: root/bin/ifuse-photos-to-tmp
blob: 3efc17240d3cdd71fceb1e8a0119faf3883636d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/perl

# ifuse-photos-to-tmp -- import photos from iPhone/iPad/etc. using ifuse

# Copyright (C) 2019 Sean Whitton
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

use 5.028;
use strict;
use warnings;

use Const::Fast;
use DateTime;
use DateTime::TimeZone::Local;
use DateTime::Format::Epoch;
use File::Copy;
use File::Find;
use File::Path qw(make_path);
use File::Spec::Functions;
use File::stat qw(stat);
use Image::ExifTool qw(ImageInfo);
use Syntax::Keyword::Try;

# should be absolute paths
const my $mount => "$ENV{HOME}/mnt/hermes";
const my $dest  => "$ENV{HOME}/tmp";

try {
    make_path($mount, $dest);
}
catch {
    die "could not mkdir $mount and/or $dest";
}

unless (grep { /ifuse on $mount/ } `mount`) {
    system "ifuse $mount";
    die "could not mount $mount with ifuse" unless ($? == 0);
}

my $epoch = DateTime->new(year => 1970, month => 1, day => 1);
my $epoch_formatter = DateTime::Format::Epoch->new(epoch => $epoch, );
find(sub {
         my $file = $_;
         # we handle any file, images or not, falling back to mtime if
         # we can't extract EXIF data
         return unless (-f $file);
         my $info = ImageInfo($file, 'FileType', 'CreateDate', 'DateCreated');

         my $ext; my $dt;
         my $no_exif = 0;
         # a closure, in particular over $info and $dt
         my $try_apple_exif = sub {
             my $key = shift;

             if ($info->{$key} =~
                 /([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/) {
                 $dt = DateTime->new(year => $1, month => $2, day => $3,
                                     hour => $4, minute => $5, second => $6);
             }
         };
         if (exists $info->{FileType} && exists $info->{CreateDate}
             && $info->{FileType} eq "JPEG") {
             $ext = "jpg";
             $try_apple_exif->("CreateDate");
         } elsif (exists $info->{FileType} && exists $info->{DateCreated}
                  && $info->{FileType} eq "PNG") {
             $ext = "png";
             $try_apple_exif->("DateCreated");
         } elsif (exists $info->{FileType} && exists $info->{MediaCreateDate}
                  && $info->{FileType} eq "MOV") {
             $ext = "mov";
             $try_apple_exif->("MediaCreateDate");
         } elsif (exists $info->{FileType} && exists $info->{CreateDate}
                  && $info->{FileType} eq "MOV") {
             $ext = "mov";
             $try_apple_exif->("CreateDate");
         } else {
             $no_exif = 1;
             $file =~ /\.([^.]+\z)/;
             $ext = lc($1) if defined $1;
             $dt = $epoch_formatter->parse_datetime(stat($file)->mtime);
             $dt->set_time_zone(DateTime::TimeZone::Local->TimeZone());
         }

         if (defined $ext && defined $dt) {
             my $target =
               catfile($dest,
                       $dt->strftime('%Y-%m-%d %H.%M.%S') . "." . $ext);

             my $counter = 1;
             $target =~ s/\.$ext\z/-1.$ext/ if -e $target;
             while (-e $target) {
                 $counter++;
                 $target =~ s/-[0-9]+\.$ext\z/-$counter.$ext/;
             }

             move($file, $target);
             say STDERR "fell back to mtime for $file $target" if $no_exif;
         } else {
             warn "not touching $file because could not determine target name";
         }
     }, catfile($mount, "DCIM"));

# this causes the device to regenerate its knowledge of what photos it
# has; otherwise they'll still appear despite the files having been moved
unlink glob "$mount/PhotoData/Photos*";
unlink "$mount/PhotoData/com.apple.photos.caches_metadata.plist";

system "fusermount -u $mount";
warn "failed to unmount $mount" unless ($? == 0);

exec ("xdg-open", "$dest")
  or warn "failed to open $dest in a graphical file manager";