File Coverage

blib/lib/WWW/MeGa.pm
Criterion Covered Total %
statement 34 36 94.4
branch n/a
condition n/a
subroutine 12 12 100.0
pod n/a
total 46 48 95.8


line stmt bran cond sub pod time code
1             # $Id: MeGa.pm 193 2009-01-16 13:42:25Z fish $
2             package WWW::MeGa;
3 1     1   774 use 5.6.0;
  1         2  
  1         43  
4 1     1   4 use strict;
  1         2  
  1         31  
5 1     1   14 use warnings;
  1         2  
  1         77  
6              
7             =head1 NAME
8              
9             WWW::MeGa - A MediaGallery
10              
11             =head1 SYNOPSIS
12              
13             use WWW::MeGa;
14             my $webapp = WWW::MeGa->new
15             $webapp->run;
16              
17             =head1 DESCRIPTION
18              
19              
20             THIS IS A SECURITY BUGFIX RELEASE.
21             PLEASE UPDATE TO 0.1.1 IF YOU HAVE 0.1
22              
23              
24             WWW::MeGa is a web based media gallery. It should
25             be run from FastCGI (see examples/gallery.fcgi) or mod_perl (not yet
26             tested) because it uses some runtime caching.
27              
28             Every file will be delievered by the CGI itself. So you don't have
29             to care about setting up picture/thumb dirs.
30              
31             To see it in action, visit: http://freigeist.org/gallery
32             or http://sophiesfotos.de
33              
34             =head1 FEATURES
35              
36             =over
37              
38             =item * on-the-fly image resizing (and orientation tag based autorotating)
39              
40             =item * video thumbnails
41              
42             =item * displays text files
43              
44             =item * reads exif tag
45              
46             =item * very easy to setup (change one path in the config and your done)
47              
48             =item * templating with L
49              
50             =back
51              
52             =head1 INSTALLATION
53              
54             =head2 Install the package
55              
56             Use your favorite way to install this CPAN-Package and make sure you
57             have C somewhere in your path (or specify the path in the
58             config) if you want video thumbnails.
59              
60             If you want to install it via the cpan-installer use:
61              
62             cpan WWW::MeGa
63              
64             To install a developer release of WWW::MeGa, use the CPAN-Shell:
65              
66             perl -MCPAN -eshell
67              
68             Now you can see all releases with C and install the one you want: C
69              
70             B: Installation via C or the CPAN-Shell is only recommended
71             if you have a local administered perl installation. If you installed
72             perl from your packet manager you should use the packet manager to
73             install this package too. Have a look at C (Gentoo) and
74             C (Debian/Ubuntu).
75              
76              
77             =head3 Use FastCGI (preferred)
78              
79             Copy C to some dir and configure your webserver to
80             use it as a FastCGI:
81              
82             Example for lighttpd:
83              
84             fastcgi.server = (
85             "/gallery" =>
86             ( "localhost" =>
87             (
88             "socket" => "/var/run/lighttpd/gallery" + PID + ".socket",
89             "check-local" => "disable",
90             "bin-path" => "/var/www/gallery.fcgi"
91             )
92             ),
93             )
94              
95             =head3 Use CGI
96              
97             Copy C to your C directory and make
98             sure its executable. Now WWW::MeGa should have created a default config
99             file. Change 'root' to your images and you are done.
100              
101             =head3 Config
102              
103             Make sure the user under which the webserver is running has write
104             permission to the config file. The path to the config file defaults to
105             to 'gallery.conf' in the same dir as your script. In these cases:
106             C (FCGI) and
107             C.
108              
109             You can (and should, at least in the CGI case) specify a custom path to
110             the config by changing the scripts to pass:
111              
112             PARAMS => { config => '/path/to/your/config' }
113              
114             to the new method of L.
115              
116             =head4 modified gallery.fcgi
117              
118             ...
119             my $app = WWW::MeGa->new
120             (
121             QUERY => $q,
122             PARAMS => { cache => \%cache, config => '/path/to/your/config' },
123             );
124             ...
125              
126             =head4 modified gallery.cgi
127              
128             ...
129             my $webapp = WWW::MeGa->new(PARAMS => {config => '/path/to/your/config'});
130             ...
131              
132             =head2 Test it
133              
134             Now visit the the URL to you script. (In these examples:
135             http://example.com/gallery (FastCGI) and
136             http://example.com/cgi-bin/gallery.cgi (CGI)) and you
137             should see the example photos.
138              
139             =head1 CONFIG
140              
141             L uses L for config handling.
142             You can specify the path to a (writable) config file in the new methode of WWW::MeGa:
143              
144             my $gallery = WWW::MeGa->new(PARAMS => { config => '/path/to/gallery.conf' })
145              
146             It defaults to $RealBin/gallery.conf, see L for more info.
147             After the first run it will create a config containing the defaults.
148              
149              
150             =head2 Parameters
151              
152             =head3 root
153              
154             Path to your images
155              
156              
157             =head3 cache
158              
159             Path where to store the thumbnails
160              
161             =head3 album-thumb
162              
163             specifies which file should be used a thumbnail for a folder. Defaults to C.
164             The file named like that will be skipped when showing the content of the folder.
165              
166             =head3 thumb-type
167              
168             Type of the thumbnails.
169             L uses L for generating thumbnails.
170             See C for file types supported by you ImageMagick
171             installation.
172              
173             =head3 video-thumbs
174              
175             If set to 1, enables video-thumbs. Default: 1
176              
177             =head3 video-thumbs-offset
178              
179             specifies which frame to grab in seconds. Default: 10
180              
181             =head3 exif
182              
183             If set to 1, enables the extraction of exif-data. Default: 1
184              
185             =head3 ffmpeg-path
186              
187             Specify the path to the ffmpeg-binary. Defaults to 'ffmpeg'. (Should be
188             looked up in your PATH)
189              
190             =head3 sizes
191              
192             A array of valid "thumbnail"/resized image sizes, defaults to
193             C<[ 120, 600, 800 ]>.
194             The CGI parameter C is the index to that array.
195              
196              
197             =head3 debug
198              
199             If set to 1, enabled debugging to your server's error log.
200              
201              
202             =head3 album_thumb
203              
204             Specify the name of the image which will be used as a thumbnail for the
205             containing album, defaults to C.
206              
207             So if you want to have the image C be the thumbnail for the album C, copy it to C (or use a symlink)
208              
209              
210             =head3 icons and templates
211              
212             Path to the icons and templates, defaults to C in the module's share dir as defined by L and L
213              
214              
215             =head1 METHODES
216              
217             =cut
218              
219 1     1   8703 use CGI::Application;
  1         9781  
  1         44  
220 1     1   1067 use File::Spec::Functions qw(splitdir catdir no_upwards);
  1         894  
  1         105  
221 1     1   7 use Scalar::Util;
  1         3  
  1         56  
222 1     1   992 use File::ShareDir;
  1         8426  
  1         65  
223 1     1   1081 use FindBin qw($RealBin);
  1         1275  
  1         150  
224              
225 1     1   7 use base ("CGI::Application::Plugin::HTCompiled", "CGI::Application");
  1         2  
  1         1232  
226              
227 1     1   114718 use CGI::Application::Plugin::Config::Simple;
  1         16335  
  1         106  
228 1     1   1070 use CGI::Application::Plugin::Stream (qw/stream_file/);
  1         963  
  1         71  
229              
230 1     1   645 use WWW::MeGa::Item;
  0            
  0            
231              
232             use Carp;
233              
234             our $VERSION = '0.11';
235             sub setup
236             {
237             my $self = shift;
238             $self->{PathPattern} = "[^-,()'.\/ _0-9A-Za-z\[\]]";
239            
240             my $share = eval { File::ShareDir::module_dir('WWW::MeGa') } || "$RealBin/../share";
241              
242             my $config = $self->config_file($self->param('config') || "$RealBin/gallery.conf");
243              
244             my %default_config =
245             (
246             'sizes' => [ 120, 600, 800 ],
247             'cache' => '/tmp/www-mega',
248             'album_thumb' => 'THUMBNAIL',
249             'thumb-type' => 'png',
250             'video-thumbs' => 1,
251             'video-thumbs-offset' => 10,
252             'exif' => 1,
253             'ffmpeg-path' => 'ffmpeg',
254             'root' => catdir($share, 'images'),
255             'debug' => 0,
256             'icons' => catdir($share, 'icons'),
257             'templates' => catdir($share, 'templates', 'default')
258             );
259              
260             unless ( -e $config )
261             {
262             warn "config '$config' not found, creating default config";
263             my $cfg = new Config::Simple(syntax=>'simple');
264             foreach my $k (keys %default_config)
265             {
266             $cfg->param($k, $default_config{$k})
267             }
268              
269             warn "saving $config";
270             $cfg->write($config) or croak "could not create config '$config': $!";
271             }
272              
273             $self->config_file($config) or croak "could not load config '$config': $!";
274              
275             foreach my $k (keys %default_config)
276             {
277             next if defined $self->config_param($k);
278             $self->config_param($k, $default_config{$k});
279             }
280              
281             croak $self->config_param('root') . " is no directory" unless -d $self->config_param('root');
282              
283             $self->tmpl_path($self->config_param('templates'));
284              
285             $self->{sizes} = $self->config_param('sizes');
286              
287             $self->{cache} = $self->param('cache');
288              
289             $self->run_modes
290             (
291             view => 'view_path',
292             image => 'view_image',
293             );
294             $self->start_mode('view');
295             $self->error_mode('view_error');
296             return;
297             }
298              
299             sub view_error
300             {
301             my $self = shift;
302             my $error = shift;
303             warn "ERROR: $error";
304             my $t = $self->load_tmpl('error.tmpl', die_on_bad_params=>0, global_vars=>1, default_escape =>'HTML');
305             $self->header_props ({-status => 404 });
306             $t->param(ERROR => $error);
307             return $t->output;
308             }
309              
310             sub saneReq
311             {
312             my $self = shift;
313             my $param = shift;
314             my $pattern = shift || $self->{PathPattern};
315             defined(my $req = $self->query->param($param)) or return;
316             $req =~ s/$pattern//g;
317             return $req;
318             }
319              
320             sub pathReq
321             {
322             my $self = shift;
323             my $path = $self->saneReq('path') || '';
324             $path = catdir no_upwards splitdir $path;
325             return $path;
326             }
327              
328             sub sizeReq
329             {
330             my $self = shift;
331             defined ( my $size = $self->saneReq('size', '[^0-9]') ) or return; # 0; #return @{$self->{sizes}}[0];
332             die "no size '$size'" unless $self->{sizes}->[$size];
333             return $size;
334             }
335              
336              
337             =head2 runmodes
338              
339             the public runmodes, accessable via the C parameter
340              
341             =head3 image
342              
343             shows a thumbnail
344              
345             =cut
346              
347             sub view_image
348             {
349             my $self = shift;
350             my $path = $self->pathReq or die 'no path specified';
351              
352             my $s = $self->sizeReq;
353             my $item = WWW::MeGa::Item->new($path,$self->config,$self->{cache});
354              
355             return $self->binary($item, defined $s ? $self->{sizes}->[$s] : undef);
356             }
357              
358              
359             =head3 view (DEFAULT RUNMODE)
360              
361             shows a html page with one or more items
362              
363             =cut
364              
365             sub view_path
366             {
367             my $self = shift;
368             my $path = $self->pathReq;
369             my $size_idx = $self->sizeReq || 0;
370             my $off;
371             {
372             my $tmp = $self->query->param('off');
373             $off = $tmp if $tmp && ($tmp eq 'next' || $tmp eq 'prev');
374             }
375              
376             my %sizes =
377             (
378             SIZE => $size_idx,
379             SIZE_IN => $size_idx+1,
380             SIZE_OUT => $size_idx-1
381             );
382              
383             my @path_e = File::Spec->splitdir($path);
384             my $parent = File::Spec->catdir(@path_e[0 .. @path_e-2]); # bei file: album des files, bei folder: enthaltener folder
385              
386             if ($off)
387             {
388             my $pitem = WWW::MeGa::Item->new($parent,$self->config,$self->{cache}); # should be a folder in every case;
389             my @n = $pitem->neighbours($path, $off);
390             $path = $off eq 'next' ? $n[1] : $n[0];
391             }
392              
393             my $item = WWW::MeGa::Item->new($path,$self->config,$self->{cache});
394              
395              
396              
397             my %hash = (PARENT => $parent, %sizes, %{ $item->data }, CONFIG => { $self->config->vars }, MIME => $item->{mime});
398             my $template;
399              
400             if (Scalar::Util::blessed($item) eq 'WWW::MeGa::Item::Folder')
401             {
402             $template = 'album.tmpl';
403             my @items = map { (WWW::MeGa::Item->new($_,$self->config(),$self->{cache}))->data } $item->list;
404             $hash{ITEMS} = \@items;
405             } else
406             {
407             $template = 'image.tmpl';
408             }
409              
410             my $t = $self->load_tmpl($template, die_on_bad_params=>0, global_vars=>1, default_escape =>'HTML');
411             $t->param(%hash);
412              
413             return $t->output;
414             }
415              
416              
417              
418              
419             sub binary
420             {
421             my $self = shift;
422             my $item = shift;
423             my $size = shift;
424              
425             $self->header_add( -'Content-disposition' => 'inline' );
426             return $self->stream_file($item->thumbnail($size)) ? undef : $self->error_mode;
427             }
428              
429             =head1 FAQ
430              
431             =head2 How do i..
432              
433             =head3 ..select a image a Folder-Thumbnail?
434              
435             L uses the image named C (or whatever you setup
436             for C in the config) in each folder as its thumbnail. So
437             if you want to have the image C to be the thumbnail for
438             C, set a symlink called C to it (or copy it there)
439              
440             =head3 ..(re)create all thumbnail so that my visitors don't have to wait?
441              
442             See L for that.
443              
444              
445             =head1 BUGS, TODO AND NEW FEATURES
446              
447             I tried to write a clean and elegant app but I'm not a perl guru so
448             B bash me about everything you think suck in this project. I'm
449             willing to learn and appreciate constructive critic.
450              
451             If you think this app is cool and you like to see new features please
452             let me know!
453              
454             =head1 THANKS
455              
456             Thanks to EXP (at least I guess he was it) who suggests me to learn
457             perl some years ago.
458              
459             And thanks alot to the people from irc.perl.org / #perlde for the
460             current support.
461              
462             =head1 COPYRIGHT
463              
464             =head2 Code
465              
466             Copyright 2008 by Johannes 'fish' Ziemke.
467              
468             This program is free software; you can redistribute it and/or modify
469             it under the same terms as Perl itself.
470              
471             =head2 Icons
472              
473             The shipped icons are copyrighted by the "Tango Desktop Project" and
474             are licensed under the Creative Commons Attribution Share-Alike 2.5
475             license. See http://creativecommons.org/licenses/by-sa/2.5
476              
477             =head2 Photos
478              
479             biene.jpg and steine.jpg are copyrighted by Sophie Bischoff. For
480             more, see: http://sophiesfotos.de
481              
482             moewe.jpg is copyrighted by Johannes 'fish' Ziemke.
483              
484             The shipped example photos are licensed unter the Creative Commons
485             Attribution Share-Alike 3.0 license. See
486             http://creativecommons.org/licenses/by-sa/3.0/
487              
488             =head1 SEE ALSO
489              
490              
491             =over
492              
493             =item * L
494              
495             =item * L
496              
497             =item * L
498              
499             =back
500              
501             =head1 AUTHOR
502              
503             Johannes 'fish' Ziemke
504              
505              
506             =cut
507              
508             1;