File Coverage

blib/lib/Net/FS/Flickr.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Net::FS::Flickr;
2 1     1   1999 use Data::Dumper;
  1         7545  
  1         79  
3 1     1   1092 use LWP::Simple;
  1         107940  
  1         12  
4 1     1   752 use Acme::Steganography::Image::Png;
  0            
  0            
5             use File::Temp qw/tempdir/;
6             use Cwd qw(cwd);
7             use Net::FS::Flickr::Access;
8             use Net::FS::Flickr::DefaultImage;
9              
10             use strict;
11             our $VERSION = "0.1";
12             our $FILESTORE_VERSION = "0.1"; # this way we can track different revisions of filestore format
13              
14              
15             =head1 NAME
16              
17             Net::FS::Flickr - store and retrieve files on Flickr
18              
19             =head1 SYNOPSIS
20              
21             my $fs = Net::FS::Flickr->new( key => $key, secret => $secret );
22              
23             $fs->set_auth($auth_key); # see API KEYS AND AUTH KEY section
24             $fs->store("file.txt");
25             $fs->store("piccy.jpg", "renamed_piccy.jpg");
26              
27             open (FILE, ">output.jpg") || die "Couldn't write to file: $!\n";
28             binmode (FILE);
29             print FILE $fs->retrieve("renamed_piccy.jpg");
30             close (FILE);
31              
32             =head1 API KEYS AND AUTH KEY
33              
34             You will need to sign up for an API key and then get the corresponding
35             secret key. You can do that from here
36              
37             http://www.flickr.com/services/api/key.gne
38              
39             Finally you will need to get an auth key. As described here
40              
41             http://www.flickr.com/services/api/auth.howto.desktop.html
42              
43             the helper script C supplied with this distribution can help with that.
44              
45             =head1 METHODS
46              
47             =cut
48              
49             =head2 new
50              
51             Takes a valid API key and a valid secret key
52              
53             =cut
54              
55             sub new {
56             my $class = shift;
57             my %opts = @_;
58             my $flickr = Net::FS::Flickr::Access->new({ key => $opts{key}, secret => $opts{secret} });
59             my $writer = Acme::Steganography::Image::Png::RGB::556FS->new();
60             my $self = { _flickr => $flickr, _writer => $writer };
61             return bless $self, $class;
62             }
63              
64             =head2 files [nsid, email or username]
65              
66             Get a list of all the files on the system
67              
68             Given an nsid, username or email, use that. Otherwise use the nsid from
69             the auth token.
70              
71             =cut
72              
73             sub files {
74             my $self = shift;
75             my $nsid = shift;
76             if (!defined $nsid) {
77             $nsid = $self->get_nsid_from_token();
78             } else {
79             $nsid = $self->{_flickr}->get_nsid($nsid);
80             }
81              
82             my %files;
83             foreach my $s ($self->{_flickr}->list_sets()) {
84             next unless $s->{title} =~ m!^FlickrStore v[\d.]+ !;
85             $files{$'}++;
86             }
87             return keys %files;
88             }
89              
90             =head2 versions [nsid, email or username]
91              
92             Returns a list of all the versions of a file
93              
94             Each item on the list is a hashref containing the date the file was saved
95             and the id of that version using the keys I and I respectively.
96              
97             The list is sorted, latest version first.
98              
99             Because of the way Flickr stores sets, timestamp will always be 0;
100              
101             Given an nsid, username or email, use that. Otherwise use the nsid from
102             the auth token.
103              
104             =cut
105              
106             sub versions {
107             my $self = shift;
108             my $file = shift;
109             my $nsid = shift;
110             if (!defined $nsid) {
111             $nsid = $self->get_nsid_from_token();
112             } else {
113             $nsid = $self->{_flickr}->get_nsid($nsid);
114             }
115              
116             my @versions;
117             foreach my $s ($self->{_flickr}->list_sets()) {
118             next unless $s->{title} =~ m!^FlickrStore v[\d.]+ $file$!;
119             my $id = $s->{id};
120             my $timestamp = 0;
121             push @versions, { id => $id };
122             }
123             return @versions;
124             }
125              
126             =head2 retrieve [version]
127              
128             Get from Flickr.
129              
130             If the file has multiple versions then you can pass in a version number to get version
131             - 1 being the oldest. If you don't pass in a version then you get the latest.
132              
133              
134             =cut
135              
136             sub retrieve {
137             my $self = shift;
138             my $file = shift;
139             my $version = shift;
140              
141             my @versions = $self->versions($file);
142              
143             die "Couldn't find $file\n" unless @versions;
144              
145             my $id;
146             if (!defined $version) {
147             $id = $versions[0]->{id};
148             } elsif ($version > @versions || $version < 1) {
149             die "No such version $version\n";
150             } else {
151             $id = $versions[-$version]->{id};
152             }
153              
154             my $dir = tempdir( CLEANUP => 1 );
155             my $old = cwd;
156             chdir($dir);
157              
158             ## first get a list of all the photos in this set
159             my @photos = $self->{_flickr}->get_set_photos($id);
160              
161             ## then download them all to the temp directory (in order of upload time)
162             my $count = 1;
163             my @files;
164             foreach my $p (@photos) {
165             my $file = "${count}.png"; $count++;
166             my $url = "http://static.flickr.com/".$p->{server}."/".$p->{id}."_".$p->{secret}."_o.png";
167             my $rc = LWP::Simple::getstore($url, $file);
168             if (is_error($rc)) {
169             die "Couldn't fetch $url - $rc";
170             }
171             push @files, $file;
172             }
173              
174             ## then fire-up our steganography stuff
175             my $data = $self->{_writer}->read_files(reverse @files);
176             chdir($old);
177             return $data;
178             }
179              
180             =head2 store [as]
181              
182             Store the file on Flickr. If a second filename is given then use that
183             as the name on Flickr
184              
185             This works by stashing the data in the least significant bits of as many images as
186             is need. by default an, err, default image is used. But you can set alternative
187             images using the C method.
188              
189             =cut
190              
191             sub store {
192             my $self = shift;
193             my $file = shift;
194             my $as = shift; $as = $file unless defined $as;
195             die "No such file $file\n" unless -f $file;
196              
197             my $name = "FlickrStore v$FILESTORE_VERSION $as";
198              
199             ## First take the file and generate the steganographic images
200             # create a temporary dir
201             my $dir = tempdir( CLEANUP => 1 );
202             my $old = cwd;
203             open (FILE, "$file") || die "Cannot read file $file: $!";
204             # read the file in
205             my $data;
206             { local $/ = undef; $data = ; }
207             close FILE;
208             $self->{_writer}->data(\$data); # warning - could take a while
209             chdir($dir);
210              
211            
212             if (!exists $self->{_images} || 'ARRAY' ne ref($self->{_images}) || !@{$self->{_images}}) {
213             $self->{_images} = [ Net::FS::Flickr::DefaultImage->restore ];
214             }
215             my $i = int(rand(scalar(@{$self->{_images}})-1));
216             my @filenames = $self->{_writer}->write_images($self->{_images}->[$i]);
217            
218              
219             ## Then upload the files to Flickr, noting the IDs
220             my @ids;
221             foreach my $fn (@filenames) {
222             my $id = $self->{_flickr}->upload( photo => $fn, auth_token => $self->{_flickr}->{auth} );
223             die "Couldn't upload files\n" unless defined $id;
224             push @ids, $id;
225             }
226              
227             # change back
228             chdir($old);
229              
230             ## Then create a new set on your flickr account with the name set as the filename
231             my $set_id = $self->{_flickr}->new_set("$name", shift @ids);
232              
233             ## Then add all the previous images to the set
234             $self->{_flickr}->add_to_set($set_id, $_) for @ids;
235              
236             ## Profit!
237             return 1;
238              
239             }
240              
241             =head2 image_pool [image[s]]
242              
243             With no arguments, returns an array of all the images in the current image pool.
244              
245             If you pass in one or more filenames or Imager objects then those are set as the current pool.
246              
247             =cut
248              
249             sub image_pool {
250             my $self = shift;
251             if (@_) {
252             $self->{_images} = [];
253             }
254              
255             for (@_) {
256             if (ref($_) && $_->isa('Imager')) {
257             push @{$self->{_images}}, $_;
258             next;
259             } elsif (ref($_)) {
260             die "$_ is not an Imager object";
261             }
262             my $tmp = Imager->new;
263             $tmp->open( file => $_ ) or die $tmp->errstr();
264             push @{$self->{_images}}, $tmp;
265             }
266             return @{$self->{_images}};
267              
268             }
269              
270              
271              
272              
273              
274              
275              
276             =head2 set_auth
277              
278             Set the app authorisation key.
279              
280             =cut
281              
282             sub set_auth {
283             my $self = shift;
284             $self->{_flickr}->{auth} = shift;
285             }
286              
287             sub get_frob {
288             my $self = shift;
289             return $self->{_flickr}->get_frob;
290             }
291              
292             sub request_auth_url {
293             my $self = shift;
294             return $self->{_flickr}->request_auth_url(@_);
295             }
296              
297             sub get_token {
298             my $self = shift;
299             return $self->{_flickr}->get_token(@_);
300             }
301              
302             sub get_nsid_from_token {
303             my $self = shift;
304             return $self->{_flickr}->get_nsid_from_token(@_);
305             }
306             1;