#!usr/bin/perl # Last updated: <2005/11/06 14:47:22 +0900> # # oekaki bbs の過去ログを変更・更新するPerlスクリプト。 # WindowsXP Home SP2 + Active Perl v5.8.6 build 811 で動作確認。 # # usage: perl makekakolog.pl # # 使用上の注意: # # ネット上のhtml、画像ファイル等は別のスクリプトでDLしておく。 # それらが保存されたフォルダを対象に、検索をして、 # コピーすべき画像ファイルや、書き換えるべき部分を求める。 # # 一応、5桁以上にも対応…したつもり。 # 4桁を超えると8桁でディレクトリ名・ファイル名等を作成、 # …したつもりではあるけど見落としがあるかも。 # # by mieki256 # 0.00 2005/11/02 とりあえず作成開始 # 0.01 2005/11/06 ひとまず動いた。かな。 use strict; use File::Copy; use Digest::MD5; use File::Path; use POSIX 'strftime'; # ---------------------------------------- # 使う人が設定する項目 # バックアップディレクトリ名 (最後の区切り文字は要らない) my $bkup_dir = "./backup"; # 過去ログディレクトリ名 (最後の区切り文字は要らない) my $kakolog_dir = "./kakolog"; # ディレクトリ名の区切り文字は '/' を使っても大丈夫。 # Windows 用 Perl = ActivePerl でも、 # ディレクトリの区切り文字として判別してくれるみたいだから。 # # ディレクトリ名の区切り文字として '\' を使いたい場合、 # 文字列中の '\' を '\\' と書く。らしい。たぶん。 # # バックアップディレクトリ名、過去ログディレクトリ名、共に、 # '20051029_100000' や '7001_7100' まで記述する必要はなし。 # それらのディレクトリ名は、スクリプトが検索して、処理対象にしてくれる。 # # フォルダ構成の例 # # oekakibbs_bkup/ # │ # ├ backup/ <-- バックアップを保存しておくディレクトリ # │ ├ 20051019_211931/ <-- 数字のみでディレクトリ名を構成 # │ ├ 20051019_213000/ # │ └ ... # │ # ├ kakolog/ <-- 過去ログを保存しておくディレクトリ # │ ├ 6801_6900/ # │ ├ 6901_7000/ # │ └ 7001_7100/ # │ ├ index.html # │ ├ oekaki_7001.html # │ ├ oekaki_7021.html # │ ├ oekaki_7041.html # │ ├ oekaki_7061.html # │ ├ oekaki_7081.html # │ ├ oekaki_0000.png # │ ├ oekaki_7001.png # │ └ ... # │ # └ makekakolog.pl <-- 過去ログ生成スクリプト # # ex. # カレントディレクトリ oekakibbs_bkup/ で、makekakolog.pl を実行すると、 # backup/ の中にバックアップされた html、画像ファイルを使って、 # kakolog/ の中に画像をコピー・html内容を更新する。 # 画像コピー先のディレクトリが過去ログディレクトリに無かったら自動で作る # 1: 作る / 0: 作らない my $makedirfg = 1; # 過去ログhtmlのバックアップを作成 # 1:作成 / 0:作成せずに上書き # バックアップファイル名は、 hoge.html.bak_yyyymmdd_HHMMSS my $kakologhtml_bkup_usage = 1; # ---------------------------------------- # 場合によっては使う人が設定すると便利かもしれない項目 # debug 表示 # 更新すべきコメント情報を表示 my $updatecomment_infodisp = 0; # 更新すべきコメント情報を表示(Noと文字数のみ) my $updatecomment_infodisp_number_only = 0; # 検索して見つかったファイル名を極力表示 my $search_filelist_output = 0; # チェック対象にしなくてよいと思われる画像ファイル名を表示 my $nochk_imglist_output = 0; # どの画像Noがどのディレクトリにコピーされるか表示 my $copy_dst_dir_output = 0; # コピー先ディレクトリが見つからなかった場合に表示 my $notfounddir_dispfg = 1; # 同じファイルサイズの画像ファイル名を表示 my $samefile_output = 0; # バックアップhtml内のコメントの検索過程(++/--/==)を表示 my $bkuphtmlcommnet_addinfo = 0; # バックアップhtml内のコメントの検索結果を表示 my $bkuphtmlcommnet_output = 0; # バックアップhtml内のコメント行を '.' で表示 my $bkuphtmlcommnet_read_disp = 0; # 過去ログhtml内のコメントの検索過程(++/--/==)を表示 my $kakologcomment_addinfo = 0; # 過去ログhtml内のコメントの検索結果を表示 my $kakologcomment_output = 0; # 過去ログhtml内のコメントで、量が 0 だったものを表示 my $kakologcomment_nocomment_disp = 0; # バックアップ & 過去ログ html内において、同じと思われるコメントNo+コメントを表示 my $samecomment_disp = 0; # バックアップ & 過去ログ html内において、同じと思われるコメントNoのみ表示 my $samecomment_disp_number_only = 0; # 更新した過去ログhtml内において、更新しなかったコメントNoを表示 my $nonupdatecomment_disp = 1; # ---------------------------------------- # 使う人が設定しなくてもいい項目 # 「Coming Seen」「Now printing」画像のサイズ、MD5 my %nochkimglist_size = ( "Coming Seen", 14515, "Now Printing", 1595 ); my %nochkimglist_md5 = ( "Coming Seen", "4279a4d86621bd343811d5b658117760", "Now Printing", "0d5c7228eec235dfefb7a0595b37fc2e" ); # etc # バックアップhtml list を記録 # 過去ログhtml list を記録 # ---------------------------------------- # まずはディレクトリ・ファイルを検索 # バックアップディレクトリ名検索・取得 (ディレクトリ名 : 数字と'_' のみで構成) my $d = $bkup_dir; my @bkup_dirlist = (); my @t = (); opendir(DH, $d) || die "$d : $!"; while ( my $file = readdir(DH) ) { next if $file =~ /^\.{1,2}$/; next unless $file =~ /^[0-9_]+$/; push(@t, "$d/$file"); } closedir(DH); @bkup_dirlist = sort(@t); # 過去ログディレクトリ名検索・取得 (ディレクトリ名 : xxxx_xxxx) $d = $kakolog_dir; my @kakolog_dirlist = (); @t = (); opendir(DH, $d) || die "$d : $!"; while ( my $file = readdir(DH) ) { next if $file =~ /^\.{1,2}$/; next unless $file =~ /^\d{4,8}_\d{4,8}$/; push(@t, "$d/$file"); } closedir(DH); @kakolog_dirlist = sort(@t); if ( $search_filelist_output ) { outputList("backup dir", "", @bkup_dirlist); outputList("kakolog dir", "", @kakolog_dirlist); } # バックアップディレクトリ内のファイル一覧を取得 my @found_imglist = (); my @t_found_imglist = (); my @same_imglist = (); my @t_same_imglist = (); my @bkup_htmllist = (); my @t_bkup_htmllist = (); my %imgsize = (); my %imgpath = (); foreach my $d (@bkup_dirlist) { opendir(DH, $d) || die "$d : $!"; while ( my $file = readdir(DH) ) { next if $file =~ /^\.{1,2}$/; if ( $file =~ /\.html$/ ) { # html 発見・記録 push(@t_bkup_htmllist,"$d/$file"); next; } if ( $file =~ /\.(gif|png|jpg)$/ ) { # image 発見・記録 my $size = -s "$d/$file"; # size 取得 if ( exists $imgsize{$file} ) { # 既に別フォルダで見つかってる if ( $imgsize{$file} < $size ) { # 既に見つかったファイルより、 # ファイルサイズが大きいので記録しておく print "break? : $imgpath{$file}\n"; $imgsize{$file} = $size; $imgpath{$file} = "$d/$file"; } elsif ( $imgsize{$file} == $size ) { push( @t_same_imglist, "$d/$file" ); } else { print "break? : $d/$file\n"; } } else { # 初めて見つかった $imgsize{$file} = $size; $imgpath{$file} = "$d/$file"; push( @t_found_imglist, $imgpath{$file}); } } } closedir(DH); } @found_imglist = sort(@t_found_imglist); @same_imglist = sort(@t_same_imglist); @bkup_htmllist = sort(@t_bkup_htmllist); # 過去ログディレクトリ内の html ファイル一覧を取得 my @kakolog_htmllist = (); @t = (); foreach my $d (@kakolog_dirlist) { opendir(DH, $d) || die "$d : $!"; while ( my $file = readdir(DH) ) { next if $file =~ /^\.{1,2}$/; push(@t, "$d/$file") if $file =~ /[a-z]+_[0-9]{4,8}.html$/; } closedir(DH); } @kakolog_htmllist = sort(@t); if ( $search_filelist_output ) { outputList("search backup dir", "found image : ", @found_imglist); if ( $samefile_output ) { outputList("same image file", "same image : ", @same_imglist); } outputList("search backup html", "", @bkup_htmllist); outputBorder("backup image file list"); foreach my $f (sort keys %imgsize) { print "$f\t$imgpath{$f}\t$imgsize{$f}\n"; } } # ---------------------------------------- # ひとまず、過去ログディレクトリに画像をコピーする my @notfound_dirlist = (); my @copy_filelist = (); my @found_nochkimglist = (); @same_imglist = (); foreach my $imgfile (keys(%imgpath)) { # image のファイル名から数字を取得して、 # コピー先のディレクトリ名を求める。 # 一応、5桁以上にも対応。その場合、8桁でディレクトリ名等作成。 unless ( $imgfile =~ /oekaki_(\d{4,8})\.(png|gif|jpg)/ ) { print "Error : Illegal Filename. $imgfile\n"; next; } $imgfile =~ /oekaki_(\d{4,8})\.(png|gif|jpg)/; my $num = int($1); my $dirname = $kakolog_dir . "/" . getDirBaseNameByNumber($num); print "$num -> $dirname\n" if $copy_dst_dir_output; unless ( -d $dirname ) { # コピー先ディレクトリが存在しない push( @notfound_dirlist, "$dirname / $imgfile"); if ( $makedirfg ) { mkpath [$dirname] or die $!; print "make dir $dirname\n"; } else { next; } } unless ( -e "$dirname/$imgfile" ) { # コピー先に同じファイル名が存在しない push( @copy_filelist, $imgpath{$imgfile} . '<>' . $dirname . '<>' . $imgfile ); next; } # コピー先に同じファイルが存在する # コピー先ファイルのサイズ取得 my $size = -s "$dirname/$imgfile"; # check しなくていい画像かどうかを確認 my $fgstr = ""; foreach my $is (keys(%nochkimglist_size)) { my $dkind = $is; my $dsize = $nochkimglist_size{$dkind}; my $dmd5 = $nochkimglist_md5{$dkind}; my $chkmd5 = ""; if ( $size == $dsize ) { open(IN, "$dirname/$imgfile") || die $!; binmode(IN); my $md5 = Digest::MD5->new; while () { $md5->add($_); } close(IN); $chkmd5 = $md5->hexdigest; if ( $dmd5 eq $chkmd5 ) { $fgstr = $dkind; last; } } } if ( $fgstr ne "" ) { # チェックしなくてもよい種類の画像だった push( @found_nochkimglist, "$dirname/$imgfile ... $fgstr" ); push( @copy_filelist, $imgpath{$imgfile} . '<>' . $dirname . '<>' . $imgfile ); } else { if ( $size == $imgsize{$imgfile} ) { # size が同じ push ( @same_imglist, "$imgfile : $dirname/$imgfile and $imgpath{$imgfile} = $size byte" ); } elsif ( $size > $imgsize{$imgfile} ) { # コピー先のほうがサイズが大きい print "break? $imgpath{$imgfile}\n"; } else { # コピー先のほうがサイズが小さい。コピーしてもよさそう print "break? $dirname/$imgfile\n"; push( @copy_filelist, $imgpath{$imgfile} . '<>' . $dirname . '<>' . $imgfile ); } } } # コピー元・コピー先で、サイズが同じだった画像群を表示 if ( $samefile_output ) { outputList("does not copy. Because image file size is equal. " , "same image : ", @same_imglist); } # コピー先ディレクトリ内で、チェックしなくても良かった画像群を表示 if ( $nochk_imglist_output ) { outputList("It is a temporary image file list. It doesn't check, and it is overwrited.", "temp image : ", @found_nochkimglist); } # 実際にコピー print "\n\n"; foreach my $s (sort(@copy_filelist)) { my($src,$dstdir,$file) = split( /<>/, $s ); print "copy $src $dstdir/$file\n"; copy $src, "$dstdir/$file" or die $!; } # コピー先ディレクトリが見つからなかった画像ファイル群を表示 if ( $notfounddir_dispfg && $makedirfg == 0 ) { outputList("The directory is not found at the copy destination.", "Error! : Not found Dir : ", @notfound_dirlist); } # ---------------------------------------- # バックアップhtml を読んで、コメント部分を取り出す my %bkup_htmlcomment = (); foreach my $htmlfile (@bkup_htmllist) { my @list = (); print "# ", $htmlfile, " / backup \n" if $bkuphtmlcommnet_addinfo; open(IN, $htmlfile) || die $!; while() { chomp; push(@list, $_); } close(IN); my $fg = 0; my $num = 0; my $cmstr = ""; foreach my $str (@list) { if ( $fg == 0 ) { if ( $str =~ /\[(\d{4,8})\]<\/B><\/FONT>/ ) { # 番号が見つかった # # [6907] $num = $1; if ( $num > 10000 ) { $num = sprintf("%08d", $num); } $fg = 1; next; } } elsif ( $fg == 1 ) { if ( $str =~ // ) { # コメント開始部が見つかった # # print "$num : " if $bkuphtmlcommnet_addinfo; $fg = 2; next; } } elsif ( $fg == 2 ) { if ( $str =~ /<\/TD>/ ) { # コメント終了部が見つかった # # print "\n" if $bkuphtmlcommnet_read_disp; if ( exists $bkup_htmlcomment{$num} ) { # 該当No は、既に出現してる # コメント部分の文字列長取得 my $newn = length($cmstr); my $oldn = length($bkup_htmlcomment{$num}); if ( $newn > $oldn ) { # 増えてる。更新する。 print " ++ (new:$newn / old:$oldn)\n" if $bkuphtmlcommnet_addinfo; $bkup_htmlcomment{$num} = $cmstr; } elsif ( $newn < $oldn ) { # 減ってる。 print " -- (new:$newn / old:$oldn)\n" if $bkuphtmlcommnet_addinfo; } else { # 同じ。 print " == (new:$newn / old:$oldn)\n" if $bkuphtmlcommnet_addinfo; } } else { # 該当No は、出現してなかった。記録する。 my $newn = length($cmstr); print " <- (new:$newn)\n" if $bkuphtmlcommnet_addinfo; $bkup_htmlcomment{$num} = $cmstr; } $fg = 0; $num = 0; $cmstr = ""; } else { # コメント部分を追加取得 print "." if $bkuphtmlcommnet_read_disp; $cmstr .= $str; } } } if ( $bkuphtmlcommnet_addinfo ) { print "\n"; } } if ( $bkuphtmlcommnet_output ) { outputBorder("comment in backup html"); foreach my $s (sort keys %bkup_htmlcomment) { print "$s<>$bkup_htmlcomment{$s}\n"; } } # ---------------------------------------- # 過去ログhtml を読んで、コメント部分を取り出す my %kakolog_htmlcomment = (); my %kakolog_tagcomment = (); my @nocomment_num = (); foreach my $htmlfile (@kakolog_htmllist) { my @list = (); print "# ", $htmlfile, " / kakolog\n" if $kakologcomment_addinfo; open(IN, $htmlfile) || die $!; while() { chomp; push(@list, $_); } close(IN); my $fg = 0; my $num = 0; my $cmstr = ""; foreach my $str (@list) { if ( $fg == 0 ) { if ( $str =~ /^\[(\d{4,8})\]<\/B><\/FONT>/ ) { # 番号が見つかった # [7020]

