File Coverage

blib/lib/WebService/Mojang/Minecraft/UUIDLookup.pm
Criterion Covered Total %
statement 17 39 43.5
branch 0 16 0.0
condition 0 3 0.0
subroutine 6 8 75.0
pod 2 2 100.0
total 25 68 36.7


line stmt bran cond sub pod time code
1             package WebService::Mojang::Minecraft::UUIDLookup;
2              
3 1     1   13565 use 5.006;
  1         2  
4 1     1   3 use strict;
  1         1  
  1         16  
5 1     1   371 use Data::UUID;
  1         531  
  1         68  
6 1     1   465 use Moo;
  1         9232  
  1         6  
7 1     1   1650 use LWP::UserAgent;
  1         35369  
  1         35  
8 1     1   574 use JSON;
  1         8524  
  1         6  
9              
10             our $VERSION = '0.05';
11              
12             =head1 NAME
13              
14             WebService::Mojang::Minecraft::UUIDLookup - look up Minecraft usernames/UUIDs
15              
16             =head1 DESCRIPTION
17              
18             A simple module to use Mojang's API to look up a Minecraft user's UUID from
19             their username (and provide any previous names they've had), or given a UUID,
20             return all names that account has had.
21              
22              
23             =head1 SYNOPSIS
24              
25              
26             use WebService::Mojang::Minecraft::UUIDLookup;
27              
28             my $mojang_lookup = WebService::Mojang::Minecraft::UUIDLookup->new();
29              
30             # Look up a username and get their UUID and previous names
31             if (my $user_details = $mojang_lookup->lookup_user($username)) {
32             say "$username's UUID is " . $user_details->{uuid};
33             if ($user_details->{previous_names}) {
34             say "Previous names for $username: "
35             . join ',', @{ $user_details->{previous_names} };
36             }
37             } else {
38             warn "Username $username not found";
39             }
40              
41             # Or lookup a UUID and find the current username, and any previous ones
42             if (my $user_details = $mojang_lookup->lookup_uuid($user_uuid)) {
43             say "$user_uuid is $user_details->{username}";
44             if ($user_details->{previous_names}) {
45             say "Previous names for $user_details_>{username}: "
46             . join ',', @{ $user_details->{previous_names} };
47             }
48             } else {
49             warn "UUID $user_uuid not found";
50             }
51              
52             =cut
53              
54             has user_agent => (
55             is => 'rw',
56             isa => sub { my $val = shift; ref $val && $val->isa('LWP::UserAgent') },
57             default => sub {
58             LWP::UserAgent->new( agent => __PACKAGE__ . "/$VERSION" ),
59             },
60             );
61             has lookup_previous_usernames => (
62             is => 'rw',
63             default => 1,
64             );
65              
66             =head1 Methods
67              
68             =head2 lookup_user
69              
70             Given a username, return their UUID and any previous usernames they had (unless
71             the lookup_previous_usernames option is set to a false value; it defaults to
72             enabled, but if you don't care about previous usernames and want to save an API
73             call you can disable it.
74              
75             Returns undef if Mojang indicated no match, otherwise a hash (in list context)
76             or hashref (in scalar context) with the keys:
77              
78             =over
79              
80             =item C
81              
82             The UUID for this username; this identifies the Mojang account, and does not
83             change, even if the user renames their account.
84              
85             =item C
86              
87             The UUID for this username - as C, but formatted using L's
88             C method (e.g. C<85d699cb21774d538366f2cdf9dc93cd> as returned by
89             Mojang becomes C<36643538-3939-6263-3231-373734643533>).
90              
91             =item C
92              
93             The current username for this account
94              
95             =item C
96              
97             An arrayref of previous usernames this account has been known by, unless the
98             C attribute is set to a false value.
99              
100             =back
101              
102             If the account wasn't found, returns undef. Dies if it wasn't possible to
103             retrieve a response from Mojang.
104              
105             =cut
106              
107             sub lookup_user {
108 0     0 1   my ($self, $username) = @_;
109              
110 0           my $response = $self->user_agent->get(
111             "https://api.mojang.com/users/profiles/minecraft/$username"
112             );
113 0 0         if (!$response->is_success) {
114 0           die "Failed to query Mojang API: " . $response->status_line;
115             }
116              
117             # If there's no such user, Mojang return status 204 with an empty body
118 0 0         if ($response->code == 204) {
119 0           return;
120             }
121              
122 0 0         my $result = JSON::from_json($response->decoded_content)
123             or die "Failed to parse Mojang API response";
124            
125             my %return = (
126             uuid => $result->{id},
127             username => $result->{name},
128 0           );
129              
130             # Provide padded uuid too
131             $return{formatted_uuid} = Data::UUID->new->to_string(
132             Data::UUID->new->from_string($result->{id})
133 0           );
134              
135 0 0 0       if ($result->{id} && $self->lookup_previous_usernames) {
136 0           my $uuid_lookup = $self->lookup_uuid($result->{id});
137 0           $return{previous_usernames} = $uuid_lookup->{previous_usernames};
138             }
139 0 0         return wantarray ? %return : \%return;
140             }
141            
142              
143              
144             =head2 lookup_uuid
145              
146             Given a Mojang account UUID, returns a hash (in list context) or a hashref (in
147             scalar context) with the following keys:
148              
149             =over
150              
151             =item C
152              
153             The account's UUID (as you supplied)
154              
155             =item C
156              
157             The account's current username
158              
159             =item C
160              
161             Any previous usernames this account has used.
162              
163             =back
164              
165             If the account wasn't found, returns undef. Dies if it wasn't possible to
166             retrieve a response from Mojang.
167              
168             =cut
169              
170             sub lookup_uuid {
171 0     0 1   my ($self, $uuid) = @_;
172              
173 0           my $response = $self->user_agent->get(
174             "https://api.mojang.com/user/profiles/$uuid/names"
175             );
176 0 0         if (!$response->is_success) {
177 0           die "Failed to query Mojang API: " . $response->status_line;
178             }
179 0 0         my $result = JSON::from_json($response->decoded_content)
180             or die "Failed to parse Mojang API response";
181            
182 0           my $primary_username = pop @$result;
183             my %return = (
184             uuid => $uuid,
185             username => $primary_username->{name},
186 0           previous_usernames => [ map { $_->{name} } @$result ],
  0            
187             );
188              
189 0 0         return wantarray ? %return : \%return;
190             }
191              
192             =head1 AUTHOR
193              
194             David Precious, C<< >>
195              
196              
197             =head1 BUGS / CONTRIBUTING
198              
199             Bug reports and pull requests are welcomed on GitHub:
200              
201             L
202              
203              
204             =head1 LICENSE AND COPYRIGHT
205              
206             Copyright 2015 David Precious.
207              
208             This program is free software; you can redistribute it and/or modify it
209             under the terms of the the Artistic License (2.0). You may obtain a
210             copy of the full license at:
211              
212             L
213              
214             Any use, modification, and distribution of the Standard or Modified
215             Versions is governed by this Artistic License. By using, modifying or
216             distributing the Package, you accept this license. Do not use, modify,
217             or distribute the Package, if you do not accept this license.
218              
219             If your Modified Version has been derived from a Modified Version made
220             by someone other than you, you are nevertheless required to ensure that
221             your Modified Version complies with the requirements of this license.
222              
223             This license does not grant you the right to use any trademark, service
224             mark, tradename, or logo of the Copyright Holder.
225              
226             This license includes the non-exclusive, worldwide, free-of-charge
227             patent license to make, have made, use, offer to sell, sell, import and
228             otherwise transfer the Package with respect to any patent claims
229             licensable by the Copyright Holder that are necessarily infringed by the
230             Package. If you institute patent litigation (including a cross-claim or
231             counterclaim) against any party alleging that the Package constitutes
232             direct or contributory patent infringement, then this Artistic License
233             to you shall terminate on the date that such litigation is filed.
234              
235             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
236             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
237             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
238             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
239             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
240             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
241             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
242             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
243              
244              
245             =cut
246              
247             1; # End of WebService::Mojang::Minecraft::UUIDLookup