You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
4.8 KiB
180 lines
4.8 KiB
package LDV::Imgbin; |
|
|
|
use strict; |
|
use warnings; |
|
use utf8; |
|
|
|
use Mojo::Base 'Mojolicious::Controller'; |
|
use JSON qw(encode_json decode_json); |
|
use Mojo::Asset::File; |
|
use Imager; |
|
|
|
sub _data_path { |
|
my ($self, $time) = @_; |
|
my $root = $self->app->config->{imgbin}->{root}; |
|
|
|
return $self->app->home->rel_file("$root/$time.json"); |
|
} |
|
|
|
sub _image_path { |
|
my ($self, $time, $ext, $full) = @_; |
|
|
|
return "/images/full/$time.$ext" unless $full; |
|
return $self->app->home->rel_file("public/images/full/$time.$ext"); |
|
} |
|
|
|
sub _thumb_path { |
|
my ($self, $time, $full) = @_; |
|
my $ext = $self->app->config->{imgbin}->{thumbs_ext}; |
|
|
|
return "/images/small/$time.$ext" unless $full; |
|
return $self->app->home->rel_file("public/images/small/$time.$ext"); |
|
} |
|
|
|
sub create { |
|
my ($self) = @_; |
|
|
|
$self->stash(maxsize => $self->config->{imgbin}->{maxsize}); |
|
$self->render(); |
|
} |
|
|
|
sub view { |
|
my ($self) = @_; |
|
my $time = $self->stash('time') || 0; |
|
|
|
eval { |
|
my $path = $self->_data_path($time); |
|
my $data = Mojo::Asset::File->new(path => $path); |
|
$data->cleanup(0); |
|
my $json = decode_json($data->slurp); |
|
die("image expired\n") if (time() > $data->{expire}); |
|
$json->{path} = $self->_image_path($time, $json->{format}); |
|
|
|
$self->stash(image => $json); 1; |
|
$self->render(); 1; |
|
} or do { |
|
$self->flash(error => $@); |
|
$self->redirect_to('/imgbin'); |
|
}; |
|
|
|
$self->rendered(); |
|
} |
|
|
|
sub save { |
|
my ($self) = @_; |
|
|
|
eval { |
|
die ("request too large\n") if $self->req->is_limit_exceeded; |
|
|
|
my $time = time(); |
|
my $conf = $self->app->config->{imgbin}; |
|
my $upload = $self->req->upload('file'); |
|
my $expire = $self->req->param('expire') || 7; # days |
|
die("no file uploaded\n") unless ($upload and $upload->size > 0); |
|
die("file too large\n") if ($upload->size > $conf->{maxsize}); |
|
|
|
# hack: don't use memory backend |
|
{ |
|
my $path = POSIX::tmpnam; |
|
$upload->move_to($path); |
|
$upload->asset(Mojo::Asset::File->new(path => $path)); |
|
$upload->asset->cleanup(1); # rearm self-destruction |
|
} |
|
|
|
my ($im_w, $im_h) = ($conf->{maxres} =~ m/(\d+)x(\d+)/oi); |
|
Imager->set_file_limits( |
|
width => $im_w, height => $im_h, |
|
bytes => $conf->{maxmem}, |
|
); |
|
|
|
my $image = Imager->new(file => $upload->asset->path) |
|
or die(Imager->errstr() . "\n"); |
|
|
|
my $json = { |
|
comment => $image->tags(name => 'i_comment') // '', |
|
format => $image->tags(name => 'i_format'), |
|
expire => $time + $expire * 86400, # expired *after* this time |
|
width => $image->getwidth, |
|
height => $image->getheight, |
|
name => $upload->filename, |
|
size => $upload->size, |
|
}; |
|
|
|
my ($th_w, $th_h) = ($conf->{thumbs_size} =~ m/(\d+)x(\d+)/oi); |
|
my $thumb = $image->scale(xpixels => $th_w, ypixels => $th_h, type => 'min'); |
|
$thumb->write(file => $self->_thumb_path($time, 'fullpath')) |
|
or die $thumb->errstr; |
|
$upload->move_to($self->_image_path($time, $json->{format}, 'fullpath')); |
|
|
|
my $data = Mojo::Asset::File->new(path => $self->_data_path($time)); |
|
$data->add_chunk(encode_json($json)); |
|
$data->move_to($self->_data_path($time)); |
|
|
|
$self->redirect_to("/imgbin/$time"); |
|
} or do { |
|
$self->app->log->error($@); |
|
$@ =~ s/\s+ at \s+ .+ \s+ line \s+ \d+//oxi; |
|
$self->flash(error => $@); |
|
$self->redirect_to('/imgbin'); |
|
}; |
|
|
|
$self->rendered(); |
|
} |
|
|
|
sub latest { |
|
my ($self) = @_; |
|
|
|
eval { |
|
my @images = (); |
|
my $root = $self->app->config->{imgbin}->{root}; |
|
opendir(my $DH, $root) |
|
or die("opendir: $!\n"); |
|
my @items = grep { m/\d+\.json/oi } readdir($DH); |
|
closedir($DH); |
|
@items = map { m/(\d+)\.json/oi } @items; |
|
@items = sort { $b <=> $a } @items; |
|
foreach my $time (splice(@items, 0, 10)) { |
|
my $data = Mojo::Asset::File->new(path => $self->_data_path($time)); |
|
my $image = decode_json($data->slurp); |
|
$image->{path} = $self->_thumb_path($time); |
|
$image->{url} = sprintf '/imgbin/%d', $time; |
|
push @images, $image; |
|
} |
|
|
|
$self->stash(images => \@images); |
|
$self->render(); |
|
} or do { |
|
$self->flash(error => $@); |
|
$self->redirect_to('/imgbin'); |
|
}; |
|
} |
|
|
|
sub prune { |
|
my ($self) = @_; |
|
|
|
eval { |
|
my $root = $self->app->config->{imgbin}->{root}; |
|
opendir(my $DH, $root) |
|
or die("opendir: $!\n"); |
|
my @files = grep { m/\d+\.json/oi } readdir($DH); |
|
my @times = map { s/\.json//oi; $_ } @files; |
|
closedir($DH); |
|
|
|
my $now = time(); |
|
foreach my $time (@times) { |
|
my $data = Mojo::Asset::File->new(path => $self->_data_path($time)); |
|
my $image = decode_json($data->slurp); |
|
next if $image->{expire} > $now; |
|
unlink $self->_image_path($time, $image->{format}, 1); |
|
unlink $self->_thumb_path($time); |
|
} 1; |
|
} or do { |
|
$self->app->log->error($@); |
|
$@ =~ s/\s+ at \s+ .+ \s+ line \s+ \d+//oxi; |
|
$self->flash(error => $@); |
|
}; |
|
$self->redirect_to('/imgbin'); |
|
$self->rendered(); |
|
} |
|
|
|
1;
|
|
|