#!/usr/bin/perl # Name: bin/from-tivo Author: Joe.Smith@inwap.com # Purpose: Pulls selected files from the mfs_ftp server running on my TiVo. $|++; use strict; use warnings; use Net::FTP; use constant USAGE => "Usage: $0 192.168.1.6:3105 'TOON|G4TTV'\n"; use constant TEMPFILE => "temp-$$.ty"; use constant MB => 1024*1024; my $debug = (@ARGV and $ARGV[0] eq '-d') ? shift : 0; my $verbose = (@ARGV and $ARGV[0] eq '-v') ? shift : ($debug or -t STDIN); my $mfs_ftp = shift or die "Server must be specified\n", USAGE; my $pattern = shift or die "Pattern to match must be specified\n",USAGE; $mfs_ftp .= ':3105' unless $mfs_ftp =~ /:/; $_ = qw(Sun Mon Tue Wed Thu Fri Sat)[(localtime)[6]]; (my $out = $mfs_ftp) =~ s/(:.*)?$/.$_/; # joe-tivo.Tue or sally-tivo.Tue my $width = (`stty size 2>/dev/null` =~ /(\d+)$/) ? $1 : 80; my $hashmarks = $verbose ? MB : 0; # Hashmark per megabyte print "Connecting to $mfs_ftp\n" if $verbose; my $ftp = Net::FTP->new($mfs_ftp, Debug => $debug, Passive => 0) or ($@ =~ /No route to host/ and exit 1) or die "Cannot connect to $mfs_ftp $@"; # No need for $ftp->login('anon','anon') with mfs_ftp. # Besides, Net::FTP::login sends 'user' instead of 'USER', which is not good. # Get a directory listing and save it to "servername.Weekday". print "Writing directory listing to $out - " if $verbose; $ftp->cwd('ty') or die "Error ftp->cwd('ty') ", $ftp->message; my @dir = $ftp->dir() or die "Error ftp->dir()", $ftp->message; $_ = join "\n",@dir,''; if (open OUT,">$out" and print OUT $_ and close OUT) { print scalar @dir, " lines\n" if $verbose; } else { print $verbose ? "Failed: $!\n" : "Problems writing to $out: $!\n"; } # Only deal with recordings that match the specified regex, which can # match series name, episode name, air date, channel name, etc. my @lines = grep /$pattern/, @dir; print "Found ",scalar @lines," shows matching /$pattern/\n" if $verbose; my %showinfo; foreach my $line (@lines) { chomp; # Here's where it would be nice if suggestions had a specific uid or gid. my($perms,$link,$uid,$gid,$size,$mon,$day,$time,$file) = split ' ',$line,9; $showinfo{$file} = sprintf "%3s %2s %5s %6dMB (%d# x %.1f)", $mon, $day, $time, $size/MB, $width, $size/MB/$width; } $ftp->binary(); $ftp->hash(1, $hashmarks) if $hashmarks; my $count; foreach my $show (sort keys %showinfo) { next if $show =~ /^\{ Recording/; my $dir = ($show =~ /.*\{(.+)\}\.ty$/) ? $1 : 'UNKNOWN'; -d $dir or mkdir($dir,0777) or warn "mkdir($dir): $!\n"; (my $dest = "$dir/$show") =~ tr/?$/__/; my $timestamp = substr $showinfo{$show},0,12; # "Mon dd hh:mm" if (-f $dest and -s $dest > 100 * MB) { system('ls', '-ls', $dest) if $debug; } else { $count++ == 0 and print "\n" and $hashmarks and print STDERR "Each hash mark indicates $hashmarks bytes\n"; print "RETR (to $dir/*.ty) $showinfo{$show}\n$show\n"; my $start = time; $ftp->get($show,TEMPFILE) or warn "\nFAILED: ftp->get($show) ", $ftp->message; my $end = time; print STDERR "\n" if $hashmarks; if (-f TEMPFILE) { rename TEMPFILE,$dest or (warn "Failed: rename($dest): $!\n" and next); system('touch', '-d', $timestamp, $dest); # Use the lazy way on Linux system('ls', '-ls', $dest) if $debug; my $secs = ($end - $start) or 1; my $megs = (-s $dest) / MB; printf "%6.1f MB in %4.1f minutes = %.1f MB/sec\n", $megs, $secs/60, $megs/$secs; } else { warn "Transfer failed to create temp file ".TEMPFILE."\n"; } } } $ftp->quit; if ($count) { my $cmd = -x '/usr/local/bin/df-i' ? '/usr/local/bin/df-i' : 'df -h'; system "$cmd ."; } else { print "All shows already copied\n" if $verbose; }