summaryrefslogtreecommitdiff
path: root/lib/VNWeb
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2020-06-09 13:08:39 +0200
committerYorhel <git@yorhel.nl>2020-06-12 16:12:14 +0200
commit3c0aa2b062738c04c43be663e88346ef8723afe2 (patch)
treecfe78c0a7cfa40990854d7860e85c5ef6163c704 /lib/VNWeb
parent4bc9f9671ac83a4dfe8f3f177b0f61fbc2a8f19f (diff)
v2rw: Convert producer pages & consolidate release row HTML
The release listing on producer pages now uses the same HTML as on VN pages, so it comes with the same information & features. Unfortunately, it also comes with the same messiness... The page is kind of large and slow for producers with lots of releases, not sure what to do with that.
Diffstat (limited to 'lib/VNWeb')
-rw-r--r--lib/VNWeb/Producers/Page.pm174
-rw-r--r--lib/VNWeb/Releases/Lib.pm68
-rw-r--r--lib/VNWeb/VN/Page.pm59
3 files changed, 245 insertions, 56 deletions
diff --git a/lib/VNWeb/Producers/Page.pm b/lib/VNWeb/Producers/Page.pm
new file mode 100644
index 00000000..2ccf3849
--- /dev/null
+++ b/lib/VNWeb/Producers/Page.pm
@@ -0,0 +1,174 @@
+package VNWeb::Producers::Page;
+
+use VNWeb::Prelude;
+use VNWeb::Releases::Lib;
+
+
+sub enrich_item {
+ my($p) = @_;
+ enrich_extlinks p => $p;
+ enrich_merge pid => 'SELECT id AS pid, name, original FROM producers WHERE id IN', $p->{relations};
+ $p->{relations} = [ sort { $a->{name} cmp $b->{name} || $a->{pid} <=> $b->{pid} } $p->{relations}->@* ];
+}
+
+
+sub rev_ {
+ my($p) = @_;
+ revision_ p => $p, \&enrich_item,
+ [ name => 'Name' ],
+ [ original => 'Original name' ],
+ [ alias => 'Aliases' ],
+ [ desc => 'Description' ],
+ [ type => 'Type', fmt => \%PRODUCER_TYPE ],
+ [ lang => 'Language', fmt => \%LANGUAGE ],
+ [ relations => 'Relations', fmt => sub {
+ txt_ $PRODUCER_RELATION{$_->{relation}}{txt}.': ';
+ a_ href => "/p$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
+ } ],
+ revision_extlinks 'p'
+}
+
+
+sub info_ {
+ my($p) = @_;
+ h1_ $p->{name};
+ h2_ class => 'alttitle', lang => $p->{lang}, $p->{original} if length $p->{original};
+
+ p_ class => 'center', sub {
+ txt_ $PRODUCER_TYPE{$p->{type}};
+ br_;
+ txt_ "Primary language: $LANGUAGE{$p->{lang}}";
+ if(length $p->{alias}) {
+ br_;
+ txt_ 'a.k.a. ';
+ txt_ $p->{alias} =~ s/\n/, /gr;
+ }
+ br_ if $p->{extlinks}->@*;
+ join_ ' - ', sub { a_ href => $_->[1], $_->[0] }, $p->{extlinks}->@*;
+ };
+
+ p_ class => 'center', sub {
+ my %rel;
+ push $rel{$_->{relation}}->@*, $_ for $p->{relations}->@*;
+ br_;
+ join_ \&br_, sub {
+ txt_ $PRODUCER_RELATION{$_}{txt}.': ';
+ join_ ', ', sub {
+ a_ href => "/p$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
+ }, $rel{$_}->@*;
+ }, grep $rel{$_}, keys %PRODUCER_RELATION;
+ } if $p->{relations}->@*;
+
+ p_ class => 'description', sub { lit_ bb2html $p->{desc} } if length $p->{desc};
+}
+
+
+sub rel_ {
+ my($p) = @_;
+
+ my $r = tuwf->dbAlli('
+ SELECT r.id, r.type, r.patch, r.released, r.gtin, rp.publisher, rp.developer, ', sql_extlinks(r => 'r.'), '
+ FROM releases r
+ JOIN releases_producers rp ON rp.id = r.id
+ WHERE rp.pid =', \$p->{id}, ' AND NOT r.hidden
+ ORDER BY r.released, r.id
+ ');
+ enrich_extlinks r => $r;
+ enrich_release $r;
+ enrich vn => id => rid => sub { sql '
+ SELECT rv.id as rid, v.id, v.title, v.original
+ FROM vn v
+ JOIN releases_vn rv ON rv.vid = v.id
+ WHERE NOT v.hidden AND rv.id IN', $_, '
+ ORDER BY v.title
+ '}, $r;
+
+ my(%vn, @vn);
+ for my $rel (@$r) {
+ for ($rel->{vn}->@*) {
+ push @vn, $_ if !$vn{$_->{id}};
+ push $vn{$_->{id}}->@*, $rel;
+ }
+ }
+
+ h1_ 'Releases';
+ debug_ $r;
+ table_ class => 'releases', sub {
+ for my $v (@vn) {
+ tr_ class => 'vn', sub {
+ # TODO: VN list status & management
+ td_ colspan => 8, sub {
+ a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, $v->{title};
+ };
+ release_row_ $_, $v->{id}, 1 for $vn{$v->{id}}->@*;
+ };
+ }
+ } if @$r;
+ p_ 'This producer has no releases in the database.' if !@$r;
+}
+
+
+sub vns_ {
+ my($p) = @_;
+ my $v = tuwf->dbAlli(q{
+ SELECT v.id, v.title, v.original, rels.developer, rels.publisher, rels.released
+ FROM vn v
+ JOIN (
+ SELECT rv.vid, bool_or(rp.developer), bool_or(rp.publisher)
+ , COALESCE(MIN(r.released) FILTER(WHERE r.type <> 'trial'), MIN(r.released))
+ FROM releases_vn rv
+ JOIN releases r ON r.id = rv.id
+ JOIN releases_producers rp ON rp.id = rv.id
+ WHERE NOT r.hidden AND rp.pid =}, \$p->{id}, '
+ GROUP BY rv.vid
+ ) rels(vid, developer, publisher, released) ON rels.vid = v.id
+ WHERE NOT v.hidden
+ ORDER BY rels.released
+ ');
+
+ h1_ 'Visual Novels';
+ debug_ $v;
+ # TODO: Perhaps something more table-like, also showing languages, platforms & VN list status
+ ul_ class => 'prodvns', sub {
+ li_ sub {
+ span_ sub { rdate_ $_->{released} };
+ a_ href => "/v$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
+ span_ join ' & ',
+ $_->{publisher} ? 'Publisher' : (),
+ $_->{developer} ? 'Developer' : ();
+ } for @$v;
+ };
+ p_ 'This producer has no releases in the database.' if !@$v;
+}
+
+
+TUWF::get qr{/$RE{prev}(?:/(?<tab>vn|rel))?}, sub {
+ my $p = db_entry p => tuwf->capture('id'), tuwf->capture('rev');
+ return tuwf->resNotFound if !$p;
+ enrich_item $p;
+
+ my $pref = tuwf->reqCookie('prodrelexpand') ? 'vn' : 'rel';
+ my $tab = tuwf->capture('tab') || $pref;
+ tuwf->resCookie(prodrelexpand => $tab eq 'vn' ? 1 : undef) if $tab && $tab ne $pref;
+ $tab = 'rel' if !$tab;
+
+ framework_ title => $p->{name}, index => !tuwf->capture('rev'), type => 'p', dbobj => $p, hiddenmsg => 1,
+ og => {
+ title => $p->{name},
+ description => bb2text($p->{desc}),
+ },
+ sub {
+ rev_ $p if tuwf->capture('rev');
+ div_ class => 'mainbox', sub { info_ $p };
+ div_ class => 'maintabs right', sub {
+ ul_ sub {
+ li_ mkclass(tabselected => $tab eq 'vn'), sub { a_ href => "/p$p->{id}/vn", 'Visual Novels' };
+ li_ mkclass(tabselected => $tab eq 'rel'), sub { a_ href => "/p$p->{id}/rel", 'Releases' };
+ };
+ };
+ div_ class => 'mainbox', sub { rel_ $p } if $tab eq 'rel';
+ div_ class => 'mainbox', sub { vns_ $p } if $tab eq 'vn';
+ }
+};
+
+1;
diff --git a/lib/VNWeb/Releases/Lib.pm b/lib/VNWeb/Releases/Lib.pm
index 29042c56..de25258a 100644
--- a/lib/VNWeb/Releases/Lib.pm
+++ b/lib/VNWeb/Releases/Lib.pm
@@ -3,10 +3,21 @@ package VNWeb::Releases::Lib;
use VNWeb::Prelude;
use Exporter 'import';
-our @EXPORT = qw/release_extlinks_/;
+our @EXPORT = qw/enrich_release release_row_/;
+
+
+# Enrich a list of releases so that it's suitable for release_row_().
+# Assumption: Each release already has id, type, patch, released, gtin and enrich_extlinks().
+sub enrich_release {
+ my($r) = @_;
+ enrich_merge id => 'SELECT id, title, original, notes, minage, freeware, doujin, resolution, voiced, ani_story, ani_ero, uncensored FROM releases WHERE id IN', $r;
+ enrich_merge id => sql('SELECT rid as id, status as rlist_status FROM rlists WHERE uid =', \auth->uid, 'AND rid IN'), $r if auth;
+ enrich_flatten lang => id => id => sub { sql 'SELECT id, lang FROM releases_lang WHERE id IN', $_, 'ORDER BY id, lang' }, $r;
+ enrich_flatten platforms => id => id => sub { sql 'SELECT id, platform FROM releases_platforms WHERE id IN', $_, 'ORDER BY id, platform' }, $r;
+ enrich media => id => id => sub { 'SELECT id, medium, qty FROM releases_media WHERE id IN', $_, 'ORDER BY id, medium' }, $r;
+}
-# Generate the html for an 'external links' dropdown, assumes enrich_extlinks() has already been called on this object.
sub release_extlinks_ {
my($r, $id) = @_;
return if !$r->{extlinks}->@*;
@@ -38,4 +49,57 @@ sub release_extlinks_ {
}
}
+
+sub release_row_ {
+ my($r, $id, $prodpage) = @_;
+
+ my sub icon_ {
+ my($img, $label, $class) = @_;
+ $class = $class ? " release_icon_$class" : '';
+ img_ src => config->{url_static}."/f/$img.svg", class => "release_icons$class", title => $label;
+ }
+
+ my sub icons_ {
+ my($r) = @_;
+ icon_ 'voiced', $VOICED{$r->{voiced}}{txt}, "voiced$r->{voiced}" if $r->{voiced};
+ icon_ 'story_animated', "Story: $ANIMATED{$r->{ani_story}}{txt}", "anim$r->{ani_story}" if $r->{ani_story};
+ icon_ 'ero_animated', "Ero: $ANIMATED{$r->{ani_ero}}{txt}", "anim$r->{ani_ero}" if $r->{ani_ero};
+ icon_ 'free', 'Freeware' if $r->{freeware};
+ icon_ 'nonfree', 'Non-free' if !$r->{freeware};
+ icon_ 'doujin', 'Doujin' if !$r->{patch} && $r->{doujin};
+ icon_ 'commercial', 'Commercial' if !$r->{patch} && !$r->{doujin};
+ if($r->{resolution} ne 'unknown') {
+ my $type = $r->{resolution} eq 'nonstandard' ? 'custom' : $RESOLUTION{$r->{resolution}}{cat} eq 'widescreen' ? '16-9' : '4-3';
+ # Ugly workaround: PC-98 has non-square pixels, thus not widescreen
+ $type = '4-3' if $type eq '16-9' && grep $_ eq 'p98', $r->{platforms}->@*;
+ icon_ "resolution_$type", $RESOLUTION{$r->{resolution}}{txt};
+ }
+ icon_ $MEDIUM{ $r->{media}[0]{medium} }{icon}, join ', ', map fmtmedia($_->{medium}, $_->{qty}), $r->{media}->@* if $r->{media}->@*;
+ icon_ 'uncensor', 'Uncensored' if $r->{uncensored};
+ icon_ 'notes', bb2text $r->{notes} if $r->{notes};
+ }
+
+ tr_ sub {
+ td_ class => 'tc1', sub { rdate_ $r->{released} };
+ td_ class => 'tc2', $r->{minage} < 0 ? '' : minage $r->{minage};
+ td_ class => 'tc3', sub {
+ abbr_ class => "icons $_", title => $PLATFORM{$_}, '' for grep $_ ne 'oth', $r->{platforms}->@*;
+ if($prodpage) {
+ abbr_ class => "icons lang $_", title => $LANGUAGE{$_}, '' for $r->{lang}->@*;
+ }
+ abbr_ class => "icons rt$r->{type}", title => $r->{type}, '';
+ };
+ td_ class => 'tc4', sub {
+ a_ href => "/r$r->{id}", title => $r->{original}||$r->{title}, $r->{title};
+ b_ class => 'grayedout', ' (patch)' if $r->{patch};
+ };
+ td_ class => 'tc_icons', sub { icons_ $r };
+ td_ class => 'tc_prod', join ' & ', $r->{publisher} ? 'Pub' : (), $r->{developer} ? 'Dev' : () if $prodpage;
+ td_ class => 'tc5 elm_dd_left', sub {
+ elm_ 'UList.ReleaseEdit', $VNWeb::User::Lists::RLIST_STATUS, { rid => $r->{id}, uid => auth->uid, status => $r->{rlist_status}, empty => '--' } if auth;
+ };
+ td_ class => 'tc6', sub { release_extlinks_ $r, "${id}_$r->{id}" };
+ }
+}
+
1;
diff --git a/lib/VNWeb/VN/Page.pm b/lib/VNWeb/VN/Page.pm
index ba2160c1..8a116391 100644
--- a/lib/VNWeb/VN/Page.pm
+++ b/lib/VNWeb/VN/Page.pm
@@ -1,7 +1,7 @@
package VNWeb::VN::Page;
use VNWeb::Prelude;
-use VNWeb::Releases::Lib 'release_extlinks_';
+use VNWeb::Releases::Lib;
use VNDB::Func 'fmtrating';
use POSIX 'strftime';
@@ -425,44 +425,11 @@ sub releases_ {
# TODO: Organize a long list of releases a bit better somehow? Collapsable language sections?
- enrich_merge id => '
- SELECT id, title, original, notes, minage, freeware, doujin, resolution, voiced, ani_story, ani_ero, uncensored
- FROM releases WHERE id IN', $v->{releases};
- enrich_merge id => sql('SELECT rid as id, status as rlist_status FROM rlists WHERE uid =', \auth->uid, 'AND rid IN'), $v->{releases} if auth;
- enrich_flatten lang => id => id => 'SELECT id, lang FROM releases_lang WHERE id IN', $v->{releases};
- enrich_flatten platforms => id => id => 'SELECT id, platform FROM releases_platforms WHERE id IN', $v->{releases};
- enrich media => id => id => 'SELECT id, medium, qty FROM releases_media WHERE id IN', $v->{releases};
-
+ enrich_release $v->{releases};
$v->{releases} = [ sort { $a->{released} <=> $b->{released} || $a->{id} <=> $b->{id} } $v->{releases}->@* ];
my %lang;
my @lang = grep !$lang{$_}++, map $_->{lang}->@*, $v->{releases}->@*;
- my sub icon_ {
- my($img, $label, $class) = @_;
- $class = $class ? " release_icon_$class" : '';
- img_ src => config->{url_static}."/f/$img.svg", class => "release_icons$class", title => $label;
- }
-
- my sub icons_ {
- my($r) = @_;
- icon_ 'voiced', $VOICED{$r->{voiced}}{txt}, "voiced$r->{voiced}" if $r->{voiced};
- icon_ 'story_animated', "Story: $ANIMATED{$r->{ani_story}}{txt}", "anim$r->{ani_story}" if $r->{ani_story};
- icon_ 'ero_animated', "Ero: $ANIMATED{$r->{ani_ero}}{txt}", "anim$r->{ani_ero}" if $r->{ani_ero};
- icon_ 'free', 'Freeware' if $r->{freeware};
- icon_ 'nonfree', 'Non-free' if !$r->{freeware};
- icon_ 'doujin', 'Doujin' if !$r->{patch} && $r->{doujin};
- icon_ 'commercial', 'Commercial' if !$r->{patch} && !$r->{doujin};
- if($r->{resolution} ne 'unknown') {
- my $type = $r->{resolution} eq 'nonstandard' ? 'custom' : $RESOLUTION{$r->{resolution}}{cat} eq 'widescreen' ? '16-9' : '4-3';
- # Ugly workaround: PC-98 has non-square pixels, thus not widescreen
- $type = '4-3' if $type eq '16-9' && grep $_ eq 'p98', $r->{platforms}->@*;
- icon_ "resolution_$type", $RESOLUTION{$r->{resolution}}{txt};
- }
- icon_ $MEDIUM{ $r->{media}[0]{medium} }{icon}, join ', ', map fmtmedia($_->{medium}, $_->{qty}), $r->{media}->@* if $r->{media}->@*;
- icon_ 'uncensor', 'Uncensored' if $r->{uncensored};
- icon_ 'notes', bb2text $r->{notes} if $r->{notes};
- }
-
my sub lang_ {
my($lang) = @_;
tr_ class => 'lang', sub {
@@ -471,31 +438,15 @@ sub releases_ {
txt_ $LANGUAGE{$lang};
}
};
- tr_ sub {
- td_ class => 'tc1', sub { rdate_ $_->{released} };
- td_ class => 'tc2', $_->{minage} < 0 ? '' : minage $_->{minage};
- td_ class => 'tc3', sub {
- abbr_ class => "icons $_", title => $PLATFORM{$_}, '' for grep $_ ne 'oth', $_->{platforms}->@*;
- abbr_ class => "icons rt$_->{type}", title => $_->{type}, '';
- };
- td_ class => 'tc4', sub {
- a_ href => "/r$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
- b_ class => 'grayedout', ' (patch)' if $_->{patch};
- };
- td_ class => 'tc_icons', sub { icons_ $_ };
- td_ class => 'tc5 elm_dd_left', sub {
- elm_ 'UList.ReleaseEdit', $VNWeb::User::Lists::RLIST_STATUS, { rid => $_->{id}, uid => auth->uid, status => $_->{rlist_status}, empty => '--' } if auth;
- };
- td_ class => 'tc6', sub { release_extlinks_ $_, "$lang$_->{id}" };
- } for grep grep($_ eq $lang, $_->{lang}->@*), $v->{releases}->@*;
+ release_row_ $_, $lang for grep grep($_ eq $lang, $_->{lang}->@*), $v->{releases}->@*;
}
- div_ class => 'mainbox releases', sub {
+ div_ class => 'mainbox', sub {
h1_ 'Releases';
if(!$v->{releases}->@*) {
p_ 'We don\'t have any information about releases of this visual novel yet...';
} else {
- table_ sub { lang_ $_ for @lang };
+ table_ class => 'releases', sub { lang_ $_ for @lang };
}
}
}