summaryrefslogtreecommitdiff
path: root/lib/VNWeb/Chars/Page.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNWeb/Chars/Page.pm')
-rw-r--r--lib/VNWeb/Chars/Page.pm192
1 files changed, 125 insertions, 67 deletions
diff --git a/lib/VNWeb/Chars/Page.pm b/lib/VNWeb/Chars/Page.pm
index 8a9966ae..e6ffc7e7 100644
--- a/lib/VNWeb/Chars/Page.pm
+++ b/lib/VNWeb/Chars/Page.pm
@@ -7,27 +7,57 @@ use VNWeb::Images::Lib qw/image_ enrich_image_obj/;
sub enrich_seiyuu {
my($vid, @chars) = @_;
enrich seiyuu => id => cid => sub { sql '
- SELECT DISTINCT vs.cid, sa.id, sa.name, sa.original, vs.note
+ SELECT DISTINCT vs.cid, sa.id, sa.title, sa.sorttitle, vs.note
FROM vn_seiyuu vs
- JOIN staff_alias sa ON sa.aid = vs.aid
- WHERE vs.cid IN', $_, $vid ? ('AND vs.id =', \$vid) : (), '
- ORDER BY sa.name'
+ ', $vid ? () : ('JOIN vn v ON v.id = vs.id'), '
+ JOIN', staff_aliast, 'sa ON sa.aid = vs.aid
+ WHERE ', $vid ? ('vs.id =', \$vid) : ('NOT v.hidden'), 'AND vs.cid IN', $_, '
+ ORDER BY sa.sorttitle'
}, @chars;
}
+sub sql_trait_overrides {
+ sql '(
+ WITH RECURSIVE trait_overrides (tid, spoil, color, childs, lvl) AS (
+ SELECT tid, spoil, color, childs, 0 FROM users_prefs_traits WHERE id =', \auth->uid, '
+ UNION ALL
+ SELECT tp.id, x.spoil, x.color, true, lvl+1
+ FROM trait_overrides x
+ JOIN traits_parents tp ON tp.parent = x.tid
+ WHERE x.childs
+ ) SELECT DISTINCT ON(tid) tid, spoil, color FROM trait_overrides ORDER BY tid, lvl
+ )';
+}
sub enrich_item {
my($c) = @_;
enrich_image_obj image => $c;
- enrich_merge vid => 'SELECT id AS vid, title, original FROM vn WHERE id IN', $c->{vns};
- enrich_merge rid => 'SELECT id AS rid, title AS rtitle, original AS roriginal FROM releases WHERE id IN', grep $_->{rid}, $c->{vns}->@*;
- enrich_merge tid =>
- 'SELECT t.id AS tid, t.name, t.sexual, coalesce(g.id, t.id) AS group, coalesce(g.name, t.name) AS groupname, coalesce(g.order,0) AS order
- FROM traits t LEFT JOIN traits g ON t.group = g.id WHERE t.id IN', $c->{traits};
-
- $c->{vns} = [ sort { $a->{title} cmp $b->{title} || $a->{vid} <=> $b->{vid} || ($a->{rid}||999999) <=> ($b->{rid}||999999) } $c->{vns}->@* ];
+ enrich_merge vid => sql('SELECT id AS vid, title, sorttitle, c_released AS vn_released FROM', vnt, 'v WHERE id IN'), $c->{vns};
+ enrich_merge rid => sql('SELECT id AS rid, title AS rtitle, released AS rel_released FROM', releasest, 'r WHERE id IN'), grep $_->{rid}, $c->{vns}->@*;
+
+ # Even with trait overrides, we'll want to see the raw data in revision diffs,
+ # so fetch the raw spoil as a separate column and do filtering/processing later.
+ enrich_merge tid => sub { sql '
+ SELECT t.id AS tid, t.name, t.hidden, t.locked, t.applicable, t.sexual, x.spoil AS override, x.color
+ , coalesce(g.id, t.id) AS group, coalesce(g.name, t.name) AS groupname, coalesce(g.gorder,0) AS order
+ FROM traits t
+ LEFT JOIN traits g ON t.gid = g.id
+ LEFT JOIN', sql_trait_overrides(), 'x ON x.tid = t.id
+ WHERE t.id IN', $_
+ }, $c->{traits};
+
+ $c->{vns} = [ sort { $a->{vn_released} <=> $b->{vn_released} || ($a->{rel_released}||0) <=> ($b->{rel_released}||0)
+ || $a->{sorttitle} cmp $b->{sorttitle} || idcmp($a->{vid}, $b->{vid}) || idcmp($a->{rid}||'r999999', $b->{rid}||'r999999') } $c->{vns}->@* ];
$c->{traits} = [ sort { $a->{order} <=> $b->{order} || $a->{groupname} cmp $b->{groupname} || $a->{name} cmp $b->{name} } $c->{traits}->@* ];
+
+ $c->{quotes} = tuwf->dbAlli('
+ SELECT q.vid, q.id, q.score, q.quote,', sql_totime('q.added'), 'AS added, q.addedby
+ FROM quotes q
+ WHERE NOT q.hidden AND vid IN', [map $_->{vid}, $c->{vns}->@*], 'AND q.cid =', \$c->{id}, '
+ ORDER BY q.score DESC, q.quote
+ ');
+ enrich_merge id => sql('SELECT id, vote FROM quotes_votes WHERE uid =', \auth->uid, 'AND id IN'), $c->{quotes} if auth;
}
@@ -36,27 +66,29 @@ sub enrich_item {
sub fetch_chars {
my($vid, $where) = @_;
my $l = tuwf->dbAlli('
- SELECT id, name, original, alias, "desc", gender, spoil_gender, b_month, b_day, s_bust, s_waist, s_hip, height, weight, bloodt, cup_size, age, image
- FROM chars WHERE NOT hidden AND (', $where, ')
- ORDER BY name
+ SELECT id, title, alias, description, gender, spoil_gender, b_month, b_day, s_bust, s_waist, s_hip, height, weight, bloodt, cup_size, age, image
+ FROM', charst, 'c WHERE NOT hidden AND (', $where, ')
+ ORDER BY sorttitle
');
enrich vns => id => id => sub { sql '
- SELECT cv.id, cv.vid, cv.rid, cv.spoil, cv.role, v.title, v.original, r.title AS rtitle, r.original AS roriginal
+ SELECT cv.id, cv.vid, cv.rid, cv.spoil, cv.role, v.title, r.title AS rtitle
FROM chars_vns cv
- JOIN vn v ON v.id = cv.vid
- LEFT JOIN releases r ON r.id = cv.rid
+ JOIN', vnt, 'v ON v.id = cv.vid
+ LEFT JOIN', releasest, 'r ON r.id = cv.rid
WHERE cv.id IN', $_, $vid ? ('AND cv.vid =', \$vid) : (), '
- ORDER BY v.title, cv.vid, cv.rid NULLS LAST'
+ ORDER BY v.c_released, r.released, v.sorttitle, cv.vid, cv.rid NULLS LAST'
}, $l;
enrich traits => id => id => sub { sql '
- SELECT ct.id, ct.tid, ct.spoil, t.name, t.sexual, coalesce(g.id, t.id) AS group, coalesce(g.name, t.name) AS groupname, coalesce(g.order,0) AS order
+ SELECT ct.id, ct.tid, ct.spoil, x.spoil AS override, x.color, ct.lie, t.name, t.hidden, t.locked, t.sexual
+ , coalesce(g.id, t.id) AS group, coalesce(g.name, t.name) AS groupname, coalesce(g.gorder,0) AS order
FROM chars_traits ct
JOIN traits t ON t.id = ct.tid
- LEFT JOIN traits g ON t.group = g.id
- WHERE ct.id IN', $_, '
- ORDER BY g.order NULLS FIRST, coalesce(g.name, t.name), t.name'
+ LEFT JOIN traits g ON t.gid = g.id
+ LEFT JOIN', sql_trait_overrides(), 'x ON x.tid = ct.tid
+ WHERE x.spoil IS DISTINCT FROM 1+1+1 AND ct.id IN', $_, '
+ ORDER BY g.gorder NULLS FIRST, coalesce(g.name, t.name), t.name'
}, $l;
enrich_seiyuu $vid, $l;
@@ -67,40 +99,43 @@ sub fetch_chars {
sub _rev_ {
my($c) = @_;
- revision_ c => $c, \&enrich_item,
+ revision_ $c, \&enrich_item,
[ name => 'Name' ],
- [ original => 'Original name' ],
+ [ latin => 'Name (latin)' ],
[ alias => 'Aliases' ],
- [ desc => 'Description' ],
+ [ description=> 'Description' ],
[ gender => 'Sex', fmt => \%GENDER ],
[ spoil_gender=> 'Sex (spoiler)',fmt => \%GENDER ],
[ b_month => 'Birthday/month',empty => 0 ],
[ b_day => 'Birthday/day', empty => 0 ],
[ s_bust => 'Bust', empty => 0 ],
[ s_waist => 'Waist', empty => 0 ],
- [ s_hip => 'Hip', empty => 0 ],
+ [ s_hip => 'Hips', empty => 0 ],
[ height => 'Height', empty => 0 ],
[ weight => 'Weight', ],
[ bloodt => 'Blood type', fmt => \%BLOOD_TYPE ],
[ cup_size => 'Cup size', fmt => \%CUP_SIZE ],
[ age => 'Age', ],
[ main => 'Instance of', empty => 0, fmt => sub {
- my $c = tuwf->dbRowi('SELECT id, name, original FROM chars WHERE id =', \$_);
- a_ href => "/c$c->{id}", title => $c->{name}, "c$c->{id}"
+ my $c = tuwf->dbRowi('SELECT id, title FROM', charst, 'c WHERE id =', \$_);
+ a_ href => "/$c->{id}", title => $c->{title}[1], $c->{id}
} ],
[ main_spoil => 'Spoiler', fmt => sub { txt_ fmtspoil $_ } ],
[ image => 'Image', fmt => sub { image_ $_ } ],
[ vns => 'Visual novels', fmt => sub {
- a_ href => "/v$_->{vid}", title => $_->{original}||$_->{title}, "v$_->{vid}";
+ a_ href => "/$_->{vid}", tlang(@{$_->{title}}[0,1]), title => $_->{title}[1], $_->{vid};
if($_->{rid}) {
- txt_ ' ['; a_ href => "/r$_->{rid}", "r$_->{rid}"; txt_ ']';
+ txt_ ' ['; a_ href => "/$_->{rid}", $_->{rid}; txt_ ']';
}
txt_ " $CHAR_ROLE{$_->{role}}{txt} (".fmtspoil($_->{spoil}).')';
} ],
[ traits => 'Traits', fmt => sub {
- b_ class => 'grayedout', "$_->{groupname} / " if $_->{group} != $_->{tid};
- a_ href => "/i$_->{tid}", $_->{name};
- txt_ ' ('.fmtspoil($_->{spoil}).')';
+ small_ "$_->{groupname} / " if $_->{group} ne $_->{tid};
+ a_ href => "/$_->{tid}", $_->{name};
+ txt_ ' ('.fmtspoil($_->{spoil}).($_->{lie} ? ', lie':'').')';
+ b_ ' (awaiting moderation)' if $_->{hidden} && !$_->{locked};
+ b_ ' (trait deleted)' if $_->{hidden} && $_->{locked};
+ b_ ' (not applicable)' if !$_->{applicable};
} ],
}
@@ -110,23 +145,26 @@ sub chartable_ {
my($c, $link, $sep, $vn) = @_;
my $view = viewget;
+ my @visvns = grep $_->{spoil} <= $view->{spoilers}, $c->{vns}->@*;
+
div_ mkclass(chardetails => 1, charsep => $sep), sub {
- div_ class => 'charimg', sub { image_ $c->{image}, alt => $c->{name} };
+ div_ class => 'charimg', sub { image_ $c->{image}, alt => $c->{title}[1] };
table_ class => 'stripe', sub {
thead_ sub { tr_ sub { td_ colspan => 2, sub {
$link
- ? a_ href => "/c$c->{id}", style => 'margin-right: 10px; font-weight: bold', $c->{name}
- : b_ style => 'margin-right: 10px', $c->{name};
- b_ class => 'grayedout', style => 'margin-right: 10px', $c->{original} if $c->{original};
- abbr_ class => "icons gen $c->{gender}", title => $GENDER{$c->{gender}}, '' if $c->{gender} ne 'unknown';
+ ? a_ href => "/$c->{id}", style => 'margin-right: 10px; font-weight: bold', tlang($c->{title}[0], $c->{title}[1]), $c->{title}[1]
+ : span_ style => 'margin-right: 10px', tlang($c->{title}[0], $c->{title}[1]), $c->{title}[1];
+ small_ style => 'margin-right: 10px', tlang($c->{title}[2], $c->{title}[3]), $c->{title}[3] if $c->{title}[3] ne $c->{title}[1];
+ abbr_ class => "icon-gen-$c->{gender}", title => $GENDER{$c->{gender}}, '' if $c->{gender} ne 'unknown';
if($view->{spoilers} == 2 && defined $c->{spoil_gender}) {
txt_ '(';
- abbr_ class => "icons gen $c->{spoil_gender}", title => $GENDER{$c->{spoil_gender}}, '' if $c->{spoil_gender} ne 'unknown';
+ abbr_ class => "icon-gen-$c->{spoil_gender}", title => $GENDER{$c->{spoil_gender}}, '' if $c->{spoil_gender} ne 'unknown';
txt_ 'unknown' if $c->{spoil_gender} eq 'unknown';
spoil_ 2;
txt_ ')';
}
span_ $BLOOD_TYPE{$c->{bloodt}} if $c->{bloodt} ne 'unknown';
+ debug_ $c;
}}};
tr_ sub {
@@ -155,22 +193,28 @@ sub chartable_ {
} if defined $c->{age};
my @groups;
- for(grep $_->{spoil} <= $view->{spoilers} && (!$_->{sexual} || $view->{traits_sexual}), $c->{traits}->@*) {
- push @groups, $_ if !@groups || $groups[$#groups]{group} != $_->{group};
+ for(grep !$_->{hidden} && ($_->{override}//$_->{spoil}) <= $view->{spoilers} && (!$_->{sexual} || $view->{traits_sexual}), $c->{traits}->@*) {
+ push @groups, $_ if !@groups || $groups[$#groups]{group} ne $_->{group};
push $groups[$#groups]{traits}->@*, $_;
}
- tr_ class => "trait_group_i$_->{group}", sub {
- td_ class => 'key', sub { a_ href => "/i$_->{group}", $_->{groupname} };
- td_ sub { join_ ', ', sub { a_ href => "/i$_->{tid}", $_->{name}; spoil_ $_->{spoil} }, $_->{traits}->@* };
+ tr_ class => "trait_group_$_->{group}", sub {
+ td_ class => 'key', sub { a_ href => "/$_->{group}", $_->{groupname} };
+ td_ sub { join_ ', ', sub {
+ a_ href => "/$_->{tid}", mkclass(
+ $_->{color} ? ($_->{color}, $_->{color} =~ /standout|grayedout/ ? 1 : 0) : (),
+ lie => $_->{lie} && (($_->{override}//1) <= 0 || $view->{spoilers} >= 2),
+ ), ($_->{color}//'') =~ /^#/ ? (style => "color: $_->{color}") : (),
+ $_->{name};
+ spoil_ $_->{spoil};
+ }, $_->{traits}->@* };
} for @groups;
- my @visvns = grep $_->{spoil} <= $view->{spoilers}, $c->{vns}->@*;
tr_ sub {
td_ class => 'key', $vn ? 'Releases' : 'Visual novels';
td_ sub {
my @vns;
for(@visvns) {
- push @vns, $_ if !@vns || $vns[$#vns]{vid} != $_->{vid};
+ push @vns, $_ if !@vns || $vns[$#vns]{vid} ne $_->{vid};
push $vns[$#vns]{rels}->@*, $_;
}
join_ \&br_, sub {
@@ -178,18 +222,18 @@ sub chartable_ {
# Just a VN link, no releases
if(!$vn && $v->{rels}->@* == 1 && !$v->{rels}[0]{rid}) {
txt_ $CHAR_ROLE{$v->{role}}{txt}.' - ';
- a_ href => "/v$v->{vid}", title => $v->{original}||$v->{title}, $v->{title};
+ a_ href => "/$v->{vid}", tattr $v;
spoil_ $v->{spoil};
# With releases
} else {
- a_ href => "/v$v->{vid}", title => $v->{original}||$v->{title}, $v->{title} if !$vn;
+ a_ href => "/$v->{vid}", tattr $v if !$vn;
br_ if !$vn;
join_ \&br_, sub {
- b_ class => 'grayedout', '> ';
+ small_ '> ';
txt_ $CHAR_ROLE{$_->{role}}{txt}.' - ';
if($_->{rid}) {
- b_ class => 'grayedout', "r$_->{rid}:";
- a_ href => "/r$_->{rid}", title => $_->{roriginal}||$_->{rtitle}, $_->{rtitle};
+ small_ "$_->{rid}:";
+ a_ href => "/$_->{rid}", tattr $_->{rtitle};
} else {
txt_ 'All other releases';
}
@@ -204,7 +248,7 @@ sub chartable_ {
td_ class => 'key', 'Voiced by';
td_ sub {
join_ \&br_, sub {
- a_ href => "/s$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", tattr $_;
txt_ " ($_->{note})" if $_->{note};
}, $c->{seiyuu}->@*;
};
@@ -213,17 +257,30 @@ sub chartable_ {
tr_ class => 'nostripe', sub {
td_ colspan => 2, class => 'chardesc', sub {
h2_ 'Description';
- p_ sub { lit_ bb_format $c->{desc}, replacespoil => $view->{spoilers} != 2, keepspoil => $view->{spoilers} == 2 };
+ p_ sub { lit_ bb_format $c->{description}, replacespoil => $view->{spoilers} != 2, keepspoil => $view->{spoilers} == 2 };
};
- } if $c->{desc};
+ } if $c->{description};
+
};
};
clearfloat_;
+
+ my %visvns = map +($_->{vid}, 1), @visvns;
+ my @quotes = grep $visvns{$_->{vid}}, $c->{quotes}->@*;
+ div_ class => 'charquotes', sub {
+ h2_ 'Quotes';
+ table_ sub {
+ tr_ sub {
+ td_ sub { VNWeb::VN::Quotes::votething_($_) };
+ td_ $_->{quote};
+ } for @quotes;
+ };
+ } if @quotes;
}
TUWF::get qr{/$RE{crev}} => sub {
- my $c = db_entry c => tuwf->capture('id'), tuwf->capture('rev');
+ my $c = db_entry tuwf->captures('id','rev');
return tuwf->resNotFound if !$c;
enrich_item $c;
@@ -241,38 +298,39 @@ TUWF::get qr{/$RE{crev}} => sub {
my $max_spoil = max(
$inst_maxspoil||0,
- (map $_->{spoil}, $c->{traits}->@*),
+ (map $_->{override}//($_->{lie}?2:$_->{spoil}), grep !$_->{hidden} && !(($_->{override}//0) == 3), $c->{traits}->@*),
(map $_->{spoil}, $c->{vns}->@*),
defined $c->{spoil_gender} ? 2 : 0,
- $c->{desc} =~ /\[spoiler\]/i ? 2 : 0, # crude
+ $c->{description} =~ /\[spoiler\]/i ? 2 : 0, # crude
);
# Only display the sexual traits toggle when there are sexual traits within the current spoiler level.
- my $has_sex = grep $_->{spoil} <= $view->{spoilers} && $_->{sexual}, map $_->{traits}->@*, $c, @$inst;
+ my $has_sex = grep !$_->{hidden} && $_->{sexual} && ($_->{override}//$_->{spoil}) <= $view->{spoilers}, map $_->{traits}->@*, $c, @$inst;
- framework_ title => $c->{name}, index => !tuwf->capture('rev'), type => 'c', dbobj => $c, hiddenmsg => 1,
+ $c->{title} = titleprefs_swap tuwf->dbVali('SELECT c_lang FROM chars WHERE id =', \$c->{id}), @{$c}{qw/ name latin /};
+ framework_ title => $c->{title}[1], index => !tuwf->capture('rev'), dbobj => $c, hiddenmsg => 1,
og => {
- description => bb_format($c->{desc}, text => 1),
- image => $c->{image} && $c->{image}{votecount} && !$c->{image}{sexual} && !$c->{image}{violence} ? tuwf->imgurl($c->{image}{id}) : undef,
+ description => bb_format($c->{description}, text => 1),
+ image => $c->{image} && $c->{image}{votecount} && !$c->{image}{sexual} && !$c->{image}{violence} ? imgurl($c->{image}{id}) : undef,
},
sub {
_rev_ $c if tuwf->capture('rev');
- div_ class => 'mainbox', sub {
- itemmsg_ c => $c;
- h1_ sub { txt_ $c->{name}; debug_ $c };
- h2_ class => 'alttitle', $c->{original} if length $c->{original};
+ article_ sub {
+ itemmsg_ $c;
+ h1_ tlang(@{$c->{title}}[0,1]), $c->{title}[1];
+ h2_ class => 'alttitle', tlang(@{$c->{title}}[2,3]), $c->{title}[3] if $c->{title}[3] && $c->{title}[3] ne $c->{title}[1];
p_ class => 'chardetailopts', sub {
if($max_spoil) {
a_ mkclass(checked => $view->{spoilers} == 0), href => '?view='.viewset(spoilers=>0, traits_sexual => $view->{traits_sexual}), 'Hide spoilers';
a_ mkclass(checked => $view->{spoilers} == 1), href => '?view='.viewset(spoilers=>1, traits_sexual => $view->{traits_sexual}), 'Show minor spoilers';
a_ mkclass(standout =>$view->{spoilers} == 2), href => '?view='.viewset(spoilers=>2, traits_sexual => $view->{traits_sexual}), 'Spoil me!' if $max_spoil == 2;
}
- b_ class => 'grayedout', ' | ' if $has_sex && $max_spoil;
+ small_ ' | ' if $has_sex && $max_spoil;
a_ mkclass(checked => $view->{traits_sexual}), href => '?view='.viewset(spoilers => $view->{spoilers}, traits_sexual=>!$view->{traits_sexual}), 'Show sexual traits' if $has_sex;
};
chartable_ $c;
};
- div_ class => 'mainbox', sub {
+ article_ sub {
h1_ 'Other instances';
chartable_ $_, 1, $_ != $inst->[0] for @$inst;
} if @$inst;