line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::FriendFeed; |
2
|
|
|
|
|
|
|
|
3
|
7
|
|
|
7
|
|
112044
|
use warnings; |
|
7
|
|
|
|
|
18
|
|
|
7
|
|
|
|
|
331
|
|
4
|
7
|
|
|
7
|
|
37
|
use strict; |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
316
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Net::FriendFeed - Perl interface to FriendFeed.com API |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=cut |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.93'; |
13
|
|
|
|
|
|
|
|
14
|
7
|
|
|
7
|
|
5767
|
use Encode; |
|
7
|
|
|
|
|
61599
|
|
|
7
|
|
|
|
|
563
|
|
15
|
7
|
|
|
7
|
|
48
|
use File::Spec; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
165
|
|
16
|
7
|
|
|
7
|
|
7551
|
use HTTP::Request::Common; |
|
7
|
|
|
|
|
59530
|
|
|
7
|
|
|
|
|
473
|
|
17
|
7
|
|
|
7
|
|
1062
|
use LWP::UserAgent; |
|
7
|
|
|
|
|
42013
|
|
|
7
|
|
|
|
|
171
|
|
18
|
7
|
|
|
7
|
|
6425
|
use MIME::Base64 qw/encode_base64/; |
|
7
|
|
|
|
|
5633
|
|
|
7
|
|
|
|
|
504
|
|
19
|
7
|
|
|
7
|
|
55
|
use URI::Escape; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
396
|
|
20
|
|
|
|
|
|
|
|
21
|
7
|
|
|
7
|
|
40
|
use base qw(Class::Accessor); |
|
7
|
|
|
|
|
9
|
|
|
7
|
|
|
|
|
6933
|
|
22
|
|
|
|
|
|
|
Net::FriendFeed->mk_accessors(qw/login remotekey ua return_feeds_as |
23
|
|
|
|
|
|
|
last_error/); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
our $API_ENTRYPOINT = 'http://friendfeed.com/api/'; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $Last_Http_Response; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 SYNOPSIS |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
FriendFeed is a social feed agregator with a clean public REST-based |
32
|
|
|
|
|
|
|
API. This package allows easy access to FriendFeed from Perl. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
Methods are named in accordance with the official Python package. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
use Net::FriendFeed; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $frf = Net::FriendFeed->new; |
39
|
|
|
|
|
|
|
$frf->publish_message('Hello, world!'); |
40
|
|
|
|
|
|
|
... |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=cut |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 GENERAL FUNCTIONS |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head2 new(\%opts) |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
This is a constructor for FriendFeed object. It takes an optional |
49
|
|
|
|
|
|
|
hashref parameter with auth credentials. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Example: |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my $frf_anon = Net::FriendFeed->new; |
54
|
|
|
|
|
|
|
my $frf = Net::FriendFeed->new({login => 'kkapp', remotekey => 'hfytr38'}); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
The remotekey is a kind of easily regeneratable password used |
57
|
|
|
|
|
|
|
only in API functions. A user can get his remotekey here: |
58
|
|
|
|
|
|
|
L |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
Authentication is needed only to post or to read private feeds. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 last_error() |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Returns machine-readable code of the last error. You should consult |
65
|
|
|
|
|
|
|
this code if an API call returns C. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
This is a list of FriendFeed error codes: |
68
|
|
|
|
|
|
|
* bad-id-format - Bad format for UUID argument. |
69
|
|
|
|
|
|
|
* bad-url-format - Bad format for URL argument. |
70
|
|
|
|
|
|
|
* entry-not-found - Entry with the specified UUID was not found. |
71
|
|
|
|
|
|
|
* entry-required - Entry UUID argument is required. |
72
|
|
|
|
|
|
|
* forbidden - User does not have access to entry, room or other entity specified in the request. |
73
|
|
|
|
|
|
|
* image-format-not-supported - Unsupported image format. |
74
|
|
|
|
|
|
|
* internal-server-error - Internal error on FriendFeed server. |
75
|
|
|
|
|
|
|
* limit-exceeded - Request limit exceeded. |
76
|
|
|
|
|
|
|
* room-not-found - Room with specified name not found. |
77
|
|
|
|
|
|
|
* room-required - Room name argument is required. |
78
|
|
|
|
|
|
|
* title-required - Entry title argument is required. |
79
|
|
|
|
|
|
|
* unauthorized - The request requires authentication. |
80
|
|
|
|
|
|
|
* user-not-found - User with specified nickname not found. |
81
|
|
|
|
|
|
|
* user-required - User nickname argument is required. |
82
|
|
|
|
|
|
|
* error - Other unspecified error. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
These error codes are generated inside Net::FriendFeed wrapper code: |
85
|
|
|
|
|
|
|
* need-auth - The request was not made because it requires authentication. |
86
|
|
|
|
|
|
|
* failed-req - The request was not made because of unknown reason. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=cut |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub new { |
91
|
8
|
|
|
8
|
1
|
2351
|
my ($proto, $fields) = @_; |
92
|
8
|
|
66
|
|
|
60
|
my $class = ref $proto || $proto; |
93
|
|
|
|
|
|
|
|
94
|
8
|
100
|
|
|
|
26
|
$fields = {} unless defined $fields; |
95
|
|
|
|
|
|
|
|
96
|
8
|
|
|
|
|
28
|
my $self = { %$fields }; |
97
|
|
|
|
|
|
|
|
98
|
8
|
|
100
|
|
|
60
|
$self->{return_feeds_as} ||= 'structure'; |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# make a copy of $fields. |
101
|
8
|
|
|
|
|
39
|
bless $self, $class; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head2 login([$login]) |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Read/Write accessor for login name. You can either get current login |
107
|
|
|
|
|
|
|
or set it if you'd like to do it after calling C. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head2 remotekey([$remotekey]) |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Read/Write accessor for remotekey. You can either get current remotekey |
112
|
|
|
|
|
|
|
or set it if you'd like to do it after calling C. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
Remotekey is a special password valid only for use via API calls. |
115
|
|
|
|
|
|
|
A user can get his remotekey here: L |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=cut |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub _connect { |
120
|
42
|
|
|
42
|
|
907
|
my $self = shift; |
121
|
|
|
|
|
|
|
|
122
|
42
|
100
|
|
|
|
137
|
unless ($self->ua) { |
123
|
1
|
50
|
|
|
|
24
|
$self->ua(new LWP::UserAgent) |
124
|
|
|
|
|
|
|
or die; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub _has_auth { |
129
|
71
|
|
|
71
|
|
827
|
my $self = shift; |
130
|
|
|
|
|
|
|
|
131
|
71
|
|
100
|
|
|
287
|
return $self->login && $self->remotekey; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 validate() |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Validates the current combination of login and remotekey. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=cut |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub validate { |
141
|
1
|
|
|
1
|
1
|
9
|
my $self = shift; |
142
|
1
|
|
|
|
|
7
|
$self->_http_req('GET', 'validate', 'need auth'); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub _api_url { |
146
|
41
|
|
|
41
|
|
64
|
my $self = shift; |
147
|
41
|
|
|
|
|
63
|
my $uri = shift; |
148
|
|
|
|
|
|
|
|
149
|
41
|
|
|
|
|
340
|
return $API_ENTRYPOINT . $uri; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub _http_req { |
153
|
44
|
|
|
44
|
|
141
|
my ($self, $method, $uri, $needauth, @args) = @_; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# all posts should be authenticated |
156
|
44
|
100
|
100
|
|
|
206
|
if ($needauth && !$self->_has_auth) { |
157
|
3
|
|
|
|
|
72
|
$self->last_error('need-auth'); |
158
|
3
|
|
|
|
|
59
|
return; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
41
|
|
|
|
|
718
|
$self->_connect(); |
162
|
|
|
|
|
|
|
|
163
|
41
|
|
|
|
|
887
|
my ($needs_parsing, $format) = ($self->return_feeds_as eq 'structure', $self->return_feeds_as); |
164
|
41
|
100
|
|
|
|
1508
|
$format = 'json' if $needs_parsing; |
165
|
|
|
|
|
|
|
|
166
|
41
|
|
|
|
|
65
|
my $req; |
167
|
41
|
100
|
|
|
|
118
|
if ($method eq 'GET') { |
168
|
20
|
|
|
|
|
70
|
my $get_uri = URI->new($self->_api_url($uri)); |
169
|
20
|
100
|
|
|
|
70342
|
$get_uri->query_form(format => $format) unless $format eq 'json'; |
170
|
20
|
100
|
|
|
|
549
|
$get_uri->query_form(@args) if @args; |
171
|
|
|
|
|
|
|
|
172
|
20
|
|
|
|
|
881
|
$req = GET $get_uri->as_string; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
else { # $method eq 'POST' |
175
|
21
|
|
|
|
|
105
|
my $post_uri = URI->new($self->_api_url($uri)); |
176
|
21
|
100
|
|
|
|
12056
|
$post_uri->query_form(format => $format) unless $format eq 'json'; |
177
|
21
|
|
|
|
|
163
|
$req = POST $post_uri, |
178
|
|
|
|
|
|
|
@args; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
41
|
100
|
|
|
|
45619
|
if ($self->_has_auth) { |
182
|
31
|
|
|
|
|
840
|
$req->header(Authorization => 'Basic ' . encode_base64($self->login . ':' . $self->remotekey, q{})); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
41
|
50
|
|
|
|
2450
|
if ($Last_Http_Response = $self->ua->request($req)) { |
186
|
41
|
100
|
|
|
|
7154
|
unless ($Last_Http_Response->is_success) { |
187
|
1
|
|
|
|
|
14
|
require JSON; # should die if absent |
188
|
1
|
|
|
|
|
17
|
JSON->VERSION(2.0); # we need newer JSON |
189
|
|
|
|
|
|
|
# do some JSON magic |
190
|
1
|
|
|
|
|
6
|
$self->last_error( |
191
|
|
|
|
|
|
|
JSON::from_json($Last_Http_Response->content, { utf8 => 1})->{errorCode} |
192
|
|
|
|
|
|
|
); |
193
|
1
|
|
|
|
|
49
|
return; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
else { |
197
|
0
|
|
|
|
|
0
|
$self->last_error('failed-req'); |
198
|
0
|
|
|
|
|
0
|
return; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
40
|
100
|
|
|
|
573
|
if ($needs_parsing) { |
202
|
35
|
|
|
|
|
322
|
require JSON; # should die if absent |
203
|
35
|
|
|
|
|
3188
|
JSON->VERSION(2.0); # we need newer JSON |
204
|
|
|
|
|
|
|
# do some JSON magic |
205
|
35
|
|
|
|
|
245
|
return JSON::from_json($Last_Http_Response->content, { utf8 => 1}); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
else { |
208
|
5
|
|
|
|
|
20
|
return $Last_Http_Response->content; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub _fetch_feed { |
213
|
19
|
|
|
19
|
|
716
|
my $self = shift; |
214
|
19
|
|
|
|
|
29
|
my $uri = shift; |
215
|
|
|
|
|
|
|
|
216
|
19
|
|
|
|
|
69
|
$self->_http_req('GET', $uri, undef, @_); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub _post { |
220
|
24
|
|
|
24
|
|
339
|
my $self = shift; |
221
|
24
|
|
|
|
|
51
|
my $uri = shift; |
222
|
|
|
|
|
|
|
|
223
|
24
|
|
|
|
|
81
|
$self->_http_req('POST', $uri, 'need auth', @_); |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 list_services |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Returns the list of all services supported by FriendFeed. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
The returned JSON has the format: |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
* services[] |
233
|
|
|
|
|
|
|
o url - the official URL of the service, e.g., http://picasaweb.google.com/ |
234
|
|
|
|
|
|
|
o iconUrl - the URL of the favicon for this service |
235
|
|
|
|
|
|
|
o id - the service's FriendFeed ID, e.g., "picasa" |
236
|
|
|
|
|
|
|
o name - the service's official name, e.g., "Picasa Web Albums" |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=cut |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub list_services { |
241
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
242
|
|
|
|
|
|
|
|
243
|
1
|
|
|
|
|
6
|
$self->_fetch_feed('services', @_); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head1 FEED FUNCTIONS |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
A number of methods fetch arrays of data or "feeds" from FriendFeed. |
249
|
|
|
|
|
|
|
All feeds are available in four different formats. They are |
250
|
|
|
|
|
|
|
C, C, C and C. JSON and XML formats are custom |
251
|
|
|
|
|
|
|
FriendFeed structures, while Atom and RSS are standard XML formats |
252
|
|
|
|
|
|
|
with all FriendFeed specific features represented as custom XML tags. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
Net::FriendFeed adds one additional format called C which |
255
|
|
|
|
|
|
|
means the feeds will be fetched as C and then deserialized into |
256
|
|
|
|
|
|
|
Perl structures using JSON.pm module. The format C is set by |
257
|
|
|
|
|
|
|
default. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
The feeds have the following structure (JSON-like notation is used): |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
* entries[] |
262
|
|
|
|
|
|
|
o id - the FriendFeed entry UUID, used to add comments/likes to the entry |
263
|
|
|
|
|
|
|
o title |
264
|
|
|
|
|
|
|
o link |
265
|
|
|
|
|
|
|
o published |
266
|
|
|
|
|
|
|
o updated |
267
|
|
|
|
|
|
|
o hidden - if true, this entry should be hidden based on the user's preferences |
268
|
|
|
|
|
|
|
o anonymous - if true, user will be present but should not be shown |
269
|
|
|
|
|
|
|
o user{} - the user who shared this entry |
270
|
|
|
|
|
|
|
+ id - the user's FriendFeed UUID |
271
|
|
|
|
|
|
|
+ name - the user's full name |
272
|
|
|
|
|
|
|
+ nickname - the user's FriendFeed nickname, used in FriendFeed URLs |
273
|
|
|
|
|
|
|
+ profileUrl - the user's profile URL on FriendFeed |
274
|
|
|
|
|
|
|
o service{} - the service from which the entry came |
275
|
|
|
|
|
|
|
+ id - the service's FriendFeed ID, e.g., "picasa" |
276
|
|
|
|
|
|
|
+ name - the service's official name, e.g., "Picasa Web Albums" |
277
|
|
|
|
|
|
|
+ iconUrl - the URL of the favicon for this service |
278
|
|
|
|
|
|
|
+ profileUrl - the user's profile URL on this service |
279
|
|
|
|
|
|
|
o comments[] |
280
|
|
|
|
|
|
|
+ date |
281
|
|
|
|
|
|
|
+ id - the UUID of the comment |
282
|
|
|
|
|
|
|
+ user{} - same structure as the user{} structure above |
283
|
|
|
|
|
|
|
+ body - the textual body of the comment |
284
|
|
|
|
|
|
|
o via{}? - present if this comment came from an API client |
285
|
|
|
|
|
|
|
+ name - the name of the API client, e.g., "fftogo" |
286
|
|
|
|
|
|
|
+ url - the official URL of the API client, e.g., http://www.fftogo.com |
287
|
|
|
|
|
|
|
o likes[] |
288
|
|
|
|
|
|
|
+ date |
289
|
|
|
|
|
|
|
+ user{} - same structure as the user{} structure above |
290
|
|
|
|
|
|
|
o media[] - the videos/images associated with the entry |
291
|
|
|
|
|
|
|
+ title? - the title of the media file |
292
|
|
|
|
|
|
|
+ player? - the player for this media file (e.g., the YouTube.com URL with the embedded video) |
293
|
|
|
|
|
|
|
+ thumbnails[] - the thumbnails for this media file |
294
|
|
|
|
|
|
|
# url |
295
|
|
|
|
|
|
|
# width |
296
|
|
|
|
|
|
|
# height |
297
|
|
|
|
|
|
|
+ content[] - the different versions of the media file |
298
|
|
|
|
|
|
|
# url |
299
|
|
|
|
|
|
|
# type - the MIME type of the media file |
300
|
|
|
|
|
|
|
# width |
301
|
|
|
|
|
|
|
# height |
302
|
|
|
|
|
|
|
o via{}? - present if this entry came from an API client |
303
|
|
|
|
|
|
|
+ name - the name of the API client, e.g., "Alert Thingy" |
304
|
|
|
|
|
|
|
+ url - the official URL of the API client, e.g., http://www.alertthingy.com/ |
305
|
|
|
|
|
|
|
o room{}? - if the entry is in a room, the room the entry is in |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
+ id - the room's FriendFeed UUID |
308
|
|
|
|
|
|
|
+ name - the room's display name |
309
|
|
|
|
|
|
|
+ nickname - the room's FriendFeed nickname, used in FriendFeed URLs |
310
|
|
|
|
|
|
|
+ url - the room's URL on FriendFeed |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
The simple XML format has the same structure as the JSON. The RSS and Atom formats use the standard RSS and Atom attributes for title, link, published, and updated, and include extension elements for all of the other meta-data. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Dates in JSON and dates in the FriendFeed extension elements in the Atom and RSS feeds are in RFC 3339 format in UTC. You can parse them with the strptime string "%Y-%m-%dT%H:%M:%SZ". |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
All feed-fetching methods support additional parameters: |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=over |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item service |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
only return entries from the service with the given ID, e.g., service=twitter |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item start |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
return entries starting with the given index, e.g., start=30 |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item num |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
return num entries starting from start, e.g., num=10 |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=back |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
They can be passed as key => value pairs after all the other arguments. |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
$frf->fetch_user_feed('kkapp', num => 50, service => 'twitter'); |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=cut |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head2 return_feeds_as($type) |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Gets or sets the type of return feeds. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
This can be one of C and defaults to |
345
|
|
|
|
|
|
|
C<'structure'> which is a parsed Perl data structure. Other types are |
346
|
|
|
|
|
|
|
string scalars. |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=cut |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 fetch_public_feed |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Fetches the most recent 30 public entries published to FriendFeed. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=cut |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub fetch_public_feed { |
357
|
1
|
|
|
1
|
1
|
8
|
my $self = shift; |
358
|
|
|
|
|
|
|
|
359
|
1
|
|
|
|
|
7
|
$self->_fetch_feed('feed/public', @_); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=head2 fetch_user_feed($nickname) |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
Fetches the most recent entries from a user feed. |
365
|
|
|
|
|
|
|
If the user has a private feed, authentication is required. |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=cut |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
sub fetch_user_feed { |
370
|
2
|
|
|
2
|
1
|
14
|
my $self = shift; |
371
|
2
|
|
|
|
|
4
|
my $nickname = shift; |
372
|
|
|
|
|
|
|
|
373
|
2
|
|
|
|
|
11
|
$self->_fetch_feed('feed/user/' . uri_escape($nickname), @_); |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head2 fetch_user_comments_feed($nickname) |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Returns the most recent entries the user has commented on, ordered by the date of that user's comments. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=cut |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub fetch_user_comments_feed { |
383
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
384
|
1
|
|
|
|
|
3
|
my $nickname = shift; |
385
|
|
|
|
|
|
|
|
386
|
1
|
|
|
|
|
6
|
$self->_fetch_feed('feed/user/' . uri_escape($nickname) . '/comments', @_); |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=head2 fetch_user_likes_feed($nickname) |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
Returns the most recent entries the user has "liked," ordered by the date of that user's "likes". |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=cut |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub fetch_user_likes_feed { |
396
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
397
|
1
|
|
|
|
|
2
|
my $nickname = shift; |
398
|
|
|
|
|
|
|
|
399
|
1
|
|
|
|
|
4
|
$self->_fetch_feed('feed/user/' . uri_escape($nickname) . '/likes', @_); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=head2 fetch_user_discussion_feed($nickname) |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
Returns the most recent entries the user has commented on or "liked". |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=cut |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub fetch_user_discussion_feed { |
409
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
410
|
1
|
|
|
|
|
3
|
my $nickname = shift; |
411
|
|
|
|
|
|
|
|
412
|
1
|
|
|
|
|
5
|
$self->_fetch_feed('feed/user/' . uri_escape($nickname) . '/discussion', @_); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head2 fetch_user_friends_feed($nickname) |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
Fetch a users "friends" feed. This feed contains entries |
418
|
|
|
|
|
|
|
from the user and her friends. No private feeds will be included |
419
|
|
|
|
|
|
|
unless you are authenticated and have access to that feed. |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=cut |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub fetch_user_friends_feed { |
424
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
425
|
1
|
|
|
|
|
3
|
my $nickname = shift; |
426
|
|
|
|
|
|
|
|
427
|
1
|
|
|
|
|
7
|
$self->_fetch_feed('feed/user/' . uri_escape($nickname) . '/friends', @_); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=head2 fetch_multi_user_feed(@nicknames) |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
Returns the most recent entries from a list of users, specified by nickname: |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
If more than one nickname is specified, the feed most recent entries |
435
|
|
|
|
|
|
|
from all of the given users. If any one of the users has a private |
436
|
|
|
|
|
|
|
feed, authentication is required. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
User nicknames may also be passed as an arrayref. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
$frf->fetch_multi_user_feed(qw/kkapp mihun/); |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=cut |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub fetch_multi_user_feed { |
445
|
3
|
|
|
3
|
1
|
20
|
my $self = shift; |
446
|
3
|
|
|
|
|
9
|
my @nicknames = @_; |
447
|
|
|
|
|
|
|
|
448
|
2
|
|
|
|
|
7
|
ref $nicknames[0] eq 'ARRAY' |
449
|
3
|
100
|
|
|
|
14
|
and @nicknames = @{$nicknames[0]}; |
450
|
|
|
|
|
|
|
|
451
|
3
|
|
|
|
|
16
|
$self->_fetch_feed('feed/user', nickname => join(',', @nicknames), @_); |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=head2 fetch_room_feed($room) |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Returns the most recent entries in the room with the given nickname. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
If the room is private, authentication is required. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=cut |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub fetch_room_feed { |
463
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
464
|
1
|
|
|
|
|
2
|
my $room = shift; |
465
|
|
|
|
|
|
|
|
466
|
1
|
|
|
|
|
6
|
$self->_fetch_feed('feed/room/' . uri_escape($room), @_); |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=head2 fetch_home_feed |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Returns the entries the authenticated user would see on their FriendFeed homepage - all of their subscriptions and friend-of-a-friend entries. |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
Authentication is always required. |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=cut |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
sub fetch_home_feed { |
478
|
2
|
|
|
2
|
1
|
472
|
my $self = shift; |
479
|
|
|
|
|
|
|
|
480
|
2
|
100
|
|
|
|
6
|
$self->_has_auth and |
481
|
|
|
|
|
|
|
$self->_fetch_feed('feed/home', @_); |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=head2 fetch_entry($uuid[, @uuids]) |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
Fetches a single or a list of entries by UUIDs. Needs authentication to read |
487
|
|
|
|
|
|
|
private entries. |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
You can request up to 100 entries on each call. The entries you don't |
490
|
|
|
|
|
|
|
have permission to read will be filtered out from the result feed. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=cut |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
sub fetch_entry { |
495
|
2
|
|
|
2
|
1
|
20
|
my $self = shift; |
496
|
2
|
|
|
|
|
5
|
my @entry_ids = @_; |
497
|
|
|
|
|
|
|
|
498
|
2
|
100
|
|
|
|
9
|
if (@entry_ids == 1) { |
499
|
1
|
|
|
|
|
10
|
$self->_fetch_feed('feed/entry/' . uri_escape($entry_ids[0])); |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
else { |
502
|
1
|
|
|
|
|
8
|
$self->_fetch_feed('feed/entry', entry_id => |
503
|
|
|
|
|
|
|
Encode::encode('UTF-8', join(',', @entry_ids))); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=head2 search($query) |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
Executes a search over the entries in FriendFeed. If the request is |
510
|
|
|
|
|
|
|
authenticated, the default scope is over all of the entries in the |
511
|
|
|
|
|
|
|
authenticated user's Friends Feed. If the request is not |
512
|
|
|
|
|
|
|
authenticated, the default scope is over all public entries. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
$frf->search('rambler service:twitter'); |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
The query syntax is the same syntax as http://friendfeed.com/search/advanced. The query operators are: |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=over |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=item who: |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
restricts the search to a specific user, e.g., who:bret |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=item service: |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
restricts the search to a specific service ID, e.g., service:twitter |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=back |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=cut |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
sub search { |
533
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
534
|
1
|
|
|
|
|
3
|
my $q = shift; |
535
|
|
|
|
|
|
|
|
536
|
1
|
|
|
|
|
7
|
$self->_fetch_feed('feed/search', q => Encode::encode('UTF-8', $q), @_); |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=head1 PUBLISHING FUNCTIONS |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
You can perform test calls from a web browser using the HTTP Basic |
542
|
|
|
|
|
|
|
Authentication built into your browser at |
543
|
|
|
|
|
|
|
L. |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
Requests to FriendFeed are rate limited, which, e.g., limits the |
546
|
|
|
|
|
|
|
number and size of thumbnails you can upload in a day. Normal uses |
547
|
|
|
|
|
|
|
should fall well within our rate limits. If you encounter HTTP 403 |
548
|
|
|
|
|
|
|
errors because of rate limits, and you think the limit is erroneous, |
549
|
|
|
|
|
|
|
please let us know in the developer forum. |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=cut |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=head2 publish_link($title, $link, $comment, [@images, [$imgN, $linkN]], $room, $via) |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
Share a link with a title, images and other possible options. |
556
|
|
|
|
|
|
|
Requires authentication. |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
All non-ASCII input data should be clean Perl Unicode (that is, decoded from |
559
|
|
|
|
|
|
|
any encoding). FriendFeed API is strictly UTF-8 so we unconditionally |
560
|
|
|
|
|
|
|
encode strings into UTF-8 via Encode::encode('UTF-8', $data) call. |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
Full signature looks like: |
563
|
|
|
|
|
|
|
$frf->publish_link($title, $link, $comment, [@images, [$imgN, $linkN]], $room, $via) |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=over |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=item $title |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Mandatory title of the shared item. |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=item $links |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
URL to refer to. If absent, the shared link reduces to text. |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=item $comment |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
Automatically add 1st comment to the item. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=item $images |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
This one is an arrayref of image items. Each image item is either an image PURL or a |
582
|
|
|
|
|
|
|
pair (taken as arrayrefs of two elements) of PURL => URL. PURL in the |
583
|
|
|
|
|
|
|
pair points to the image and URL is used as a href to follow when the |
584
|
|
|
|
|
|
|
user clicks on this very image. URL defaults to the main $link. |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
Each PURL may be either an (http|https|ftp) URL or a PATH to a local |
587
|
|
|
|
|
|
|
file in which case that file gets uploaded directly to FriendFeed. |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=item $room |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
This is a room nickname to which the link should be published. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=item $via |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
This is an identifier of your software. It's ignored unless you |
596
|
|
|
|
|
|
|
register it with FriendFeed administration. |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=back |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
=cut |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
sub publish_link { |
603
|
13
|
|
|
13
|
1
|
68
|
my $self = shift; |
604
|
13
|
|
|
|
|
28
|
my ($msg, $link, $comment, $imgs, $room, $via) = @_; |
605
|
|
|
|
|
|
|
|
606
|
13
|
|
|
|
|
41
|
my @args = (); |
607
|
|
|
|
|
|
|
|
608
|
13
|
|
|
|
|
83
|
push @args, title => Encode::encode('UTF-8', $msg); |
609
|
13
|
100
|
|
|
|
859
|
push @args, 'link' => $link if defined $link; |
610
|
13
|
100
|
|
|
|
46
|
push @args, comment => Encode::encode('UTF-8', $comment) if defined $comment; |
611
|
13
|
100
|
|
|
|
95
|
push @args, room => $room if defined $room; |
612
|
13
|
100
|
|
|
|
34
|
push @args, via => $via if defined $via; |
613
|
|
|
|
|
|
|
|
614
|
13
|
|
|
|
|
16
|
my $multipart; |
615
|
|
|
|
|
|
|
|
616
|
13
|
100
|
100
|
|
|
59
|
if ($imgs && ref $imgs eq 'ARRAY') { |
617
|
3
|
|
|
|
|
12
|
foreach (0 .. $#$imgs) { |
618
|
5
|
100
|
|
|
|
13
|
if (ref $imgs->[$_]) { # image AND link |
619
|
|
|
|
|
|
|
|
620
|
2
|
100
|
|
|
|
13
|
if ($imgs->[$_]->[0] =~ m{^(?:http|https|ftp)://}) { # remote image |
621
|
1
|
|
|
|
|
10
|
push @args, ("image${_}_url" => $imgs->[$_]->[0], "image${_}_link" => $imgs->[$_]->[1]); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
else { |
624
|
1
|
|
|
|
|
2
|
$multipart = 1; |
625
|
1
|
|
|
|
|
27
|
my $filename = (File::Spec->splitpath($imgs->[$_]->[0]))[2]; # kinda basename |
626
|
1
|
|
|
|
|
8
|
push @args, ("image${_}" => [$imgs->[$_]->[0], $filename], "${filename}_link" => $imgs->[$_]->[1]); |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
else { |
630
|
3
|
100
|
|
|
|
24
|
if ($imgs->[$_] =~ m{^(?:http|https|ftp)://}) { # remote image |
631
|
2
|
|
|
|
|
14
|
push @args, ("image${_}_url" => $imgs->[$_]); |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
else { |
634
|
1
|
|
|
|
|
3
|
$multipart = 1; |
635
|
1
|
|
|
|
|
5
|
push @args, ("image${_}" => [$imgs->[$_]]); |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
13
|
100
|
|
|
|
74
|
$self->_post('share', Content => \@args, |
642
|
|
|
|
|
|
|
$multipart ? (Content_Type => 'form-data') : ()); |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=head2 publish_message($msg) |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
Share a piece of text. The simplest form of FriendFeed sharing. |
648
|
|
|
|
|
|
|
Requires authentication. |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
This is actually a special case of publish_link with only $title set. |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=cut |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
sub publish_message { |
655
|
5
|
|
|
5
|
1
|
632
|
my $self = shift; |
656
|
5
|
|
|
|
|
8
|
my $msg = shift; |
657
|
|
|
|
|
|
|
|
658
|
5
|
|
|
|
|
17
|
$self->publish_link($msg); |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=head2 delete_entry($entry_id) |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Delete an entry. The arguments are: |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
=over |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=item $entry_id |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry. |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
=back |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=cut |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
sub delete_entry { |
676
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
677
|
1
|
|
|
|
|
2
|
my $entry_id = shift; |
678
|
|
|
|
|
|
|
|
679
|
1
|
|
|
|
|
16
|
$self->_post('entry/delete', [entry => $entry_id]); |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=head2 undelete_entry($entry_id) |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
Undelete a deleted entry. The arguments are: |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=over |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=item $entry_id |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry. |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=back |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=cut |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
sub undelete_entry { |
697
|
1
|
|
|
1
|
1
|
5
|
my $self = shift; |
698
|
1
|
|
|
|
|
3
|
my $entry_id = shift; |
699
|
|
|
|
|
|
|
|
700
|
1
|
|
|
|
|
4
|
$self->_post('entry/delete', [ |
701
|
|
|
|
|
|
|
entry => $entry_id, |
702
|
|
|
|
|
|
|
undelete => 1, |
703
|
|
|
|
|
|
|
]); |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=head2 hide_entry($entry_id) |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
Hides an entry for current user. The arguments are: |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=over |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=item $entry_id |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry. |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=back |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=cut |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub hide_entry { |
721
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
722
|
1
|
|
|
|
|
2
|
my $entry_id = shift; |
723
|
|
|
|
|
|
|
|
724
|
1
|
|
|
|
|
5
|
$self->_post('entry/hide', [entry => $entry_id]); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=head2 unhide_entry($entry_id) |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
Unhide a hidden entry. The arguments are: |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=over |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=item $entry_id |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry. |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=back |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=cut |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
sub unhide_entry { |
742
|
1
|
|
|
1
|
1
|
5
|
my $self = shift; |
743
|
1
|
|
|
|
|
2
|
my $entry_id = shift; |
744
|
|
|
|
|
|
|
|
745
|
1
|
|
|
|
|
5
|
$self->_post('entry/hide', [ |
746
|
|
|
|
|
|
|
entry => $entry_id, |
747
|
|
|
|
|
|
|
unhide => 1, |
748
|
|
|
|
|
|
|
]); |
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
=head1 COMMENT AND LIKE FUNCTIONS |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=head2 add_comment($entry_id, $body, $via) |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
Add a comment on a FriendFeed entry. The arguments are: |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=over |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
=item $entry_id |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry to which this comment is attached. |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
=item $body |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
required - The textual body of the comment. |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
=item $via |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
This is an identifier of your software. It's ignored unless you |
770
|
|
|
|
|
|
|
register it with FriendFeed administration. |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
=back |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
$frf->add_comment('550e8400-e29b-41d4-a716-446655440000', 'Testing the FriendFeed API', 'Microsoft Word'); |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=cut |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
sub add_comment { |
779
|
2
|
|
|
2
|
1
|
12
|
my $self = shift; |
780
|
2
|
|
|
|
|
5
|
my ($entry_id, $comment_text, $via) = @_; |
781
|
|
|
|
|
|
|
|
782
|
2
|
100
|
|
|
|
14
|
$self->_post('comment', [entry => $entry_id, body => Encode::encode('UTF-8', $comment_text), defined $via ? (via => $via) : ()]); |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
=head2 edit_comment($entry_id, $body, $comment_id) |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
Edit an existing comment on a FriendFeed entry. The arguments are: |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
=over |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
=item $entry_id |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry to which this comment is attached. |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
=item $body |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
required - The textual body of the comment. |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
=item $comment_id |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
The FriendFeed UUID of the comment to edit. If not given, the request will create a new comment. |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=back |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=cut |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
sub edit_comment { |
808
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
809
|
1
|
|
|
|
|
4
|
my ($entry_id, $comment_text, $comment_id) = @_; |
810
|
|
|
|
|
|
|
|
811
|
1
|
|
|
|
|
8
|
$self->_post('comment', [ |
812
|
|
|
|
|
|
|
entry => $entry_id, |
813
|
|
|
|
|
|
|
comment => $comment_id, |
814
|
|
|
|
|
|
|
body => Encode::encode('UTF-8', $comment_text), |
815
|
|
|
|
|
|
|
]); |
816
|
|
|
|
|
|
|
} |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=head2 delete_comment($entry_id, $comment_id) |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
Delete an existing comment. The arguments are: |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
=over |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
=item $entry_id |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry to which this comment is attached. |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=item $comment_id |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
required - The FriendFeed UUID of the comment to delete. |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
=back |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
=cut |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
sub delete_comment { |
837
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
838
|
1
|
|
|
|
|
3
|
my ($entry_id, $comment_id) = @_; |
839
|
|
|
|
|
|
|
|
840
|
1
|
|
|
|
|
5
|
$self->_post('comment/delete', [entry => $entry_id, comment => $comment_id]); |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=head2 undelete_comment($entry_id, $comment_id) |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
Undelete a deleted comment. The arguments are: |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=over |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=item $entry_id |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry to which this comment is attached. |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
=item $comment_id |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
required - The FriendFeed UUID of the comment to undelete. |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
=back |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
=cut |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
sub undelete_comment { |
862
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
863
|
1
|
|
|
|
|
2
|
my ($entry_id, $comment_id) = @_; |
864
|
|
|
|
|
|
|
|
865
|
1
|
|
|
|
|
6
|
$self->_post('comment/delete', [ |
866
|
|
|
|
|
|
|
entry => $entry_id, |
867
|
|
|
|
|
|
|
comment => $comment_id, |
868
|
|
|
|
|
|
|
undelete => 1, |
869
|
|
|
|
|
|
|
]); |
870
|
|
|
|
|
|
|
} |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=head2 add_like($entry_id) |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
Add a "Like" to a FriendFeed entry for the authenticated user. |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=over |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=item $entry_id |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry to which this comment is attached |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
=back |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
$frf->add_like("550e8400-e29b-41d4-a716-446655440000"); |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
=cut |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
sub add_like { |
889
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
890
|
1
|
|
|
|
|
3
|
my $entry_id = shift; |
891
|
|
|
|
|
|
|
|
892
|
1
|
|
|
|
|
5
|
$self->_post('like', [entry => $entry_id]); |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
=head2 delete_like($entry_id) |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
Delete an existing "Like". The arguments are: |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
=over |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=item $entry_id |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
required - The FriendFeed UUID of the entry to which this comment is attached. |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
=back |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
=cut |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
sub delete_like { |
910
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
911
|
1
|
|
|
|
|
2
|
my $entry_id = shift; |
912
|
|
|
|
|
|
|
|
913
|
1
|
|
|
|
|
5
|
$self->_post('like/delete', [entry => $entry_id]); |
914
|
|
|
|
|
|
|
} |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=head1 PROFILE FUNCTIONS |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
=head2 fetch_user_profile($nickname) |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
Returns list of all of the user's subscriptions (people) and services connected to their account. |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
The returned data has this structure: |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
* id - the user's FriendFeed UUID |
925
|
|
|
|
|
|
|
* name - the user's full name |
926
|
|
|
|
|
|
|
* nickname - the user's FriendFeed nickname, used in FriendFeed URLs |
927
|
|
|
|
|
|
|
* profileUrl - the user's profile URL on FriendFeed |
928
|
|
|
|
|
|
|
* services[] - the services connected to the user's account |
929
|
|
|
|
|
|
|
o id - the service's FriendFeed ID, e.g., "picasa" |
930
|
|
|
|
|
|
|
o name - the service's official name, e.g., "Picasa Web Albums" |
931
|
|
|
|
|
|
|
o url - the official URL of the service, e.g., http://picasaweb.google.com/ |
932
|
|
|
|
|
|
|
o iconUrl - the URL of the favicon for this service |
933
|
|
|
|
|
|
|
o profileUrl? - the user's profile URL on this service, if any |
934
|
|
|
|
|
|
|
o username? - the user's username for this service, if any |
935
|
|
|
|
|
|
|
* subscriptions[] - the users this user is subscribed to |
936
|
|
|
|
|
|
|
o id |
937
|
|
|
|
|
|
|
o name |
938
|
|
|
|
|
|
|
o nickname |
939
|
|
|
|
|
|
|
o profileUrl |
940
|
|
|
|
|
|
|
* rooms[] - the rooms this user is a member of |
941
|
|
|
|
|
|
|
o id - the room's FriendFeed UUID |
942
|
|
|
|
|
|
|
o name - the room's display name |
943
|
|
|
|
|
|
|
o nickname - the room's FriendFeed nickname, used in FriendFeed URLs |
944
|
|
|
|
|
|
|
o url - the room's URL on FriendFeed |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
=cut |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
sub fetch_user_profile { |
949
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
950
|
1
|
|
|
|
|
3
|
my $nickname = shift; |
951
|
|
|
|
|
|
|
|
952
|
1
|
|
|
|
|
8
|
$self->_fetch_feed('user/' . uri_escape($nickname) . '/profile', @_); |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
=head2 fetch_user_profiles(@nicknames) |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
Returns profiles for multiple users. The returned structure has one |
958
|
|
|
|
|
|
|
element C which is an array of profile structures described |
959
|
|
|
|
|
|
|
alongside C method. |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
User nicknames may also be passed as an arrayref. |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=cut |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
sub fetch_user_profiles { |
966
|
2
|
|
|
2
|
1
|
12
|
my $self = shift; |
967
|
2
|
|
|
|
|
6
|
my @nicknames = @_; |
968
|
|
|
|
|
|
|
|
969
|
1
|
|
|
|
|
3
|
ref $nicknames[0] eq 'ARRAY' |
970
|
2
|
100
|
|
|
|
9
|
and @nicknames = @{$nicknames[0]}; |
971
|
|
|
|
|
|
|
|
972
|
2
|
|
|
|
|
12
|
$self->_fetch_feed('profiles', nickname => join(',', @nicknames), @_); |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=head1 AUTHOR |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
Alex Kapranoff, C<< >> |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=head1 BUGS |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
982
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
983
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
=head1 SUPPORT |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
perldoc Net::FriendFeed |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
You can also look for information at: |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
=over 4 |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
L |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
L |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
=item * CPAN Ratings |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
L |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
=item * Search CPAN |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
L |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
=back |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
Mark Carey prompted to implement C for comments. |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
Copyright 2008 Alex Kapranoff, all rights reserved. |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
This program is released under the following license: GPLv3 |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=cut |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
1; # End of Net::FriendFeed |