<commit_before>
package VNDB::Handler::VNPage;

use strict;
use warnings;
use TUWF ':html', 'xml_escape';
use VNDB::Func;


TUWF::register(
  qr{v/rand}                        => \&rand,
  qr{v([1-9]\d*)/rg}                => \&rg,
  qr{v([1-9]\d*)/(chars)}           => \&page,
  qr{v([1-9]\d*)(?:\.([1-9]\d*))?}  => \&page,
);


sub rand {
  my $self = shift;
  $self->resRedirect('/v'.$self->filFetchDB(vn => undef, undef, {results => 1, sort => 'rand'})->[0]{id}, 'temp');
}


sub rg {
  my($self, $vid) = @_;

  my $v = $self->dbVNGet(id => $vid, what => 'relgraph')->[0];
  return $self->resNotFound if !$v->{id} || !$v->{rgraph};

  my $title = mt '_vnrg_title', $v->{title};
  return if $self->htmlRGHeader($title, 'v', $v);

  $v->{svg} =~ s/id="node_v$vid"/id="graph_current"/;
  $v->{svg} =~ s/\$___(_vnrel_[a-z]+)____\$/mt $1/eg;

  div class => 'mainbox';
   h1 $title;
   p class => 'center';
    lit $v->{svg};
   end;
  end;
  $self->htmlFooter;
}


