package VNDB::Handler::VNPage; use strict; use warnings; use YAWF ':html', 'xml_escape'; use VNDB::Func; YAWF::register( qr{v([1-9]\d*)/rg} => \&rg, qr{v([1-9]\d*)(?:\.([1-9]\d*))?} => \&page, ); sub rg { my($self, $vid) = @_; my $v = $self->dbVNGet(id => $vid, what => 'relgraph')->[0]; return 404 if !$v->{id} || !$v->{rgraph}; my $title = mt '_vnrg_title', $v->{title}; $self->htmlHeader(title => $title); $self->htmlMainTabs('v', $v, 'rg'); div class => 'mainbox'; h1 $title; lit $v->{cmap}; p class => 'center'; img src => sprintf('%s/rg/%02d/%d.png', $self->{url_static}, $v->{rgraph}%100, $v->{rgraph}), alt => $title, usemap => '#rgraph'; end; end; } sub page { my($self, $vid, $rev) = @_; my $v = $self->dbVNGet( id => $vid, what => 'extended anime relations screenshots ranking'.($rev ? ' changes' : ''), $rev ? (rev => $rev) : (), )->[0]; return 404 if !$v->{id}; my $r = $self->dbReleaseGet(vid => $vid, what => 'producers platforms'); $self->htmlHeader(title => $v->{title}, noindex => $rev); $self->htmlMainTabs('v', $v); return if $self->htmlHiddenMessage('v', $v); _revision($self, $v, $rev); div class => 'mainbox'; $self->htmlItemMessage('v', $v); h1 $v->{title}; h2 class => 'alttitle', $v->{original} if $v->{original}; div class => 'vndetails'; # image div class => 'vnimg'; if(!$v->{image}) { p mt '_vnpage_noimg'; } elsif($v->{image} < 0) { p mt '_vnpage_imgproc'; } elsif($v->{img_nsfw} && !$self->authInfo->{show_nsfw}) { img id => 'nsfw_hid', src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title}; p id => 'nsfw_show'; txt mt('_vnpage_imgnsfw_msg')."\n\n"; a href => '#', mt '_vnpage_imgnsfw_show'; txt "\n\n".mt '_vnpage_imgnsfw_note'; end; } else { img src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title}; i mt '_vnpage_imgnsfw_foot' if $v->{img_nsfw} && $self->authInfo->{show_nsfw}; } end; # general info table; my $i = 0; Tr ++$i % 2 ? (class => 'odd') : (); td class => 'key', mt '_vnpage_vntitle'; td $v->{title}; end; if($v->{original}) { Tr ++$i % 2 ? (class => 'odd') : (); td mt '_vnpage_original'; td $v->{original}; end; } if($v->{alias}) { Tr ++$i % 2 ? (class => 'odd') : (); td mt '_vnpage_alias'; td $v->{alias}; end; } if($v->{length}) { Tr ++$i % 2 ? (class => 'odd') : (); td mt '_vnpage_length'; td "$self->{vn_lengths}[$v->{length}][0] ($self->{vn_lengths}[$v->{length}][1])"; end; } my @links = ( $v->{l_wp} ? [ 'Wikipedia', 'http://en.wikipedia.org/wiki/%s', $v->{l_wp} ] : (), $v->{l_encubed} ? [ 'Encubed', 'http://novelnews.net/tag/%s/', $v->{l_encubed} ] : (), $v->{l_renai} ? [ 'Renai.us', 'http://renai.us/game/%s.shtml', $v->{l_renai} ] : (), $v->{l_vnn} ? [ 'V-N.net', 'http://visual-novels.net/vn/index.php?option=com_content&task=view&id=%d', $v->{l_vnn} ] : (), ); if(@links) { Tr ++$i % 2 ? (class => 'odd') : (); td mt '_vnpage_links'; td; for(@links) { a href => sprintf($_->[1], $_->[2]), $_->[0]; txt ', ' if $_ ne $links[$#links]; } end; end; } _producers($self, \$i, $r); _relations($self, \$i, $v) if @{$v->{relations}}; _anime($self, \$i, $v) if @{$v->{anime}}; _useroptions($self, \$i, $v) if $self->authInfo->{id}; Tr; td class => 'vndesc', colspan => 2; h2 mt '_vnpage_description'; p; lit bb2html $v->{desc}; end; end; end; end; end; clearfloat; # tags my $t = $self->dbTagStats(vid => $v->{id}, order => 'avg(tv.vote) DESC', minrating => 0, results => 999); if(@$t) { div id => 'tagops'; a href => '#', mt '_vnpage_tags_spoil0'; a href => '#', class => 'tsel', mt '_vnpage_tags_spoil1'; a href => '#', mt '_vnpage_tags_spoil2'; a href => '#', class => 'sec', mt '_vnpage_tags_summary'; a href => '#', mt '_vnpage_tags_all'; end; div id => 'vntags'; for (@$t) { span class => sprintf 'tagspl%.0f %s', $_->{spoiler}, $_->{spoiler} > 1 ? 'hidden' : ''; a href => "/g$_->{id}", style => sprintf('font-size: %dpx', $_->{rating}*3.5+6), $_->{name}; b class => 'grayedout', sprintf ' %.1f', $_->{rating}; end; txt ' '; } end; } end; _releases($self, $v, $r); _stats($self, $v); _screenshots($self, $v, $r) if @{$v->{screenshots}}; $self->htmlFooter; } sub _revision { my($self, $v, $rev) = @_; return if !$rev; my $prev = $rev && $rev > 1 && $self->dbVNGet( id => $v->{id}, rev => $rev-1, what => 'extended anime relations screenshots changes' )->[0]; $self->htmlRevision('v', $prev, $v, [ title => diff => 1 ], [ original => diff => 1 ], [ alias => diff => 1 ], [ desc => diff => 1 ], [ length => serialize => sub { $self->{vn_lengths}[$_[0]][0] } ], [ l_wp => htmlize => sub { $_[0] ? sprintf '%1$s', xml_escape $_[0] : mt '_vndiff_nolink' }], [ l_encubed => htmlize => sub { $_[0] ? sprintf '%1$s', xml_escape $_[0] : mt '_vndiff_nolink' }], [ l_renai => htmlize => sub { $_[0] ? sprintf '%1$s', xml_escape $_[0] : mt '_vndiff_nolink' }], [ l_vnn => htmlize => sub { $_[0] ? sprintf '%1$d', xml_escape $_[0] : mt '_vndiff_nolink' }], [ relations => join => '
', split => sub { my @r = map sprintf('%s: %s', $self->{vn_relations}[$_->{relation}][0], $_->{id}, xml_escape($_->{original}||$_->{title}), xml_escape shorten $_->{title}, 40 ), sort { $a->{id} <=> $b->{id} } @{$_[0]}; return @r ? @r : (mt '_vndiff_none'); }], [ anime => join => ', ', split => sub { my @r = map sprintf('a%1$d', $_->{id}), sort { $a->{id} <=> $b->{id} } @{$_[0]}; return @r ? @r : (mt '_vndiff_none'); }], [ screenshots => join => '
', split => sub { my @r = map sprintf('[%s] %4$d (%s)', $_->{rid} ? qq|r$_->{rid}| : 'no release', $self->{url_static}, $_->{id}%100, $_->{id}, $_->{width}, $_->{height}, $_->{nsfw} ? 'NSFW' : 'Safe' ), @{$_[0]}; return @r ? @r : (mt '_vndiff_none'); }], [ image => htmlize => sub { my $url = sprintf "%s/cv/%02d/%d.jpg", $self->{url_static}, $_[0]%100, $_[0]; if($_[0] > 0) { return $_[1]->{img_nsfw} && !$self->authInfo->{show_nsfw} ? "(NSFW)" : ""; } else { return $_[0] < 0 ? '[processing]' : 'No image'; } }], [ img_nsfw => serialize => sub { $_[0] ? 'Not safe' : 'Safe' } ], ); } sub _producers { my($self, $i, $r) = @_; return if !grep @{$_->{producers}}, @$r; my %lang; my @lang = grep !$lang{$_}++, map @{$_->{languages}}, @$r; Tr ++$$i % 2 ? (class => 'odd') : (); td mt '_vnpage_producers'; td; for my $l (@lang) { my %p = map { $_->{id} => $_ } map @{$_->{producers}}, grep grep($_ eq $l, @{$_->{languages}}), @$r; my @p = values %p; next if !@p; cssicon "lang $l", mt "_lang_$l"; for (@p) { a href => "/p$_->{id}", title => $_->{original}||$_->{name}, shorten $_->{name}, 30; txt ' & ' if $_ != $p[$#p]; } txt "\n"; } end; end; } sub _relations { my($self, $i, $v) = @_; my %rel; push @{$rel{$_->{relation}}}, $_ for (sort { $a->{title} cmp $b->{title} } @{$v->{relations}}); Tr ++$$i % 2 ? (class => 'odd') : (); td mt '_vnpage_relations'; td class => 'relations'; dl; for(sort keys %rel) { dt $self->{vn_relations}[$_][0]; dd; for (@{$rel{$_}}) { a href => "/v$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 40; br; } end; } end; end; end; } sub _anime { my($self, $i, $v) = @_; Tr ++$$i % 2 ? (class => 'odd') : (); td mt '_vnpage_anime'; td class => 'anime'; for (sort { ($a->{year}||9999) <=> ($b->{year}||9999) } @{$v->{anime}}) { if(!$_->{lastfetch} || !$_->{year} || !$_->{title_romaji}) { b; lit mt '_vnpage_anime_noinfo', $_->{id}, "http://anidb.net/a$_->{id}"; end; } else { b; txt '['; a href => "http://anidb.net/a$_->{id}", title => 'AniDB', 'DB'; if($_->{nfo_id}) { txt '-'; a href => "http://animenfo.com/animetitle,$_->{nfo_id},a.html", title => 'AnimeNFO', 'NFO'; } if($_->{ann_id}) { txt '-'; a href => "http://www.animenewsnetwork.com/encyclopedia/anime.php?id=$_->{ann_id}", title => 'Anime News Network', 'ANN'; } txt '] '; end; acronym title => $_->{title_kanji}||$_->{title_romaji}, shorten $_->{title_romaji}, 50; b ' ('.(defined $_->{type} ? $self->{anime_types}[$_->{type}].', ' : '').$_->{year}.')'; txt "\n"; } } end; end; } sub _useroptions { my($self, $i, $v) = @_; my $vote = $self->dbVoteGet(uid => $self->authInfo->{id}, vid => $v->{id})->[0]; my $wish = $self->dbWishListGet(uid => $self->authInfo->{id}, vid => $v->{id})->[0]; Tr ++$$i % 2 ? (class => 'odd') : (); td mt '_vnpage_uopt'; td; if($vote || !$wish) { Select id => 'votesel'; option $vote ? mt '_vnpage_uopt_voted', $vote->{vote} : mt '_vnpage_uopt_novote'; optgroup label => $vote ? mt '_vnpage_uopt_changevote' : mt '_vnpage_uopt_dovote'; option value => $_, "$_ (".mt("_vote_$_").')' for (reverse 1..10); end; option value => -1, mt '_vnpage_uopt_delvote' if $vote; end; br; } if(!$vote || $wish) { Select id => 'wishsel'; option $wish ? mt '_vnpage_uopt_wishlisted', mt '_wish_'.$wish->{wstat} : mt '_vnpage_uopt_nowish'; optgroup label => $wish ? mt '_vnpage_uopt_changewish' : mt '_vnpage_uopt_addwish'; option value => $_, mt "_wish_$_" for (@{$self->{wishlist_status}}); end; option value => -1, mt '_vnpage_uopt_delwish'; end; } end; end; } sub _releases { my($self, $v, $r) = @_; div class => 'mainbox releases'; a class => 'addnew', href => "/v$v->{id}/add", mt '_vnpage_rel_add'; h1 mt '_vnpage_rel'; if(!@$r) { p mt '_vnpage_rel_none'; end; return; } if($self->authInfo->{id}) { my $l = $self->dbVNListGet(uid => $self->authInfo->{id}, rid => [map $_->{id}, @$r]); for my $i (@$l) { [grep $i->{rid} == $_->{id}, @$r]->[0]{ulist} = $i; } } my %lang; my @lang = grep !$lang{$_}++, map @{$_->{languages}}, @$r; table; for my $l (@lang) { Tr class => 'lang'; td colspan => 6; cssicon "lang $l", mt "_lang_$l"; txt mt "_lang_$l"; end; end; for my $rel (grep grep($_ eq $l, @{$_->{languages}}), @$r) { Tr; td class => 'tc1'; lit $self->{l10n}->datestr($rel->{released}); end; td class => 'tc2', $rel->{minage} < 0 ? '' : $self->{age_ratings}{$rel->{minage}}[0]; td class => 'tc3'; for (sort @{$rel->{platforms}}) { next if $_ eq 'oth'; cssicon $_, mt "_plat_$_"; } cssicon "rt$rel->{type}", mt "_rtype_$rel->{type}"; end; td class => 'tc4'; a href => "/r$rel->{id}", title => $rel->{original}||$rel->{title}, $rel->{title}; b class => 'grayedout', ' '.mt '_vnpage_rel_patch' if $rel->{patch}; end; td class => 'tc5'; if($self->authInfo->{id}) { a href => "/r$rel->{id}", id => "rlsel_$rel->{id}"; lit $rel->{ulist} ? liststat $rel->{ulist} : '--'; end; } else { txt ' '; } end; td class => 'tc6'; if($rel->{website}) { a href => $rel->{website}, rel => 'nofollow'; cssicon 'ext', mt '_vnpage_rel_extlink'; end; } else { txt ' '; } end; end; } } end; end; } sub _screenshots { my($self, $v, $r) = @_; div class => 'mainbox', id => 'screenshots'; if(grep $_->{nsfw}, @{$v->{screenshots}}) { p class => 'nsfwtoggle'; lit mt '_vnpage_scr_showing', sprintf('%d', $self->authInfo->{show_nsfw} ? scalar @{$v->{screenshots}} : scalar grep(!$_->{nsfw}, @{$v->{screenshots}})), scalar @{$v->{screenshots}}; txt " "; a href => '#', id => "nsfwhide", mt '_vnpage_scr_nsfwhide'; end; } h1 mt '_vnpage_scr'; table; for my $rel (@$r) { my @scr = grep $_->{rid} && $rel->{id} == $_->{rid}, @{$v->{screenshots}}; next if !@scr; Tr class => 'rel'; td colspan => 5; cssicon "lang $_", mt "_lang_$_" for (@{$rel->{languages}}); txt $rel->{title}; end; end; Tr; td class => 'scr'; for (@scr) { div $_->{nsfw} ? (class => 'nsfw'.(!$self->authInfo->{show_nsfw} ? ' hidden' : '')) : (); a href => sprintf('%s/sf/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}), rel => "iv:$_->{width}x$_->{height}:scr", $_->{nsfw} && !$self->authInfo->{show_nsfw} ? (class => 'hidden') : (); img src => sprintf('%s/st/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}), alt => mt '_vnpage_scr_num', $_->{id}; end; end; } end; end; } end; end; } sub _stats { my($self, $v) = @_; my $stats = $self->dbVoteStats(vid => $v->{id}, 1); div class => 'mainbox'; h1 mt '_vnpage_stats'; if(!grep $_ > 0, @$stats) { p mt '_vnpage_stats_none'; } else { $self->htmlVoteStats(v => $v, $stats); } end; } 1;