Skip to content

Commit

Permalink
LANraragi Release 0.8.8
Browse files Browse the repository at this point in the history
Merge pull request #723 from Difegue/dev
  • Loading branch information
Difegue authored Dec 20, 2022
2 parents fe84fa2 + 1a8e152 commit a688ff3
Show file tree
Hide file tree
Showing 45 changed files with 1,606 additions and 1,066 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ Open source server for archival of comics/manga, running on Mojolicious + Redis.

#### [📄 Documentation](https://sugoi.gitbook.io/lanraragi/v/dev) | [⏬ Download](https://github.com/Difegue/LANraragi/releases/latest) | [🎞 Demo](https://lrr.tvc-16.science) | [🪟🌃 Windows Nightlies](https://nightly.link/Difegue/LANraragi/workflows/push-continous-delivery/dev) | [💵 Sponsor Development](https://ko-fi.com/T6T2UP5N)

## The 2021 User Survey results have landed!

Check [here](https://tvc-16.science/lrr-survey-3-results.html) for more info.

## Screenshots

|Main Page, Thumbnail View | Main Page, List View |
Expand All @@ -43,9 +39,9 @@ Check [here](https://tvc-16.science/lrr-survey-3-results.html) for more info.

* Read archives directly from your web browser: the server reads from within compressed files using temporary folders.

* Read your archives in dedicated reader software using the built-in OPDS Catalog
* Read your archives in dedicated reader software using the built-in OPDS Catalog (now with PSE support!)

* Use the Client API to interact with LANraragi from other programs
* Use the Client API to interact with LANraragi from other programs (Available for [many platforms!](https://sugoi.gitbook.io/lanraragi/v/dev/advanced-usage/external-readers))

* Two different user interfaces : compact archive list with thumbnails-on-hover, or thumbnail view.

Expand Down
4 changes: 1 addition & 3 deletions lib/LANraragi.pm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use Config;
use LANraragi::Utils::Generic qw(start_shinobu start_minion);
use LANraragi::Utils::Logging qw(get_logger);
use LANraragi::Utils::Plugins qw(get_plugins);
use LANraragi::Utils::Database qw(invalidate_cache);
use LANraragi::Utils::TempFolder qw(get_temp);
use LANraragi::Utils::Routing;
use LANraragi::Utils::Minion;
Expand Down Expand Up @@ -142,10 +141,9 @@ sub startup {
LANraragi::Utils::Minion::add_tasks( $self->minion );
$self->LRR_LOGGER->debug("Registered tasks with Minion.");

# Warm search cache
# Rebuild stat hashes
# /!\ Enqueuing tasks must be done either before starting the worker, or once the IOLoop is started!
# Anything else can cause weird database lockups.
$self->minion->enqueue('warm_cache');
$self->minion->enqueue('build_stat_hashes');

# Start a Minion worker in a subprocess
Expand Down
24 changes: 9 additions & 15 deletions lib/LANraragi/Controller/Api/Archive.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use Mojo::JSON qw(decode_json);
use Scalar::Util qw(looks_like_number);

use LANraragi::Utils::Generic qw(render_api_response);
use LANraragi::Utils::Database qw(get_archive_json);
use LANraragi::Utils::Database qw(get_archive_json set_isnew);

use LANraragi::Model::Archive;
use LANraragi::Model::Category;
Expand Down Expand Up @@ -36,9 +36,13 @@ sub serve_archivelist {
}

sub serve_untagged_archivelist {
my $self = shift;
my @idlist = LANraragi::Model::Archive::find_untagged_archives;
$self->render( json => \@idlist );
my $self = shift;
my $redis = $self->LRR_CONF->get_redis_search;

my @untagged = $redis->smembers("LRR_UNTAGGED");
$redis->quit;

$self->render( json => \@untagged );
}

sub serve_metadata {
Expand Down Expand Up @@ -127,17 +131,7 @@ sub clear_new {
my $self = shift;
my $id = check_id_parameter( $self, "clear_new" ) || return;

my $redis = $self->LRR_CONF->get_redis();

# Just set isnew to false for the provided ID.
if ( $redis->hget( $id, "isnew" ) ne "false" ) {

# Bust search cache...partially!
LANraragi::Utils::Database::invalidate_isnew_cache();

$redis->hset( $id, "isnew", "false" );
}
$redis->quit();
set_isnew( $id, "false" );

$self->render(
json => {
Expand Down
14 changes: 9 additions & 5 deletions lib/LANraragi/Controller/Api/Database.pm
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ sub serve_tag_stats {
sub clean_database {
my ( $deleted, $unlinked ) = LANraragi::Utils::Database::clean_database;

#Force a refresh
# Force a refresh
invalidate_cache(1);

shift->render(
Expand All @@ -45,8 +45,9 @@ sub clean_database {
#Clear new flag in all archives.
sub clear_new_all {

my $self = shift;
my $redis = $self->LRR_CONF->get_redis();
my $self = shift;
my $redis = $self->LRR_CONF->get_redis();
my $redis_search = $self->LRR_CONF->get_redis_search();

# Get all archives thru redis
# 40-character long keys only => Archive IDs
Expand All @@ -56,9 +57,12 @@ sub clear_new_all {
$redis->hset( $idall, "isnew", "false" );
}

# Bust search cache completely, this is a big change
invalidate_cache(1);
$redis->quit();

# Bust isnew cache
$redis_search->del("LRR_NEW");
$redis_search->quit();

render_api_response( $self, "clear_new_all" );
}

Expand Down
21 changes: 18 additions & 3 deletions lib/LANraragi/Controller/Api/Other.pm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use Mojo::JSON qw(encode_json decode_json);
use Redis;

use LANraragi::Model::Stats;
use LANraragi::Model::Opds;
use LANraragi::Utils::TempFolder qw(get_tempsize clean_temp_full);
use LANraragi::Utils::Generic qw(render_api_response);
use LANraragi::Utils::Plugins qw(get_plugin get_plugins get_plugin_parameters use_plugin);
Expand Down Expand Up @@ -37,11 +38,25 @@ sub serve_serverinfo {
);
}

sub serve_opds {
# Basic OPDS catalog
sub serve_opds_catalog {
my $self = shift;
$self->render( text => LANraragi::Model::Opds::generate_opds_catalog($self), format => 'xml' );
}

sub serve_opds_item {
my $self = shift;
my $id = $self->stash('id');
$self->render( text => LANraragi::Model::Opds::generate_opds_item( $self, $id ), format => 'xml' );
}

# OPDS-PSE specific endpoint
sub serve_opds_page {
my $self = shift;
my $id = $self->stash('id');
my $page = $self->req->param('page') || 1;

# TODO: Move to LRR::Model::Opds
$self->render( text => LANraragi::Model::Archive::generate_opds_catalog($self), format => 'xml' );
LANraragi::Model::Opds::render_archive_page( $self, $id, $page );
}

#Remove temp dir.
Expand Down
50 changes: 20 additions & 30 deletions lib/LANraragi/Controller/Api/Search.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ use LANraragi::Utils::Database qw(invalidate_cache get_archive_json_multi);
# Undocumented API matching the Datatables spec.
sub handle_datatables {

my $self = shift;
my $redis = $self->LRR_CONF->get_redis();
my $req = $self->req;
my $self = shift;
my $req = $self->req;

my $draw = $req->param('draw');
my $start = $req->param('start');
Expand Down Expand Up @@ -54,17 +53,14 @@ sub handle_datatables {
my ( $total, $filtered, @ids ) =
LANraragi::Model::Search::do_search( $filter, $categoryfilter, $start, $sortkey, $sortorder, $newfilter, $untaggedfilter );

$self->render( json => get_datatables_object( $draw, $redis, $total, $filtered, @ids ) );
$redis->quit();

$self->render( json => get_datatables_object( $draw, $total, $filtered, @ids ) );
}

# Public search API with saner parameters.
sub handle_api {

my $self = shift;
my $redis = $self->LRR_CONF->get_redis();
my $req = $self->req;
my $self = shift;
my $req = $self->req;

my $filter = $req->param('filter');
my $category = $req->param('category') || "";
Expand All @@ -82,54 +78,48 @@ sub handle_api {
$untaggedf eq "true"
);

$self->render( json => get_datatables_object( 0, $redis, $total, $filtered, @ids ) );
$redis->quit();

$self->render( json => get_datatables_object( 0, $total, $filtered, @ids ) );
}

sub clear_cache {
invalidate_cache(1);
invalidate_cache();
render_api_response( shift, "clear_cache" );
}

# Pull random archives out of the given search
sub get_random_archives {

my $self = shift;
my $redis = $self->LRR_CONF->get_redis();
my $req = $self->req;
my $self = shift;
my $req = $self->req;

my $filter = $req->param('filter');
my $category = $req->param('category') || "";
my $newfilter = $req->param('newonly') || "false";
my $untaggedf = $req->param('untaggedonly') || "false";
my $random_count = $req->param('count') || 5;

# Use the search engine to get IDs matching the filter/category selection, with start=-1 to get all data
# This method could be extended later to also use isnew/untagged filters.
my ( $total, $filtered, @ids ) = LANraragi::Model::Search::do_search( $filter, $category, -1, "title", 0, "", "" );
my ( $total, $filtered, @ids ) =
LANraragi::Model::Search::do_search( $filter, $category, -1, "title", 0, $newfilter eq "true", $untaggedf eq "true" );
my @random_ids;

$random_count = min( $random_count, scalar(@ids) );

while ( $random_count > 0 ) {
my $random_id = $ids[ int( rand( scalar @ids ) ) ];
next if ( grep { $_ eq $random_id } @random_ids );

push @random_ids, $random_id;
$random_count--;
# Get random IDs out of the array
for ( 1 .. $random_count ) {
my $random_index = int( rand( scalar(@ids) ) );
push( @random_ids, splice( @ids, $random_index, 1 ) );
}

$self->render( json => { data => \@random_ids } );
$redis->quit();
my @data = get_archive_json_multi(@random_ids);
$self->render( json => { data => \@data } );
}

# get_datatables_object($draw, $total, $totalsearched, @pagedkeys)
# Creates a Datatables-compatible json from the given data.
sub get_datatables_object {

my ( $draw, $redis, $total, $filtered, @keys ) = @_;

# Get IDs from keys
my @ids = map { $_->{id} } @keys;
my ( $draw, $total, $filtered, @ids ) = @_;

# Get archive data
my @data = get_archive_json_multi(@ids);
Expand Down
13 changes: 8 additions & 5 deletions lib/LANraragi/Controller/Batch.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use Mojo::JSON qw(decode_json);

use LANraragi::Utils::Generic qw(generate_themes_header);
use LANraragi::Utils::Tags qw(rewrite_tags split_tags_to_array restore_CRLF);
use LANraragi::Utils::Database qw(get_computed_tagrules);
use LANraragi::Utils::Database qw(get_computed_tagrules set_tags set_title set_isnew invalidate_cache);
use LANraragi::Utils::Plugins qw(get_plugins get_plugin get_plugin_parameters);
use LANraragi::Utils::Logging qw(get_logger);

Expand Down Expand Up @@ -88,7 +88,7 @@ sub socket {
}

if ( $operation eq "clearnew" ) {
$redis->hset( $id, "isnew", "false" );
set_isnew( $id, "false" );

$client->send(
{ json => {
Expand Down Expand Up @@ -128,7 +128,7 @@ sub socket {
# Merge array with commas
my $newtags = join( ', ', @tagarray );
$logger->debug("New tags: $newtags");
$redis->hset( $id, "tags", $newtags );
set_tags( $id, $newtags );

$client->send(
{ json => {
Expand All @@ -138,6 +138,9 @@ sub socket {
}
}
);

invalidate_cache();

return;
}

Expand Down Expand Up @@ -195,10 +198,10 @@ sub batch_plugin {

# If the plugin exec returned tags, add them
unless ( exists $plugin_result{error} ) {
LANraragi::Utils::Database::add_tags( $id, $plugin_result{new_tags} );
set_tags( $id, $plugin_result{new_tags}, 1 );

if ( exists $plugin_result{title} ) {
LANraragi::Utils::Database::set_title( $id, $plugin_result{title} );
set_title( $id, $plugin_result{title} );
}
}

Expand Down
20 changes: 14 additions & 6 deletions lib/LANraragi/Controller/Login.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use LANraragi::Utils::Generic qw(generate_themes_header);
sub check {
my $self = shift;

my $pw = $self->req->param('password') || '';
my $pw = $self->req->param('password') || '';
my $redirect = $self->req->param('redirect') || 'index';

#match password we got with the authen hash stored in redis
my $ppr = Authen::Passphrase->from_rfc2307( $self->LRR_CONF->get_password );
Expand All @@ -21,7 +22,7 @@ sub check {

$self->session( is_logged => 1 );
$self->session( expiration => 60 * 60 * 24 );
$self->redirect_to('index');
$self->redirect_to($redirect);
} else {

$self->LRR_LOGGER->warn( "Failed login attempt with password '$pw' from " . $self->tx->remote_address );
Expand All @@ -45,7 +46,9 @@ sub logged_in {
return 1
if $self->session('is_logged')
|| $self->LRR_CONF->enable_pass == 0;
$self->redirect_to('login');

my $url = $self->url_for("login");
$self->redirect_to( $url->query( redirect => $self->req->url->path_query ) );
return 0;
}

Expand All @@ -55,12 +58,16 @@ sub logged_in_api {

# The API key is in the Authentication header.
my $expected_key = $self->LRR_CONF->get_apikey;
my $expected_header = "Bearer " . encode_base64( $expected_key, "" );

my $auth_header = $self->req->headers->authorization || "";
my $expected_header = "Bearer " . encode_base64( $expected_key, "" );

# It can also be passed as a parameter. (Undocumented, mostly just meant for OPDS)
my $param_key = $self->req->param('key') || '';

return 1
if ( $expected_key ne "" && $auth_header eq $expected_header )
|| ( $param_key ne "" && $param_key eq $expected_key )
|| $self->session('is_logged')
|| $self->LRR_CONF->enable_pass == 0;
$self->render(
Expand All @@ -73,8 +80,9 @@ sub logged_in_api {
sub setup_cors {
my $self = shift;

# Set Allow-Origin to wildcard
$self->res->headers->header( 'Access-Control-Allow-Origin' => '*' );
# Set Allow-Origin to wildcard and Allow-Methods to most common ones
$self->res->headers->header( 'Access-Control-Allow-Origin' => '*' );
$self->res->headers->header( 'Access-Control-Allow-Methods' => 'GET, OPTIONS, POST, DELETE, PUT' );

# Explicitly say requests with an Authorization header (private API requests) are allowed
$self->res->headers->header( 'Access-Control-Allow-Headers' => 'Authorization' );
Expand Down
Loading

0 comments on commit a688ff3

Please sign in to comment.