Search ebooks with File::Find

使用HTML::Pager可以写一个列出电子书的cgi小程序,在此基础上,可以很容易地增加文件名搜索功能。

首先增加搜索框和按钮,只需修改最后的打印语句:

my $title = "Book List ($num_of_books)";

print $cgi->header,
    $cgi->start_html($title),
    $cgi->h3($title),
    $pager->output,
    $cgi->h3('Book Search'),
    $cgi->start_form,
    $cgi->textfield('search'),
    $cgi->submit,
    $cgi->end_form,
    $cgi->end_html;

接下来要构造搜索匹配字符串表,当输出框内为空时,搜索结果与以前一样,否则搜索结果应该包括所有用户提供的单词,为了简单起见,我们认为单词由空格分隔,暂不考虑引号。

my $cgi = CGI->new;

my @search_pattern = (qr/.(?:chm|pdf)$/i);
if ($cgi->param('search')) {
    push @search_pattern,
      map { qr/Q$_E/i }
        split('s+', $cgi->param('search'));
}

my @books;
sub search_book {
    for my $pattern (@search_pattern) {
      return unless $_ =~ /$pattern/;
    }
    push @books, $_;
}

find( { wanted => &search_book, no_chdir => 1 }, '.');

程序截图如下:

List ebooks with HTML::Pager

自从皈依了FOSS,盗版软件是不用了,电子书还是照下不误。曾经想过用apache和scuttle来管理,然而使用起来仍然很麻烦,所以找书的时候还是到各个目录里面去翻。

feedman的时候学会了HTML::Pager,于是写了一个简单的CGI脚本,放到电子书的根目录下。缺省情况下,apache打开一个目录的样子很难看,而且长一点的文件名都被截断了,偏偏电子书的文件名都很长。这个CGI程序的作用就是输出一个文件列表,提供完成的文件名和链接。程序出奇的简单,首先用File::Find找出想要列出的文件,如所有的chm和pdf文件。

#!/usr/bin/perl -T

use File::Find;
use HTML::Pager;
use CGI;
use URI::Escape;
use File::Basename;

my @books;
find({ wanted => sub{ push @books $_ if /.(?:chm|pdf)$/ },
       no_chdir => 1 },
     '.');

my $num_of_books = scalar @books;

这样,所有的文件名就保存在数组@books里面,文件总数保存在变量$num_of_books里面。接下来我们要写一个函数,从@books中抽取出部分文件,供HTML::Pager输出到页面上。

sub list_book_callback {
  my ($offset, $rows) = @_;
  my $current_books;

  for my $b ($offset .. $offset + $rows - 1) {
    last if $b == $num_of_books;
    my $filename = $books[$b];
    $filename =~ s{^./}{};
    my $url = 'http://localhost/book/'
              . uri_escape($filename);
    my $title = basename($filename);
    if ($title =~ /^(?:ch(?:apter)?)?d+.(?:chm|pdf)$/i) {
         $title = $filename;
    }
    push @current_books, [ qq(<a href="$url">$title</a>) ];
  }
  return @current_books;
}

这段函数对文件名做了一些特殊的处理,一般来讲,文件名即书名,我们可以去掉路径部分。而有些特殊的文件名字可能为ch01.pdf或ch02.pdf等等,上一层目录名才是书名,这时就将路径和文件名一起输出。最后就是用HTML::Pager生成列表并用CGI输出。

my $cgi = CGI->new;

my $pager = HTML::Pager->new
    (query => $cgi,
     get_data_callback => &list_book_callback,
     rows => $num_of_books,
     page_size => 25,
    );

print $cgi->header,
   $cgi->start_html,
   $pager->output,
   $cgi->end_html;

程序运行结果如截图: