summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/docs/1472
-rw-r--r--lib/Multi/APIDump.pm62
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;