package WCL; use strict; use warnings; use JSON::PP; use MIME::Base64 qw(encode_base64); use Exporter 'import'; our @EXPORT_OK = qw( wcl_token wcl_query fetch_glaive_deaths HEAVENS_GLAIVES_ID ENCOUNTER_NAME DIFFICULTY ); use constant HEAVENS_GLAIVES_ID => 1254076; use constant ENCOUNTER_NAME => 'Midnight Falls'; use constant DIFFICULTY => 5; my $FIGHTS_QUERY = <<'GQL'; query($code: String!) { reportData { report(code: $code) { startTime title zone { name } fights { id name difficulty } } } } GQL my $TABLE_QUERY = <<'GQL'; query($code: String!, $fightIDs: [Int]!, $wipeCutoff: Int!) { reportData { report(code: $code) { table(dataType: Deaths, fightIDs: $fightIDs, wipeCutoff: $wipeCutoff, startTime: 0, endTime: 999999999999) } } } GQL sub wcl_token { my ($http, $client_id, $client_secret) = @_; my $auth = encode_base64("$client_id:$client_secret", ''); my $resp = $http->post_form( 'https://www.warcraftlogs.com/oauth/token', { grant_type => 'client_credentials' }, { headers => { Authorization => "Basic $auth" } }, ); die "WCL token request failed ($resp->{status} $resp->{reason})\n" unless $resp->{success}; return decode_json($resp->{content})->{access_token}; } sub wcl_query { my ($http, $token, $query, $variables) = @_; my $resp = $http->post( 'https://www.warcraftlogs.com/api/v2/client', { headers => { Authorization => "Bearer $token", 'Content-Type' => 'application/json', }, content => encode_json({ query => $query, variables => $variables // {} }), }, ); die "WCL query failed ($resp->{status} $resp->{reason})\n" unless $resp->{success}; my $decoded = decode_json($resp->{content}); return $decoded->{data}; } sub epoch_to_date { my ($epoch) = @_; my @t = localtime($epoch); return sprintf '%04d-%02d-%02d', $t[5] + 1900, $t[4] + 1, $t[3]; } sub fetch_glaive_deaths { my ($http, $token, $code, $wipe_cutoff) = @_; my $fdata = wcl_query($http, $token, $FIGHTS_QUERY, { code => $code }); my $report = $fdata->{reportData}{report}; return undef unless $report; my @fight_ids = map { $_->{id} } grep { $_->{name} eq ENCOUNTER_NAME && ($_->{difficulty} // -1) == DIFFICULTY } @{ $report->{fights} }; my @deaths; if (@fight_ids) { my $tdata = wcl_query($http, $token, $TABLE_QUERY, { code => $code, fightIDs => \@fight_ids, wipeCutoff => $wipe_cutoff, }); my $entries = $tdata->{reportData}{report}{table}{data}{entries} // []; for my $e (@$entries) { my $kb = $e->{killingBlow} or next; next unless ($kb->{guid} // -1) == HEAVENS_GLAIVES_ID; push @deaths, $e->{name}; } } return { title => $report->{title}, raid_date => epoch_to_date($report->{startTime} / 1000), zone_name => $report->{zone}{name} // 'Unknown', fight_count => scalar(@fight_ids), deaths => \@deaths, }; } 1;