#! /usr/local/bin/perl # MANGAOH CLUB Csv file to iCal file (.ics) # $Id: comic2ics.pl,v 1.3 2004/08/03 12:46:22 fuseda Exp $ use Jcode; use strict; use Time::Local; my $input_file = 'comic200408.csv'; my $output_file = 'comic.ics'; my @values = (); my $sequence = 20000; my %TenDays = ( '上' => 1, '中' => 15, '下' => 28, '未' => 28); my $rev = '$Revision: 1.3 $'; $rev =~ s/.*(\d+\.\d+).*/$1/; $input_file =~ /(\d\d\d\d)(\d\d)\.csv/; my ($fileyear,$filemonth) = ($1,$2); parse_options(); open ICS,">$output_file" or die "Couldn't create $output_file\n"; print ICS put_ics_head(); open CSV,"$input_file" or die "Cannot open $input_file\n"; while ( ) { my $cnt = 0; my @fields = qw(company date title writer price genre); csvparse(jcode($_)->euc); my %comic = map { $fields[$cnt++], $_ } @values; if ( $comic{'genre'} !~ "成年" and $comic{'genre'} !~ "耽美" ) { print ICS put_vevent( \%comic ); } } print ICS put_ics_tail(); close ICS; # 連想配列を頂いてエントリーに変換する sub put_vevent() { my $item = shift; my $outstring = ""; my $crlf = "\n"; $outstring .= "BEGIN:VEVENT$crlf"; $outstring .= "SEQUENCE:$sequence$crlf"; $sequence++; $outstring .= "DTSTAMP:" . get_timestamp($item->{date}) . "$crlf"; $outstring .= "PRIORITY:3$crlf"; $outstring .= "SUMMARY:" . $item->{title} . "$crlf"; $outstring .= "DTSTART:" . get_timestamp($item->{date}) . "$crlf"; $outstring .= "DTEND:" . get_tdend($item->{date}) . "$crlf"; $outstring .= "DESCRIPTION;QUOTED-PRINTABLE:"; $outstring .= ' ' . $item->{company} . "=0D=0A"; $outstring .= ' ' . $item->{date} . "=0D=0A"; $outstring .= ' ' . $item->{writer} . "=0D=0A"; $outstring .= ' ' . $item->{price} . "円=0D=0A"; $outstring .= " $crlf"; $outstring .= "END:VEVENT$crlf"; return jcode($outstring)->sjis; } # 2004/1/1 とかを、20040101T000000 にする sub get_timestamp() { my $string = shift; my ($year,$month,$date) = parse_date($string); my $out = sprintf "%04d%02d%02dT000000", $year, $month, $date; $out; } # 2004/1/1 とかを次の日の、20040101T000000 にする sub get_tdend() { my $string = shift; my ($year,$month,$date) = parse_date($string); # 60(sec)*60(min)*24(hour)=1日後(86400) my $time = timelocal( 0, 0, 0, $date, $month - 1, $year) + 86400; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($time); my $out = sprintf "%04d%02d%02dT000000", $year+1900, $mon+1, $mday; $out; } # 2004/1/1 とかを上中下対応して、数値配列にしてかえす sub parse_date() { my $string = shift; $string =~ m|([^/]+)/([^/]+)/([^/]+)|; my ($year,$month,$date) = ($1,$2,$3); if ( $date !~ /^\d/ ) { # 上中下対応 $TenDays{'下'} = getlastday( $year,$month); $TenDays{'未'} = getlastday( $year,$month); $date = $TenDays{$date}; } ($year,$month,$date); } # csv 形式から値を取り出して @valuesに入れる sub csvparse { my $tmp = shift; $tmp =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/; @values = map {/^\"(.*)\"$/ ? scalar($_ = $1, s/\"\"/\"/g, $_) : $_} ($tmp =~ /(\"[^\"]*(?:\"\"[^\"]*)*\"|[^,]*),/g); } # ics のヘッダーを返す # for iPod。UTF8でないと表示できないようだ。 sub put_ics_head { my $header = <<"__ICS_HEAD__"; BEGIN:VCALENDAR PRODID:-//qux//comic2ics.pl $rev//EN X-WR-CALNAME;VALUE=TEXT:Comics($fileyear/$filemonth) X-WR-TIMEZONE;VALUE=TEXT:Japan VERSION:1.0 METHOD:PUBLISH X-WR-AUTOGEN:Comic __ICS_HEAD__ return jcode($header)->utf8; } # ics のしっぽを返す sub put_ics_tail { return jcode("END:VCALENDAR\n")->utf8; } #### 指定年月の最終日を求める sub getlastday { # $year年 $mon月の末日 $lastday を求める my ($year,$mon) = @_; (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[$mon - 1] + ($mon == 2 and $year % 4 == 0 and ($year % 400 == 0 or $year % 100 != 0)); } #### コマンドライン引数をひらう sub parse_options () { while ( my $arg = shift (@ARGV) ) { if ( $arg =~ /^-o$|^--output$/o ) { $output_file = shift(@ARGV) || die "$arg needs argument.\n"; } else { $input_file = "$arg"; } } }