diff options
author | Yorhel <git@yorhel.nl> | 2009-11-07 15:41:08 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2009-11-07 15:41:08 +0100 |
commit | a418f879fc377c64e2acbbf5d54f97ad524f3302 (patch) | |
tree | a7679f2e552426dc1d2b94f429c764418501874c | |
parent | 4b73f8b3d33344432f464dc6d8f8258d3dea5295 (diff) |
API: Added get release command
Still needs more filters, and info flags for producers and vns.
-rw-r--r-- | data/docs/11 | 144 | ||||
-rw-r--r-- | lib/Multi/API.pm | 152 |
2 files changed, 272 insertions, 24 deletions
diff --git a/data/docs/11 b/data/docs/11 index 70c5b2f5..99c727d7 100644 --- a/data/docs/11 +++ b/data/docs/11 @@ -402,6 +402,150 @@ however still required.<br /> novel and its releases. Note that the algorithm of this search may change and that it can use a different algorithm than the search function on the website. </td> +</table><br /><br /> + +<b>Returned object members for the 'release' type:</b> +<table style="margin: 5px 2%; width: 95%"> + <thead><tr> + <td style="width: 80px">Member</td> + <td style="width: 50px">Flag</td> + <td style="width: 90px">Type</td> + <td style="width: 40px">null</td> + <td>Description</td> + </tr></thead> + <tr class="odd"> + <td>id</td> + <td>-</td> + <td>integer</td> + <td>no</td> + <td>Release ID</td> + </tr> + <tr> + <td>title</td> + <td>basic</td> + <td>string</td> + <td>no</td> + <td>Release title (romaji)</td> + </tr> + <tr class="odd"> + <td>original</td> + <td>basic</td> + <td>string</td> + <td>yes</td> + <td>Original/official title of the release.</td> + </tr> + <tr> + <td>released</td> + <td>basic</td> + <td>date (string)</td> + <td>yes</td> + <td>Release date</td> + </tr> + <tr class="odd"> + <td>type</td> + <td>basic</td> + <td>string</td> + <td>no</td> + <td>"complete", "partial" or "trial"</td> + </tr> + <tr> + <td>patch</td> + <td>basic</td> + <td>boolean</td> + <td>no</td> + <td> </td> + </tr> + <tr class="odd"> + <td>freeware</td> + <td>basic</td> + <td>boolean</td> + <td>no</td> + <td> </td> + </tr> + <tr> + <td>doujin</td> + <td>basic</td> + <td>boolean</td> + <td>no</td> + <td> </td> + </tr> + <tr class="odd"> + <td>languages</td> + <td>basic</td> + <td>array of strings</td> + <td>no</td> + <td> </td> + </tr> + <tr> + <td>website</td> + <td>details</td> + <td>string</td> + <td>yes</td> + <td>Official website URL</td> + </tr> + <tr class="odd"> + <td>notes</td> + <td>details</td> + <td>string</td> + <td>yes</td> + <td>Random notes, can contain formatting codes as described in <a href="/d9.3">d9.3</a></td> + </tr> + <tr> + <td>minage</td> + <td>details</td> + <td>integer</td> + <td>yes</td> + <td>Age rating, 0 = all ages.</td> + </tr> + <tr class="odd"> + <td>gtin</td> + <td>details</td> + <td>string</td> + <td>yes</td> + <td>JAN/UPC/EAN code. This is actually an integer, but formatted as a string to avoid an overflow on 32bit platforms.</td> + </tr> + <tr> + <td>catalog</td> + <td>details</td> + <td>string</td> + <td>yes</td> + <td>Catalog number.</td> + </tr> + <tr class="odd"> + <td>platforms</td> + <td>details</td> + <td>array of strings</td> + <td>no</td> + <td>Empty array when platform is unknown.</td> + </tr> + <tr> + <td>media</td> + <td>details</td> + <td>array of objects</td> + <td>no</td> + <td> + Objects have the following two members:<br /> + "medium", string<br /> + "qty", integer, the quantity. <b>null</b> when it is not applicable for the medium.<br /> + An empty array is returned when the media are unknown. + </td> + </tr> +</table> + +<b>Accepted filters for the 'release' type:</b> +<table style="margin: 5px 2%; width: 95%"> + <thead><tr> + <td style="width: 80px">Field</td> + <td style="width: 90px">Value</td> + <td style="width: 90px">Operators</td> + <td> </td> + </tr></thead> + <tr class="odd"> + <td>id</td> + <td>integer<br />array of integers</td> + <td>= != > >= < <=<br />= !=</td> + <td> </td> + </tr> </table> diff --git a/lib/Multi/API.pm b/lib/Multi/API.pm index 7b36755d..20b89778 100644 --- a/lib/Multi/API.pm +++ b/lib/Multi/API.pm @@ -17,9 +17,14 @@ use Time::HiRes 'time'; # important for throttling # not exported by Socket, taken from netinet/tcp.h (specific to Linux, AFAIK) -sub TCP_KEEPIDLE { 4 } -sub TCP_KEEPINTVL { 5 } -sub TCP_KEEPCNT { 6 } +sub TCP_KEEPIDLE () { 4 } +sub TCP_KEEPINTVL () { 5 } +sub TCP_KEEPCNT () { 6 } + + +# what our JSON encoder considers 'true' or 'false' +sub TRUE () { JSON::XS::true } +sub FALSE () { JSON::XS::false } # Global throttle hash, key = username, value = [ cmd_time, sql_time ] @@ -33,8 +38,7 @@ sub spawn { package_states => [ $p => [qw| _start shutdown log server_error client_connect client_error client_input - login login_res - get_vn get_vn_res + login login_res get_results get_vn get_vn_res get_release get_release_res |], ], heap => { @@ -279,7 +283,7 @@ sub client_input { # handle get command return cerr $c, 'parse', "Unkown command '$cmd'" if $cmd ne 'get'; my $type = shift @$arg; - return cerr $c, 'gettype', "Unknown get type: '$type'" if $type ne 'vn'; + return cerr $c, 'gettype', "Unknown get type: '$type'" if $type !~ /^(?:vn|release)$/; $_[KERNEL]->yield("get_$type", $c, @$arg); } @@ -327,6 +331,20 @@ sub login_res { # num, res, [ c, arg ] } +sub get_results { + my $get = $_[ARG0]; # hashref, must contain: type, c, queries, time, list, info, filters, + + # update sql throttle + $get->{c}{throttle}[1] += $get->{time}*$_[HEAP]{throttle_sql}[0]; + + # send and log + my $num = @{$get->{list}}; + $get->{c}{wheel}->put([ results => { num => $num, items => $get->{list} }]); + $_[KERNEL]->yield(log => $get->{c}, "T:%4.0fms Q:%d R:%02d get %s %s %s", + $get->{time}*1000, $get->{queries}, $num, $get->{type}, join(',', @{$get->{info}}), encode_filters $get->{filters}); +} + + sub get_vn { my($c, $info, $filters) = @_[ARG0..$#_]; @@ -438,29 +456,115 @@ sub get_vn_res { my @ids = map $_->{latest}, @{$get->{list}}; my $ids = join ',', map '?', @ids; - if(!$get->{anime} && grep /anime/, @{$get->{info}}) { - return $_[KERNEL]->post(pg => query => qq| - SELECT va.vid, a.id, a.year, a.ann_id, a.nfo_id, a.type, a.title_romaji, a.title_kanji - FROM anime a JOIN vn_anime va ON va.aid = a.id WHERE va.vid IN($ids)|, - \@ids, 'get_vn_res', { %$get, type => 'anime' }); - } + !$get->{anime} && grep(/anime/, @{$get->{info}}) && return $_[KERNEL]->post(pg => query => qq| + SELECT va.vid, a.id, a.year, a.ann_id, a.nfo_id, a.type, a.title_romaji, a.title_kanji + FROM anime a JOIN vn_anime va ON va.aid = a.id WHERE va.vid IN($ids)|, + \@ids, 'get_vn_res', { %$get, type => 'anime' }); + + !$get->{relations} && grep(/relations/, @{$get->{info}}) && return $_[KERNEL]->post(pg => query => qq| + SELECT vl.vid1, v.id, vl.relation, vr.title, vr.original FROM vn_relations vl + JOIN vn v ON v.id = vl.vid2 JOIN vn_rev vr ON vr.id = v.latest WHERE vl.vid1 IN($ids) AND NOT v.hidden|, + \@ids, 'get_vn_res', { %$get, type => 'relations' }); + + # send results + delete $_->{latest} for @{$get->{list}}; + $_[KERNEL]->yield(get_results => { %$get, type => 'vn' }); +} + + +sub get_release { + my($c, $info, $filters) = @_[ARG0..$#_]; + + return cerr $c, getinfo => "Unkown info flag '$_'", flag => $_ for (grep !/^(basic|details)$/, @$info); + + my $select = 'r.id, r.latest'; + $select .= ', rr.title, rr.original, rr.released, rr.type, rr.patch, rr.freeware, rr.doujin' if grep /basic/, @$info; + $select .= ', rr.website, rr.notes, rr.minage, rr.gtin, rr.catalog' if grep /details/, @$info; + + my @placeholders; + my $where = encode_filters $filters, \&filtertosql, $c, \@placeholders, [ + [ 'id', + [ 'int' => 'r.id :op: :value:', {qw|= = != <> > > >= >= < < <= <=|} ], + [ inta => 'r.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',' ], + ], + ]; + return if !$where; + + $_[KERNEL]->post(pg => query => + qq|SELECT $select FROM releases r JOIN releases_rev rr ON rr.id = r.latest WHERE $where AND NOT hidden LIMIT 10|, + \@placeholders, 'get_release_res', { c => $c, info => $info, filters => $filters }); +} + + +sub get_release_res { + my($num, $res, $get, $time) = (@_[ARG0..$#_]); - if(!$get->{relations} && grep /relations/, @{$get->{info}}) { - return $_[KERNEL]->post(pg => query => qq| - SELECT vl.vid1, v.id, vl.relation, vr.title, vr.original FROM vn_relations vl - JOIN vn v ON v.id = vl.vid2 JOIN vn_rev vr ON vr.id = v.latest WHERE vl.vid1 IN($ids) AND NOT v.hidden|, - \@ids, 'get_vn_res', { %$get, type => 'relations' }); + $get->{time} += $time; + $get->{queries}++; + + # process the results + if(!$get->{type}) { + for (@$res) { + $_->{id}*=1; + if(grep /basic/, @{$get->{info}}) { + $_->{original} ||= undef; + $_->{released} = formatdate($_->{released}); + $_->{patch} = $_->{patch} ? TRUE : FALSE; + $_->{freeware} = $_->{freeware} ? TRUE : FALSE; + $_->{doujin} = $_->{doujin} ? TRUE : FALSE; + } + if(grep /details/, @{$get->{info}}) { + $_->{website} ||= undef; + $_->{notes} ||= undef; + $_->{minage} = $_->{minage} < 0 ? undef : $_->{minage}*1; + $_->{gtin} ||= undef; + $_->{catalog} ||= undef; + } + } + $get->{list} = $res; + } + elsif($get->{type} eq 'languages') { + for my $i (@{$get->{list}}) { + $i->{languages} = [ map $i->{latest} == $_->{rid} ? $_->{lang} : (), @$res ]; + } + $get->{languages} = 1; + } + elsif($get->{type} eq 'platforms') { + for my $i (@{$get->{list}}) { + $i->{platforms} = [ map $i->{latest} == $_->{rid} ? $_->{platform} : (), @$res ]; + } + $get->{platforms} = 1; + } + elsif($get->{type} eq 'media') { + for my $i (@{$get->{list}}) { + $i->{media} = [ grep $i->{latest} == $_->{rid}, @$res ]; + } + for (@$res) { + delete $_->{rid}; + $_->{qty} = $VNDB::S{media}{$_->{medium}} ? $_->{qty}*1 : undef; + } + $get->{media} = 1; } - # update sql throttle - $get->{c}{throttle}[1] += $get->{time}*$_[HEAP]{throttle_sql}[0]; + # get more info + my @ids = map $_->{latest}, @{$get->{list}}; + my $ids = join ',', map '?', @ids; - # send and log + !$get->{languages} && grep(/basic/, @{$get->{info}}) && return $_[KERNEL]->post(pg => query => + qq|SELECT rid, lang FROM releases_lang WHERE rid IN($ids)|, + \@ids, 'get_release_res', { %$get, type => 'languages' }); + + !$get->{platforms} && grep(/details/, @{$get->{info}}) && return $_[KERNEL]->post(pg => query => + qq|SELECT rid, platform FROM releases_platforms WHERE rid IN($ids)|, + \@ids, 'get_release_res', { %$get, type => 'platforms' }); + + !$get->{media} && grep(/details/, @{$get->{info}}) && return $_[KERNEL]->post(pg => query => + qq|SELECT rid, medium, qty FROM releases_media WHERE rid IN($ids)|, + \@ids, 'get_release_res', { %$get, type => 'media' }); + + # send results delete $_->{latest} for @{$get->{list}}; - $num = @{$get->{list}}; - $get->{c}{wheel}->put([ results => { num => $num, items => $get->{list} }]); - $_[KERNEL]->yield(log => $get->{c}, "T:%4.0fms Q:%d R:%02d get vn %s %s", - $get->{time}*1000, $get->{queries}, $num, join(',', @{$get->{info}}), encode_filters $get->{filters}); + $_[KERNEL]->yield(get_results => { %$get, type => 'release' }); } |