photo_album
mojoliciousのメモ
mojoliciousを使って見たかったので、CGI.pmベースのalbum.cgi(アルバム)をmojolicious(Photo_album)に書き直す事にした。
[tree]
.[photo_album] ├── lib │ ├── album.pm │ ├── myconstant.pm │ ├── PhotoAlbum │ │ └── Example.pm │ └── PhotoAlbum.pm ├── log │ ├── development.log │ └── production.log ├── public │ ├── css │ │ ├── demo.css │ │ ├── reset.css │ │ └── style.css │ ├── images │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── hide.png │ │ └── show.png │ ├── img │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── hide.png │ │ └── show.png │ ├── index2.html │ ├── index3.html │ └── js │ ├── jquery.montage.js │ ├── jquery.montage.js.bak │ ├── jquery.montage.min.js │ └── jquery.montage.min.js.bak ├── script │ ├── hypnotoad.pid │ └── photo_album ├── t │ └── basic.t └── templates ├── example │ ├── next.html.ep │ ├── onepic.html.ep │ └── welcome.html.ep ├── index.html.ep └── layouts └── default.html.ep
SOURCE
photo_album/lib/PhotoAlbum.pm
package PhotoAlbum; use utf8; use Mojo::Base 'Mojolicious'; use album; # This method will run once at server start sub startup { my $self = shift; $self->attr( album => sub { album->new() } ); # Documentation browser under "/perldoc" $self->plugin('PODRenderer'); # Router my $r = $self->routes; # Normal route to controller $r->get('/')->to('example#welcome'); $r->get('/onepic')->to('example#onepic'); $r->post('/upload')->to('example#upload'); $r->post('/edit')->to('example#edit'); $r->get('/next')->to('example#next'); $r->get('/flick')->to('example#flick'); } 1;
photo_album/lib/album.pm
package album; use strict; use utf8; use Mojo::Base 'Mojolicious::Controller'; use myconstant; my $cons = myconstant->new(); my $imagedir = $cons->{imagedir}; my $img = $cons->{img}; my $max_size = $cons->{max_size}; my $img_size = $cons->{img_size}; my $item_count = $cons->{item_count}; my $real = 'public'; sub rotate { my ( $s, $c ) = @_; my $filename = $c->param('_name'); if ( $filename ne '' ) { if ( $c->param('_action') =~ /^\d{1,3}$/ ) { system( "/usr/bin/mogrify -rotate @{[$c->param('_action')]} $real/$img/$filename" ); system( "/usr/bin/mogrify -rotate @{[$c->param('_action')]} $real/$imagedir/$filename" ); } elsif ( $c->param('_action') eq 'touch' ) { system("/usr/bin/touch $real/$img/$filename"); system("/usr/bin/touch $real/$imagedir/$filename"); } } } sub get_images { my $s = shift; my $opt = shift || ''; my $st = shift || 0; my $items = shift || $item_count; my @files = $s->images_select( $st, $item_count, $s->get_images_sort() ); my $text = join( "\n", map { qq{ <a href="/onepic?_name=$_"><img src="/$imagedir/$_" $opt></img></a>} } @files ); return $text; } sub get_images_sort { my $s = shift; opendir my $dh, "$real/$imagedir" or die "Can't open $real/$imagedir"; my @files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, -M "$real/$imagedir/$_" ] } grep { !/(hide\.png|show\.png|arrow.*\.png|black\.png)/ } grep { -s "$real/$imagedir/$_" != 0 } grep ( /^[^.]/, readdir $dh ); return @files; } sub images_select { my $s = shift; my ( $next, $item, @files ) = @_; my $i = -1; my $st = $next * $item; my @select = (); SELECT: for (@files) { $i++; next SELECT if $i < $st; last SELECT if ( $i >= ( $next + 1 ) * $item ); push @select, $_; } return @select; } sub flick{ my ($s,$r) = @_; my $flick = { "name" => $s->get_next_image($r,$r->param('_count')), "preload" => $s->get_next_image($r,$r->param('_count')*3), }; return $flick; } sub get_next_image{ my $s = shift; my $r = shift; my $count = shift; my $file = $r->param('_name'); $file =~ s|.*?([^/]+\.[a-zA-Z0-9]*)(\?.*)*$|$1|; my @files = $s->get_images_sort(); my $i = $s->search_index($file,@files); $i += $count; $i -= ($#files + 1) if($i > $#files); my $img = "$img/$files[$i]"; return $img; } sub preload{ my $s = shift; my $name = shift; my @files = get_images_sort(); $name =~ s|.*?([^/]+\.[a-zA-Z]*)(\?.*)*$|$1|; my $i = $s->search_index($name,@files); my $text = "<script>\n"; for my $j (1 .. 2){ $text .= qq{\$('<img src="$img/$files[$i + $j]">');\n}; $text .= qq{\$('<img src="$img/$files[$i - $j]">');\n}; } $text .= "</script>\n"; return $text; } sub search_index{ my ($s,$item,@arry) = @_; my $i = 0; for(@arry){ if($item eq $_){ return $i; } $i++; } return; } sub up_load { my $s = shift; my $upload = shift; my $filename = $upload->filename; $filename = $ENV{REMOTE_USER} . "_" . $upload->filename if ( $ENV{REMOTE_USER} ); $upload->move_to("$real/$img/$filename"); if($filename =~ /(.*)\.mp4/i){ my $outfile = "$1_mp4.jpg"; system("ffmpeg -i $real/$img/$filename -vframes 1 $real/$imagedir/$outfile"); $filename = $outfile; }else{ my $size = -s "$real/$img/$filename"; if ( $size > $max_size ) { system( "convert -resize @{[int($img_size / $size * 100)]}% $real/$img/$filename $real/$imagedir/$filename" ); } else { system("cp $real/$img/$filename $real/$imagedir/$filename"); } } return $filename; } sub put_inner { my $s = shift; return $cons->{inner}; } sub imgTag{ my $s = shift; my $file = shift; my $text; if($file =~ /(.*)_mp4.jpg$/){ $text = <<TAG_END; <br /><br /><br /><br /><br /> <br /><br /><br /><br /><br /> <div align="center"> <video src="$img/$1.mp4" preload="none" onclick="this.play();" poster="$imagedir/$file" width="640" controls> <source src="$img/$1.mp4"> </video> </div> TAG_END }else{ $text = <<TAG_END; <a href="$img/$file" id="bigimg"> <img src="$img/$file?@{[(stat("$real/$img/$file"))[9]]}" width=100% name="img"></img> </a> TAG_END } return $text; } 1;
photo_album/lib/myconstant.pm
package myconstant; sub new { my $class = shift; my $self = bless {}, $class; $self->_initalize; return $self; } sub _initalize{ my $s = shift; $s->{pub} = 'public/'; $s->{css} = 'css/'; $s->{js} = 'js/'; $s->{imagedir} = 'images'; $s->{img} = 'img'; $s->{max_size} = 500_000; $s->{img_size} = 100_000; $s->{item_count} = 20; $s->{inner} = <<End_Text; <h1>Automatic Image Montage <span>with jQuery</span></h1> <h2>Fullscreen liquid example with alternating heights, last image will fill the last row. Refresh the browser to see a different arrangement.</h2> <div class="snippet"> <span id="showcode" class="down">View the options for this example</span> <pre> fillLastRow : true, alternateHeight : true, alternateHeightRange : { min : 90, max : 240 } </pre> </div> <div class="more"> <ul> <li>More examples:</li> <li class="selected"><a href="index.html">Example 1</a></li> <li><a href="index2.html">Example 2</a></li> <li><a href="index3.html">Example 3</a></li> <li><a href="index4.html">Example 4</a></li> <li><a href="index5.html">Example 5</a></li> <li><a href="index6.html">Example 6</a></li> <li><a href="index7.html">Example 7</a></li> <li><a href="index8.html">Example 8</a></li> </ul> </div> End_Text } 1;
photo_album/lib/PhotoAlbum/Example.pm
package PhotoAlbum::Example; use Mojo::Base 'Mojolicious::Controller'; # This action will render a template sub welcome { my $self = shift; # Render template "example/welcome.html.ep" with message $self->render( message => 'Welcome to the Mojolicious real-time web framework!'); } sub onepic { my $self = shift; $self->render('example/onepic'); } sub upload { my $self = shift; my $name = $self->app->album->up_load($self->param('image')); $self->param('_name',$name); $self->render('example/onepic'); } sub edit { my $self = shift; $self->app->album->rotate($self); $self->render('example/onepic'); } sub next{ my $self = shift; $self->render('example/next'); } sub flick{ my $self = shift; my $json = $self->app->album->flick($self); $self->render(json => $json); } 1;
photo_album/templates/example/welcome.html.ep
<!DOCTYPE html> <html lang="en"> <head> <title>album</title> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="Automatic Image Montage with jQuery" /> <meta name="keywords" content="jquery, images, montage, fullscreen, floating, grid, automatic" /> <link rel="stylesheet" type="text/css" href="/css/demo.css" /> <%= stylesheet '/css/style.css' %> <link href='http://fonts.googleapis.com/css?family=PT+Sans+Narrow&v1' rel='stylesheet' type='text/css' /> <link href='http://fonts.googleapis.com/css?family=Monoton' rel='stylesheet' type='text/css' /> </head> <body> <div class="container"> <div class="header"> % # @{[$cgi->param('_action')]} <span class="right_ab"> % # @{[up_load_form()]} <form method="post" action="<%= url_for('upload') %>" enctype ="multipart/form-data"> <input type="file" name="image" /> <input type="submit" value="Upload" style="width:80px" /> </form> </span> </div> <div id="overlay" class="content"> <div class="inner"> <%== app->album->put_inner %> <div class="clr"></div> <div id="panel" class="panel hide"></div> </div> </div> <div class="am-container" id="am-container"> <%== app->album->get_images('',0,25) %> </div> <div id="loadmore" class="loadmore" style="width:100%;">load more...</div> </div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> <%= javascript '/js/jquery.montage.min.js' %> <script type="text/javascript"> var ix = 0; $(function() { /* * just for this demo: */ $('#showcode').toggle( function() { $(this).addClass('up').removeClass('down').next().slideDown(); }, function() { $(this).addClass('down').removeClass('up').next().slideUp(); } ); $('#panel').toggle( function() { $(this).addClass('show').removeClass('hide'); $('#overlay').stop().animate( { left : - $('#overlay').width() + 20 + 'px' }, 300 ); }, function() { $(this).addClass('hide').removeClass('show'); $('#overlay').stop().animate( { left : '20px' }, 300 ); } ); var $container = $('#am-container'), $imgs = $container.find('img').hide(), totalImgs = $imgs.length, cnt = 0; $imgs.each(function(i) { var $img = $(this); $('<img/>').load(function() { ++cnt; if( cnt === totalImgs ) { $imgs.show(); $container.montage({ fillLastRow : true, alternateHeight : true, alternateHeightRange : { min : 90, max : 240 } }); $('#overlay').fadeIn(500); $('#loadmore').show().bind('click', function() { $.ajax({ url: '/next', type: 'GET', data: { _action: 'next', _count: ++ix }, success: function( data,textStatus,jqXHR){ var $newimages = $( data ); $newimages.imagesLoaded( function(){ $container.append( $newimages ).montage( 'add',$newimages); }); } }) }); } }).attr('src',$img.attr('src')); }); }); </script> </body> </html>
photo_album/templates/example/onepic.html.ep
<!DOCTYPE html> <html lang="en"> <head> <title>album</title> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <link rel="stylesheet" type="text/css" href="/css/demo.css" /> </head> <body> <div class="container"> <div class="header"> <a href='/'>ALBUM</a><div id="flick"><%== "<br>" x 5 %><hr></div> </dev> <div id="overlay" class="content"> <div class="inner"> <style type="text/css"> div.example1 { overflow-x: auto; white-space: nowrap; } </style> %= form_for edit => (method => 'post') => begin %= hidden_field '_name' => <%= param '_name' %= submit_button '90',name =>'_action',style =>'width:30px' %= submit_button '270',name =>'_action',style =>'width:30px' %= submit_button 'touch',name =>'_action',style =>'width:50px' % end <div class="example1"> <%== app->album->get_images('width=80px height=120px',0,9999) %> </div> <div class="clr"></div> <div id="panel" class="panel hide"></div> </div> </div> </div> </div> <%== app->album->imgTag(param '_name') %> %# @{[imgTag($cgi->param('_name'))]} %# <a href="/img/<%=param '_name'%>"> %# <img src="/img/<%=param '_name'%>" width=100%></img> %# </a> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> <script type="text/javascript" src="/js/jquery.montage.min.js"></script> <script type="text/javascript"> $(function() { /* * just for this demo: */ /* $('#showcode').toggle( function() { $(this).addClass('up').removeClass('down').next().slideDown(); }, function() { $(this).addClass('down').removeClass('up').next().slideUp(); } ); */ $('#panel').toggle( function() { $(this).addClass('show').removeClass('hide'); $('#overlay').stop().animate( { left : - $('#overlay').width() + 20 + 'px' }, 300 ); }, function() { $(this).addClass('hide').removeClass('show'); $('#overlay').stop().animate( { left : '20px' }, 300 ); } ); $('#overlay').fadeIn(500); }); </script> <script type="text/javascript"> $(function() { $('#flick').bind("touchstart touchmove touchend",touchHandler); function touchHandler(e){ e.preventDefault(); var touch = e.originalEvent.touches[0]; if(e.type == "touchstart"){ startX = touch.pageX; }else if(e.type == "touchmove"){ diffX = touch.pageX - startX; }else if(e.type == "touchend"){ if(diffX > 50){ $.ajax({ url: '/flick', type: 'GET', dataType: 'json', data: { _action: 'flick', _name: document.img.src, _count: '-1', }, success: function( data,textStatus,jqXHR){ // $("#flick").text(data.name); // var res = JSON.parse(data); document.img.src=data.name; $("#bigimg").attr("href",data.name); $("<img>").attr("src",data.preload); } }) } if(diffX < -50){ $.ajax({ url: '/flick', type: 'GET', dataType: 'json', data: { _action: 'flick', _name: document.img.src, _count: '1', }, success: function( data,textStatus,jqXHR){ document.img.src=data.name; $("#bigimg").attr("href",data.name); $("<img>").attr("src",data.preload); } }) } } } }); </script> <%== app->album->preload(param '_name') %> </body> </html>
photo_album/templates/example/next.html.ep
<!DOCTYPE html> <html lang="en"> <head> <title>album</title> </head> <body> <%== app->album->get_images('',param('_count') ) %> </body> </html>
サンプル
- 無精・短気・傲慢