Changeset 182 for shepherd

Show
Ignore:
Timestamp:
11/06/06 15:31:42 (7 years ago)
Author:
lincoln
Message:

first pass at splitting update/install/check/enable/disable from main shepherd script

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • shepherd

    r180 r182  
    22 
    33# "Shepherd" 
    4  
    5 my $version = '0.2.30'; 
    6  
    74# A wrapper for various Aussie TV guide data grabbers 
    85# 
    96# Use --help for command-line options. 
    107# 
     8# Shepherd is an attempt to reconcile many different tv_grab_au scripts and 
     9# make one cohesive reliable data set. It works by calling a series of 
     10# scripts that grab data from a large variety of sources, and then 
     11# analysing the resulting XML data sets and determining which of the many 
     12# is the most reliable. 
     13 
     14# Shepherd runs in 4 passes: 
     15#  pass 1: (tv_grab_au)  Checks that all components are up-to-date, auto- 
     16#                        updates if not. 
     17#                        Passes control onto shepherd 
     18#  pass 2: (shepherd)    calls grabbers to fill in missing data 
     19#  pass 3: (shepherd)    calls reconciler to reconcile overlapping data 
     20#                        and normalize programme titles to our preferred title 
     21#  pass 4: (shepherd)    calls postprocessors to postprocess data 
     22#                        (e.g. flag HDTV programmes, augment with IMDb etc.) 
     23 
     24my $version = '0.2.31'; 
     25 
    1126# Changelog: 
    1227# 0.1.0   : Basic self-updating and grabber management 
     
    3954# 0.2.30  : Run transitional grabber(s) as a once-off to establish preferred 
    4055#           title translations. 
     56# 0.2.31  : split tv_grab_au (install/test/upgrade/enable/disable) from 
     57#           shepherd (grab/reconcile/postprocess) 
    4158 
    4259BEGIN { *CORE::GLOBAL::die = \&my_die; } 
     
    6481my $progname = 'shepherd'; 
    6582 
    66 my $HOME = 'http://www.whuffy.com/shepherd'; 
    67  
    68 my $invoked = Cwd::realpath($0); 
    6983my @options = @ARGV; 
    7084 
     
    7488-d $CWD or mkdir $CWD or die "Cannot create directory $CWD: $!"; 
    7589chdir($CWD); 
    76  
    77 my $ARCHIVE_DIR = "$CWD/archive"; 
    78  
    7990 
    8091#### analyzer settings #### 
     
    151162&get_initial_command_line_options; 
    152163 
    153 &capabilities if ($opt->{capabilities}); 
    154 &description if ($opt->{description}); 
    155  
    156164$| = 1;  
    157165print ucfirst($progname) . " v$version\n\n"; 
     
    163171 
    164172&get_remaining_command_line_options; 
    165  
    166 if ($opt->{status}) 
    167 { 
    168     &status; 
    169     exit; 
    170 } 
    171  
    172 if ($opt->{show_config}) 
    173 { 
    174     &show_config; 
    175     exit; 
    176 } 
    177  
    178173&open_logfile unless ($opt->{nolog}); 
    179174 
    180175&process_setup_commands; 
    181  
    182 # --------------------------------------------------------------------------- 
    183 # --- Update 
    184 # --------------------------------------------------------------------------- 
    185  
    186 unless ($opt->{noupdate}) 
    187 { 
    188     if (&update($progname, $version))  
    189     { 
    190         &write_config_file; 
    191     } 
    192 } 
    193  
    194 if ($opt->{configure}) 
    195 { 
    196     &configure; 
    197 } 
    198176 
    199177# --------------------------------------------------------------------------- 
     
    14531431 
    14541432# ----------------------------------------- 
    1455 # Subs: Updates & Installations 
    1456 # ----------------------------------------- 
    1457  
    1458 sub update 
    1459 { 
    1460     &log("\nChecking for updates:\n\n"); 
    1461  
    1462     my $data = fetch_shepherd_file("status"); 
    1463  
    1464     return 0 unless ($data); 
    1465  
    1466     my $made_changes = 0; 
    1467     my %clist = %$components; 
    1468  
    1469     # TEMPORARY CODE FOR TRANSITION TO NEW FORMAT: REMOVE THIS LATER 
    1470     if ($data =~ /:/) 
    1471     { 
    1472         while ($data =~ /(.*):(.*):(.*)/g) 
    1473         { 
    1474             my ($progtype, $proggy, $latestversion) = ($1,$2,$3); 
    1475             # TEMP HACK FOR TRANSITION: REMOVE LATER 
    1476             if ($latestversion eq 'shepherd') 
    1477             { 
    1478                 $latestversion = $proggy; 
    1479                 $proggy = 'shepherd'; 
    1480             } 
    1481             if (update_component($proggy, $latestversion, $progtype)) 
    1482             { 
    1483                 $made_changes = 1; 
    1484             } 
    1485             delete $clist{$proggy}; 
    1486         } 
    1487     } 
    1488     else 
    1489     { 
    1490     # END TEMPORARY CODE 
    1491         while ($data =~ /(\S+)\s+(\S+)\s+(\S+)/g) 
    1492         { 
    1493             my ($progtype, $proggy, $latestversion) = ($1,$2,$3); 
    1494             if (update_component($proggy, $latestversion, $progtype)) 
    1495             { 
    1496                 $made_changes = 1; 
    1497             } 
    1498             delete $clist{$proggy}; 
    1499         } 
    1500     } 
    1501  
    1502     # work out what components disappeared (if any) 
    1503     foreach (keys %clist) { 
    1504         unless ($components->{$_}->{disabled}) { 
    1505             &log("\nDeleted component: $_.\n"); 
    1506             disable($_, 2); 
    1507             $made_changes = 1; 
    1508         } 
    1509     } 
    1510     $made_changes; 
    1511 } 
    1512  
    1513 sub update_component 
    1514 { 
    1515     my ($proggy, $latestversion, $progtype) = @_; 
    1516  
    1517     my $ver = 0; 
    1518  
    1519     if ($progtype eq "shepherd") 
    1520     { 
    1521         $ver = $version if (-e "$CWD/$progname"); 
    1522     } else { 
    1523         $ver = $components->{$proggy}->{ver} if (defined $components->{$proggy} and -e ($progtype . "s/$proggy/$proggy")); 
    1524     } 
    1525  
    1526     my $result = versioncmp($ver, $latestversion); 
    1527     my $action =    $result == -1 ? ($ver ? "UPGRADING" : "NEW") : 
    1528                     $result ==  1 ? "DOWNGRADING" : 
    1529                     "up to date"; 
    1530     &log(sprintf    "* %-40s %30s\n", 
    1531                     ucfirst($progtype) . " $proggy" . 
    1532                         ($ver ? " v$ver" : '') . "...", 
    1533                     $action); 
    1534     return 0 unless ($result); 
    1535     install($proggy, $latestversion, $progtype); 
    1536     return 1; 
    1537 } 
    1538  
    1539 sub install 
    1540 { 
    1541     my ($proggy, $latestversion, $progtype) = @_; 
    1542     my $config; 
    1543  
    1544     &log("Downloading $proggy v$latestversion.\n"); 
    1545  
    1546     my $rdir = ""; 
    1547     my $ldir = $CWD; 
    1548     my $ver = "unknown"; 
    1549  
    1550     if ($progtype eq "shepherd") { 
    1551         $ver = $version; 
    1552     } else { 
    1553         $rdir = $progtype . "s"; 
    1554         $ldir = "$CWD/$progtype" . "s/$proggy"; 
    1555         $ver = $components->{$proggy}->{ver} if ((defined $components->{$proggy}) && $components->{$proggy}->{ver}); 
    1556         -d ("$CWD/$progtype" . "s") or mkdir ("$CWD/$progtype" . "s") or die "Cannot create directory $CWD/$progtype" . "s: $!"; 
    1557     } 
    1558     -d $ldir or mkdir $ldir or die "Cannot create directory $ldir: $!"; 
    1559  
    1560     my $newfile = "$ldir/$proggy-$latestversion"; 
    1561     my $rfile = "$rdir/$proggy"; 
    1562  
    1563     return unless (fetch_shepherd_file($rfile, $newfile)); 
    1564  
    1565     # Fetch grabber config file 
    1566     if ($progtype eq 'grabber') 
    1567     { 
    1568         $rfile .= ".conf"; 
    1569         $config = fetch_shepherd_file($rfile); 
    1570         return unless ($config); # grabbers MUST have config files 
    1571         eval $config; 
    1572     } 
    1573  
    1574     # Make component executable 
    1575     chmod 0755,$newfile; 
    1576  
    1577     -d $ARCHIVE_DIR or mkdir $ARCHIVE_DIR or die "Cannot create directory $ARCHIVE_DIR: $!"; 
    1578  
    1579     if (-e "$ldir/$proggy") 
    1580     { 
    1581         rename("$ldir/$proggy", "$ARCHIVE_DIR/$proggy-$ver"); 
    1582     } 
    1583     rename($newfile, "$ldir/$proggy"); 
    1584      
    1585     &log("Installed $proggy v$latestversion.\n") if ($debug); 
    1586  
    1587     # if the update was for shepherd itself, restart it 
    1588     if ($progtype eq "shepherd") { 
    1589         &log("\n*** Restarting ***\n\n"); 
    1590         &close_logfile unless $opt->{nolog}; 
    1591         exec("$ldir/$proggy @options"); 
    1592         # This exits. 
    1593     } 
    1594  
    1595     my $result = test_proggy($ldir,"$ldir/$proggy"); 
    1596  
    1597     $components->{$proggy}->{type} = $progtype; 
    1598     $components->{$proggy}->{ver} = $latestversion; 
    1599     $components->{$proggy}->{ready} = $result; 
    1600     $components->{$proggy}->{config} = $config if ($progtype eq 'grabber'); 
    1601  
    1602     # If this component was disabled automatically, re-enable it. 
    1603     # But if it was disabled manually, leave it off. 
    1604     my $d = $components->{$proggy}->{disabled}; 
    1605     if ($d and $d == 2) 
    1606     { 
    1607         enable($proggy); 
    1608     } 
    1609  
    1610     $components->{$proggy}->{laststatus} = sprintf "updated to %s on %s", $latestversion, (strftime "%a%d%b%y",localtime(time)); 
    1611  
    1612 } 
    1613  
    1614 sub fetch_shepherd_file 
    1615 { 
    1616     my ($fn, $store) = @_; 
    1617  
    1618     my $sites = ""; 
    1619     $sites = "$mirror_site," if ($mirror_site); 
    1620     $sites .= $HOME; 
    1621  
    1622     my $ret; 
    1623     foreach my $site (split(/,/,$sites))  
    1624     { 
    1625         $ret = fetch_file("$site/$fn", $store, 1); 
    1626         return $ret if ($ret); 
    1627     } 
    1628     return undef; 
    1629 } 
    1630  
    1631 sub test_proggy 
    1632 { 
    1633     my ($testdir,$proggyexec) = @_; 
    1634  
    1635     &log("Testing $proggyexec...\n"); 
    1636  
    1637     chdir($testdir); 
    1638     my $result = call_prog("$proggyexec --ready"); 
    1639     chdir ($CWD); 
    1640  
    1641     print "Return value: $result\n" if ($debug); 
    1642  
    1643     if ($result) 
    1644     { 
    1645         &log("\nComponent $proggyexec did not exit cleanly!\n" . 
    1646              "It may require configuration.\n\n"); 
    1647     } 
    1648     else 
    1649     { 
    1650         &log("OK.\n"); 
    1651     } 
    1652     return !$result; 
    1653 } 
    1654  
    1655 sub enable 
    1656 { 
    1657     my $proggy = shift; 
    1658  
    1659     # confirm it exists first 
    1660     if (!$components->{$proggy}) { 
    1661         printf "No such component: \"%s\".\n",$proggy; 
    1662         return; 
    1663     } 
    1664     print "Enabling $proggy.\n"; 
    1665  
    1666     delete $components->{$proggy}->{disabled}; 
    1667     $components->{$proggy}->{laststatus} = sprintf "enabled on %s, not run yet",(strftime "%a%d%b%y", localtime(time)); 
    1668 } 
    1669  
    1670 sub disable 
    1671 { 
    1672     my ($proggy, $n) = @_; 
    1673  
    1674     # confirm it exists first 
    1675     if (!$components->{$proggy}) { 
    1676         printf "No such component: \"%s\".\n",$proggy; 
    1677         return; 
    1678     } 
    1679     print "Disabling $proggy.\n"; 
    1680      
    1681     $n ||= 1; 
    1682     $components->{$proggy}->{disabled} = $n; 
    1683     $components->{$proggy}->{laststatus} = sprintf "manually disabled on %s",(strftime "%a%d%b%y", localtime(time)); 
    1684 } 
    1685  
    1686 sub check 
    1687 { 
    1688     my $result; 
    1689     foreach my $proggy (keys %$components) { 
    1690         my $progtype = $components->{$proggy}->{type}; 
    1691         $result = test_proggy("$CWD/$progtype" . "s/$proggy", "$CWD/$progtype" . "s/$proggy/$proggy"); 
    1692         if (!$result ne !$components->{$proggy}->{ready}) { 
    1693             $components->{$proggy}->{ready} = $result; 
    1694         } 
    1695     } 
    1696 } 
    1697 # ----------------------------------------- 
    16981433# Subs: Utilities 
    16991434# ----------------------------------------- 
     
    17531488} 
    17541489 
    1755 sub rotate_logfiles 
    1756 { 
    1757     # keep last 4 log files 
    1758     my $num; 
    1759     for ($num = 4; $num > 0; $num--) { 
    1760         my $f1 = sprintf "%s.%d.gz",$log_file,$num; 
    1761         my $f2 = sprintf "%s.%d.gz",$log_file,$num+1; 
    1762         unlink($f2); 
    1763         rename($f1,$f2); 
    1764     } 
    1765  
    1766     my $f2 = sprintf "%s.1",$log_file; 
    1767     rename($log_file,$f2); 
    1768 } 
    1769  
    1770 sub compress_file 
    1771 { 
    1772     my $infile = shift; 
    1773     my $outfile = sprintf "%s.gz",$infile; 
    1774     my $gz; 
    1775  
    1776     if (!(open(INFILE,"<$infile"))) { 
    1777         warn "could not open file $infile for reading: $!\n"; 
    1778         return; 
    1779     } 
    1780  
    1781     if (!($gz = gzopen($outfile,"wb"))) { 
    1782         warn "could not open file $outfile for writing: $!\n"; 
    1783         return; 
    1784     } 
    1785  
    1786     while (<INFILE>) { 
    1787         my $byteswritten = $gz->gzwrite($_); 
    1788         warn "error writing to compressed file: error $gz->gzerror" 
    1789           if ($byteswritten == 0); 
    1790     } 
    1791     close(INFILE); 
    1792     $gz->gzclose(); 
    1793     unlink($infile); 
    1794 } 
    1795  
    17961490sub open_logfile 
    17971491{ 
    1798     &rotate_logfiles; 
    17991492    printf "Logging to $log_file.\n"; 
    1800     open(LOG_FILE,">$log_file") || die "can't open log file $log_file for writing: $!\n"; 
     1493    open(LOG_FILE,">>$log_file") || die "can't open log file $log_file for writing: $!\n"; 
    18011494 
    18021495    my $now = localtime(time); 
     
    18071500{ 
    18081501    close(LOG_FILE); 
    1809     compress_file($log_file.".1"); 
    18101502} 
    18111503 
     
    18421534} 
    18431535 
    1844 sub fetch_file 
    1845 { 
    1846     my ($url, $store, $id_self) = @_; 
    1847  
    1848     &log("Fetching $url.\n"); 
    1849      
    1850     my $ua = LWP::UserAgent->new(); 
    1851     if ($id_self) 
    1852     { 
    1853         $ua->agent(ucfirst("$progname/$version")); 
    1854     } 
    1855     else 
    1856     { 
    1857         $ua->agent('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322') 
    1858     } 
    1859  
    1860     my $response = $ua->get($url); 
    1861     if ($response->is_success()) 
    1862     { 
    1863         if ($store) 
    1864         { 
    1865             open (FILE, ">$store")  
    1866                 or (&log("ERROR: Unable to open $store for writing.\n") and return undef); 
    1867             print FILE $response->content(); 
    1868             close FILE; 
    1869             return 1; 
    1870         } 
    1871         else  
    1872         { 
    1873             return $response->content(); 
    1874         }  
    1875     } 
    1876     &log("Failed to retrieve $url!\n" . $response->status_line() . "\n"); 
    1877     return undef; 
    1878 } 
    1879  
    18801536# ----------------------------------------- 
    18811537# Subs: Setup 
     
    19521608  GetOptions( 'config-file=s'   => \$opt->{configfile}, 
    19531609              'help'            => \$opt->{help}, 
    1954               'configure'       => \$opt->{configure}, 
    1955               'setmirror=s'     => \$opt->{setmirror}, 
    1956               'setpreftitle=s'  => \$opt->{setpreftitlesource}, 
    1957               'clearpreftitle'  => \$opt->{clearpreftitlesource}, 
    19581610              'dontcallgrabbers' => \$opt->{dontcallgrabbers}, 
    19591611               
     
    20111663} 
    20121664 
    2013 # if a preferred title source has been specified, add it to our config 
    2014 sub setpreftitlesource 
    2015 { 
    2016     my $arg = shift; 
    2017     $pref_title_source = $arg; 
    2018     print "Added preferred title source: $pref_title_source\n"; 
    2019     1; 
    2020 } 
    2021  
    2022 # if requesting to clear preferred title and we have one, remove it 
    2023 sub clearpreftitlesource 
    2024 { 
    2025     $pref_title_source = undef; 
    2026     print "Removed preferred title source $pref_title_source\n"; 
    2027     1; 
    2028 } 
    2029  
    2030 # if a mirror has been specified, add it into our config 
    2031 sub setmirror 
    2032 { 
    2033     my $arg = shift; 
    2034     $mirror_site = $arg; 
    2035     print "Setting mirror site(s): $mirror_site\n"; 
    2036 } 
    2037  
    2038 # ----------------------------------------- 
    2039 # Subs: Configuration 
    2040 # ----------------------------------------- 
    2041  
    2042 sub configure 
    2043 { 
    2044     my $REGIONS = { 
    2045         "ACT" => 126, 
    2046         "NSW: Sydney" => 73, 
    2047         "NSW: Newcastle" => 184, 
    2048         "NSW: Central Coast" => 66, 
    2049         "NSW: Griffith" => 67, 
    2050         "NSW: Broken Hill" => 63, 
    2051         "NSW: Northern NSW" => 69, 
    2052         "NSW: Southern NSW" => 71, 
    2053         "NSW: Remote and Central" => 106, 
    2054         "NT: Darwin" => 74, 
    2055         "NT: Remote & Central" => 108, 
    2056         "QLD: Brisbane" => 75, 
    2057         "QLD: Gold Coast" => 78, 
    2058         "QLD: Regional" => 79, 
    2059         "QLD: Remote & Central" => 114, 
    2060         "SA: Adelaide" => 81, 
    2061         "SA: Renmark" => 82, 
    2062         "SA: Riverland" => 83, 
    2063         "SA: South East SA" => 85, 
    2064         "SA: Spencer Gulf" => 86, 
    2065         "SA: Remote & Central" => 107, 
    2066         "Tasmania" => 88, 
    2067         "VIC: Melbourne" => 94, 
    2068         "VIC: Geelong" => 93, 
    2069         "VIC: Eastern Victoria" => 90, 
    2070         "VIC: Mildura/Sunraysia" => 95, 
    2071         "VIC: Western Victoria" => 98, 
    2072         "WA: Perth" => 101, 
    2073         "WA: Regional" => 102 
    2074     }; 
    2075  
    2076     print "\nConfiguring.\n\n" . 
    2077           "Select your region:\n"; 
    2078     foreach (sort keys %$REGIONS) 
    2079     { 
    2080         printf(" (%3d) %s\n", $REGIONS->{$_}, $_); 
    2081     } 
    2082     $region = ask_choice("Enter region code:", "94", values %$REGIONS); 
    2083  
    2084     print "\nFetching channel information... "; 
    2085  
    2086     my @channellist = get_channels(); 
    2087  
    2088     print "done.\n\n" . 
    2089           "For each channel you want guide data for, enter an XMLTV id\n" . 
    2090           "of your choice (e.g. \"seven.free.au\"). If you don't need\n" . 
    2091           "guide data for this channel, just press Enter.\n\n" . 
    2092           "Please don't subscribe to unneeded channels.\n\nChannels:\n"; 
    2093     $channels = {}; 
    2094     my $line; 
    2095     foreach (@channellist) 
    2096     { 
    2097         $line = ask(" \"$_\"? "); 
    2098         $channels->{$_} = $line if ($line); 
    2099     } 
    2100  
    2101     print "\nHigh Definition TV (HDTV)\n". 
    2102           "Most Australian TV networks broadcast at least some\n". 
    2103           "programmes in HDTV each week, but for the most part\n". 
    2104           "either upsample SD to HD or play a rolling demonstration\n". 
    2105           "HD clip when they don't have the programme in HD format.\n\n". 
    2106           "If you have a HDTV capable system and are interested in\n". 
    2107           "having Shepherd's postprocessors populate HDTV content\n". 
    2108           "then Shepherd will need to know the XMLTV IDs for the HD\n". 
    2109           "channels also.\n"; 
    2110     if (ask_boolean("\nDo you wish to include HDTV channels?")) { 
    2111         print "\nFor each channel you want guide data for, enter an XMLTV id\n" . 
    2112               "of your choice (e.g. \"sevenhd.free.au\"). If you don't need\n" . 
    2113               "guide data for this channel, just press Enter.\n\n"; 
    2114  
    2115         $opt_channels = {}; 
    2116         foreach (@channellist) 
    2117         { 
    2118             next if (($_ =~ /ABC2/i) || ($_ =~ /SBS News/i) || ($_ =~ /31/)); 
    2119             $_ .= "HD"; 
    2120             $line = ask(" \"$_\"? "); 
    2121             $opt_channels->{$_} = $line if ($line); 
    2122         } 
    2123     } 
    2124  
    2125  
    2126     print "\nWould you like to transition seamlessly from your current grabber?\n\n". 
    2127           "Different data sources can have different names for the same show. For\n". 
    2128           "example, one grabber might call a show \"Spicks & Specks\" while another\n". 
    2129           "calls it \"Spicks and Specks\". These differences can make MythTV think\n". 
    2130           "they're actually different shows.\n\n". 
    2131           ucfirst($progname) . " is able to merge these differences so that it always\n". 
    2132           "presents shows with a consistent name, no matter where it actually sourced\n". 
    2133           "show data from. If you'd like, it can also rename shows so they're consistent\n". 
    2134           "with whichever grabber you've been using until now.\n\n". 
    2135           "The advantage of this is that you should get a smoother transition to\n". 
    2136           ucfirst($progname) . ", with no shows changing names and no need to re-create\n". 
    2137           "any recording rules. The main disadvantage is that if your previous grabber\n". 
    2138           "used an inferior data source -- i.e. it sometimes has typos or less\n". 
    2139           "informative program names -- then you'll continue to see these.\n\n". 
    2140           "If you were using one of the following grabbers previously AND you want\n". 
    2141           ucfirst($progname) . " to use that grabber's program names, select it here.\n\n"; 
    2142  
    2143     my $def = "Do not transition; just use best quality titles"; 
    2144     my %transition = (  "ltd (aka tv_grab_au, versions 1,30, 1.40 or 1.41)" => "yahoo7widget,abc2_website", 
    2145                         "OzTivo" => 'oztivo', 
    2146                         "JRobbo" => 'jrobbo' ); 
    2147     my $pref = ask_choice("Transition from grabber?", $def, 
    2148                 $def, keys %transition); 
    2149     $pref_title_source = $transition{$pref}; 
    2150      
    2151     print "\n"; 
    2152     show_channels(); 
    2153     unless(ask_boolean("\nCreate configuration file?")) 
    2154     { 
    2155         print "Aborting configuration.\n"; 
    2156         exit 0; 
    2157     } 
    2158  
    2159     write_config_file(); 
    2160     write_channels_file(); 
    2161  
    2162     print "Finished configuring.\n\n" . 
    2163           "Shepherd is installed into $CWD.\n\n"; 
    2164      
    2165     if ($invoked ne "$CWD/$progname" and $invoked =~ /$progname/) 
    2166     { 
    2167         print "Warning: you invoked this program as $invoked.\n" . 
    2168             "In the future, it should be run as $CWD/$progname,\n" . 
    2169             "to avoid constantly re-downloading the latest version.\n\n" . 
    2170             "MythTV users may wish to create the following symlink, by " . 
    2171             "doing this (as root):\n" . 
    2172             "\"ln -s $CWD/$progname /usr/bin/tv_grab_au\".\n\n" . 
    2173             "You may safely delete $invoked.\n\n"; 
    2174     } 
    2175  
    2176     status(); 
    2177  
    2178     unless (ask_boolean("\nGrab data now?")) 
    2179     { 
    2180         exit 0; 
    2181     } 
    2182 } 
    2183  
    2184 sub get_channels 
    2185 { 
    2186     my @date = localtime; 
    2187     my $page = fetch_file( 
    2188         "http://au.tv.yahoo.com/results.html?rg=$region&dt=" . 
    2189         ($date[5] + 1900) . "-$date[4]-$date[3]"); 
    2190     my @channellist; 
    2191     while ($page =~ /<tr class=rtb><td class=rth><a .*?>(.*?)<\/a>/g) 
    2192     { 
    2193         push @channellist, $1; 
    2194     } 
    2195     return @channellist; 
    2196 } 
    2197  
    21981665# ----------------------------------------- 
    21991666# Subs: Status & Help 
    22001667# ----------------------------------------- 
    2201  
    2202 sub show_config 
    2203 { 
    2204     print "\nConfiguration\n". 
    2205           "-------------\n" . 
    2206           "Config file: $config_file\n" . 
    2207           "Debug mode : " . is_set($debug) . "\n" . 
    2208           "Output file: " . ($opt->{output} ? $opt->{output} : "None") . "\n" . 
    2209           "Region ID  : $region\n"; 
    2210   show_channels(); 
    2211   print "\n"; 
    2212   status(); 
    2213   print "\n"; 
    2214 } 
    2215  
    2216 sub show_channels 
    2217 { 
    2218   print "Subscribed channels:\n"; 
    2219   print "    $_ -> $channels->{$_}\n" for sort keys %$channels; 
    2220   print "Optional (HDTV) channels:\n"; 
    2221   print "    $_ -> $opt_channels->{$_}\n" for sort keys %$opt_channels; 
    2222 } 
    2223  
    2224 sub is_set 
    2225 { 
    2226     my $arg = shift; 
    2227     return $arg ? "Yes" : "No"; 
    2228 } 
    2229  
    2230 sub pretty_print 
    2231 { 
    2232     my ($p, $len) = @_; 
    2233     my $spaces = ' ' x (79-$len); 
    2234     my $ret = ""; 
    2235  
    2236     while (length($p) > 0) { 
    2237         if (length($p) <= $len) { 
    2238             $ret .= $p; 
    2239             $p = ""; 
    2240         } else { 
    2241             # find a space to the left of cutoff 
    2242             my $len2 = $len; 
    2243             while ((substr($p,$len2,1) ne ' ') && ($len2 > 0)) { 
    2244                 $len2--; 
    2245             } 
    2246             if ($len2 == 0) { 
    2247                 # no space - just print it with cutoff 
    2248                 $ret .= substr($p,0,$len); 
    2249                 $p = substr($p,$len,(length($p)-$len)); 
    2250             } else { 
    2251                 # print up to space 
    2252                 $ret .= substr($p,0,$len2); 
    2253                 $p = substr($p,($len2+1),(length($p)-$len2+1)); 
    2254             } 
    2255             # print whitespace 
    2256             $ret .= "\n".$spaces; 
    2257         } 
    2258     } 
    2259     return $ret; 
    2260 } 
    2261  
    2262 sub status 
    2263 { 
    2264     print "\nThe following plugins are known:\n", 
    2265           " Type     Name           Version Description\n". 
    2266           " -------- -------------- ------- ----------------------------------------------\n"; 
    2267  
    2268     foreach (sort { $components->{$a}->{type} cmp $components->{$b}->{type} } keys %{$components}) { 
    2269         printf " %-8s %-15s%7s %46s\n", 
    2270           substr($components->{$_}->{type},0,8),  
    2271           length($_) > 15 ? substr($_,0,13).".." : $_, 
    2272           ($components->{$_}->{ver} ? substr($components->{$_}->{ver},0,7) : "unknown"), 
    2273           (defined $components->{$_}->{config}->{desc} ? 
    2274             pretty_print($components->{$_}->{config}->{desc},46) : ""); 
    2275     } 
    2276     printf "\n"; 
    2277  
    2278     print "Grabbers, listed in order of quality:\n". 
    2279           "                   Enabled/\n". 
    2280           " Grabber        Qual Ready Last Run   Status\n" . 
    2281           " -------------- ---- ----- ---------- -----------------------------------------\n"; 
    2282     my %qual_table = ( 3 => "Best", 2 => "Good", 1 => "Avg" ); 
    2283     foreach (sort { $components->{$b}->{config}->{quality} <=> $components->{$a}->{config}->{quality} } query_grabbers()) { 
    2284         my $h = $components->{$_}; 
    2285         printf  " %-15s%-4s  %1s/%1s %11s %s\n", 
    2286           length($_) > 15 ? substr($_,0,13).".." : $_, 
    2287           $qual_table{($h->{config}->{quality})}, 
    2288           $h->{disabled} ? 'N' : 'Y', 
    2289           $h->{ready} ? 'Y' : 'N', 
    2290           $h->{lastdata} ? (strftime "%a%d%b%y", localtime($h->{lastdata})) : 'never', 
    2291           $h->{laststatus} ? pretty_print($h->{laststatus},41) : ''; 
    2292     } 
    2293  
    2294     print "\n". 
    2295           "              Enabled/\n". 
    2296           " Reconciler     Ready Last Run   Status\n" . 
    2297           " -------------- ----- ---------- ----------------------------------------------\n"; 
    2298     foreach (sort { $components->{$a} <=> $components->{$b} } query_reconcilers()) { 
    2299         my $h = $components->{$_}; 
    2300         printf  " %-15s %1s/%1s %11s %s\n", 
    2301           length($_) > 15 ? substr($_,0,13).".." : $_, 
    2302           $h->{disabled} ? 'N' : 'Y', 
    2303           $h->{ready} ? 'Y' : 'N', 
    2304           $h->{lastdata} ? (strftime "%a%d%b%y", localtime($h->{lastdata})) : 'never', 
    2305           $h->{laststatus} ? pretty_print($h->{laststatus},46) : ''; 
    2306     } 
    2307  
    2308     print "\n". 
    2309           "              Enabled/\n". 
    2310           " Postprocessor  Ready Last Run   Status\n" . 
    2311           " -------------- ----- ---------- ----------------------------------------------\n"; 
    2312     foreach (sort { $components->{$a} <=> $components->{$b} } query_postprocessors()) { 
    2313         my $h = $components->{$_}; 
    2314         printf  " %-15s %1s/%1s %11s %s\n", 
    2315           length($_) > 15 ? substr($_,0,13).".." : $_, 
    2316           $h->{disabled} ? 'N' : 'Y', 
    2317           $h->{ready} ? 'Y' : 'N', 
    2318           $h->{lastdata} ? (strftime "%a%d%b%y", localtime($h->{lastdata})) : 'never', 
    2319           $h->{laststatus} ? pretty_print($h->{laststatus},46) : ''; 
    2320     } 
    2321     printf "\nPreferred titles from grabber '%s'\n",$pref_title_source if ($pref_title_source); 
    2322     printf "\n"; 
    2323 } 
    23241668 
    23251669sub capabilities 
     
    23401684Command-line options: 
    23411685    --help                Print this message 
    2342  
    2343     --status              Print a list of grabbers maintained 
    2344     --list                Print a detailed list of grabbers 
    2345     --setmirror <s>       Set URL <s> as primary location to check for updates 
    2346  
    2347     --configure           Setup 
    2348     --show-config         Print setup details 
    2349  
    2350     --setpreftitle <s>    Set preferred 'title' source as grabber <s> 
    2351     --clearpreftitle      clear preferred 'title' source 
    2352  
    2353     --disable <s>         Don't ever use grabber/postprocessor <s> 
    2354     --enable <s>          Okay, maybe use it again then 
    2355     --uninstall <s>       Remove a disabled grabber/postprocessor 
    2356  
    2357     --noupdate            Do not attempt to update before running 
    2358     --update              Update only; do not grab data 
    2359  
    2360     --check               Check status of all grabbers and postprocessors 
    23611686 
    23621687    --capabilities        Report capabilities to XMLTV