From 5d4ea45a86d8316aeae789f614057795715d9e67 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Fri, 27 May 2022 08:35:26 +0200 Subject: Staff editions As discussed in https://vndb.org/t13027 and from https://vndb.org/t6138.327 onwards. --- lib/VNDB/Types.pm | 5 ++- lib/VNWeb/Staff/Page.pm | 7 ++-- lib/VNWeb/User/Edit.pm | 11 ++++-- lib/VNWeb/VN/Edit.pm | 15 +++++++- lib/VNWeb/VN/Page.pm | 94 ++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 105 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/VNDB/Types.pm b/lib/VNDB/Types.pm index 684c3602..9f61fe2c 100644 --- a/lib/VNDB/Types.pm +++ b/lib/VNDB/Types.pm @@ -165,11 +165,14 @@ hash PRODUCER_TYPE => # SQL: ENUM credit_type hash CREDIT_TYPE => scenario => 'Scenario', + director => 'Director', chardesign => 'Character design', art => 'Artist', music => 'Composer', songs => 'Vocals', - director => 'Director', + translator => 'Translator', + editor => 'Editor', + qa => 'Quality assurance', staff => 'Staff'; diff --git a/lib/VNWeb/Staff/Page.pm b/lib/VNWeb/Staff/Page.pm index 8d143fcc..d1ee5bf3 100644 --- a/lib/VNWeb/Staff/Page.pm +++ b/lib/VNWeb/Staff/Page.pm @@ -74,12 +74,13 @@ sub _roles_ { my %alias = map +($_->{aid}, $_), $s->{alias}->@*; my $roles = tuwf->dbAlli(q{ - SELECT v.id, vs.aid, vs.role, vs.note, v.c_released, v.title, v.alttitle + SELECT v.id, vs.aid, vs.role, vs.note, ve.name, ve.official, v.c_released, v.title, v.alttitle FROM vn_staff vs JOIN vnt v ON v.id = vs.id + LEFT JOIN vn_editions ve ON ve.id = vs.id AND ve.eid = vs.eid WHERE vs.aid IN}, [ keys %alias ], q{ AND NOT v.hidden - ORDER BY v.c_released ASC, v.title ASC, vs.role ASC + ORDER BY v.c_released ASC, v.title ASC, ve.lang NULLS FIRST, ve.name NULLS FIRST, vs.role ASC }); return if !@$roles; enrich_ulists_widget $roles; @@ -101,6 +102,8 @@ sub _roles_ { td_ class => 'tc_ulist', sub { ulists_widget_ $v if !$vns{$v->{id}}++ } if auth; td_ class => 'tc1', sub { a_ href => "/$v->{id}", title => $v->{alttitle}||$v->{title}, shorten $v->{title}, 60; + txt_ " $v->{name}" if $v->{name} && $v->{official}; + b_ class => 'grayedout', " $v->{name}" if $v->{name} && !$v->{official}; }; td_ class => 'tc2', sub { rdate_ $v->{c_released} }; td_ class => 'tc3', $CREDIT_TYPE{$v->{role}}; diff --git a/lib/VNWeb/User/Edit.pm b/lib/VNWeb/User/Edit.pm index cf544179..c33f04e7 100644 --- a/lib/VNWeb/User/Edit.pm +++ b/lib/VNWeb/User/Edit.pm @@ -44,6 +44,9 @@ my $FORM = { vnrel_langs => { type => 'array', values => { enum => \%LANGUAGE }, sort => 'str', unique => 1 }, vnrel_olang => { anybool => 1 }, vnrel_mtl => { anybool => 1 }, + staffed_langs => { type => 'array', values => { enum => \%LANGUAGE }, sort => 'str', unique => 1 }, + staffed_olang => { anybool => 1 }, + staffed_unoff => { anybool => 1 }, skin => { enum => skins }, customcss => { required => 0, default => '', maxlength => 2000 }, @@ -93,7 +96,8 @@ TUWF::get qr{/$RE{uid}/edit}, sub { $u->{prefs} = $u->{id} eq auth->uid || auth->permUsermod ? tuwf->dbRowi( 'SELECT max_sexual, max_violence, traits_sexual, tags_all, tags_cont, tags_ero, tags_tech, prodrelexpand - , spoilers, vnrel_langs::text[], vnrel_olang, vnrel_mtl, skin, customcss, title_langs, alttitle_langs + , vnrel_langs::text[], vnrel_olang, vnrel_mtl, staffed_langs::text[], staffed_olang, staffed_unoff + , spoilers, skin, customcss, title_langs, alttitle_langs , nodistract_noads, nodistract_nofancy, support_enabled, uniname, pubskin_enabled FROM users u JOIN users_prefs up ON up.id = u.id WHERE u.id =', \$u->{id} ) : undef; @@ -101,6 +105,7 @@ TUWF::get qr{/$RE{uid}/edit}, sub { $u->{prefs}{email} = _getmail $u->{id}; $u->{prefs}{skin} ||= config->{skin_default}; $u->{prefs}{vnrel_langs} ||= [ keys %LANGUAGE ]; + $u->{prefs}{staffed_langs} ||= [ keys %LANGUAGE ]; $u->{prefs}{title_langs} = langpref_parse($u->{prefs}{title_langs}) // $DEFAULT_TITLE_LANGS; $u->{prefs}{alttitle_langs} = langpref_parse($u->{prefs}{alttitle_langs}) // $DEFAULT_ALTTITLE_LANGS; $u->{prefs}{traits} = tuwf->dbAlli('SELECT u.tid, t.name, g.name AS "group" FROM users_traits u JOIN traits t ON t.id = u.tid LEFT JOIN traits g ON g.id = t.group WHERE u.id =', \$u->{id}, 'ORDER BY g.order, t.name'); @@ -143,10 +148,12 @@ elm_api UserEdit => $FORM_OUT, $FORM_IN, sub { $p->{title_langs} = undef if $p->{title_langs} && ($p->{title_langs} eq langpref_fmt($DEFAULT_TITLE_LANGS) || $p->{title_langs} eq '[]'); $p->{alttitle_langs} = undef if $p->{alttitle_langs} && $p->{alttitle_langs} eq langpref_fmt $DEFAULT_ALTTITLE_LANGS; $p->{vnrel_langs} = $p->{vnrel_langs}->@* == keys %LANGUAGE ? undef : '{'.join(',',$p->{vnrel_langs}->@*).'}'; + $p->{staffed_langs} = $p->{staffed_langs}->@* == keys %LANGUAGE ? undef : '{'.join(',',$p->{staffed_langs}->@*).'}'; $set{$_} = $p->{$_} for qw/nodistract_noads nodistract_nofancy support_enabled uniname pubskin_enabled/; $setp{$_} = $p->{$_} for qw/ max_sexual max_violence traits_sexual tags_all tags_cont tags_ero tags_tech prodrelexpand - vnrel_langs vnrel_olang vnrel_mtl spoilers skin customcss title_langs alttitle_langs + vnrel_langs vnrel_olang vnrel_mtl staffed_langs staffed_olang staffed_unoff + spoilers skin customcss title_langs alttitle_langs /; tuwf->dbExeci('DELETE FROM users_traits WHERE id =', \$data->{id}); tuwf->dbExeci('INSERT INTO users_traits', { id => $data->{id}, tid => $_->{tid} }) for $p->{traits}->@*; diff --git a/lib/VNWeb/VN/Edit.pm b/lib/VNWeb/VN/Edit.pm index 0cacbb0f..09608ef7 100644 --- a/lib/VNWeb/VN/Edit.pm +++ b/lib/VNWeb/VN/Edit.pm @@ -33,8 +33,15 @@ my $FORM = { } }, image => { required => 0, vndbid => 'cv' }, image_info => { _when => 'out', required => 0, type => 'hash', keys => $VNWeb::Elm::apis{ImageResult}[0]{aoh} }, - staff => { sort_keys => ['aid','role'], aoh => { + editions => { sort_keys => 'eid', aoh => { + eid => { uint => 1, max => 500 }, + lang => { required => 0, language => 1 }, + name => {}, + official => { anybool => 1 }, + } }, + staff => { sort_keys => ['aid','eid','role'], aoh => { aid => { id => 1 }, + eid => { required => 0, uint => 1 }, role => { enum => \%CREDIT_TYPE }, note => { required => 0, default => '', maxlength => 250 }, id => { _when => 'out', vndbid => 's' }, @@ -100,6 +107,8 @@ TUWF::get qr{/$RE{vrev}/edit} => sub { $e->{staff} = [ grep $_->{id}, $e->{staff}->@* ]; $e->{seiyuu} = [ grep $_->{id}, $e->{seiyuu}->@* ]; + $e->{editions} = [ sort { ($a->{lang}||'') cmp ($b->{lang}||'') || $b->{official} cmp $a->{official} || $a->{name} cmp $b->{name} } $e->{editions}->@* ]; + $e->{releases} = releases_by_vn $e->{id}; $e->{chars} = tuwf->dbAlli(' @@ -148,6 +157,10 @@ elm_api VNEdit => $FORM_OUT, $FORM_IN, sub { validate_dbid 'SELECT aid FROM staff_alias WHERE aid IN', map $_->{aid}, $data->{staff}->@*; validate_dbid 'SELECT aid FROM staff_alias WHERE aid IN', map $_->{aid}, $data->{seiyuu}->@*; + # Drop unused staff editions + my %editions = map defined $_->{eid} ? +($_->{eid},1) : (), $data->{staff}->@*; + $data->{editions} = [ grep $editions{$_->{eid}}, $data->{editions}->@* ]; + $data->{relations} = [] if $data->{hidden}; validate_dbid 'SELECT id FROM vn WHERE id IN', map $_->{vid}, $data->{relations}->@*; die "Relation with self" if grep $_->{vid} eq $e->{id}, $data->{relations}->@*; diff --git a/lib/VNWeb/VN/Page.pm b/lib/VNWeb/VN/Page.pm index 77e4883b..e140cb59 100644 --- a/lib/VNWeb/VN/Page.pm +++ b/lib/VNWeb/VN/Page.pm @@ -59,7 +59,8 @@ sub enrich_item { $v->{relations} = [ sort { idcmp($a->{vid}, $b->{vid}) } $v->{relations}->@* ]; $v->{anime} = [ sort { $a->{aid} <=> $b->{aid} } $v->{anime}->@* ]; - $v->{staff} = [ sort { $a->{aid} <=> $b->{aid} || $a->{role} cmp $b->{role} } $v->{staff}->@* ]; + $v->{editions} = [ sort { ($a->{lang}||'') cmp ($b->{lang}||'') || $b->{official} cmp $a->{official} || $a->{name} cmp $b->{name} } $v->{editions}->@* ]; + $v->{staff} = [ sort { ($a->{eid}//-1) <=> ($b->{eid}//-1) || $a->{aid} <=> $b->{aid} || $a->{role} cmp $b->{role} } $v->{staff}->@* ]; $v->{seiyuu} = [ sort { $a->{aid} <=> $b->{aid} || idcmp($a->{cid}, $b->{cid}) || $a->{note} cmp $b->{note} } $v->{seiyuu}->@* ]; $v->{screenshots} = [ sort { idcmp($a->{scr}{id}, $b->{scr}{id}) } $v->{screenshots}->@* ]; } @@ -75,6 +76,25 @@ sub og { } +sub prefs { + state $default = { + vnrel_langs => \%LANGUAGE, vnrel_olang => 1, vnrel_mtl => 0, + staffed_langs => \%LANGUAGE, staffed_olang => 1, staffed_unoff => 0, + }; + tuwf->req->{vnpage_prefs} //= auth ? do { + my $v = tuwf->dbRowi(' + SELECT vnrel_langs::text[], vnrel_olang, vnrel_mtl + , staffed_langs::text[], staffed_olang, staffed_unoff + FROM users_prefs + WHERE id =', \auth->uid + ); + $v->{vnrel_langs} = $v->{vnrel_langs} ? { map +($_,1), $v->{langs}->@* } : \%LANGUAGE; + $v->{staffed_langs} = $v->{staffed_langs} ? { map +($_,1), $v->{langs}->@* } : \%LANGUAGE; + $v + } : $default; +} + + # The voting and review options are hidden if nothing has been released yet. sub canvote { my($v) = @_; @@ -96,7 +116,15 @@ sub rev_ { [ desc => 'Description' ], [ devstatus => 'Development status',fmt => \%DEVSTATUS ], [ length => 'Length', fmt => \%VN_LENGTH ], + [ editions => 'Editions', fmt => sub { + abbr_ class => "icons lang $_->{lang}", title => $LANGUAGE{$_->{lang}}, '' if $_->{lang}; + txt_ $_->{name}; + b_ class => 'grayedout', ' (unofficial)' if !$_->{official}; + }], [ staff => 'Credits', fmt => sub { + my $eid = $_->{eid}; + my $e = defined $eid && (grep $eid == $_->{eid}, $_[0]{editions}->@*)[0]; + txt_ "[$e->{name}] " if $e; a_ href => "/$_->{sid}", title => $_->{original}||$_->{name}, $_->{name} if $_->{sid}; b_ class => 'grayedout', '[removed alias]' if !$_->{sid}; txt_ " [$CREDIT_TYPE{$_->{role}}]"; @@ -498,8 +526,6 @@ sub tabs_ { sub releases_ { my($v) = @_; - # TODO: Organize a long list of releases a bit better somehow? Collapsable language sections? - enrich_release $v->{releases}; $v->{releases} = sort_releases $v->{releases}; @@ -512,18 +538,13 @@ sub releases_ { } $langrel{$_} = min map $_->{released}, $lang{$_}->@* for keys %lang; my @lang = sort { $langrel{$a} <=> $langrel{$b} || ($b eq $v->{olang}) cmp ($a eq $v->{olang}) || $a cmp $b } keys %lang; - - my $pref = auth ? do { - my $v = tuwf->dbRowi('SELECT vnrel_langs::text[] AS langs, vnrel_olang AS olang, vnrel_mtl AS mtl FROM users_prefs WHERE id =', \auth->uid); - $v->{langs} = $v->{langs} ? { map +($_,1), $v->{langs}->@* } : \%LANGUAGE; - $v - } : { langs => \%LANGUAGE, olang => 1, mtl => 0 }; + my $pref = prefs; my sub lang_ { my($lang) = @_; my $ropt = { id => $lang, lang => $lang }; my $mtl = $langmtl{$lang}; - my $open = ($pref->{olang} && $lang eq $v->{olang} && !$mtl) || ($pref->{langs}{$lang} && (!$mtl || $pref->{mtl})); + my $open = ($pref->{vnrel_olang} && $lang eq $v->{olang} && !$mtl) || ($pref->{vnrel_langs}{$lang} && (!$mtl || $pref->{vnrel_mtl})); details_ open => $open?'open':undef, sub { summary_ $mtl ? (class => 'mtl') : (), sub { abbr_ class => "icons lang $lang".($mtl?' mtl':''), title => $LANGUAGE{$lang}, ''; @@ -547,8 +568,8 @@ sub releases_ { } -sub staff_ { - my($v) = @_; +sub staff_cols_ { + my($lst) = @_; # XXX: The staff listing is included in the page 3 times, for 3 different # layouts. A better approach to get the same layout is to add the boxes to @@ -560,7 +581,7 @@ sub staff_ { # Step 1: Get a list of 'boxes'; Each 'box' represents a role with a list of staff entries. # @boxes = [ $height, $roleimp, $html ] my %roles; - push $roles{$_->{role}}->@*, $_ for grep $_->{sid}, $v->{staff}->@*; + push $roles{$_->{role}}->@*, $_ for grep $_->{sid}, @$lst; my $i=0; my @boxes = sort { $b->[0] <=> $a->[0] || $a->[1] <=> $b->[1] } @@ -569,7 +590,7 @@ sub staff_ { li_ class => 'vnstaff_head', $CREDIT_TYPE{$_}; li_ sub { a_ href => "/$_->{sid}", title => $_->{original}||$_->{name}, $_->{name}; - b_ title => $_->{note}, class => 'grayedout', $_->{note} if $_->{note}; + b_ class => 'grayedout', $_->{note} if $_->{note}; } for sort { $a->{name} cmp $b->{name} } $roles{$_}->@*; } ], grep $roles{$_}, keys %CREDIT_TYPE; @@ -591,14 +612,45 @@ sub staff_ { @$c = sort { $a->[1] <=> $b->[1] } @$c; } - div_ class => 'mainbox', id => 'staff', 'data-mainbox-summarize' => 200, sub { + div_ class => sprintf('vnstaff-%d', scalar @$_), sub { + ul_ sub { + lit_ $_->[2] for $_->[2]->@*; + } for @$_ + } for @cols; +} + + +sub staff_ { + my($v) = @_; + return if !$v->{staff}->@*; + + my %staff; + push $staff{ $_->{eid} // '' }->@*, $_ for $v->{staff}->@*; + my $pref = prefs; + + div_ class => 'mainbox vnstaff', id => 'staff', sub { h1_ 'Staff'; - div_ class => sprintf('vnstaff vnstaff-%d', scalar @$_), sub { - ul_ sub { - lit_ $_->[2] for $_->[2]->@*; - } for @$_ - } for @cols; - } if $v->{staff}->@*; + if (!$v->{editions}->@*) { + staff_cols_ $v->{staff}; + return; + } + for my $e (undef, $v->{editions}->@*) { + my $lst = $staff{ $e ? $e->{eid} : '' }; + next if !$lst; + my $lang = ($e && $e->{lang}) || $v->{olang}; + my $unoff = $e && !$e->{official}; + my $open = ($pref->{staffed_olang} && !$e) || ($pref->{staffed_langs}{$lang} && (!$unoff || $pref->{staffed_mtl})); + details_ open => $open?'open':undef, sub { + summary_ sub { + abbr_ class => "icons lang $e->{lang}", title => $LANGUAGE{$e->{lang}}, '' if $e && $e->{lang}; + txt_ 'Original edition' if !$e; + txt_ $e->{name} if $e; + b_ class => 'grayedout', ' (unofficial)' if $unoff; + }; + staff_cols_ $lst; + }; + } + }; } -- cgit v1.2.3