diff options
-rw-r--r-- | data/docs/14 | 72 | ||||
-rw-r--r-- | lib/Multi/APIDump.pm | 62 |
2 files changed, 122 insertions, 12 deletions
diff --git a/data/docs/14 b/data/docs/14 index 7bc8e32d..5b6ca8a7 100644 --- a/data/docs/14 +++ b/data/docs/14 @@ -74,3 +74,75 @@ <td>List of parent tags (empty for root tags).</td> </tr> </table> +<p> + Tag names and their aliases are globally unique and self-describing. See the + <a href="/d10#2.2">tag creation guidelines</a> for more information. +</p> + + +:SUB:Traits +<p> + <b>URL:</b> <a href="http://vndb.org/api/traits.json.gz">http://vndb.org/api/traits.json.gz</a><br /> + <b>Updated:</b> Every 24 hours.<br /> + <b>Size:</b> ~170 KiB compressed, ~550 KiB uncompressed.<br /> + This dump includes information about all (approved) character traits in the + JSON format. The top-level type is an array of traits, and each trait is + represented as an object with the following members: +</p> +<table style="margin: 5px 2%; width: 95%"> + <thead><tr> + <td style="width: 80px">Member</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>integer</td> + <td>no</td> + <td>Trait ID</td> + </tr> + <tr> + <td>name</td> + <td>string</td> + <td>no</td> + <td>Trait name</td> + </tr> + <tr class="odd"> + <td>description</td> + <td>string</td> + <td>no</td> + <td>Can include formatting codes as described in <a href="/d9.3">d9.3</a>.</td> + </tr> + <tr> + <td>meta</td> + <td>bool</td> + <td>no</td> + <td>Whether this is a meta trait or not.</td> + </tr> + <tr class="odd"> + <td>vns</td> + <td>integer</td> + <td>no</td> + <td>Number of characters on which this trait and any child traits is used.</td> + </tr> + <tr class="odd"> + <td>aliases</td> + <td>array of strings</td> + <td>no</td> + <td>(Possibly empty) list of alternative names.</td> + </tr> + <tr> + <td>parents</td> + <td>array of integers</td> + <td>no</td> + <td>List of parent traits (empty for root traits).</td> + </tr> +</table> +<p> + Unlike with tags, trait names and aliases are neither globally unique nor + self-describing. If you wish display a trait (name) to the user, you should + do so in combination with its associated root trait. For example, <a + href="/i112">i112</a> is often displayed as "Eyes > Green", to differentiate + it with <a href="/i50">i50</a>, which is "Hair > Green". +</p> diff --git a/lib/Multi/APIDump.pm b/lib/Multi/APIDump.pm index 22f02bad..b9723e67 100644 --- a/lib/Multi/APIDump.pm +++ b/lib/Multi/APIDump.pm @@ -17,11 +17,12 @@ sub spawn { my $p = shift; POE::Session->create( package_states => [ - $p => [qw| _start shutdown generate tags_write |], + $p => [qw| _start shutdown tags_gen tags_write traits_gen traits_write writejson|], ], heap => { regenerate_interval => 86400, # daily min. - tagsfile => "$VNDB::ROOT/www/api/tags.json.gz", + tagsfile => "$VNDB::ROOT/www/api/tags.json.gz", + traitsfile => "$VNDB::ROOT/www/api/traits.json.gz", @_, }, ); @@ -30,19 +31,21 @@ sub spawn { sub _start { $_[KERNEL]->alias_set('apidump'); - $_[KERNEL]->yield('generate'); + $_[KERNEL]->yield('tags_gen'); + $_[KERNEL]->delay(traits_gen => 10); $_[KERNEL]->sig(shutdown => 'shutdown'); } sub shutdown { - $_[KERNEL]->delay('generate'); + $_[KERNEL]->delay('tags_gen'); + $_[KERNEL]->delay('traits_gen'); $_[KERNEL]->alias_remove('apidump'); } -sub generate { - $_[KERNEL]->alarm(generate => int((time+3)/$_[HEAP]{regenerate_interval}+1)*$_[HEAP]{regenerate_interval}); +sub tags_gen { + $_[KERNEL]->alarm(tags_gen => int((time+3)/$_[HEAP]{regenerate_interval}+1)*$_[HEAP]{regenerate_interval}); # The subqueries are kinda ugly, but it's convenient to have everything in a single query. $_[KERNEL]->post(pg => query => q{ @@ -61,18 +64,53 @@ sub tags_write { for(@$res) { $_->{id} *= 1; $_->{meta} = $_->{meta} ? JSON::XS::true : JSON::XS::false; + $_->{vns} *= 1; $_->{aliases} = [ split /\$\$\$-\$\$\$/, ($_->{aliases}||'') ]; $_->{parents} = [ map $_*1, split /,/, ($_->{parents}||'') ]; } - open my $f, '>:gzip:utf8', "$_[HEAP]{tagsfile}~" or die $!; - print $f JSON::XS->new->encode($res); + $_[KERNEL]->yield(writejson => $res, $_[HEAP]{tagsfile}, $time, $ws); +} + + +sub traits_gen { + $_[KERNEL]->alarm(traits_gen => int((time+3)/$_[HEAP]{regenerate_interval}+1)*$_[HEAP]{regenerate_interval}); + + $_[KERNEL]->post(pg => query => q{ + SELECT id, name, alias AS aliases, description, meta, c_items AS chars, + (SELECT string_agg(parent::text, ',') FROM traits_parents WHERE trait = id) AS parents + FROM traits WHERE state = 2 + }, undef, 'traits_write'); +} + + +sub traits_write { + my($res, $time) = @_[ARG1,ARG3]; + my $ws = time; + + for(@$res) { + $_->{id} *= 1; + $_->{meta} = $_->{meta} ? JSON::XS::true : JSON::XS::false; + $_->{chars} *= 1; + $_->{aliases} = [ split /\r?\n/, ($_->{aliases}||'') ]; + $_->{parents} = [ map $_*1, split /,/, ($_->{parents}||'') ]; + } + + $_[KERNEL]->yield(writejson => $res, $_[HEAP]{traitsfile}, $time, $ws); +} + + +sub writejson { + my($data, $file, $sqltime, $procstart) = @_[ARG0..$#_]; + + open my $f, '>:gzip:utf8', "$file~" or die "Writing $file: $!"; + print $f JSON::XS->new->encode($data); close $f; - rename "$_[HEAP]{tagsfile}~", $_[HEAP]{tagsfile} or die $!; + rename "$file~", $file or die "Renaming $file: $!"; - my $wt = time-$ws; - $_[KERNEL]->call(core => log => 'Wrote %s in %.2fs query + %.2fs write, size: %.1fkB, tags: %d.', - $_[HEAP]{tagsfile}, $time, $wt, (-s $_[HEAP]{tagsfile})/1024, scalar @$res); + my $wt = time-$procstart; + $_[KERNEL]->call(core => log => 'Wrote %s in %.2fs query + %.2fs write, size: %.1fkB, items: %d.', + $file, $sqltime, $wt, (-s $file)/1024, scalar @$data); } 1; |