$num = $1; if ( $num > 10000 ) { $num = sprintf("%08d", $num); } $fg = 1; next; } } elsif ( $fg == 1 ) { if ( $str =~ // ) { # コメント開始部が見つかった # print "$num : " if $kakologcomment_addinfo; $fg = 2; next; } } elsif ( $fg == 2 ) { if ( $str =~ /<\/TD>/ ) { # コメント終了部が見つかった #

print "\n" if $bkuphtmlcommnet_read_disp; if ( exists $kakolog_htmlcomment{$num} ) { # 該当No は、既に出現してる # コメント部分の文字列長取得 my $newn = length($cmstr); my $oldn = length($kakolog_htmlcomment{$num}); if ( $newn > $oldn ) { # 増えてる。更新する。 print " ++ (new:$newn / old:$oldn)\n" if $kakologcomment_addinfo; $kakolog_htmlcomment{$num} = $cmstr; } elsif ( $newn < $oldn ) { # 減ってる。 print " -- (new:$newn / old:$oldn)\n" if $kakologcomment_addinfo; } else { # 同じ。 print " == (new:$newn / old:$oldn)\n" if $kakologcomment_addinfo; } } else { # 該当No は、出現してなかった。記録する。 my $newn = length($cmstr); print " <- (new:$newn)\n" if $kakologcomment_addinfo; $kakolog_htmlcomment{$num} = $cmstr; } $fg = 0; $num = 0; $cmstr = ""; } else { # コメント部分を追加取得 print "." if $bkuphtmlcommnet_read_disp; if ( $str =~ // ) { # コメントタグが埋め込まれていた # my $s1 = $1; my $s2 = $2; $kakolog_tagcomment{$num} = ""; $str =~ s/$kakolog_tagcomment{$num}//; } if ( $str =~ /  ( (Coming Seen|No Comment) )<\/FONT>
/ ) { # No comment だった $str =~ s/  ( (Coming Seen|No Comment) )<\/FONT>
//; push(@nocomment_num, $num); } $cmstr .= $str; } } } if ( $kakologcomment_addinfo ) { print "\n"; } } if ( $kakologcomment_output ) { outputBorder("html comment in kakolog html"); foreach my $s (sort keys %kakolog_htmlcomment) { print "$s<>$kakolog_tagcomment{$s}<>$kakolog_htmlcomment{$s}\n"; } } if ( $kakologcomment_nocomment_disp ) { print "\n# No Comment or Coming Seen Number : "; foreach my $n (sort @nocomment_num) { print "$n,"; }; print "\n"; } # ---------------------------------------- # 更新すべきコメント部分を取得 my %update_comment = (); my %update_tagcommnet = (); foreach my $n (sort keys %bkup_htmlcomment) { unless ( exists $kakolog_htmlcomment{$n} ) { # 過去ログhtml内にバックアップhtml内のコメントNoが存在しない # 問答無用で更新コメント扱いにする $update_comment{$n} = $bkup_htmlcomment{$n}; $update_tagcommnet{$n} = ""; next; } # それぞれのコメントの文字数を取得 my $oldn = length($kakolog_htmlcomment{$n}); my $newn = length($bkup_htmlcomment{$n}); if ( $oldn < $newn ) { # バックアップhtml内コメントのほうが文字数が多い $update_comment{$n} = $bkup_htmlcomment{$n}; } elsif ( $oldn > $newn ) { # 過去ログhtml内のコメントのほうが文字数が多い # バックアップhtmlが異常? print "break? $n backup log\n"; } else { # バックアップhtml内コメントと過去ログhtml内コメントの文字数が同じ # つまり、変化なし print "same comment : $n<>$bkup_htmlcomment{$n}\n" if $samecomment_disp; if ( $samecomment_disp_number_only ) { print "same comment : $n ", length($bkup_htmlcomment{$n}), "\n"; } } } if ( $updatecomment_infodisp ) { outputBorder("update comment"); foreach my $n (sort keys %update_comment) { print $n,"<>",$update_comment{$n},"\n"; } } if ( $updatecomment_infodisp_number_only ) { outputBorder("update comment number"); foreach my $n (sort keys %update_comment) { print $n," : length ", length($update_comment{$n}),"\n"; } } # ---------------------------------------- # 更新すべき過去ログhtmlファイル名を取得 my %nonexistent_dir = (); my %nonexistent_html = (); my %update_htmllist = (); my %update_htmllist_key_num = (); foreach my $n (sort keys %update_comment) { my $dirname = $kakolog_dir . "/" . getDirBaseNameByNumber($n); unless ( -d $dirname ) { # 更新すべき過去ログhtmlディレクトリが存在しない $nonexistent_dir{$dirname}++; next; } my $htmlname = $dirname . "/" . getKakologHtmlNameByNumber($n); unless ( -e $htmlname ) { $nonexistent_html{$htmlname}++; next; } $update_htmllist{$htmlname}++; $update_htmllist_key_num{$n} = $htmlname; } # outputList( "Update html List", "", sort keys %update_htmllist ); outputList("Not Found Kakolog dir", "Error! : Not Found ", sort keys %nonexistent_dir ); outputList("Not Found Kakolog html", "Error! : Not Found ", sort keys %nonexistent_html ); # 必要であれば過去ログhtmlをバックアップしておく if ( $kakologhtml_bkup_usage ) { my $tmstr = ".bak_" . strftime "%Y%m%d_%H%M%S", localtime; foreach my $f (sort keys %update_htmllist) { copy $f, "$f$tmstr" or die $!; } } # ---------------------------------------- # 過去ログhtml を書き換える print "\n# ", '-' x 40, "\n# Update Kakolog Html\n"; my $updatefilenum = 0; foreach my $f (sort keys %update_htmllist) { my %targetlist = (); my @list = (); open(IN,$f) || die $!; while() { chomp; push(@list,$_); } close(IN); my @newlist = (); my @updatenum = (); my @nonupdatenum = (); my $fg = 0; my $num = 0; my $cmstr = ""; foreach my $str (@list) { if ( $fg == 0 ) { if ( $str =~ /^\[(\d{4,8})\]<\/B><\/FONT>/ ) { # 番号が見つかった # [7020]

$num = $1; if ( $num > 10000 ) { $num = sprintf("%08d", $num); } $fg = 1; } } elsif ( $fg == 1 ) { if ( $str =~ // ) { # コメント開始部が見つかった # $fg = 2; } } elsif ( $fg == 2 ) { if ( $str =~ /<\/TD>/ ) { # コメント終了部が見つかった #

$fg = 0; $num = 0; $cmstr = ""; } elsif ( $str =~ // ) { # コメントタグが見つかった # my $s1 = $1; my $s2 = $2; unless ( exists $update_comment{$num} ) { push(@nonupdatenum, $num); } else { $str = "" . $update_comment{$num}; push(@updatenum, $num); } } } push(@newlist, $str); } print "\nupdate $f : "; foreach my $n (sort @updatenum) { print "$n,"; }; print "\n"; open(OUT,"> $f") || die $!; foreach my $s (@newlist) { print OUT $s, "\n"; } close(OUT); if ( $nonupdatecomment_disp ) { print "warning : no update $f : "; foreach my $n (sort @nonupdatenum) { print "$n,"; }; print "\n"; } $updatefilenum++; } print "\n# $updatefilenum file update\n"; exit; # ---------- subroutine ---------- # Number から、保存すべき過去ログディレクトリ名(xxxx_xxxx)を得る sub getDirBaseNameByNumber() { my($num) = @_; my $snum = ($num - 1) - (($num - 1) % 100); my $enum = $snum + 100; $snum++; my $dirname = ""; if ( $num < 10000 ) { $dirname = sprintf("%04d_%04d", $snum, $enum); } else { $dirname = sprintf("%08d_%08d", $snum, $enum); } return $dirname; } # Number から、更新すべき過去ログhtmlファイル名(oekaki_xxxx.html)を得る # example : xx01,xx21,xx41,xx61,xx81 sub getKakologHtmlNameByNumber { my($num) = @_; my $snum = ($num - 1) - (($num - 1) % 20); $snum++; my $filename = "oekaki_"; if ( $num < 10000 ) { $filename .= sprintf("%04d", $snum); } else { $filename .= sprintf("%08d", $snum); } $filename .= ".html"; return $filename; } # 各種情報表示の区切りを出力 sub outputBorder { my($s) = @_; print "\n"; print "# ", '-' x 40, "\n"; print "# ", $s, "\n\n"; } # 一覧を表示 sub outputList { my($title, $info, @lst) = @_; unless ( $#lst < 0 ) { outputBorder($title); foreach my $f (sort @lst) { print $info, $f,"\n"; } } }