sub page {
  my($self, $vid, $rev) = @_;

  my $char = $rev && $rev eq 'chars';
  $rev = undef if $char;

  my $v = $self->dbVNGet(
    id => $vid,
    what => 'extended anime relations screenshots rating ranking'.($rev ? ' changes' : ''),
    $rev ? (rev => $rev) : (),
  )->[0];
  return $self->resNotFound 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';
     } else {
       p $v->{img_nsfw} ? (id => 'nsfw_hid', style => $self->authPref('show_nsfw') ? 'display: block' : '') : ();
        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};
       end;
       if($v->{img_nsfw}) {
         p id => 'nsfw_show', $self->authPref('show_nsfw') ? (style => 'display: none') : ();
          txt mt('_vnpage_imgnsfw_msg');
          br; br;
          a href => '#', mt '_vnpage_imgnsfw_show';
          br; br;
          txt mt '_vnpage_imgnsfw_note';
         end;
       }
     }
    end 'div'; # /vnimg

    # 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}) {
       $v->{alias} =~ s/\n/, /g;
       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 mt '_vnlength_'.$v->{length}, 1;
       end;
     }
     my @links = (
       $v->{l_wp} ?      [ 'wp', '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',  'http://renai.us/game/%s.shtml', $v->{l_renai} ] : (),
     );
     if(@links) {
       Tr ++$i % 2 ? (class => 'odd') : ();
        td mt '_vnpage_links';
        td;
         for(@links) {
           a href => sprintf($_->[1], $_->[2]), mt "_vnpage_l_$_->[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 $v->{desc} ? bb2html $v->{desc} : '-';
       end;
      end;
     end;

    end 'table';
   end 'div';
   clearfloat;

   # tags
   my $t = $self->dbTagStats(vid => $v->{id}, sort => 'rating', reverse => 1, minrating => 0, results => 999);
   if(@$t) {
     div id => 'tagops';
      # NOTE: order of these links is hardcoded in JS
      a href => '#cont', lc mt '_tagcat_cont';
      a href => '#ero',  lc mt '_tagcat_ero';
      a href => '#tech', lc mt '_tagcat_tech';
      a href => '#', class => 'sec tsel', mt '_vnpage_tags_spoil0';
      a href => '#', 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 cat_%s %s', $_->{spoiler}, $_->{cat}, $_->{spoiler} > 0 ? '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 'div'; # /mainbox

  my $haschar = $self->dbVNHasChar($v->{id});
  if($haschar) {
    ul class => 'maintabs notfirst';
     li class => 'left '.(!$char ? ' tabselected' : ''); a href => "/v$v->{id}", mt '_vnpage_tab_main'; end;
     li class => 'left '.( $char ? ' tabselected' : ''); a href => "/v$v->{id}/chars", mt '_vnpage_tab_chars'; end;
    end;
  }

  if(!$char) {
    _releases($self, $v, $r);
    _stats($self, $v);
    _screenshots($self, $v, $r) if @{$v->{screenshots}};
  } else {
    _chars($self, $haschar, $v);
  }

  $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];
<commit_msg>chardb: Scroll down to the info boxes when using the tabs on VN pages<commit_after>
package VNDB::Handler::VNPage;

use strict;
use warnings;
use TUWF ':html', 'xml_escape';
use VNDB::Func;


TUWF::register(
  qr{v/rand}                        => \&rand,
  qr{v([1-9]\d*)/rg}                => \&rg,
  qr{v([1-9]\d*)/(chars)}           => \&page,
  qr{v([1-9]\d*)(?:\.([1-9]\d*))?}  => \&page,
);


sub rand {
  my $self = shift;
  $self->resRedirect('/v'.$self->filFetchDB(vn => undef, undef, {results => 1, sort => 'rand'})->[0]{id}, 'temp');
}


sub rg {
  my($self, $vid) = @_;

  my $v = $self->dbVNGet(id => $vid, what => 'relgraph')->[0];
  return $self->resNotFound if !$v->{id} || !$v->{rgraph};

  my $title = mt '_vnrg_title', $v->{title};
  return if $self->htmlRGHeader($title, 'v', $v);

  $v->{svg} =~ s/id="node_v$vid"/id="graph_current"/;
  $v->{svg} =~ s/\$___(_vnrel_[a-z]+)____\$/mt $1/eg;

  div class => 'mainbox';
   h1 $title;
   p class => 'center';
    lit $v->{svg};
   end;
  end;
  $self->htmlFooter;
}


sub page {
  my($self, $vid, $rev) = @_;

  my $char = $rev && $rev eq 'chars';
  $rev = undef if $char;

  my $v = $self->dbVNGet(
    id => $vid,
    what => 'extended anime relations screenshots rating ranking'.($rev ? ' changes' : ''),
    $rev ? (rev => $rev) : (),
  )->[0];
  return $self->resNotFound 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';
     } else {
       p $v->{img_nsfw} ? (id => 'nsfw_hid', style => $self->authPref('show_nsfw') ? 'display: block' : '') : ();
        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};
       end;
       if($v->{img_nsfw}) {
         p id => 'nsfw_show', $self->authPref('show_nsfw') ? (style => 'display: none') : ();
          txt mt('_vnpage_imgnsfw_msg');
          br; br;
          a href => '#', mt '_vnpage_imgnsfw_show';
          br; br;
          txt mt '_vnpage_imgnsfw_note';
         end;
       }
     }
    end 'div'; # /vnimg

    # 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}) {
       $v->{alias} =~ s/\n/, /g;
       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 mt '_vnlength_'.$v->{length}, 1;
       end;
     }
     my @links = (
       $v->{l_wp} ?      [ 'wp', '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',  'http://renai.us/game/%s.shtml', $v->{l_renai} ] : (),
     );
     if(@links) {
       Tr ++$i % 2 ? (class => 'odd') : ();
        td mt '_vnpage_links';
        td;
         for(@links) {
           a href => sprintf($_->[1], $_->[2]), mt "_vnpage_l_$_->[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 $v->{desc} ? bb2html $v->{desc} : '-';
       end;
      end;
     end;

    end 'table';
   end 'div';
   clearfloat;

   # tags
   my $t = $self->dbTagStats(vid => $v->{id}, sort => 'rating', reverse => 1, minrating => 0, results => 999);
   if(@$t) {
     div id => 'tagops';
      # NOTE: order of these links is hardcoded in JS
      a href => '#cont', lc mt '_tagcat_cont';
      a href => '#ero',  lc mt '_tagcat_ero';
      a href => '#tech', lc mt '_tagcat_tech';
      a href => '#', class => 'sec tsel', mt '_vnpage_tags_spoil0';
      a href => '#', 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 cat_%s %s', $_->{spoiler}, $_->{cat}, $_->{spoiler} > 0 ? '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 'div'; # /mainbox

  my $haschar = $self->dbVNHasChar($v->{id});
  if($haschar) {
    ul class => 'maintabs notfirst';
     li class => 'left '.(!$char ? ' tabselected' : ''); a href => "/v$v->{id}#main", name => 'main', mt '_vnpage_tab_main'; end;
     li class => 'left '.( $char ? ' tabselected' : ''); a href => "/v$v->{id}/chars#chars", name => 'chars', mt '_vnpage_tab_chars'; end;
    end;
  }

  if(!$char) {
    _releases($self, $v, $r);
    _stats($self, $v);
    _screenshots($self, $v, $r) if @{$v->{screenshots}};
  } else {
    _chars($self, $haschar, $v);
  }

  $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];

{'fraction_non_alphanumeric': 0.24276261373035565, 'fraction_numerical': 0.008602150537634409, 'mean_word_length': 2.3345284059569775, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 301, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7456267', 'n_tokens_mistral': 5005, 'n_tokens_neox': 4781, 'n_words': 1069}