diff options
author | Yorhel <git@yorhel.nl> | 2022-11-16 16:55:42 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2022-11-16 17:01:25 +0100 |
commit | 06a3e3b28bf79d9023423e2a07c0498f99d5eb6c (patch) | |
tree | f73636c9b53089715e3b1c6309678ac1d4c7385c | |
parent | 33c83c7d94857df03b4872388b570cf3a04dad7c (diff) |
API2: Document the release `extlink` filter + add id/url lookup
-rw-r--r-- | data/api-kana.md | 19 | ||||
-rw-r--r-- | lib/VNWeb/AdvSearch.pm | 67 |
2 files changed, 75 insertions, 11 deletions
diff --git a/data/api-kana.md b/data/api-kana.md index b9a4cf85..90a1b4d3 100644 --- a/data/api-kana.md +++ b/data/api-kana.md @@ -600,6 +600,8 @@ Name [F] Description Otherwise, this matches the `rtype` of any linked visual novel. +`extlink` m Match on external links, see below for details. + `patch` Integer, only accepts the value `1`. `freeware` See `patch`. @@ -617,7 +619,22 @@ Name [F] Description matching the given [producer filters](#producer-filters). ----------------------------------------------------------------------------- -*Undocumented: animation, extlinks* +The `extlink` filter can be used with three types of values: + +- Just a site name, e.g. `["extlink","=","steam"]` matches all releases that + have a steam ID. +- A two-element array indicating the site name and the remote identifier, e.g. + `["extlink","=",["steam",702050]]` to match the Saya no Uta release on Steam. + The second element can be either an int or a string, depending on the site, + but integer identifiers are also accepted when formatted as a string. +- A URL, e.g. `["extlink","=","https://store.steampowered.com/app/702050/"]` is + equivalent to the above example. + +In all of the above forms, an error is returned if the site is not known in the +database or if the URL format is not recognized. The list of supported sites +and URL formats tends to change over time. + +*Undocumented: animation* ### Fields {#release-fields} diff --git a/lib/VNWeb/AdvSearch.pm b/lib/VNWeb/AdvSearch.pm index 4cd0fcf5..7a3d78a5 100644 --- a/lib/VNWeb/AdvSearch.pm +++ b/lib/VNWeb/AdvSearch.pm @@ -392,16 +392,7 @@ f r => 18 => 'rlist', { uint => 1, enum => \%RLIST_STATUS }, sql_list => sub return '1=0' if !auth; sql 'r.id', $neg ? 'NOT' : '', 'IN(SELECT rid FROM rlists WHERE uid =', \auth->uid, 'AND status IN', $val, $all && @$val > 1 ? ('GROUP BY rid HAVING COUNT(status) =', \scalar @$val) : (), ')'; }; -f r => 19 => 'extlink', { enum => [map s/^l_//r, keys $VNDB::ExtLinks::LINKS{r}->%*] }, '=' => sub { - my $arg = $_; - state $schema = (grep +($_->{dbentry_type}||'') eq 'r', values VNDB::Schema::schema->%*)[0]; - state %L = map { - my($f, $n, $p) = ($_, s/^l_//r, $VNDB::ExtLinks::LINKS{r}{$_}); - my($s) = grep $_->{name} eq $f, $schema->{cols}->@*; - +($n, 'r.'.$f.' <> '.($s->{type} =~ /\[\]/ ? "'{}'" : $s->{type} =~ /^(big)?int/ ? 0 : "''")) - } keys $VNDB::ExtLinks::LINKS{r}->%*; - $L{$arg} // $L{"l_$arg"}; - }; +f r => 19 => 'extlink', _extlink_filter('r'); f r => 61 => 'patch', { uint => 1, range => [1,1] }, '=' => sub { 'r.patch' }; f r => 62 => 'freeware', { uint => 1, range => [1,1] }, '=' => sub { 'r.freeware' }; f r => 64 => 'uncensored',{uint => 1, range => [1,1] }, '=' => sub { 'r.uncensored' }; @@ -484,6 +475,61 @@ f i => 2 => 'id', { vndbid => 'i' }, sql => sub { sql 't.id', $_[0], \$_ f i => 80 => 'search', {}, '=' => sub { sql 't.c_search LIKE ALL (search_query(', \$_, '))' }; + +# 'extlink' filter accepts the following values: +# - $name - Whether the entry has a link of site $name +# - [ $name, $val ] - Whether the entry has a link of site $name with the given $val +# - "$name,$val" - Compact version of above (not really *compact* by any means, but this filter isn't common anyway) +# - "http://..." - Auto-detect version of [$name,$val] +# TODO: This only handles links defined in %LINKS, but it would be nice to also support links from Wikidata & PlayAsia. +sub _extlink_filter { + my($type) = @_; + my $schema = (grep +($_->{dbentry_type}||'') eq $type, values VNDB::Schema::schema->%*)[0]; + my %links = map { + my $n = $_; + my $l = $VNDB::ExtLinks::LINKS{$type}{$n}; + my $s = (grep $_->{name} eq $n, $schema->{cols}->@*)[0]; + (s/^l_//r, +{ %$l, + _col => $n, + _schema => $s, + _regex => $l->{regex} && VNDB::ExtLinks::full_regex($l->{regex}), + _empty => $s->{type} =~ /\[\]/ ? "'{}'" : $s->{type} =~ /^(big)?int/i ? 0 : "''" + }) + } keys $VNDB::ExtLinks::LINKS{$type}->%*; + + my sub _val { + return 1 if !ref $_[0] && $links{$_[0]}; # just $name + if(!ref $_[0] && $_[0] =~ /^https?:/) { # URL + for (keys %links) { + if($links{$_}{_regex} && $_[0] =~ $links{$_}{_regex}) { + $_[0] = [ $_, $1 ]; + last; + } + } + return { msg => 'Unrecognized URL format' } if !ref $_[0]; + } + $_[0] = [ split /,/, $_[0], 2 ] if !ref $_[0]; # compact $name,$val form + + # normalized $name,$val form + return 0 if ref $_[0] ne 'ARRAY' || $_[0]->@* != 2 || ref $_[0][0] || ref $_[0][1] || !defined $_[0][1]; + my $l = $links{$_[0][0]}; + return { msg => "Unknown field '$_[0][0]'" } if !$l; + return { msg => "Invalid value '$_[0][1]'" } if $l->{_schema}{type} =~ /^int/i && ($_[0][1] !~ /^-?[0-9]+$/ || $_[0][1] >= (1<<31) || $_[0][1] <= -(1<<31)); + return { msg => "Invalid value '$_[0][1]'" } if $l->{_schema}{type} =~ /^bigint/i && ($_[0][1] !~ /^-?[0-9]+$/ || $_[0][1] >= (1<<63) || $_[0][1] <= -(1<<63)); + $_[0][1] *= 1 if $l->{_schema}{type} =~ /^(big)?int/i; + 1 + } + + my sub _sql { + return "$type.$links{$_}{_col} <> $links{$_}{_empty}" if !ref; # just name + my($l, $v) = ($links{$_->[0]}, $_->[1]); + sql "$type.$l->{_col}", $l->{_schema}{type} =~ /\[\]/ ? ('&& ARRAY[', \$v, ']::', $l->{_schema}{type}) : ('=', \$v); + } + my sub _comp { ref $_ ? $_->[0].','.(my $x=$_->[1]) : $_ } + ({ type => 'any', func => \&_val }, '=' => \&_sql, compact => \&_comp) +} + + # Accepts either: # - $tag # - [$tag, $exclude_lies*16*3 + int($minlevel*5)*3 + $maxspoil] (compact form) @@ -597,6 +643,7 @@ sub _validate_adv { } + # 'advsearch' validation, accepts either a compact encoded string, JSON string or an already decoded array. TUWF::set('custom_validations')->{advsearch} = sub { my($t) = @_; +{ required => 0, type => 'any', default => bless({type=>$t}, __PACKAGE__), func => sub { _validate_adv $t, @_ } } }; |