package PoorBooru; use v5.32; use Dancer2; use HTTP::Tiny; our $VERSION = v0.0.1; my $POORBOORU_API = setting("poorbooru_api"); sub validate_page_number ($) { $_[0] =~ /^[1-9][0-9]*$/ } sub api_request ($$;%) { my ($method, $path, $params_hashref) = @_; my $http = HTTP::Tiny->new( timeout => 15, verify_SSL => true, agent => setting("appname") . " backend " . version::->parse($VERSION)->normal, default_headers => { "Accept" => "application/json", "Content-Type" => "application/json", }, ); my $params = $http->www_form_urlencode($params_hashref // {}); return $http->request($method, "$POORBOORU_API$path" . ($params ne "" ? "?$params" : "")); } sub api_get ($;%) { api_request("GET", shift, @_) } sub nav_pager ($$) { my ($p, $uri) = @_; my (%pager, %res); %pager = %$p; $res{first} = $pager{first} != $pager{cur} ? uri_for($uri, { page => $pager{first} }) : undef; $res{prev} = defined($pager{prev}) && $pager{prev} != $pager{first} ? uri_for($uri, { page => $pager{prev} }) : undef; $res{cur} = $pager{cur}; $res{next} = defined($pager{next}) && $pager{next} != $pager{last} ? uri_for($uri, { page => $pager{next} }) : undef; $res{last} = $pager{last} != $pager{cur} ? uri_for($uri, { page => $pager{last} }) : undef; return \%res; } hook before_template_render => sub { my $tokens = shift; $tokens->{uris}->{root} = uri_for("/"); $tokens->{uris}->{login} = uri_for("/login"); $tokens->{uris}->{logout} = uri_for("/logout"); $tokens->{uris}->{random} = uri_for("/random/media"); $tokens->{uris}->{tags} = uri_for("/tags"); }; get "/" => sub { my $page = query_parameters->get("page") // 1; send_error("Invalid page number", 400) if !validate_page_number($page); my $res = api_get("/media", { page => $page }); send_error("API error", 500) if !$res->{success}; my $data = decode_json($res->{content}); my @media = map +{ # XXX point to a cache image_src => "$POORBOORU_API/download/$_", media_uri => uri_for("/media/$_"), }, @{$data->{media}}; template "gallery" => { title => "PoorBooru", media => \@media, pager => nav_pager($data->{pager}, "/"), }; }; get "/tags" => sub { my $page = query_parameters->get("page") // 1; send_error("Invalid page number", 400) if !validate_page_number($page); my $res = api_get("/tags", { page => $page }); send_error("API error", 500) if !$res->{success}; my $data = decode_json($res->{content}); my @tags = map +{ name => $_->{name}, count => $_->{count}, uri => uri_for("/tag/$_->{name}"), }, @{$data->{tags}}; template "tags" => { title => "Tags", tags => \@tags, pager => nav_pager($data->{pager}, "/tags"), }; }; get "/tag/:tag_id_or_name" => sub { my $page = query_parameters->get("page") // 1; send_error("Invalid page number", 400) if !validate_page_number($page); my $tag_id_or_name = route_parameters->get("tag_id_or_name"); my $res = api_get("/tag/$tag_id_or_name", { page => $page }); send_error("API error", 500) if !$res->{success}; my $data = decode_json($res->{content}); my @media = map +{ # XXX point to a cache image_src => "$POORBOORU_API/download/$_", media_uri => uri_for("/media/$_"), }, @{$data->{media}}; template "gallery" => { title => $data->{name}, media => \@media, pager => nav_pager($data->{pager}, "/tag/$tag_id_or_name"), }; }; get "/media/:media_id" => sub { my $media_id = route_parameters->get("media_id"); my $res = api_get("/media/$media_id"); send_error("API error", 500) if !$res->{success}; my $data = decode_json($res->{content}); template "media" => { no_title => 1, title => $data->{id}, image_src => "$POORBOORU_API/download/$data->{id}", media_id => $data->{id}, media_filename => $data->{filename}, media_size => $data->{size}, media_tags => [], }; }; get "/random/media" => sub { my $res = api_get("/random/media"); send_error("API error", 500) if !$res->{success}; my $data = decode_json($res->{content}); # XXX body content. redirect "/media/$data->{id}"; }; get "/random/tag" => sub { my $res = api_get("/random/tag"); send_error("API error", 500) if !$res->{success}; my $data = decode_json($res->{content}); # XXX body content. redirect "/tag/$data->{name}"; }; true;