line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
use warnings; |
3
|
1
|
|
|
1
|
|
90921
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
34
|
|
4
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
17
|
|
5
|
|
|
|
|
|
|
use WebService::Simple; |
6
|
1
|
|
|
1
|
|
426
|
use base 'WebService::Simple'; |
|
1
|
|
|
|
|
65689
|
|
|
1
|
|
|
|
|
9
|
|
7
|
1
|
|
|
1
|
|
35
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
113
|
|
8
|
|
|
|
|
|
|
use JSON (); |
9
|
1
|
|
|
1
|
|
1703
|
|
|
1
|
|
|
|
|
11393
|
|
|
1
|
|
|
|
|
281
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.11'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# overide our base modules WebService::Simple _agent() method with our own: |
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
12162
|
# similarly for the WebService::Simple built-in config(), which we overwrite like this: |
15
|
|
|
|
|
|
|
__PACKAGE__->config( |
16
|
|
|
|
|
|
|
base_url => 'https://api.twitch.tv/helix/', # needs a trailing slash |
17
|
|
|
|
|
|
|
response_parser => 'JSON', |
18
|
|
|
|
|
|
|
); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# we wrap the underlying base's new() method to attach credentials (which are normally discarded) |
21
|
|
|
|
|
|
|
my $class = shift; |
22
|
|
|
|
|
|
|
my %args = @_; |
23
|
|
|
|
|
|
|
|
24
|
1
|
|
|
1
|
1
|
107
|
die "Net::Twitch::API: new: no access_token provided!" unless $args{access_token}; |
25
|
1
|
|
|
|
|
5
|
die "Net::Twitch::API: new: no client_id provided!" unless $args{client_id}; |
26
|
|
|
|
|
|
|
|
27
|
1
|
50
|
|
|
|
3
|
$args{croak} = 0; # WebService::Simple by default croaks() - which we do not want |
28
|
1
|
50
|
|
|
|
4
|
|
29
|
|
|
|
|
|
|
my $self = $class->SUPER::new(%args); |
30
|
1
|
|
|
|
|
2
|
|
31
|
|
|
|
|
|
|
$self->{access_token} = $args{access_token}; |
32
|
1
|
|
|
|
|
11
|
$self->{client_id} = $args{client_id}; |
33
|
|
|
|
|
|
|
|
34
|
1
|
|
|
|
|
28
|
return $self; |
35
|
1
|
|
|
|
|
2
|
} |
36
|
|
|
|
|
|
|
|
37
|
1
|
|
|
|
|
4
|
my $self = shift; |
38
|
|
|
|
|
|
|
my $params = shift || {}; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $response = $self->get('/users', $params, |
41
|
0
|
|
|
0
|
1
|
|
'Authorization' => 'Bearer '. $self->{access_token}, |
42
|
0
|
|
0
|
|
|
|
'Client-Id' => $self->{client_id}, |
43
|
|
|
|
|
|
|
); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
return $self->_responseParser($response,'getUsers'); |
46
|
|
|
|
|
|
|
} |
47
|
0
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
my $self = shift; |
49
|
0
|
|
|
|
|
|
my $response = shift; |
50
|
|
|
|
|
|
|
my $methodName = shift || '<empty methodName>'; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
## WebService::Simple doesn't wrap error responses, so handle this case here |
53
|
0
|
|
|
0
|
|
|
unless($response->is_success){ |
54
|
0
|
|
|
|
|
|
unless($response->content_length() ){ |
55
|
0
|
|
0
|
|
|
|
return { error => $methodName ." request failed!", status => $response->code, message => $response->message, response => $response }; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
0
|
0
|
|
|
|
|
$response = WebService::Simple::Response->new_from_response( |
59
|
0
|
0
|
|
|
|
|
response => $response, |
60
|
0
|
|
|
|
|
|
parser => $self->response_parser |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
} |
63
|
0
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
my $result = {}; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
$result = $response->parse_response() if $response->content_length(); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
return $result; |
69
|
0
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
0
|
0
|
|
|
|
|
=pod |
72
|
|
|
|
|
|
|
|
73
|
0
|
|
|
|
|
|
=head1 NAME |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
Net::Twitch::API - Helper methods for Twitch's "new" helix API |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=head1 SYNOPSIS |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
use Net::Twitch::API; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
my $api = Net::Twitch::API->new( |
82
|
|
|
|
|
|
|
access_token => 'your-token', |
83
|
|
|
|
|
|
|
client_id => 'your-id', |
84
|
|
|
|
|
|
|
debug => 1, |
85
|
|
|
|
|
|
|
); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
my $response = $api->getUsers({ login => 'twitchdev' }); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head1 DESCRIPTION |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
This module provides methods and helper wrappers to work with what Twitch "new" helix API. The I<new> API is |
92
|
|
|
|
|
|
|
prefixed with the I<helix> codename/namespace and the successor of the old I<kraken> API which was decommissioned |
93
|
|
|
|
|
|
|
on February 28, 2022. A little more about that on dev.twitch.tv L<"legacy v5 integrations" migration guide|https://dev.twitch.tv/docs/api/migration>. |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Using this module to issue requests against Twitch's API requires you to register your "application" with Twitch |
96
|
|
|
|
|
|
|
first. Authentication then is either faciliated via L<OAuth 2.0|https://dev.twitch.tv/docs/authentication/getting-tokens-oauth> |
97
|
|
|
|
|
|
|
or L<OpenID Connect|https://dev.twitch.tv/docs/authentication/getting-tokens-oidc>. We here use the OAuth2 scheme. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Twitch uses several types of auth tokens. Use the twitch CLI client to obtain an "app access token". This type of |
100
|
|
|
|
|
|
|
token enables your app to make secure API requests that are not on behalf of a specific user. App access tokens are |
101
|
|
|
|
|
|
|
meant only for server-to-server API requests and should never be included in client code. Normally, such tokens |
102
|
|
|
|
|
|
|
would be programmatically refreshed at arbitrary intervals according to OAuth2 RFC but on Twitch app access tokens |
103
|
|
|
|
|
|
|
are valid for 60 days and cannot be refreshed. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
This module uses Yosukebe's excellent L<WebService::Simple> as base calss. So look there for addditonal documentation. |
106
|
|
|
|
|
|
|
You might also note that Yosukebe himself recently switched over to the newer L<WebService::Client>, but that's a |
107
|
|
|
|
|
|
|
Moo based module. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head1 FUNCTIONS |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head2 new() |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Calls underlying WebService::Simple's new(), with additional checks and defaults for Twitch. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
You must provide your I<access_token> and I<client_id>. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
If I<debug> is set, the request URL will be dumped via warn() on get or post method calls. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
WebService::Simple by default croaks (dies) on a failed request. This module returns on error and success with a |
120
|
|
|
|
|
|
|
reference to a hash containing received data. The hash key I<error> is defined on unsuccessful requests. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
If you supply a Cache object to new(), each request is prepended by a cache look-up. Refer to L<WebService::Simple> |
123
|
|
|
|
|
|
|
for an example. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 getUsers() |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Expects a hashref. Users can be looked up either via their I<login> name (username / nickname) or via their numeric |
128
|
|
|
|
|
|
|
user I<id>. Twitch allows to ask for multiple names in one request. Current limit is 100. Use an arrayref of values |
129
|
|
|
|
|
|
|
instead of a scalar then. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Returns a hashref with hash-key I<data> holding a reference to an array of users. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head1 EXPORT |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Nothing by default. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=head1 CAVEATS |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Note that Net::Twitch::API is a WIP module. Things are incomplete or may change without notice. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head1 SEE ALSO |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Official Twitch documents: |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=over |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item * |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
L<Getting Started|https://dev.twitch.tv/docs/api> walks you through basic setup of your app and helps with |
150
|
|
|
|
|
|
|
a first request. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item * |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
L<Reference|https://dev.twitch.tv/docs/api/guide> gives an overview of core principles like pagination and rate |
155
|
|
|
|
|
|
|
limits. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=item * |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
L<Reference|https://dev.twitch.tv/docs/api/reference> si the canonical Twitch API endpoints reference. A little |
160
|
|
|
|
|
|
|
more an be found in the L<api docs|https://github.com/twitchdev/twitch-cli/blob/main/docs/api.md> for the twitch-cli command-line client. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=back |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Within the Perl universe, Twitch related code can be found in outdated modules L<App::Twitch> and L<Net::Twitch::Oauth2> |
165
|
|
|
|
|
|
|
and Corion's non-API helper module L<WWW::Twitch|https://github.com/Corion/WWW-Twitch>. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 AUTHOR |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Clipland GmbH L<https://www.clipland.com/> |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
This module was developed for L<"Sendung verpasst?"|https://mediatheksuche.de/> I<video> search engine L<MediathekSuche.de|https://mediatheksuche.de/>. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Copyright 2022 Clipland GmbH. All rights reserved. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
This library is free software, dual-licensed under L<GPLv3|http://www.gnu.org/licenses/gpl>/L<AL2|http://opensource.org/licenses/Artistic-2.0>. |
178
|
|
|
|
|
|
|
You can redistribute it and/or modify it under the same terms as Perl itself. |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=cut |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
1; |