#!/usr/bin/perl
package MT::Plugins::TextHatena;
use vars qw($VERSION);
$VERSION = 0.01;
use strict;
use Jcode;
use Text::Hatena;
use MT;
use MT::Blog;
use MT::Entry;
use MT::Template::Context;
MT->add_text_filter(text_hatena => {
label => 'MT::Text::Hatena',
on_format => sub {
my ($text, $ctx) = @_;
if($text eq ''){
return "";
}
my $entry = $ctx->stash('entry');
my $permalink = "";
if ($entry && $entry->id) {
$permalink = $entry->permalink;
}
my $parser = Text::Hatena->new(
permalink => $permalink,
);
my $html = $parser->parse($text);
parseLinks($parser->html);
},
});
sub parseLinks{
my $source = shift;
my @lines = split(/\n/, $source);
foreach my $line(@lines){
# さまざまなパターンについて分岐
$line =~ s!(
# src="URL", href="url"
((src|href|cite)=[\'\"](http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*[\'\"])
|
# []URL[]
(\[\](http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*\[\])
|
# [URL]
(\[(http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*(:image)?\])
|
# [URL]
(\[(http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*(:title=.*)?\])
|
# [URL]
((http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*)
|
# [map:WORDs]
#map:x139.6983y35.6514
#[map:渋谷区鉢山町]
#[map:150-0035]
#[map:株式会社はてな]
(\[(map):[^\]]+\])
|
# [search:WORDs]
(\[(search):((keyword|question|asin):)?[^\]]+\])
|
# [google:WORDs]
(\[(google):((image|news):)?[^\]]+\])
|
# [amazon:WORDs]
(\[(amazon):[^\]]+\])
|
# [rakuten:WORDs]
(\[(rakuten):[^\]]+\])
|
# id:hogehoge:yyyymmdd
(id:\w+(:\d+)?)
|
# g:hugahuga:id:hogehoge:yyyymmdd
(g:\w+(:id:\w+(:\d+)?)?)
|
# ?:id:hogehoge:〜
#a:id:sample
#b:id:sample,b:id:sample:20050707,b:id:sample:favorite,b:id:sample:asin
#d:id:hatenadiary,d:id:hatenadiary:20040510
#i:id:sample
#r:id:sample
#f:id:hatenadiary:20041007101545j:image,f:id:hatenadiary:20041007101545j:image:small
#f:id:hatenadiary:20041007101545j:image:w50,f:id:hatenadiary:favorite
((a|b|i|r|f|map):id:\w+(:\w+)?)
|
# [keyword:WORDs]
#[keyword:はてな]
#[keyword:はてな:graph]
#[keyword:はてな:graph:accessrank:3d]
(\[(keyword):[^\]]+\])
|
#[g:hatena:keyword:はてなダイアリー利用可能タグ]
(\[g:\w+:(keyword):[^\]]+\])
|
)!&toHtml($1)!igex;
#idea:182,idea:182:title
#graph:id:sample
#[graph:id:sample:しなもんの体重]
#[graph:id:sample:しなもんの体重:image]
#jan:4981254610640
#ean:4981254610640
#jan:4981254610640:title
#[jan:4981254610640:title=この商品]
#jan:4981254610640:image
#jan:4981254610640:barcode
#id:hatenadiary:about
#id:hatenadiary:archive
#id:hatenadiary:archive:200508
#question:1096559040
#question:1096559040:title
#question:1092057258:detail
#uestion:1092057258:image
#question:1092057258:image:small
}
join("\n",@lines);
}
sub toHtml{
my $line = shift;
# src="URL", href="url"
if($line =~ /(src|href|cite)=[\'\"](http|https|ftp|mailto):([^\x00-\x20()<>\x7F-\xFF])*[\'\"]/){
return $line;
}
# []URL[]
if($line=~/\[\]((http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*)\[\]/){
return $1;
}
# [URL:image]
if($line=~/\[((http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*)(:image)?\]/){
return qq(
);
}
# [URL]
if($line=~/\[((http|https|ftp|mailto|isbn|asin|ISBN|ASIN):([^\x00-\x20()<>\x7F-\xFF])*)(:title=(.*))?\]/){
return ($4 eq '') ? qq($1) : qq($5);
}
# [URL]
if($line=~/((http|https|ftp|mailto):([^\x00-\x20()<>\x7F-\xFF])*)/){
return qq($1);
}
# [map:WORDs]
#未対応:map:x139.6983y35.6514
#[map:渋谷区鉢山町],[map:150-0035],[map:株式会社はてな]
if($line=~/\[(map:([^\]]+))\]/){
my $encoded = toUtf8($2);
return qq($1);
}
# [search:WORDs]
if($line=~/\[(search:((keyword|question|asin):)?([^\]]+))\]/){
my $u = 'http://search.hatena.ne.jp';
if($3 ne ''){
$u .= ($3 eq 'keyword') ? '/keyword' :
($3 eq 'question') ? '/questsearch' :
($3 eq 'asin') ? '/asinsearch' : '';
}
else{
$u .= '/keyword';
}
$u .= '?word=' . toEuc($4);
return qq($1);
}
# [google:WORDs]
if($line=~/\[(google:((image|news):)?([^\]]+))\]/){
my $u='http://www.google.com/search';
my $encoded = toEuc($4);
if($2){
$u = ($3 eq 'image') ? 'http://images.google.com/images' :
($3 eq 'news') ? 'http://news.google.com/news' : '';
}
return qq($1);
}
# [ASIN:xxx]
if($line=~/((isbn|asin|ISBN|ASIN):(\w+)(:(detail|image)(:(small|large))?)?)/){
return qq($1);
}
# [amazon:WORDs]
if($line=~/\[(amazon:([^\]]+))\]/){
my $encoded = toEuc($2);
return qq($1);
}
# [rakuten:WORDs]
if($line=~/\[(rakuten:([^\]]+))\]/){
my $encoded = toEuc($2);
return qq($1);
}
# [keyword:WORDs]
#(\[(keyword):[^\]]+\])
if($line=~/\[(keyword:([^\]]+))\]/){
my $encoded = toEuc($2);
return qq($1);
}
# id:hogehoge:yyyymmdd
#d:id:hatenadiary,d:id:hatenadiary:20040510
if($line =~ /((d:)?id:(\w+)(:(\d+))?)/){
return qq($1);
}
# g:hugahuga:id:hogehoge:yyyymmdd
if($line =~ /(g:(\w+)(:id:(\w+)(:(\d+))?))/){
return qq($1);
}
#b:id:sample,b:id:sample:20050707,b:id:sample:favorite,b:id:sample:asin
if($line =~ /\[?(b:id:(\w+)(:(\w+))?)\]?/){
return qq($1);
}
#b:keyword:xxx
if($line=~/\[(b:keyword:([^\]]+))\]/){
my $encoded = toEuc($2);
return qq($1);
}
#idea:999
if($line =~ /(idea:(\d+))/){
return qq($1);
}
#?:id:hogehoge:〜
if($line =~ /((a|b|d|f|i|r|f|map):id:(\w+))/){
return qq($1);
}
#f:id:hatenadiary:20041007101545j:image,f:id:hatenadiary:20041007101545j:image:small
#f:id:hatenadiary:20041007101545j:image:w50,f:id:hatenadiary:favorite
#[g:hatena:keyword:はてなダイアリー利用可能タグ]
#(\[g:\w+:(keyword):[^\]]+\])
$line;
}
sub toEuc(){
my $src = shift;
my $enc = Jcode->new($src)->euc;
$enc =~ s/(\W)/'%' . unpack('H2', $1)/eg;
$enc =~ tr/ /+/;
$enc;
}
sub toUtf8(){
my $src = shift;
my $enc = Jcode->new($src)->utf8;
$enc =~ s/(\W)/'%' . unpack('H2', $1)/eg;
$enc =~ tr/ /+/;
$enc;
}
1;