diff options
author | Yorhel <git@yorhel.nl> | 2009-06-07 10:36:13 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2009-06-07 10:36:53 +0200 |
commit | f74e08f3d2665c3af5adf4d3668998ed29da275e (patch) | |
tree | de52ac9d5e986deebfee26a11be6e8a45075fa76 /lib/VNDB | |
parent | 44451507a9cc577aa6c6d127cbc9e301691b97fd (diff) | |
parent | f258f3d8d6b7a6dab970ba6e0c4cbd7172c652e5 (diff) |
Merge branch 'beta'2.4
+ Set 2.4 date in ChangeLog
Diffstat (limited to 'lib/VNDB')
-rw-r--r-- | lib/VNDB/DB/Releases.pm | 58 | ||||
-rw-r--r-- | lib/VNDB/DB/VN.pm | 23 | ||||
-rw-r--r-- | lib/VNDB/Func.pm | 9 | ||||
-rw-r--r-- | lib/VNDB/Handler/Misc.pm | 2 | ||||
-rw-r--r-- | lib/VNDB/Handler/Producers.pm | 7 | ||||
-rw-r--r-- | lib/VNDB/Handler/Releases.pm | 300 | ||||
-rw-r--r-- | lib/VNDB/Handler/Tags.pm | 16 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNBrowse.pm | 42 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNEdit.pm | 6 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNPage.pm | 2 | ||||
-rw-r--r-- | lib/VNDB/Util/CommonHTML.pm | 28 | ||||
-rw-r--r-- | lib/VNDB/Util/FormHTML.pm | 17 | ||||
-rw-r--r-- | lib/VNDB/Util/LayoutHTML.pm | 3 |
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?'▾':'▸').'</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>▸</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/&/&/; $txt =~ s/</</; 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; |