#!/usr/local/bin/perl # search for EyeTV recordings # pudge@pobox.com, http://dev.macperl.org/ # Wed Nov 13 11:43:21 2002 # This program is free and open software. You may use, modify, # distribute, and sell this program (and any modified variants) in any # way you wish, provided you do not restrict others from doing the same. use strict; use warnings; no warnings 'uninitialized'; # all modules on the CPAN or included with perl use Date::Format; use Date::Parse; use File::Basename; use File::Glob ':glob'; use File::Spec::Functions; use Getopt::Std; use Mac::Files; use Mac::Memory; use Mac::PropertyList 'parse_plist'; use Text::Autoformat; my $PROGNAME = basename($0); my %opts; usage('Options used incorrectly') unless getopts('d:t:t2:phfluq:', \%opts); usage() if $opts{'h'}; my $match = shift @ARGV; my $eyetvdir = $opts{'d'}; if (!$eyetvdir) { # find proper file from preferences, it's a Base64'd alias, # so get the data, stick it in a handle, and resolve it my $prefs = catfile( FindFolder(kOnSystemDisk, kPreferencesFolderType), 'com.elgato.eyetv.plist' ); my $data = get_plist($prefs); my $handle = new Handle $data->{'value'}{'archive folder'}{value}; $eyetvdir = catdir(scalar ResolveAlias($handle), 'EyeTV Archive'); } opendir my $dh, $eyetvdir or die "Can't open $eyetvdir: $!"; my %matches; for my $dir (grep { /^[0-9a-f]{16}/ } readdir $dh) { next if $dir eq ('f' x 16) && !$opts{'f'}; my %files = map { ($_, 1) } glob( catfile($eyetvdir, $dir, '*.eyetv[pr]') ); my @files = grep { /r$/ } keys %files; my @pfiles = grep { /p$/ } keys %files; push @files, @pfiles if $opts{'p'} || $opts{'t'} == 1; my $pdata = get_plist($pfiles[0]); for my $file (@files) { my $nfile = catfile($dir, basename($file, '\.*')); my $data = get_plist($file); # sometimes the title or description is not # properly filled in, find it in the 'p' file for (qw(description)) { $data->{value}{$_}{value} ||= $pdata->{value}{$_}{value}; } # ... but if both titles are defined, the r one is probably # the episode title, so combine them if (!$data->{value}{title}{value}) { $data->{value}{title}{value} = $pdata->{value}{title}{value}; } elsif ($data->{value}{title}{value} && $data->{value}{title}{value}) { $data->{value}{title}{value} = $pdata->{value}{title}{value} . ' - ' . $data->{value}{title}{value}; } if ($match) { $matches{$nfile} = $data if grep { /\Q$match\E/i } map { $data->{value}{$_}{value} } qw(title description); } else { $matches{$nfile} = $data; } # unfinished code: grep by time if ($opts{t}) { my($t1, $t2); if ($opts{t} == 1) { $t1 = time() } else { $t1 = str2time($opts{t}) } if ($opts{t2} == 1) { $t2 = time() } else { $t2 = str2time($opts{t2}) } for my $file (keys %matches) { delete $matches{$file} if get_date($matches{$file}{value}) < $t1; } } } } unless ($opts{'q'}) { print "TV recordings in directory '$eyetvdir':\n"; print keys %matches ? "\n" : "No matches found.\n"; } my %playlists; for my $file (sort { $matches{$a}{value}{start}{value} cmp $matches{$b}{value}{start}{value} } keys %matches) { my $info = $matches{$file}{value}; my $description = $info->{description}{value} || ''; $description &&= autoformat( $description, { left => 5, right => 74, all => 1 } ); if (!$opts{'q'}) { if ($opts{'u'}) { $file =~ s/eyetvr/mpg/; $file = "http://mp3.pudge.net:8080/private/eyetv/$file"; } elsif ($opts{'l'}) { $file =~ s/eyetvr/mpg/; $file = catfile($eyetvdir, $file); } } my @values = ( $info->{title}{value}, $file, scalar localtime get_date($info), $info->{duration}{value}/3600, $description ); if ($opts{'q'}) { push @{$playlists{ $info->{title}{value} }}, \@values; } else { printf <<'EOT', @values; %s %s %s (%.2f hours) %s EOT } } if ($opts{'q'}) { opendir my $dh, $opts{'q'} or die $!; for my $file (readdir $dh) { if ($file =~ /^EyeTV: /) { unlink catfile($opts{'q'}, $file); } } for my $title (keys %playlists) { my $file = catfile($opts{'q'}, "EyeTV: $title.bqp"); open my $fh, '>', $file or die $!; for my $program (@{$playlists{$title}}) { $program->[1] =~ s/eyetvr$/mpg/; printf $fh <<'EOT', @{$program}[1, 2]; EyeTV/%s %s EOT } } } sub get_plist { my($file) = @_; open my $fh, '<', $file or die "Can't open '$file': $!"; my $data = do { local $/; <$fh> }; # flatten $data =~ s{ [^<]+\s+ }{}sgx; $data =~ s{ (?!\n) }{}sgx; return Mac::PropertyList::parse_plist($data); } sub get_date { my($info) = @_; my $date = $info->{start}{value}; $date =~ s/T/ /; $date =~ s/Z/ GMT/; return str2time($date); } sub usage { print "*** $_[0]\n" if $_[0]; print <