use strict; use warnings; use Path::Tiny; use JSON::XS; # JSON parser module use DDP; use v5.36; use DateTime::Format::ISO8601; use Try::Catch; use Getopt::Long; use Image::MetaData::JPEG; use File::stat; GetOptions( "pull-versions" => \my $get_versions, "restore" => \my $do_restores, "verbose" => \my $verbose, "print" => \my $print, "copy" => \my $copy, "overwrite" => \my $overwrite, "folder=s" => \my $folder_name, "update-ts" => \my $update_ts, "since" => \my $since, "match" => \my $match, ) or die("Error in command line arguments\n"); $match = '.*' unless $match; my %restores; my %stats = ( exists => 0, restored => 0, failed => 0, selected => 0, ); my %folders = ( 'koku_downloads' => { 'id' => 'm7ko5-adoga', 'path' => '/mnt/nasty/koku_downloads', }, 'koku_documents' => { 'id' => 'krvxc-ajsfv', 'path' => '/mnt/nasty/Koku', }, 'koku_desktop' => { 'id' => 'vhimk-o3gwx', 'path' => '/mnt/nasty/koku_desktop', }, 'shared_pictures' => { 'id' => 'p6jqq-nouth', 'path' => '/mnt/nasty/Media/Pictures' }, 'koku_music' => { 'id' => 'mdhgr-gd7rv', 'path' => '/mnt/nasty/Media/Music/Natalia' }, 'project-conquer' => { 'id' => 'qypth-g6xkb', 'path' => '/mnt/nasty/project-conquer' }, 'highpoint' => { 'id' => 'jekig-3yzvw', 'path' => '/mnt/nasty/highpoint' }, ); my $folder_id = $folders{$folder_name}{'id'}; my $target_dir = $folders{$folder_name}{'path'}; my $source_dir = $folders{$folder_name}{'path'} . "/.stversions"; my $version_data = "$folder_name.json"; sub get_versions() { my $curl = qq{curl -k -X GET -H "X-API-KEY: oemTvSg94cShmEymeuct66GRsyutLTGg" https://dri.tz:8090/rest/folder/versions?folder=$folder_id > $folder_name.json}; system($curl); say $curl; } sub get_json() { my $json_file = path($version_data); my $decoded_json; if (-e $json_file) { my $json_data = $json_file->slurp; $decoded_json = decode_json($json_data); } else { die "JSON file not found at $json_file"; } return $decoded_json; }; sub generate_restores($path, $version_date, $version_time, $restore_path) { if ($restores{$path}) { say "Path exists, checking for latest verson" if $verbose; if ($version_date > $restores{$path}{'version_time'}) { say "Later version found" if $verbose; $restores{$path} = { 'version_date' => $version_date, 'version_time' => $version_time, 'restore_path' => $restore_path, }; } else { say "Keeping current version" if $verbose; } } else { say "Inserting new path" if $verbose; $restores{$path} = { 'version_date' => $version_date, 'version_time' => $version_time, 'restore_path' => $restore_path, }; } } sub restore_versions() { for my $path (sort keys %restores) { my $source = path("$source_dir/" . $restores{$path}{'restore_path'}); my $dest = path("$target_dir/$path"); say "Source: $source" if $verbose; say "Dest: $dest" if $verbose; my $res; unless (-d $dest->parent) { $dest->parent->mkdir; } if (! -f $dest || $overwrite) { try { $res = 'restored'; # my $restore_copy = $source->copy($dest) if $copy; # Doesn't preserve timestamps my $restore_copy = system('cp', '-p', $source, $dest) if $copy; say "$restore_copy successfully restored" if $verbose; ++$stats{'restored'}; } catch { $res = 'failed '; say "$source -> $dest failed to restore" if $verbose; ++$stats{'failed'}; } } else { $res = 'exists '; ++$stats{'exists'}; } if ($update_ts) { update_timestamp($path); say "updated timestamp" if $verbose; } my $processed = $stats{'restored'} + $stats{'exists'} + $stats{'failed'}; my $selected = $stats{'selected'}; say sprintf('%.2f', $processed * 100 / $selected) . "% $processed/$selected $res\t$dest" if $print; } } sub do_restores() { my $decoded_json = get_json(); foreach my $path (sort keys %$decoded_json) { # Perform your operations on each item # For example, print the item for my $version (@{$decoded_json->{$path}}) { my $ts = DateTime::Format::ISO8601->parse_datetime($version->{'versionTime'}); if ($ts ge $since) { my $version_date = $ts->ymd(''); my $version_time = $ts->hms(''); my $fullpath = path($path); $fullpath =~ /(.*)(\.\w{2,4}$)/; my $base = $1; my $ext = $2; say $path unless ($1 && $2); unless ($1 && $2) { ++$stats{'skipped'}; next; }; ++$stats{'selected'}; my $restore_path = path("$base~${version_date}-${version_time}${ext}"); generate_restores($path, $version_date, $version_time, $restore_path); say "$path: $restore_path" if $verbose; } } } restore_versions(); p % stats; } sub update_timestamp($path) { # return unless $path =~ /\.jpe?g$/i; try { my $source = path("$source_dir/" . $restores{$path}{'restore_path'}); my $dest = path("$target_dir/$path"); my $stat = stat($source); utime($stat->atime, $stat->mtime, $dest); } catch { say "unable to update timestamp"; } } get_versions() if $get_versions; do_restores() if $do_restores;