use Encode;
# common functions for all recent_list_*.wml
sub get_recent_list {
my ($time, $number, $rel_path, $english_dir, $files_match, $data_callback, $format_list_callback, $format_item_callback) =@_;
#warn "get_recent_list($time, $number, $rel_path, $english_dir, $files_match, $data_callback, $format_list_callback, $format_item_callback)\n";
my $since_date = determine_since_date($time);
#warn "since_date=$since_date\n";
my $files = get_matching_filenames_by_time($rel_path, $english_dir, $files_match, $since_date);
my $data = get_files_data($files, $english_dir, $data_callback);
my $filtered_data = filter_items($data, $since_date, $number);
my $str = $format_list_callback->($filtered_data, $format_item_callback);
return $str;
}
sub slurp_file_openrecode {
my ($file, $eng_dir) = @_;
(my $trans_title = $file) =~ s/\.wml$/\.title/;
# read file in
my $fh = openrecode($file, $trans_title, "$eng_dir/$file")
or die "couldn't open $eng_dir/$file: $!\n";
my $content;
{
local $/;
$content = <$fh>;
}
close $fh;
return $content;
}
sub slurp_file {
my ($file) = @_;
open my $fh, '<', $file
or die "couldn't open $file: $!\n";
my $content;
{
local $/;
$content = <$fh>;
}
close $fh;
return $content;
}
sub match_tag {
my ($content, $tag) = @_;
my $value;
$content = Encode::decode_utf8($content);
if ($content =~ m|^\s*(.*?)\s*|ms) {
$value = Encode::encode_utf8(qq/$1/); } # all
return $value;
}
sub match_tag_first_p {
my ($content, $tag) = @_;
my $value;
if ($content =~ m"^\s*(?:(.*?)|(.*?))"ms) {
$value = qq/$1/; } # all
return $value;
}
sub determine_since_date {
my ($time) = @_;
return parse_time($time) if $time;
return '';
}
sub determine_relevant_years {
my ($since_date) = @_;
my $year = $(CUR_YEAR);
$since_year = $year;
if ($since_date){
$since_year = (gmtime($since_date))[5] + 1900;
if ($since_year > $year) {
warn "since_year > year ($since_year > $year)\n";
}
}
# djpig: take $since_year-1, perhaps better define an $oldest_year?
# djpig: but there should be no more updates to an item after a year
# djpig: we're saving time so.
return [($since_year-1) .. $year];
}
sub get_matching_filenames_by_time {
my ($rel_path, $english_dir, $match, $since_date) =@_;
my @files;
my $years = determine_relevant_years($since_date);
for my $act_year (@$years) {
my $act_path = $rel_path eq '.' ? $act_year : "$rel_path/$act_year";
my $new_files = get_matching_filenames($act_path, "$english_dir/$act_year", $match);
push @files, @$new_files;
}
return \@files;
}
sub get_matching_filenames {
my ($rel_path, $eng_dir, $match) = @_;
#warn "get_match_filesnames( $rel_path, $eng_dir, $match )\n";
opendir my $dir_h, $eng_dir
or die "couldn't open dir $eng_dir: $!\n";
my @files = grep { ($_ =~ $match)
&& -f "$eng_dir/$_"
&& ($_="$rel_path/$_")
} readdir($dir_h);
closedir $dir_h;
return \@files;
}
sub get_files_data {
my ($files, $eng_dir, $callback) = @_;
my %data;
foreach my $file (@$files) {
$callback->($file, $eng_dir, \%data);
}
return \%data;
}
sub filter_items {
my ($data, $since_date, $minnumber) = @_;
my @dates = sort { $b <=> $a } keys %$data;
#warn "since_date: ".scalar gmtime($since_date)." minnum: $minnumber\n";
my $count = 0;
my %filtered_data;
foreach my $date (@dates) {
#warn "date: ".scalar gmtime($date)." ($count >= $minnumber) && ($date < $since_date)\n";
if ($count >= $minnumber) {
if((!$since_date && $minnumber)
|| (($since_date || !$minnum)
&& ($date lt $since_date)) ) {
last;
}
}
$filtered_data{$date} = $data->{$date};
$count += scalar @{$data->{$date}};
}
return \%filtered_data;
}
# parse_time gets as argument a string and returns a unix timestamp
# Input: $time_str - String with the following format
# $time_str ::= (d|w|m|y)
# Output: integer timestamp
#
# parse_time subtracts days/weeks/months from the actual time and
# returns the corresponding timestamp. Years are handled special: 1y means
# "since January, 1st of actual year", 2y means "since January, 1st of
# last year", etc.
sub parse_time {
my $time_str = shift;
my $year = (gmtime())[5] + 1900;
my $time = time();
my $res;
for ($time_str) {
/\d{4}/ && do {
$res = timegm(0,0,0,1,0,$year);
last;
};
/(\d+)d/ && do {
$res = $time - 86400 * $1;
last;
};
/(\d+)w/ && do {
$res = $time - 86400 * 7 * $1;
last;
};
/(\d+)m/ && do {
# All months have 30 days,
# all other would be far more complicated
$res = $time - 86400 * 30 * $1;
last;
};
/(\d+)y/ && do {
# years are handled special
my $ryear = $year - $1 + 1; # the actual year count as a whole one
$res = timegm(0,0,0,1,0,$ryear); # 01.01.$ryear 00:00:00
last;
};
}
return $res;
}
# iso2stamp converts a date in ISO format (YYYY-MM-DD) to an
# unix timestamp for 23:59:59 on the specified day
# Input: $time - String with the ISO date
# Output: integer timestamp
sub iso2stamp {
my $time = shift;
if ($time =~ /undated/) {
return 0;
}
my ($year, $month, $day) = ($time =~ /(\d{4})-(\d{1,2})-(\d{1,2})/);
unless ($year && $month && $day) { warn "not an ISO date: $time\n"; }
return timegm( 59, 59, 23, $day, $month-1, $year);
}