diff options
author | Yorhel <git@yorhel.nl> | 2020-12-17 13:01:01 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2020-12-17 13:01:03 +0100 |
commit | d96b545dc45a0f85239dc36738ceb5fbe25d47e5 (patch) | |
tree | ee45dfc8726eee0567ee3ae41a37ab74e251b505 /lib | |
parent | 590dc058575065967194f54e725fdda55f7ab13c (diff) |
AdvSearch: Add conversion from old filter URLs to new queries
Haven't spent as much effort on testing the conversion as I should have,
but that'll come later when I migrate the saved filters.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/VNWeb/Filters.pm | 92 | ||||
-rw-r--r-- | lib/VNWeb/VN/List.pm | 30 |
2 files changed, 114 insertions, 8 deletions
diff --git a/lib/VNWeb/Filters.pm b/lib/VNWeb/Filters.pm index 75e82336..039d3a32 100644 --- a/lib/VNWeb/Filters.pm +++ b/lib/VNWeb/Filters.pm @@ -1,14 +1,13 @@ package VNWeb::Filters; -# This module implements validating and querying the search filters. I'm not -# sure yet if this filter system will continue to exist in this form or if -# there will be a better advanced search system to replace it, but either way -# we'll need to support these filters for the forseeable future. +# This module implements validating and querying the old search filters. These +# filters are replaced with the new AdvSearch framework and this code only +# exists to convert old URLs. use VNWeb::Prelude; use Exporter 'import'; -our @EXPORT = qw/filter_parse filter_vn_query filter_release_query/; +our @EXPORT = qw/filter_parse filter_vn_query filter_release_query filter_vn_adv filter_release_adv filter_char_adv/; my $VN = form_compile any => { @@ -123,11 +122,12 @@ sub filter_vn_compat { # Throws error on failure. sub filter_parse { my($type, $str) = @_; + return {} if !$str; my $s = {v => $VN, r => $RELEASE, c => $CHAR, s => $STAFF}->{$type}; my $data = ref $str ? $str : $str =~ /^{/ ? JSON::XS->new->decode($str) : VNDB::Func::fil_parse $str, keys $s->{known_keys}->%*; die "Invalid filter data: $str\n" if !$data; my $f = $s->validate($data)->data; - filter_vn_compat $f if $type eq 'vn'; + filter_vn_compat $f if $type eq 'v'; $f } @@ -192,4 +192,84 @@ sub filter_release_query { defined $fil->{engine} ? sql 'r.engine =', \$fil->{engine} : (), } + +sub filter_vn_adv { + my($fil) = @_; + [ 'and', + defined $fil->{date_before} ? [ 'released', '<=', $fil->{date_before} ] : (), + defined $fil->{date_after} ? [ 'released', '>=', $fil->{date_after} ] : (), + defined $fil->{released} ? [ 'released', $fil->{released} ? '<=' : '>', 1 ] : (), + defined $fil->{length} ? map [ 'length', '=', $_ ], $fil->{length}->@* : (), + defined $fil->{hasani} ? [ 'has-anime', $fil->{hasani} ? '=' : '!=', 1 ] : (), + defined $fil->{hasshot} ? [ 'has-screenshot', $fil->{hasshot} ? '=' : '!=', 1 ] : (), + defined $fil->{tag_inc} ? [ 'and', map [ 'tag', '=', [ $_, $fil->{tagspoil}, 0 ] ], $fil->{tag_inc}->@* ] : (), + defined $fil->{tag_exc} ? [ 'and', map [ 'tag', '!=', [ $_, 2, 0 ] ], $fil->{tag_exc}->@* ] : (), + defined $fil->{lang} ? [ 'or', map [ 'lang', '=', $_ ], $fil->{lang}->@* ] : (), + defined $fil->{olang} ? [ 'or', map [ 'olang', '=', $_ ], $fil->{olang}->@* ] : (), + defined $fil->{plat} ? [ 'or', map [ 'platform', '=', $_ ], $fil->{plat}->@* ] : (), + defined $fil->{staff_inc} ? [ 'staff', '=', [ 'or', map [ 'id', '=', $_ ], $fil->{staff_inc} ] ] : (), + defined $fil->{staff_exc} ? [ 'staff', '!=', [ 'or', map [ 'id', '=', $_ ], $fil->{staff_exc} ] ] : (), + auth ? ( + defined $fil->{ul_notblack} ? [ 'label', '!=', 6 ] : (), + defined $fil->{ul_onwish} ? [ 'label', $fil->{ul_onwish} ? '=' : '!=', 5 ] : (), + defined $fil->{ul_voted} ? [ 'label', $fil->{ul_voted} ? '=' : '!=', 7 ] : (), + # XXX: "Not on list" can't be represented in the same way with an AdvSearch query, so it's instead taken to mean "not assigned any of the built-in labels" + defined $fil->{ul_onlist} ? [$fil->{ul_onlist} ? ('or', [ 'label', '=', 0 ], [ 'label', '!=', 0 ]) : ('and', map [ 'label', '!=', $_ ], 1..7)] : (), + ) : () + ] +} + + +sub filter_release_adv { + my($fil) = @_; + [ 'and', + defined $fil->{type} ? [ 'rtype', '=', $fil->{type} ] : (), + defined $fil->{patch} ? [ 'patch', $fil->{patch} ? '=' : '!=', 1 ] : (), + defined $fil->{freeware} ? [ 'freeware', $fil->{freeware} ? '=' : '!=', 1 ] : (), + defined $fil->{doujin} ? [ 'doujin', $fil->{doujin} ? '=' : '!=', 1 ] : (), + defined $fil->{uncensored} ? [ 'uncensored', $fil->{uncensored} ? '=' : '!=', 1 ] : (), + defined $fil->{date_before} ? [ 'released', '<=', $fil->{date_before} ] : (), + defined $fil->{date_after} ? [ 'released', '>=', $fil->{date_after} ] : (), + defined $fil->{released} ? [ 'released', $fil->{released} ? '<=' : '>', 1 ] : (), + defined $fil->{minage} ? [ 'or', map [ 'minage', '=', $_ ], $fil->{minage}->@* ] : (), + defined $fil->{lang} ? [ 'or', map [ 'lang', '=', $_ ], $fil->{lang}->@* ] : (), + defined $fil->{olang} ? () : (), # TODO: This isn't supported (yet? it's more like a VN filter). + defined $fil->{resolution} ? [ 'or', map [ 'resolution', '=', $_ eq 'unknown' ? [0,0] : $_ eq 'nonstandard' ? [0,1] : [split /x/] ], $fil->{resolution}->@* ] : (), + defined $fil->{plat} ? [ 'or', map [ 'platform', '=', $_ eq 'unk' ? '' : $_ ], $fil->{plat}->@* ] : (), + defined $fil->{prod_inc} ? [ 'or', map [ 'producer', '=', $_ ], $fil->{prod_inc}->@* ] : (), + defined $fil->{prod_exc} ? [ 'and', map [ 'producer', '!=', $_ ], $fil->{prod_exc}->@* ] : (), + defined $fil->{med} ? [ 'or', map [ 'medium', '=', $_ eq 'unk' ? '' : $_ ], $fil->{med}->@* ] : (), + defined $fil->{voiced} ? [ 'or', map [ 'voiced', '=', $_ ], $fil->{voiced}->@* ] : (), + defined $fil->{ani_story} ? [ 'or', map [ 'animation-story', '=', $_ ], $fil->{ani_story}->@* ] : (), + defined $fil->{ani_ero} ? [ 'or', map [ 'animation-ero', '=', $_ ], $fil->{ani_ero}->@* ] : (), + defined $fil->{engine} ? [ 'or', map [ 'engine', '=', $_ ], $fil->{engine}->@* ] : (), + ] +} + + +sub filter_char_adv { + my($fil) = @_; + [ 'and', + defined $fil->{gender} ? [ 'or', map [ 'sex', '=', $_ ], $fil->{gender}->@* ] : (), + defined $fil->{bloodt} ? [ 'or', map [ 'blood-type', '=', $_ ], $fil->{bloodt}->@* ] : (), + defined $fil->{bust_min} ? [ 'bust', '>=', $fil->{bust_min} ] : (), + defined $fil->{bust_max} ? [ 'bust', '<=', $fil->{bust_max} ] : (), + defined $fil->{waist_min} ? [ 'waist', '>=', $fil->{waist_min} ] : (), + defined $fil->{waist_max} ? [ 'waist', '<=', $fil->{waist_max} ] : (), + defined $fil->{hip_min} ? [ 'hips', '>=', $fil->{hip_min} ] : (), + defined $fil->{hip_max} ? [ 'hips', '<=', $fil->{hip_max} ] : (), + defined $fil->{height_min} ? [ 'height', '>=', $fil->{height_min} ] : (), + defined $fil->{height_max} ? [ 'height', '<=', $fil->{height_max} ] : (), + defined $fil->{weight_min} ? [ 'weight', '>=', $fil->{weight_min} ] : (), + defined $fil->{weight_max} ? [ 'weight', '<=', $fil->{weight_max} ] : (), + defined $fil->{cup_min} ? [ 'cup', '>=', $fil->{cup_min} ] : (), + defined $fil->{cup_max} ? [ 'cup', '<=', $fil->{cup_max} ] : (), + defined $fil->{va_inc} ? [ 'seiyuu', '=', [ 'or', map [ 'id', '=', $_ ], $fil->{va_inc}->@* ] ] : (), + defined $fil->{va_exc} ? [ 'seiyuu', '!=', [ 'or', map [ 'id', '=', $_ ], $fil->{va_exc}->@* ] ] : (), + defined $fil->{trait_inc} ? [ 'and', map [ 'trait', '=', [ $_, $fil->{tagspoil} ] ], $fil->{trait_inc}->@* ] : (), + defined $fil->{trait_exc} ? [ 'and', map [ 'trait', '!=', [ $_, 2 ] ], $fil->{trait_exc}->@* ] : (), + defined $fil->{role} ? [ 'or', map [ 'role', '=', $_ ], $fil->{role}->@* ] : (), + ] +} + 1; diff --git a/lib/VNWeb/VN/List.pm b/lib/VNWeb/VN/List.pm index 08cce9bc..df6c54b5 100644 --- a/lib/VNWeb/VN/List.pm +++ b/lib/VNWeb/VN/List.pm @@ -2,6 +2,7 @@ package VNWeb::VN::List; use VNWeb::Prelude; use VNWeb::AdvSearch; +use VNWeb::Filters; sub listing_ { @@ -45,15 +46,40 @@ sub listing_ { TUWF::get qr{/experimental/v}, sub { my $opt = tuwf->validate(get => - q => { onerror => '' }, + q => { onerror => undef }, + sq=> { onerror => undef }, p => { upage => 1 }, f => { advsearch => 'v' }, s => { onerror => 'title', enum => [qw/title rel pop rating/] }, o => { onerror => 'a', enum => ['a','d'] }, ch=> { onerror => [], type => 'array', scalar => 1, values => { onerror => undef, enum => ['0', 'a'..'z'] } }, + fil => { required => 0 }, + rfil => { required => 0 }, + cfil => { required => 0 }, )->data; + $opt->{q} //= $opt->{sq}; $opt->{ch} = $opt->{ch}[0]; + # URL compatibility with old filters + if(!$opt->{f}->{query} && ($opt->{fil} || $opt->{rfil} || $opt->{cfil})) { + my $q = eval { + my $fil = filter_vn_adv filter_parse v => $opt->{fil}; + my $rfil = filter_release_adv filter_parse r => $opt->{rfil}; + my $cfil = filter_char_adv filter_parse c => $opt->{cfil}; + my @q = ( + $fil && @$fil > 1 ? $fil : (), + $rfil && @$rfil > 1 ? [ 'release', '=', $rfil ] : (), + $cfil && @$cfil > 1 ? [ 'character', '=', $cfil ] : (), + ); + tuwf->compile({ advsearch => 'v' })->validate(@q > 1 ? ['and',@q] : @q)->data; + }; + if(!$q) { + warn "Filter compatibility conversion failed\n$@"; + } else { + return tuwf->resRedirect(tuwf->reqPath().'?'.query_encode(%$opt, fil => undef, rfil => undef, cfil => undef, f => $q), 'temp'); + } + } + my $where = sql_and 'NOT v.hidden', $opt->{f}->sql_where(), $opt->{q} ? map sql('v.c_search LIKE', \"%$_%"), normalize_query $opt->{q} : (), @@ -111,7 +137,7 @@ TUWF::get qr{/experimental/v}, sub { }; br_; form_ action => '/experimental/v', method => 'get', sub { - searchbox_ v => $opt->{q}; + searchbox_ v => $opt->{q}//''; p_ class => 'browseopts', sub { button_ type => 'submit', name => 'ch', value => ($_//''), ($_//'') eq ($opt->{ch}//'') ? (class => 'optselected') : (), !defined $_ ? 'ALL' : $_ ? uc $_ : '#' for (undef, 'a'..'z', 0); |