summaryrefslogtreecommitdiff
path: root/lib/VNDB
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2009-06-07 10:36:13 +0200
committerYorhel <git@yorhel.nl>2009-06-07 10:36:53 +0200
commitf74e08f3d2665c3af5adf4d3668998ed29da275e (patch)
treede52ac9d5e986deebfee26a11be6e8a45075fa76 /lib/VNDB
parent44451507a9cc577aa6c6d127cbc9e301691b97fd (diff)
parentf258f3d8d6b7a6dab970ba6e0c4cbd7172c652e5 (diff)
Merge branch 'beta'2.4
+ Set 2.4 date in ChangeLog
Diffstat (limited to 'lib/VNDB')
-rw-r--r--lib/VNDB/DB/Releases.pm58
-rw-r--r--lib/VNDB/DB/VN.pm23
-rw-r--r--lib/VNDB/Func.pm9
-rw-r--r--lib/VNDB/Handler/Misc.pm2
-rw-r--r--lib/VNDB/Handler/Producers.pm7
-rw-r--r--lib/VNDB/Handler/Releases.pm300
-rw-r--r--lib/VNDB/Handler/Tags.pm16
-rw-r--r--lib/VNDB/Handler/VNBrowse.pm42
-rw-r--r--lib/VNDB/Handler/VNEdit.pm6
-rw-r--r--lib/VNDB/Handler/VNPage.pm2
-rw-r--r--lib/VNDB/Util/CommonHTML.pm28
-rw-r--r--lib/VNDB/Util/FormHTML.pm17
-rw-r--r--lib/VNDB/Util/LayoutHTML.pm3
13 files changed, 378 insertions, 135 deletions
diff --git a/lib/VNDB/DB/Releases.pm b/lib/VNDB/DB/Releases.pm
index 1df13894..bd5d8fcb 100644
--- a/lib/VNDB/DB/Releases.pm
+++ b/lib/VNDB/DB/Releases.pm
@@ -9,7 +9,8 @@ use Exporter 'import';
our @EXPORT = qw|dbReleaseGet dbReleaseAdd dbReleaseEdit|;
-# Options: id vid rev order unreleased page results what
+# Options: id vid rev order unreleased page results what date media
+# platforms languages type minage search resolutions freeware doujin
# What: extended changes vn producers platforms media
sub dbReleaseGet {
my($self, %o) = @_;
@@ -18,19 +19,46 @@ sub dbReleaseGet {
$o{what} ||= '';
$o{order} ||= 'rr.released ASC';
- my %where = (
- !$o{id} && !$o{rev} ? (
- 'r.hidden = FALSE' => 0 ) : (),
- $o{id} ? (
- 'r.id = ?' => $o{id} ) : (),
- $o{rev} ? (
- 'c.rev = ?' => $o{rev} ) : (),
- $o{vid} ? (
- 'rv.vid = ?' => $o{vid} ) : (),
+ my @where = (
+ !$o{id} && !$o{rev} ? ( 'r.hidden = FALSE' => 0 ) : (),
+ $o{id} ? ( 'r.id = ?' => $o{id} ) : (),
+ $o{rev} ? ( 'c.rev = ?' => $o{rev} ) : (),
+ $o{vid} ? ( 'rv.vid = ?' => $o{vid} ) : (),
+ $o{patch} ? ( 'rr.patch = ?' => $o{patch} == 1 ? 1 : 0) : (),
+ $o{freeware} ? ( 'rr.freeware = ?' => $o{freeware} == 1 ? 1 : 0) : (),
+ $o{doujin} ? ( 'rr.doujin = ?' => $o{doujin} == 1 ? 1 : 0) : (),
defined $o{unreleased} ? (
q|rr.released !s ?| => [ $o{unreleased} ? '>' : '<=', strftime('%Y%m%d', gmtime) ] ) : (),
+ $o{date} ? (
+ '(rr.released >= ? AND rr.released <= ?)' => [ $o{date}[0], $o{date}[1] ] ) : (),
+ $o{languages} ? (
+ 'rr.language IN(!l)', => [ $o{languages} ] ) : (),
+ $o{platforms} ? (
+ #'EXISTS(SELECT 1 FROM releases_platforms rp WHERE rp.rid = rr.id AND rp.platform IN(!l))' => [ $o{platforms} ] ) : (),
+ 'rr.id IN(SELECT irp.rid FROM releases_platforms irp JOIN releases ir ON ir.latest = irp.rid WHERE irp.platform IN(!l))' => [ $o{platforms} ] ) : (),
+ defined $o{type} ? (
+ 'rr.type = ?' => $o{type} ) : (),
+ $o{minage} ? (
+ '(rr.minage !s ? AND rr.minage <> -1)' => [ $o{minage}[0] ? '<=' : '>=', $o{minage}[1] ] ) : (),
+ $o{media} ? (
+ 'rr.id IN(SELECT irm.rid FROM releases_media irm JOIN releases ir ON ir.latest = irm.rid WHERE irm.medium IN(!l))' => [ $o{media} ] ) : (),
+ $o{resolutions} ? (
+ 'rr.resolution IN(!l)' => [ $o{resolutions} ] ) : (),
);
+ if($o{search}) {
+ for (split /[ -,._]/, $o{search}) {
+ s/%//g;
+ if(/^\d+$/ && gtintype($_)) {
+ push @where, 'rr.gtin = ?', $_;
+ } elsif(length($_) > 0) {
+ $_ = "%$_%";
+ push @where, '(rr.title ILIKE ? OR rr.original ILIKE ? OR rr.catalog = ?)',
+ [ $_, $_, $_ ];
+ }
+ }
+ }
+
my @join = (
$o{rev} ? 'JOIN releases r ON r.id = rr.rid' : 'JOIN releases r ON rr.id = r.latest',
$o{vid} ? 'JOIN releases_vn rv ON rv.rid = rr.id' : (),
@@ -43,7 +71,7 @@ sub dbReleaseGet {
my @select = (
qw|r.id rr.title rr.original rr.language rr.website rr.released rr.minage rr.type rr.patch|,
'rr.id AS cid',
- $o{what} =~ /extended/ ? qw|rr.notes rr.catalog rr.gtin r.hidden r.locked| : (),
+ $o{what} =~ /extended/ ? qw|rr.notes rr.catalog rr.gtin rr.resolution rr.voiced rr.freeware rr.doujin rr.ani_story rr.ani_ero r.hidden r.locked| : (),
$o{what} =~ /changes/ ? qw|c.added c.requester c.comments r.latest u.username c.rev| : (),
);
@@ -53,7 +81,7 @@ sub dbReleaseGet {
!s
!W
ORDER BY !s|,
- join(', ', @select), join(' ', @join), \%where, $o{order}
+ join(', ', @select), join(' ', @join), \@where, $o{order}
);
if(@$r && $o{what} =~ /(vn|producers|platforms|media)/) {
@@ -138,9 +166,11 @@ sub insert_rev {
my($self, $cid, $rid, $o) = @_;
$self->dbExec(q|
- INSERT INTO releases_rev (id, rid, title, original, gtin, catalog, language, website, released, notes, minage, type, patch)
+ INSERT INTO releases_rev (id, rid, title, original, gtin, catalog, language, website, released,
+ notes, minage, type, patch, resolution, voiced, freeware, doujin, ani_story, ani_ero)
VALUES (!l)|,
- [ $cid, $rid, @$o{qw| title original gtin catalog language website released notes minage type patch|} ]);
+ [ $cid, $rid, @$o{qw| title original gtin catalog language website released
+ notes minage type patch resolution voiced freeware doujin ani_story ani_ero|} ]);
$self->dbExec(q|
INSERT INTO releases_producers (rid, pid)
diff --git a/lib/VNDB/DB/VN.pm b/lib/VNDB/DB/VN.pm
index 4f04edd5..d0a38ced 100644
--- a/lib/VNDB/DB/VN.pm
+++ b/lib/VNDB/DB/VN.pm
@@ -9,7 +9,7 @@ use VNDB::Func 'gtintype';
our @EXPORT = qw|dbVNGet dbVNAdd dbVNEdit dbVNImageId dbVNCache dbScreenshotAdd dbScreenshotGet dbScreenshotRandom|;
-# Options: id, rev, char, search, cati, cate, lang, platform, results, page, order, what
+# Options: id, rev, char, search, lang, platform, results, page, order, what
# What: extended categories anime relations screenshots relgraph ranking changes
sub dbVNGet {
my($self, %o) = @_;
@@ -27,19 +27,6 @@ sub dbVNGet {
'LOWER(SUBSTR(vr.title, 1, 1)) = ?' => $o{char} ) : (),
defined $o{char} && !$o{char} ? (
'(ASCII(vr.title) < 97 OR ASCII(vr.title) > 122) AND (ASCII(vr.title) < 65 OR ASCII(vr.title) > 90)' => 1 ) : (),
- $o{cati} && @{$o{cati}} ? ( q|
- v.id IN(SELECT iv.id
- FROM vn_categories ivc
- JOIN vn iv ON iv.latest = ivc.vid
- WHERE cat IN(!l)
- GROUP BY iv.id
- HAVING COUNT(cat) = ?)| => [ $o{cati}, $#{$o{cati}}+1 ] ) : (),
- $o{cate} && @{$o{cate}} ? ( q|
- v.id NOT IN(SELECT iv.id
- FROM vn_categories ivc
- JOIN vn iv ON iv.latest = ivc.vid
- WHERE cat IN(!l)
- GROUP BY iv.id)| => [ $o{cate} ] ) : (),
$o{lang} && @{$o{lang}} ? (
'('.join(' OR ', map "v.c_languages ILIKE '%%$_%%'", @{$o{lang}}).')' => 1 ) : (),
$o{platform} && @{$o{platform}} ? (
@@ -50,20 +37,18 @@ sub dbVNGet {
);
if($o{search}) {
- my @w = (
- '(irr.id IS NULL OR ir.latest = irr.id)' => 1
- );
+ my @w;
for (split /[ -,._]/, $o{search}) {
s/%//g;
- next if length($_) < 2;
if(/^\d+$/ && gtintype($_)) {
push @w, 'irr.gtin = ?', $_;
- } else {
+ } elsif(length($_) > 0) {
$_ = "%$_%";
push @w, '(ivr.title ILIKE ? OR ivr.original ILIKE ? OR ivr.alias ILIKE ? OR irr.title ILIKE ? OR irr.original ILIKE ?)',
[ $_, $_, $_, $_, $_ ];
}
}
+ push @w, '(irr.id IS NULL OR ir.latest = irr.id)' => 1 if @w;
$where{ q|
v.id IN(SELECT iv.id
FROM vn iv
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index 0a5a9038..4ca20dc5 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -42,9 +42,9 @@ sub date {
# argument: database release date format (yyyymmdd)
-# y = 0000 -> unkown
+# y = 0000 -> unknown
# y = 9999 -> TBA
-# m = 99 -> month+day unkown
+# m = 99 -> month+day unknown
# d = 99 -> day unknown
# return value: (unknown|TBA|yyyy|yyyy-mm|yyyy-mm-dd)
# if date > now: <b class="future">str</b>
@@ -66,11 +66,12 @@ sub datestr {
# e.g.: 'Jan 2009', '2009', 'unknown', 'TBA'
sub monthstr {
my $date = sprintf '%08d', shift||0;
- my($y, $m) = ($1, $2) if $date =~ /^([0-9]{4})([0-9]{2})/;
+ my($y, $m, $d) = ($1, $2, $3) if $date =~ /^([0-9]{4})([0-9]{2})([0-9]{2})/;
return 'TBA' if $y == 9999;
return 'unknown' if $y == 0;
return $y if $m == 99;
- return sprintf '%s %d', [qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)]->[$m-1], $y;
+ my $r = sprintf '%s %d', [qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)]->[$m-1], $y;
+ return $d == 99 ? "<i>$r</i>" : $r;
}
diff --git a/lib/VNDB/Handler/Misc.pm b/lib/VNDB/Handler/Misc.pm
index fca3e5a7..f2f66f0b 100644
--- a/lib/VNDB/Handler/Misc.pm
+++ b/lib/VNDB/Handler/Misc.pm
@@ -212,7 +212,7 @@ sub history {
page => $f->{p},
results => 50,
auto => $f->{m},
- hidden => $f->{h},
+ hidden => $type && $type ne 'u' ? 0 : $f->{h},
edit => $f->{e},
releases => $f->{r},
);
diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm
index 7f43dd78..5977ac1e 100644
--- a/lib/VNDB/Handler/Producers.pm
+++ b/lib/VNDB/Handler/Producers.pm
@@ -171,11 +171,8 @@ sub list {
div class => 'mainbox';
h1 'Browse producers';
- form class => 'search', action => '/p/all', 'accept-charset' => 'UTF-8', method => 'get';
- fieldset;
- input type => 'text', name => 'q', id => 'q', class => 'text', value => $f->{q};
- input type => 'submit', class => 'submit', value => 'Search!';
- end;
+ form action => '/p/all', 'accept-charset' => 'UTF-8', method => 'get';
+ $self->htmlSearchBox('p', $f->{q});
end;
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm
index 8cd2eb43..d031340d 100644
--- a/lib/VNDB/Handler/Releases.pm
+++ b/lib/VNDB/Handler/Releases.pm
@@ -5,12 +5,12 @@ use strict;
use warnings;
use YAWF ':html';
use VNDB::Func;
-use POSIX 'strftime';
YAWF::register(
qr{r([1-9]\d*)(?:\.([1-9]\d*))?} => \&page,
qr{(v)([1-9]\d*)/add} => \&edit,
+ qr{r} => \&browse,
qr{r(?:([1-9]\d*)(?:\.([1-9]\d*))?/edit)}
=> \&edit,
);
@@ -41,6 +41,8 @@ sub page {
} ],
[ type => 'Type', serialize => sub { $self->{release_types}[$_[0]] } ],
[ patch => 'Patch', serialize => sub { $_[0] ? 'Patch' : 'Not a patch' } ],
+ [ freeware => 'Freeware', serialize => sub { $_[0] ? 'yes' : 'nope' } ],
+ [ doujin => 'Doujin', serialize => sub { $_[0] ? 'yups' : 'nope' } ],
[ title => 'Title (romaji)', diff => 1 ],
[ original => 'Original title', diff => 1 ],
[ gtin => 'JAN/UPC/EAN', serialize => sub { $_[0]||'[none]' } ],
@@ -57,6 +59,10 @@ sub page {
$med->[1] ? sprintf('%d %s%s', $_->{qty}, $med->[0], $_->{qty}>1?'s':'') : $med->[0]
} @{$_[0]};
} ],
+ [ resolution => 'Resolution', serialize => sub { $self->{resolutions}[$_[0]][0] } ],
+ [ voiced => 'Voiced', serialize => sub { $self->{voiced}[$_[0]] } ],
+ [ ani_story => 'Story animation',serialize => sub { $self->{animated}[$_[0]] } ],
+ [ ani_ero => 'Ero animation', serialize => sub { $self->{animated}[$_[0]] } ],
[ producers => 'Producers', join => '<br />', split => sub {
map sprintf('<a href="/p%d" title="%s">%s</a>', $_->{id}, $_->{original}||$_->{name}, shorten $_->{name}, 50), @{$_[0]};
} ],
@@ -126,6 +132,11 @@ sub _infotable {
end;
end;
+ Tr ++$i % 2 ? (class => 'odd') : ();
+ td 'Publication';
+ td join ', ', $r->{freeware} ? 'Freeware' : 'Non-free', $r->{patch} ? () : $r->{doujin} ? 'doujin' : 'commercial';
+ end;
+
if(@{$r->{platforms}}) {
Tr ++$i % 2 ? (class => 'odd') : ();
td 'Platform'.($#{$r->{platforms}} ? 's' : '');
@@ -149,6 +160,29 @@ sub _infotable {
end;
}
+ if($r->{resolution}) {
+ Tr ++$i % 2 ? (class => 'odd') : ();
+ td 'Resolution';
+ td $self->{resolutions}[$r->{resolution}][0];
+ end;
+ }
+
+ if($r->{voiced}) {
+ Tr ++$i % 2 ? (class => 'odd') : ();
+ td 'Voiced';
+ td $self->{voiced}[$r->{voiced}];
+ end;
+ }
+
+ if($r->{ani_story} || $r->{ani_ero}) {
+ Tr ++$i % 2 ? (class => 'odd') : ();
+ td 'Animation';
+ td join ', ',
+ $r->{ani_story} ? ('Story: ' .$self->{animated}[$r->{ani_story}]):(),
+ $r->{ani_ero} ? ('Ero scenes: '.$self->{animated}[$r->{ani_ero} ]):();
+ end;
+ }
+
Tr ++$i % 2 ? (class => 'odd') : ();
td 'Released';
td;
@@ -159,7 +193,7 @@ sub _infotable {
if($r->{minage} >= 0) {
Tr ++$i % 2 ? (class => 'odd') : ();
td 'Age rating';
- td $self->{age_ratings}{$r->{minage}};
+ td $self->{age_ratings}{$r->{minage}}[0];
end;
}
@@ -247,8 +281,8 @@ sub edit {
my $vn = $rid ? $r->{vn} : [{ vid => $vid, title => $v->{title} }];
my %b4 = !$rid ? () : (
- (map { $_ => $r->{$_} } qw|type title original gtin catalog language website notes minage platforms patch|),
- released => $r->{released} =~ /^([0-9]{4})([0-9]{2})([0-9]{2})$/ ? [ $1, $2, $3 ] : [ 0, 0, 0 ],
+ (map { $_ => $r->{$_} } qw|type title original gtin catalog language website released
+ notes minage platforms patch resolution voiced freeware doujin ani_story ani_ero|),
media => join(',', sort map "$_->{medium} $_->{qty}", @{$r->{media}}),
producers => join('|||', map "$_->{id},$_->{name}", sort { $a->{id} <=> $b->{id} } @{$r->{producers}}),
);
@@ -259,6 +293,8 @@ sub edit {
$frm = $self->formValidate(
{ name => 'type', enum => [ 0..$#{$self->{release_types}} ] },
{ name => 'patch', required => 0, default => 0 },
+ { name => 'freeware', required => 0, default => 0 },
+ { name => 'doujin', required => 0, default => 0 },
{ name => 'title', maxlength => 250 },
{ name => 'original', required => 0, default => '', maxlength => 250 },
{ name => 'gtin', required => 0, default => '0',
@@ -266,38 +302,41 @@ sub edit {
{ name => 'catalog', required => 0, default => '', maxlength => 50 },
{ name => 'language', enum => [ keys %{$self->{languages}} ] },
{ name => 'website', required => 0, default => '', template => 'url' },
- { name => 'released', required => 0, default => 0, multi => 1, template => 'int' },
+ { name => 'released', required => 0, default => 0, template => 'int' },
{ name => 'minage' , required => 0, default => -1, enum => [ keys %{$self->{age_ratings}} ] },
{ name => 'notes', required => 0, default => '', maxlength => 10240 },
{ name => 'platforms', required => 0, default => '', multi => 1, enum => [ keys %{$self->{platforms}} ] },
{ name => 'media', required => 0, default => '' },
+ { name => 'resolution',required => 0, default => 0, enum => [ 0..$#{$self->{resolutions}} ] },
+ { name => 'voiced', required => 0, default => 0, enum => [ 0..$#{$self->{voiced}} ] },
+ { name => 'ani_story', required => 0, default => 0, enum => [ 0..$#{$self->{animated}} ] },
+ { name => 'ani_ero', required => 0, default => 0, enum => [ 0..$#{$self->{animated}} ] },
{ name => 'producers', required => 0, default => '' },
{ name => 'vn', maxlength => 5000 },
{ name => 'editsum', maxlength => 5000 },
);
if(!$frm->{_err}) {
# de-serialize
- my $released = !$frm->{released}[0] ? 0 : $frm->{released}[0] == 9999 ? 99999999 :
- sprintf '%04d%02d%02d', $frm->{released}[0], $frm->{released}[1]||99, $frm->{released}[2]||99;
my $media = [ map [ split / / ], split /,/, $frm->{media} ];
my $producers = [ map { /^([0-9]+)/ ? $1 : () } split /\|\|\|/, $frm->{producers} ];
my $new_vn = [ map { /^([0-9]+)/ ? $1 : () } split /\|\|\|/, $frm->{vn} ];
$frm->{platforms} = [ grep $_, @{$frm->{platforms}} ];
- $frm->{patch} = $frm->{patch} ? 1 : 0;
+ $frm->{$_} = $frm->{$_} ? 1 : 0 for (qw|patch freeware doujin|);
+ $frm->{doujin} = 0 if $frm->{patch};
return $self->resRedirect("/r$rid", 'post')
- if $rid && $released == $r->{released} &&
+ if $rid &&
(join(',', sort @{$b4{platforms}}) eq join(',', sort @{$frm->{platforms}})) &&
(join(',', sort @$producers) eq join(',', sort map $_->{id}, @{$r->{producers}})) &&
(join(',', sort @$new_vn) eq join(',', sort map $_->{vid}, @$vn)) &&
- !grep !/^(released|platforms|producers|vn)$/ && $frm->{$_} ne $b4{$_}, keys %b4;
+ !grep !/^(platforms|producers|vn)$/ && $frm->{$_} ne $b4{$_}, keys %b4;
my %opts = (
- (map { $_ => $frm->{$_} } qw| type title original gtin catalog language website notes minage platforms editsum patch|),
+ (map { $_ => $frm->{$_} } qw| type title original gtin catalog language website released
+ notes minage platforms resolution editsum patch voiced freeware doujin ani_story ani_ero|),
vn => $new_vn,
producers => $producers,
media => $media,
- released => $released,
);
$rev = 1;
@@ -332,6 +371,8 @@ sub _form {
[ select => short => 'type', name => 'Type',
options => [ map [ $_, $self->{release_types}[$_] ], 0..$#{$self->{release_types}} ] ],
[ check => short => 'patch', name => 'This release is a patch to another release.' ],
+ [ check => short => 'freeware', name => 'Freeware (i.e. available at no cost)' ],
+ [ check => short => 'doujin', name => 'Doujin (self-published / not by a commercial company)' ],
[ input => short => 'title', name => 'Title (romaji)', width => 300 ],
[ input => short => 'original', name => 'Original title', width => 300 ],
[ static => content => 'The original title of this release, leave blank if it already is in the Latin alphabet.' ],
@@ -340,32 +381,26 @@ sub _form {
[ input => short => 'gtin', name => 'JAN/UPC/EAN' ],
[ input => short => 'catalog', name => 'Catalog number' ],
[ input => short => 'website', name => 'Official website' ],
- [ static => label => 'Release date', content => sub {
- Select id => 'released', name => 'released';
- option value => $_, $frm->{released} && $frm->{released}[0] == $_ ? (selected => 'selected') : (),
- !$_ ? '-year-' : $_ < 9999 ? $_ : 'TBA'
- for (0, 1980..((localtime())[5]+1905), 9999);
- end;
- Select id => 'released_m', name => 'released';
- option value => $_, $frm->{released} && $frm->{released}[1] == $_ ? (selected => 'selected') : (),
- !$_ ? '-month-' : strftime '%B', 0, 0, 0, 0, $_, 0, 0, 0
- for(0..12);
- end;
- Select id => 'released_d', name => 'released';
- option value => $_, $frm->{released} && $frm->{released}[2] == $_ ? (selected => 'selected') : (),
- !$_ ? '-day-' : $_
- for(0..31);
- end;
- }],
+ [ date => short => 'released', name => 'Release date' ],
[ static => content => 'Leave month or day blank if they are unknown' ],
[ select => short => 'minage', name => 'Age rating',
- options => [ map [ $_, $self->{age_ratings}{$_} ], sort { $a <=> $b } keys %{$self->{age_ratings}} ] ],
+ options => [ map [ $_, $self->{age_ratings}{$_}[0].($self->{age_ratings}{$_}[1]?" (e.g. $self->{age_ratings}{$_}[1])":'') ],
+ sort { $a <=> $b } keys %{$self->{age_ratings}} ] ],
[ textarea => short => 'notes', name => 'Notes' ],
[ static => content => 'Miscellaneous notes/comments, information that does not fit in the above fields. '
.'E.g.: Censored/uncensored or for which releases this patch applies. Max. 250 characters.' ],
],
- 'Platforms & Media' => [
+ 'Format' => [
+ [ select => short => 'resolution', name => 'Resolution', options => [
+ map [ $_, @{$self->{resolutions}[$_]} ], 0..$#{$self->{resolutions}} ] ],
+ [ select => short => 'voiced', name => 'Voiced', options => [
+ map [ $_, $self->{voiced}[$_] ], 0..$#{$self->{voiced}} ] ],
+ [ select => short => 'ani_story', name => 'Story animation', options => [
+ map [ $_, $self->{animated}[$_] ], 0..$#{$self->{animated}} ] ],
+ [ select => short => 'ani_ero', name => 'Ero animation', options => [
+ map [ $_, $_ ? $self->{animated}[$_] : 'Unknown / no ero scenes' ], 0..$#{$self->{animated}} ] ],
+ [ static => content => 'Animation in erotic scenes, leave to unknown if there are no ero scenes.' ],
[ hidden => short => 'media' ],
[ static => nolabel => 1, content => sub {
h2 'Platforms';
@@ -423,5 +458,208 @@ sub _form {
}
+sub browse {
+ my $self = shift;
+
+ my $f = $self->formValidate(
+ { name => 'p', required => 0, default => 1, template => 'int' },
+ { name => 's', required => 0, default => 'title', enum => [qw|released minage title|] },
+ { name => 'o', required => 0, default => 'a', enum => ['a', 'd'] },
+ { name => 'q', required => 0, default => '', maxlength => 500 },
+ { name => 'ln', required => 0, multi => 1, default => '', enum => [ keys %{$self->{languages}} ] },
+ { name => 'pl', required => 0, multi => 1, default => '', enum => [ keys %{$self->{platforms}} ] },
+ { name => 'me', required => 0, multi => 1, default => '', enum => [ keys %{$self->{media}} ] },
+ { name => 'tp', required => 0, default => -1, enum => [ -1..$#{$self->{release_types}} ] },
+ { name => 'pa', required => 0, default => 0, enum => [ 0..2 ] },
+ { name => 'fw', required => 0, default => 0, enum => [ 0..2 ] },
+ { name => 'do', required => 0, default => 0, enum => [ 0..2 ] },
+ { name => 'ma_m', required => 0, default => 0, enum => [ 0, 1 ] },
+ { name => 'ma_a', required => 0, default => 0, enum => [ keys %{$self->{age_ratings}} ] },
+ { name => 'mi', required => 0, default => 0, template => 'int' },
+ { name => 'ma', required => 0, default => 99999999, template => 'int' },
+ { name => 're', required => 0, multi => 1, default => 0, enum => [ 1..$#{$self->{resolutions}} ] },
+ );
+ return 404 if $f->{_err};
+
+ my @filters = (
+ $f->{mi} > 0 || $f->{ma} < 99990000 ? (date => [ $f->{mi}, $f->{ma} ]) : (),
+ $f->{q} ? (search => $f->{q}) : (),
+ $f->{pl}[0] ? (platforms => $f->{pl}) : (),
+ $f->{ln}[0] ? (languages => $f->{ln}) : (),
+ $f->{me}[0] ? (media => $f->{me}) : (),
+ $f->{re}[0] ? (resolutions => $f->{re} ) : (),
+ $f->{tp} >= 0 ? (type => $f->{tp}) : (),
+ $f->{ma_a} || $f->{ma_m} ? (minage => [$f->{ma_m}, $f->{ma_a}]) : (),
+ $f->{pa} ? (patch => $f->{pa}) : (),
+ $f->{fw} ? (freeware => $f->{fw}) : (),
+ $f->{do} ? (doujin => $f->{do}) : (),
+ );
+ my($list, $np) = !@filters ? ([], 0) : $self->dbReleaseGet(
+ order => $f->{s}.($f->{o}eq'd'?' DESC':' ASC'),
+ page => $f->{p},
+ results => 50,
+ what => 'platforms',
+ @filters,
+ );
+
+ my $url = "/r?tp=$f->{tp};pa=$f->{pa};ma_m=$f->{ma_m};ma_a=$f->{ma_a};q=$f->{q};mi=$f->{mi};ma=$f->{ma}";
+ $_&&($url .= ";ln=$_") for @{$f->{ln}};
+ $_&&($url .= ";pl=$_") for @{$f->{pl}};
+ $_&&($url .= ";re=$_") for @{$f->{re}};
+ $_&&($url .= ";me=$_") for @{$f->{me}};
+
+ $self->htmlHeader(title => 'Browse releases');
+ _filters($self, $f, !@filters || !@$list);
+ $self->htmlBrowse(
+ class => 'relbrowse',
+ items => $list,
+ options => $f,
+ nextpage => $np,
+ pageurl => "$url;s=$f->{s};o=$f->{o}",
+ sorturl => $url,
+ header => [
+ [ 'Released', 'released' ],
+ [ 'Rating', 'minage' ],
+ [ '', '' ],
+ [ 'Title', 'title' ],
+ ],
+ row => sub {
+ my($s, $n, $l) = @_;
+ Tr $n % 2 ? (class => 'odd') : ();
+ td class => 'tc1';
+ lit datestr $l->{released};
+ end;
+ td class => 'tc2', $l->{minage} > -1 ? $self->{age_ratings}{$l->{minage}}[0] : '';
+ td class => 'tc3';
+ $_ ne 'oth' && cssicon $_, $self->{platforms}{$_} for (@{$l->{platforms}});
+ cssicon "lang $l->{language}", $self->{languages}{$l->{language}};
+ cssicon lc(substr($self->{release_types}[$l->{type}],0,3)), $self->{release_types}[$l->{type}];
+ end;
+ td class => 'tc4';
+ a href => "/r$l->{id}", title => $l->{original}||$l->{title}, shorten $l->{title}, 90;
+ b class => 'grayedout', ' (patch)' if $l->{patch};
+ end;
+ end;
+ },
+ ) if @$list;
+ if(@filters && !@$list) {
+ div class => 'mainbox';
+ h1 'No results found';
+ div class => 'notice';
+ p qq|Sorry, couldn't find anything that comes through your filters. You might want to disable a few filters to get more results.\n\n|
+ .qq|Also, keep in mind that we don't have all information about all releases. So e.g. filtering on screen resolution will exclude |
+ .qq|all releases of which we don't know it's resolution, even though it might in fact be in the resolution you're looking for.|;
+ end;
+ end;
+ }
+ $self->htmlFooter;
+}
+
+
+sub _filters {
+ my($self, $f, $shown) = @_;
+
+ form method => 'get', action => '/r', 'accept-charset' => 'UTF-8';
+ div class => 'mainbox';
+ h1 'Browse releases';
+
+ $self->htmlSearchBox('r', $f->{q});
+
+ a id => 'advselect', href => '#';
+ lit '<i>'.($shown?'&#9662;':'&#9656;').'</i> filters';
+ end;
+ div id => 'advoptions', !$shown ? (class => 'hidden') : ();
+
+ h2 'Filters';
+ table class => 'formtable', style => 'margin-left: 0';
+ Tr class => 'newfield';
+ td class => 'label'; label for => 'ma_m', 'Age rating'; end;
+ td class => 'field';
+ Select id => 'ma_m', name => 'ma_m', style => 'width: 70px';
+ option value => 0, $f->{ma_m} == 0 ? ('selected' => 'selected') : (), 'greater';
+ option value => 1, $f->{ma_m} == 1 ? ('selected' => 'selected') : (), 'smaller';
+ end;
+ txt ' than or equal to ';
+ Select id => 'ma_a', name => 'ma_a', style => 'width: 80px; text-align: center';
+ $_>=0 && option value => $_, $f->{ma_a} == $_ ? ('selected' => 'selected') : (), $self->{age_ratings}{$_}[0]
+ for (sort { $a <=> $b } keys %{$self->{age_ratings}});
+ end;
+ end;
+ td rowspan => 5, style => 'padding-left: 40px';
+ label for => 're', 'Screen resolution'; br;
+ Select id => 're', name => 're', multiple => 'multiple', size => 8;
+ my $l='';
+ for my $i (1..$#{$self->{resolutions}}) {
+ if($l ne $self->{resolutions}[$i][1]) {
+ end if $l;
+ $l = $self->{resolutions}[$i][1];
+ optgroup label => $l;
+ }
+ option value => $i, scalar grep($i==$_, @{$f->{re}}) ? (selected => 'selected') : (), $self->{resolutions}[$i][0];
+ }
+ end if $l;
+ end;
+ end;
+ end;
+ $self->htmlFormPart($f, [ select => short => 'tp', name => 'Release type',
+ options => [ [-1, 'All'], map [ $_, $self->{release_types}[$_] ], 0..$#{$self->{release_types}} ]]);
+ $self->htmlFormPart($f, [ select => short => 'pa', name => 'Patch status',
+ options => [ [0, 'All'], [1, 'Only patches'], [2, 'Only standalone releases']]]);
+ $self->htmlFormPart($f, [ select => short => 'fw', name => 'Freeware',
+ options => [ [0, 'All'], [1, 'Freeware only'], [2, 'Only non-free releases']]]);
+ $self->htmlFormPart($f, [ select => short => 'do', name => 'Doujin',
+ options => [ [0, 'All'], [1, 'Only doujin releases'], [2, 'Only commercial releases']]]);
+ $self->htmlFormPart($f, [ date => short => 'mi', name => 'Released after' ]);
+ $self->htmlFormPart($f, [ date => short => 'ma', name => 'Released before' ]);
+ end;
+
+ h2;
+ lit 'Languages <b>(boolean or, selecting more gives more results)</b>';
+ end;
+ for my $i (sort @{$self->dbLanguages}) {
+ span;
+ input type => 'checkbox', name => 'ln', value => $i, id => "lang_$i", grep($_ eq $i, @{$f->{ln}}) ? (checked => 'checked') : ();
+ label for => "lang_$i";
+ cssicon "lang $i", $self->{languages}{$i};
+ txt $self->{languages}{$i};
+ end;
+ end;
+ }
+
+ h2;
+ lit 'Platforms <b>(boolean or, selecting more gives more results)</b>';
+ end;
+ for my $i (sort keys %{$self->{platforms}}) {
+ next if $i eq 'oth';
+ span;
+ input type => 'checkbox', name => 'pl', value => $i, id => "plat_$i", grep($_ eq $i, @{$f->{pl}}) ? (checked => 'checked') : ();
+ label for => "plat_$i";
+ cssicon $i, $self->{platforms}{$i};
+ txt $self->{platforms}{$i};
+ end;
+ end;
+ }
+
+ h2;
+ lit 'Media <b>(boolean or, selecting more gives more results)</b>';
+ end;
+ for my $i (sort keys %{$self->{media}}) {
+ next if $i eq 'otc';
+ span;
+ input type => 'checkbox', name => 'me', value => $i, id => "med_$i", grep($_ eq $i, @{$f->{me}}) ? (checked => 'checked') : ();
+ label for => "med_$i", $self->{media}{$i}[0];
+ end;
+ }
+
+ div style => 'text-align: center; clear: left;';
+ input type => 'submit', value => 'Apply', class => 'submit';
+ input type => 'reset', value => 'Clear', class => 'submit', onclick => 'location.href="/r"';
+ end;
+ end;
+ end;
+ end;
+}
+
+
1;
diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm
index d10de195..a6d02698 100644
--- a/lib/VNDB/Handler/Tags.pm
+++ b/lib/VNDB/Handler/Tags.pm
@@ -367,12 +367,9 @@ sub taglist {
$self->htmlHeader(title => $title);
div class => 'mainbox';
h1 $title;
- form class => 'search', action => '/g/list', 'accept-charset' => 'UTF-8', method => 'get';
- fieldset;
- input type => 'hidden', name => 't', value => $f->{t};
- input type => 'text', name => 'q', id => 'q', class => 'text', value => $f->{q};
- input type => 'submit', class => 'submit', value => 'Search!';
- end;
+ form action => '/g/list', 'accept-charset' => 'UTF-8', method => 'get';
+ input type => 'hidden', name => 't', value => $f->{t};
+ $self->htmlSearchBox('g', $f->{q});
end;
p class => 'browseopts';
a href => "/g/list?q=$f->{q};t=-1", $f->{t} == -1 ? (class => 'optselected') : (), 'All';
@@ -589,11 +586,8 @@ sub tagindex {
div class => 'mainbox';
a class => 'addnew', href => "/g/new", ($self->authCan('tagmod')?'Create':'Request').' new tag' if $self->authCan('tag');
h1 'Search tags';
- form class => 'search', action => '/g/list', 'accept-charset' => 'UTF-8', method => 'get';
- fieldset;
- input type => 'text', name => 'q', id => 'q', class => 'text';
- input type => 'submit', class => 'submit', value => 'Search!';
- end;
+ form action => '/g/list', 'accept-charset' => 'UTF-8', method => 'get';
+ $self->htmlSearchBox('g', '');
end;
end;
diff --git a/lib/VNDB/Handler/VNBrowse.pm b/lib/VNDB/Handler/VNBrowse.pm
index f50a8500..d5791907 100644
--- a/lib/VNDB/Handler/VNBrowse.pm
+++ b/lib/VNDB/Handler/VNBrowse.pm
@@ -25,11 +25,7 @@ sub list {
return 404 if $f->{_err};
$f->{q} ||= $f->{sq};
- # NOTE: this entire search thingy can also be done using a PgSQL fulltext search,
- # which is faster and requires less code. It does require an extra database
- # column, index and some triggers, though
-
- my(@cati, @cate, @plat, @lang);
+ my(@plat, @lang);
my $q = $f->{q};
if($q) {
# VNDBID
@@ -37,15 +33,6 @@ sub list {
if $q =~ /^([gvrptud])([0-9]+)(?:\.([0-9]+))?$/;
if(!($q =~ s/^title://)) {
- # categories
- my %catl = map {
- my $ic = $_;
- map { $ic.$_ => $self->{categories}{$ic}[1]{$_} } keys %{$self->{categories}{$ic}[1]}
- } keys %{$self->{categories}};
-
- $q =~ s/-(?:$catl{$_}|c:$_)//ig && push @cate, $_ for keys %catl;
- $q =~ s/(?:$catl{$_}|c:$_)//ig && push @cati, $_ for keys %catl;
-
# platforms
$_ ne 'oth' && $q =~ s/(?:$self->{platforms}{$_}|p:$_)//ig && push @plat, $_ for keys %{$self->{platforms}};
@@ -62,8 +49,6 @@ sub list {
results => 50,
page => $f->{p},
order => ($f->{s} eq 'rel' ? 'c_released' : $f->{s} eq 'pop' ? 'c_popularity' : 'title').($f->{o} eq 'a' ? ' ASC' : ' DESC'),
- @cati ? ( cati => \@cati ) : (),
- @cate ? ( cate => \@cate ) : (),
@lang ? ( lang => \@lang ) : (),
@plat ? ( platform => \@plat ) : (),
);
@@ -117,11 +102,8 @@ sub _filters {
div class => 'mainbox';
h1 'Browse visual novels';
- form class => 'search', action => '/v/all', 'accept-charset' => 'UTF-8', method => 'get';
- fieldset;
- input type => 'text', name => 'q', id => 'q', class => 'text', value => $f->{q};
- input type => 'submit', class => 'submit', value => 'Search!';
- end;
+ form action => '/v/all', 'accept-charset' => 'UTF-8', method => 'get';
+ $self->htmlSearchBox('v', $f->{q});
end;
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
@@ -131,23 +113,7 @@ sub _filters {
a id => 'advselect', href => '#';
lit '<i>&#9656;</i> advanced search';
end;
- div id => 'advoptions', class => 'hidden';
-
- h2;
- lit 'Categories <b>(boolean and, selecting more gives less results. The categories are explained on <a href="/d1">this page</a>)</b>';
- end;
- ul id => 'catselect';
- for my $c (qw| e g t p h l s |) {
- $c !~ /[thl]/ ? li : br;
- txt $self->{categories}{$c}[0];
- ul;
- li id => "cat_$c$_", $self->{categories}{$c}[1]{$_}
- for (sort keys %{$self->{categories}{$c}[1]});
- end;
- end if $c !~ /[gph]/;
- }
- end;
-
+ div id => 'advoptions', class => 'hidden vnoptions';
h2;
lit 'Languages <b>(boolean or, selecting more gives more results)</b>';
end;
diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index 8363b500..3b0619ab 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -55,11 +55,11 @@ sub edit {
if(!$frm->{_err}) {
# parse and re-sort fields that have multiple representations of the same information
- my $anime = [ grep /^[0-9]+$/, split /[ ,]+/, $frm->{anime} ];
+ my $anime = { map +($_=>1), grep /^[0-9]+$/, split /[ ,]+/, $frm->{anime} };
my $relations = [ map { /^([0-9]+),([0-9]+),(.+)$/ && (!$vid || $2 != $vid) ? [ $1, $2, $3 ] : () } split /\|\|\|/, $frm->{relations} ];
my $screenshots = [ map /^[0-9]+,[01],[0-9]+$/ ? [split /,/] : (), split / +/, $frm->{screenshots} ];
- $frm->{anime} = join ' ', sort { $a <=> $b } @$anime;
+ $frm->{anime} = join ' ', sort { $a <=> $b } keys %$anime;
$frm->{relations} = join '|||', map $_->[0].','.$_->[1].','.$_->[2], sort { $a->[1] <=> $b->[1]} @{$relations};
$frm->{img_nsfw} = $frm->{img_nsfw} ? 1 : 0;
$frm->{screenshots} = join ' ', map sprintf('%d,%d,%d', $_->[0], $_->[1]?1:0, $_->[2]), sort { $a->[0] <=> $b->[0] } @$screenshots;
@@ -71,7 +71,7 @@ sub edit {
# execute the edit/add
my %args = (
(map { $_ => $frm->{$_} } qw|title original alias desc length l_wp l_encubed l_renai l_vnn editsum img_nsfw|),
- anime => $anime,
+ anime => [ keys %$anime ],
categories => $v->{categories},
relations => $relations,
image => $image,
diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm
index d5d1c0a1..fac6305b 100644
--- a/lib/VNDB/Handler/VNPage.pm
+++ b/lib/VNDB/Handler/VNPage.pm
@@ -422,7 +422,7 @@ sub _releases {
for my $rel (grep $l eq $_->{language}, @$r) {
Tr;
td class => 'tc1'; lit datestr $rel->{released}; end;
- td class => 'tc2', $rel->{minage} < 0 ? '' : $self->{age_ratings}{$rel->{minage}};
+ td class => 'tc2', $rel->{minage} < 0 ? '' : $self->{age_ratings}{$rel->{minage}}[0];
td class => 'tc3';
for (sort @{$rel->{platforms}}) {
next if $_ eq 'oth';
diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm
index 744216c1..7421b1c0 100644
--- a/lib/VNDB/Util/CommonHTML.pm
+++ b/lib/VNDB/Util/CommonHTML.pm
@@ -8,10 +8,11 @@ use Exporter 'import';
use Algorithm::Diff::XS 'compact_diff';
use VNDB::Func;
use Encode 'encode_utf8', 'decode_utf8';
+use POSIX 'ceil';
our @EXPORT = qw|
htmlMainTabs htmlDenied htmlHiddenMessage htmlBrowse htmlBrowseNavigate
- htmlRevision htmlEditMessage htmlItemMessage htmlVoteStats htmlHistory
+ htmlRevision htmlEditMessage htmlItemMessage htmlVoteStats htmlHistory htmlSearchBox
|;
@@ -419,7 +420,7 @@ sub htmlVoteStats {
end; end;
tfoot; Tr;
td colspan => 2, sprintf '%d vote%s total, average %.2f%s', $count, $count != 1 ? 's' : '', $total/$count,
- $type eq 'v' ? ' ('.$self->{votes}[sprintf '%.0f', $total/$count-1].')' : '';
+ $type eq 'v' ? ' ('.$self->{votes}[ceil($total/$count-1)].')' : '';
end; end;
for (reverse 0..$#$stats) {
Tr;
@@ -483,7 +484,7 @@ sub htmlHistory {
sub { td colspan => 2, class => 'tc1', 'Rev.' },
[ 'Date' ],
[ 'User' ],
- [ 'Page' ],
+ sub { td; a href => '#', id => 'history_comments', 'expand'; txt 'Page'; end; }
],
row => sub {
my($s, $n, $i) = @_;
@@ -506,8 +507,8 @@ sub htmlHistory {
end;
end;
if($i->{comments}) {
- Tr $n % 2 ? ( class => 'odd' ) : ();
- td colspan => 5, class => 'editsum';
+ Tr class => $n % 2 ? 'editsum odd hidden' : 'editsum hidden';
+ td colspan => 5;
lit bb2html $i->{comments}, 150;
end;
end;
@@ -517,4 +518,21 @@ sub htmlHistory {
}
+sub htmlSearchBox {
+ my($self, $sel, $v) = @_;
+
+ p class => 'searchtabs';
+ a href => '/v/all', $sel eq 'v' ? (class => 'sel') : (), 'Visual novels';
+ a href => '/r', $sel eq 'r' ? (class => 'sel') : (), 'Releases';
+ a href => '/p/all', $sel eq 'p' ? (class => 'sel') : (), 'Producers';
+ a href => '/g', $sel eq 'g' ? (class => 'sel') : (), 'Tags';
+ end;
+ fieldset class => 'search';
+ input type => 'text', name => 'q', id => 'q', class => 'text', value => $v;
+ input type => 'submit', class => 'submit', value => 'Search!';
+ end;
+}
+
+
+
1;
diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm
index 17de6663..111fa5a6 100644
--- a/lib/VNDB/Util/FormHTML.pm
+++ b/lib/VNDB/Util/FormHTML.pm
@@ -5,6 +5,7 @@ use strict;
use warnings;
use YAWF ':html';
use Exporter 'import';
+use POSIX 'strftime';
our @EXPORT = qw| htmlFormError htmlFormPart htmlForm |;
@@ -116,6 +117,7 @@ sub htmlFormError {
# check name, short, (value)
# select name, short, options, (width)
# text name, short, (rows, cols)
+# date name, short
# part title
# TODO: Find a way to write this function in a readable way...
sub htmlFormPart {
@@ -184,11 +186,22 @@ sub htmlFormPart {
lit ref $o{content} eq 'CODE' ? $o{content}->($self, \%o) : $o{content};
}
if(/select/) {
+ my $l='';
Select name => $o{short}, id => $o{short}, $o{width} ? (style => "width: $o{width}px") : ();
- option value => $_->[0], defined $frm->{$o{short}} && $frm->{$o{short}} eq $_->[0] ? (selected => 'selected') : (), $_->[1]
- for @{$o{options}};
+ for (@{$o{options}}) {
+ if($_->[2] && $l ne $_->[2]) {
+ end if $l;
+ $l = $_->[2];
+ optgroup label => $l;
+ }
+ option value => $_->[0], defined $frm->{$o{short}} && $frm->{$o{short}} eq $_->[0] ? (selected => 'selected') : (), $_->[1];
+ }
+ end if $l;
end;
}
+ if(/date/) {
+ input type => 'hidden', id => $o{short}, name => $o{short}, value => $frm->{$o{short}}||'', class => 'dateinput';
+ }
if(/text/) {
(my $txt = $frm->{$o{short}}||'') =~ s/&/&amp;/;
$txt =~ s/</&lt;/;
diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm
index fcd088a4..1e6d8a60 100644
--- a/lib/VNDB/Util/LayoutHTML.pm
+++ b/lib/VNDB/Util/LayoutHTML.pm
@@ -57,8 +57,9 @@ sub _menu {
div;
a href => '/', 'Home'; br;
a href => '/v/all', 'Visual novels'; br;
- a href => '/g', 'Tags'; br;
+ a href => '/r', 'Releases'; br;
a href => '/p/all', 'Producers'; br;
+ a href => '/g', 'Tags'; br;
a href => '/u/all', 'Users'; br;
a href => '/hist', 'Recent changes'; br;
a href => '/t', 'Discussion board'; br;