-[% END %]
\ No newline at end of file
+[% END %]
diff --git a/templates/templates_config/config_tags.html.tt2 b/templates/templates_config/config_tags.html.tt2
index d2fd636db..34be63c3f 100644
--- a/templates/templates_config/config_tags.html.tt2
+++ b/templates/templates_config/config_tags.html.tt2
@@ -27,6 +27,21 @@
+
+
+
Use JPEG XL for thumbnails
+
+
+ [% IF jxlthumbpages %]
+ [% ELSE %]
+ [% END %]
+
+
+
+
@@ -95,4 +110,4 @@
tag -> new-tag : replaces one tag
namespace:* -> new-namespace:* : replaces the namespace with the new one
-
\ No newline at end of file
+
diff --git a/tests/LANraragi/Plugin/Metadata/ChaikaFile.t b/tests/LANraragi/Plugin/Metadata/ChaikaFile.t
index 16903b38b..2e850726c 100644
--- a/tests/LANraragi/Plugin/Metadata/ChaikaFile.t
+++ b/tests/LANraragi/Plugin/Metadata/ChaikaFile.t
@@ -18,21 +18,23 @@ require "$cwd/tests/mocks.pl";
use_ok('LANraragi::Plugin::Metadata::ChaikaFile');
-my @tags_list= (
- 'full censorship', 'female:sole female', 'male:sole male', 'artist:kemuri haku', 'female:tall girl',
- 'female:cunnilingus', 'male:shotacon', 'female:defloration', 'female:nakadashi', 'female:x-ray',
- 'female:big breasts', 'language:translated', 'language:english'
+my @tags_list = (
+ 'full censorship', 'female:sole female', 'male:sole male', 'artist:kemuri haku',
+ 'female:tall girl', 'female:cunnilingus', 'male:shotacon', 'female:defloration',
+ 'female:nakadashi', 'female:x-ray', 'female:big breasts', 'language:translated',
+ 'language:english'
);
-my @tags_list_extra= (
- 'other:full censorship', 'female:sole female', 'male:sole male', 'artist:kemuri haku', 'female:tall girl',
- 'female:cunnilingus', 'male:shotacon', 'female:defloration', 'female:nakadashi', 'female:x-ray',
- 'female:big breasts', 'language:translated', 'language:english', 'category:manga', 'download:/archive/27240/download/',
- 'gallery:23532', 'timestamp:1521357552', 'source:chaika'
+my @tags_list_extra = (
+ 'other:full censorship', 'female:sole female', 'male:sole male', 'artist:kemuri haku',
+ 'female:tall girl', 'female:cunnilingus', 'male:shotacon', 'female:defloration',
+ 'female:nakadashi', 'female:x-ray', 'female:big breasts', 'language:translated',
+ 'language:english', 'category:manga', 'download:/archive/27240/download/', 'gallery:23532',
+ 'timestamp:1521357552', 'source:chaika'
);
use_ok('LANraragi::Plugin::Metadata::ChaikaFile');
-note ( 'testing reading file without extra data...' );
+note('testing reading file without extra data...');
{
# Copy the sample json to a temporary directory as it's deleted once parsed
my ( $fh, $filename ) = tempfile();
@@ -46,16 +48,19 @@ note ( 'testing reading file without extra data...' );
my %dummyhash = ( file_path => "test" );
my $saveTitle = 0;
- my $addextra = 0;
- my $addother = 0;
+ my $addextra = 0;
+ my $addother = 0;
my $addsource = '';
- my %ko_tags = trap { LANraragi::Plugin::Metadata::ChaikaFile::get_tags( "", \%dummyhash, $saveTitle, $addextra, $addother, $addsource ); };
+ my %ko_tags = trap { LANraragi::Plugin::Metadata::ChaikaFile::get_tags( "", \%dummyhash, $addextra, $addother, $addsource ); };
- is( $ko_tags{title}, undef, 'gallery title');
- is( $ko_tags{tags}, join(", ", @tags_list), 'gallery tag list');
+ is( $ko_tags{title},
+ "[Kemuri Haku] Zettai Seikou Keikaku | Absolute Intercourse Plan (COMIC Shitsurakuten 2016-03) [English] [Redlantern]",
+ 'gallery title'
+ );
+ is( $ko_tags{tags}, join( ", ", @tags_list ), 'gallery tag list' );
}
-note ( 'testing reading file with extra data...' );
+note('testing reading file with extra data...');
{
# Copy the sample json to a temporary directory as it's deleted once parsed
my ( $fh, $filename ) = tempfile();
@@ -68,15 +73,17 @@ note ( 'testing reading file with extra data...' );
my %dummyhash = ( file_path => "test" );
- my $saveTitle = 1;
- my $addextra = 1;
- my $addother = 1;
+ my $addextra = 1;
+ my $addother = 1;
my $addsource = 'chaika';
- my %ko_tags = trap { LANraragi::Plugin::Metadata::ChaikaFile::get_tags( "", \%dummyhash, $saveTitle, $addextra, $addother, $addsource ); };
+ my %ko_tags = trap { LANraragi::Plugin::Metadata::ChaikaFile::get_tags( "", \%dummyhash, $addextra, $addother, $addsource ); };
- is( $ko_tags{title}, "[Kemuri Haku] Zettai Seikou Keikaku | Absolute Intercourse Plan (COMIC Shitsurakuten 2016-03) [English] [Redlantern]", 'gallery title');
- is( $ko_tags{tags}, join(", ", @tags_list_extra), 'gallery tag list');
+ is( $ko_tags{title},
+ "[Kemuri Haku] Zettai Seikou Keikaku | Absolute Intercourse Plan (COMIC Shitsurakuten 2016-03) [English] [Redlantern]",
+ 'gallery title'
+ );
+ is( $ko_tags{tags}, join( ", ", @tags_list_extra ), 'gallery tag list' );
}
done_testing();
diff --git a/tests/LANraragi/Plugin/Metadata/Eze.t b/tests/LANraragi/Plugin/Metadata/Eze.t
index 7e20fe9da..2c00bfaed 100644
--- a/tests/LANraragi/Plugin/Metadata/Eze.t
+++ b/tests/LANraragi/Plugin/Metadata/Eze.t
@@ -19,12 +19,12 @@ require "$cwd/tests/mocks.pl";
use_ok('LANraragi::Plugin::Metadata::Eze');
sub eve_test {
-
- my ($jsonpath, $save_title, $origin_title, $additional_tags) = @_;
+
+ my ( $jsonpath, $save_title, $origin_title, $additional_tags ) = @_;
# Copy the eze sample json to a temporary directory as it's deleted once parsed
my ( $fh, $filename ) = tempfile();
- cp( $SAMPLES . $jsonpath , $fh );
+ cp( $SAMPLES . $jsonpath, $fh );
# Mock LANraragi::Utils::Archive's subs to return the temporary sample JSON
# Since we're using exports, the methods are under the plugin's namespace.
@@ -37,19 +37,19 @@ sub eve_test {
# Since this is calling the sub directly and not in an object context,
# we pass a dummy string as first parameter to replace the object.
- my %ezetags = trap { LANraragi::Plugin::Metadata::Eze::get_tags( "", \%dummyhash, $save_title, $origin_title, $additional_tags ); };
+ my %ezetags =
+ trap { LANraragi::Plugin::Metadata::Eze::get_tags( "", \%dummyhash, $save_title, $origin_title, $additional_tags ); };
return %ezetags;
}
-note("eze-lite Tests, save_title on, origin_title off, additional_tags off");
+note("eze-lite Tests, origin_title off, additional_tags off");
{
- my $save_title = 1;
- my $origin_title = 0;
+ my $origin_title = 0;
my $additional_tags = 0;
-
- my %ezetags = eve_test("/eze/eze_lite_sample.json", $save_title, $origin_title, $additional_tags);
+
+ my %ezetags = eve_test( "/eze/eze_lite_sample.json", $origin_title, $additional_tags );
is( $ezetags{title},
"(C72) [Mitarashi Club (Mitarashi Kousei)] Akiko-san to Issho (Kanon) [English] [Belldandy100] [Decensored]",
@@ -61,14 +61,12 @@ note("eze-lite Tests, save_title on, origin_title off, additional_tags off");
);
}
-
-note("eze-lite Tests, save_title on, origin_title on, additional_tags on");
+note("eze-lite Tests, origin_title on, additional_tags on");
{
- my $save_title = 1;
- my $origin_title = 1;
+ my $origin_title = 1;
my $additional_tags = 1;
-
- my %ezetags = eve_test("/eze/eze_lite_sample.json", $save_title, $origin_title, $additional_tags);
+
+ my %ezetags = eve_test( "/eze/eze_lite_sample.json", $origin_title, $additional_tags );
is( $ezetags{title},
"(C72) [Mitarashi Club (Mitarashi Kousei)] Akiko-san to Issho (Kanon) [English] [Belldandy100] [Decensored]",
@@ -80,56 +78,30 @@ note("eze-lite Tests, save_title on, origin_title on, additional_tags on");
);
}
-note("eze-full Tests, save_title off, origin_title off, additional_tags off");
-{
- my $save_title = 0;
- my $origin_title = 0;
- my $additional_tags = 0;
-
- my %ezetags = eve_test("/eze/eze_full_sample.json", $save_title, $origin_title, $additional_tags);
-
- is( $ezetags{title},
- undef,
- "title parsing test 1/2"
- );
- is( $ezetags{tags},
- "artist:hiten, female:defloration, female:pantyhose, female:sole female, group:hitenkei, language:chinese, language:translated, male:sole male, parody:original, category:doujinshi, source:exhentai.org/g/1017975/49b3c275a1",
- "tags parsing test 2/2"
- );
-}
-
-note("eze-full Tests, save_title on, origin_title off, additional_tags on");
+note("eze-full Tests, origin_title off, additional_tags on");
{
- my $save_title = 1;
- my $origin_title = 0;
+ my $origin_title = 0;
my $additional_tags = 1;
-
- my %ezetags = eve_test("/eze/eze_full_sample.json", $save_title, $origin_title, $additional_tags);
- is( $ezetags{title},
- "(C91) [HitenKei (Hiten)] R.E.I.N.A [Chinese] [無邪気漢化組]",
- "title parsing test 1/2"
- );
+ my %ezetags = eve_test( "/eze/eze_full_sample.json", $origin_title, $additional_tags );
+
+ is( $ezetags{title}, "(C91) [HitenKei (Hiten)] R.E.I.N.A [Chinese] [無邪気漢化組]", "title parsing test 1/2" );
is( $ezetags{tags},
"artist:hiten, female:defloration, female:pantyhose, female:sole female, group:hitenkei, language:chinese, language:translated, male:sole male, parody:original, category:doujinshi, uploader:cocy, timestamp:1484412360, source:exhentai.org/g/1017975/49b3c275a1",
"tags parsing test 2/2"
);
}
-note("eze-full Tests, save_title on, origin_title on, additional_tags on");
+note("eze-full Tests, origin_title on, additional_tags off");
{
- my $save_title = 1;
- my $origin_title = 1;
- my $additional_tags = 1;
-
- my %ezetags = eve_test("/eze/eze_full_sample.json", $save_title, $origin_title, $additional_tags);
+ my $origin_title = 1;
+ my $additional_tags = 0;
- is( $ezetags{title},
- "(C91) [HitenKei (Hiten)] R.E.I.N.A [ä¸å›½ç¿»è¨³]",
- "title parsing test 1/2"
- );
+ my %ezetags = eve_test( "/eze/eze_full_sample.json", $origin_title, $additional_tags );
+
+ is( $ezetags{title}, "(C91) [HitenKei (Hiten)] R.E.I.N.A [ä¸å›½ç¿»è¨³]", "title parsing test 1/2" );
is( $ezetags{tags},
- "artist:hiten, female:defloration, female:pantyhose, female:sole female, group:hitenkei, language:chinese, language:translated, male:sole male, parody:original, category:doujinshi, uploader:cocy, timestamp:1484412360, source:exhentai.org/g/1017975/49b3c275a1",
+ "artist:hiten, female:defloration, female:pantyhose, female:sole female, group:hitenkei, language:chinese, language:translated, male:sole male, parody:original, category:doujinshi, source:exhentai.org/g/1017975/49b3c275a1",
"tags parsing test 2/2"
);
}
diff --git a/tests/LANraragi/Plugin/Metadata/HentagOnline.t b/tests/LANraragi/Plugin/Metadata/HentagOnline.t
index 94e9d1d58..870c25105 100644
--- a/tests/LANraragi/Plugin/Metadata/HentagOnline.t
+++ b/tests/LANraragi/Plugin/Metadata/HentagOnline.t
@@ -3,6 +3,7 @@ use strict;
use warnings;
use utf8;
use feature qw(signatures);
+no warnings 'experimental::signatures';
use Cwd qw( getcwd );
@@ -10,7 +11,7 @@ use Test::Trap;
use Test::More;
use Test::Deep;
-my $cwd = getcwd();
+my $cwd = getcwd();
my $SAMPLES = "$cwd/tests/samples";
require "$cwd/tests/mocks.pl";
@@ -30,27 +31,27 @@ note("00 - api response");
return $mock_json;
};
- my %get_tags_params = ( archive_title => $archive_title);
+ my %get_tags_params = ( archive_title => $archive_title );
- my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, 1 );
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
my $expected_title = "[Doi Sakazaki] Boin Tantei vs Kaitou Sanmensou [ENG]";
my $expected_tags =
"artist:doi sakazaki, female:big breasts, female:maid, female:paizuri, language:english, source:https://hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- is( $received_title, $archive_title, "sent correct title to get_json_from_api");
+ is( $received_title, $archive_title, "sent correct title to get_json_from_api" );
is( $response{title}, $expected_title, "correct title" );
- is( $response{tags}, $expected_tags, "correct tags" );
+ is( $response{tags}, $expected_tags, "correct tags" );
}
note("01 - vault url parsing");
{
- my $url_nowww = "https://hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- my $url_www = "https://www.hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
+ my $url_nowww = "https://hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
+ my $url_www = "https://www.hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
my $expected_id = "QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- is(LANraragi::Plugin::Metadata::HentagOnline::parse_vault_url($url_nowww), $expected_id, "got correct id, without www");
- is(LANraragi::Plugin::Metadata::HentagOnline::parse_vault_url($url_www), $expected_id, "got correct id, with www");
- is(LANraragi::Plugin::Metadata::HentagOnline::parse_vault_url(''), undef, "empty URL returns nothing");
+ is( LANraragi::Plugin::Metadata::HentagOnline::parse_vault_url($url_nowww), $expected_id, "got correct id, without www" );
+ is( LANraragi::Plugin::Metadata::HentagOnline::parse_vault_url($url_www), $expected_id, "got correct id, with www" );
+ is( LANraragi::Plugin::Metadata::HentagOnline::parse_vault_url(''), undef, "empty URL returns nothing" );
}
note("02 - multilaguage hit");
@@ -67,39 +68,39 @@ note("02 - multilaguage hit");
return $mock_json;
};
- my %get_tags_params = ( archive_title => $archive_title);
+ my %get_tags_params = ( archive_title => $archive_title );
- my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, 1 );
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
my $expected_title = "Do match this title";
my $expected_tags =
- "artist:the artist, female:penis, language:english, source:https://hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- is( $received_title, $archive_title, "sent correct title to get_json_from_api");
+ "artist:the artist, female:penis, language:english, source:https://hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
+ is( $received_title, $archive_title, "sent correct title to get_json_from_api" );
is( $response{title}, $expected_title, "correct title" );
- is( $response{tags}, $expected_tags, "correct tags" );
+ is( $response{tags}, $expected_tags, "correct tags" );
}
note("03 - source tag parsing");
{
my $expected_source = "https://hentag.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- my @split_tags = split(",", "artist:the artist, female:penis, language:english, source:$expected_source");
- my $received_source = LANraragi::Plugin::Metadata::HentagOnline::get_existing_hentag_source_url( @split_tags );
- is( $received_source, $expected_source, "got correct url");
+ my @split_tags = split( ",", "artist:the artist, female:penis, language:english, source:$expected_source" );
+ my $received_source = LANraragi::Plugin::Metadata::HentagOnline::get_existing_hentag_source_url(@split_tags);
+ is( $received_source, $expected_source, "got correct url" );
}
note("04 - other source tag parsing");
{
- my $wrong = "https://example.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- my @split_tags = split(",", "artist:the artist, female:penis, language:english, source:$wrong");
- my $received_source = LANraragi::Plugin::Metadata::HentagOnline::get_existing_hentag_source_url( @split_tags );
- is( $received_source, undef, "don't detect false positive");
+ my $wrong = "https://example.com/vault/QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
+ my @split_tags = split( ",", "artist:the artist, female:penis, language:english, source:$wrong" );
+ my $received_source = LANraragi::Plugin::Metadata::HentagOnline::get_existing_hentag_source_url(@split_tags);
+ is( $received_source, undef, "don't detect false positive" );
}
note("05 - hentag source tag usage");
{
my $archive_title = "The adventures of irrelevant title";
- my $expected_id = "QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
- my $mock_json = Mojo::File->new("$SAMPLES/hentag/02_search_response.json")->slurp;
+ my $expected_id = "QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
+ my $mock_json = Mojo::File->new("$SAMPLES/hentag/02_search_response.json")->slurp;
my $received_id;
no warnings 'once', 'redefine';
@@ -108,30 +109,31 @@ note("05 - hentag source tag usage");
fail("get_json_by_title should not have been called");
return;
};
- local *LANraragi::Plugin::Metadata::HentagOnline::get_json_by_vault_id = sub($ua, $vault_id, $logger) {
+ local *LANraragi::Plugin::Metadata::HentagOnline::get_json_by_vault_id = sub ( $ua, $vault_id, $logger ) {
$received_id = $vault_id;
return $mock_json;
};
- my %get_tags_params = ( archive_title => $archive_title, existing_tags => "sometag, source:https://hentag.com/vault/$expected_id");
+ my %get_tags_params =
+ ( archive_title => $archive_title, existing_tags => "sometag, source:https://hentag.com/vault/$expected_id" );
- my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, 1 );
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
my $expected_title = "[Doi Sakazaki] Boin Tantei vs Kaitou Sanmensou [ENG]";
my $expected_tags =
- "artist:doi sakazaki, female:big breasts, female:maid, female:paizuri, language:english, source:https://hentag.com/vault/$expected_id";
- is( $received_id, $expected_id, "sent correct id to get_json_by_vault_id");
+ "artist:doi sakazaki, female:big breasts, female:maid, female:paizuri, language:english, source:https://hentag.com/vault/$expected_id";
+ is( $received_id, $expected_id, "sent correct id to get_json_by_vault_id" );
is( $response{title}, $expected_title, "correct title" );
- is( $response{tags}, $expected_tags, "correct tags" );
+ is( $response{tags}, $expected_tags, "correct tags" );
}
note("06 - source url lookups");
{
- my $expected_id = "QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
+ my $expected_id = "QNWPNY5lxYtqOxDN7OgqsyqW0pZDNwf3REXoLyb4iWpkR8n5qrfm3Bw";
my $archive_title = "The adventures of irrelevant title";
- my $url1 = "https://example.com/big-tiddy-anime-waifus";
- my $url2 = "https://example.com/big-tiddy-anime-waifus-vol2";
- my $mock_json = Mojo::File->new("$SAMPLES/hentag/02_search_response.json")->slurp;
+ my $url1 = "https://example.com/big-tiddy-anime-waifus";
+ my $url2 = "https://example.com/big-tiddy-anime-waifus-vol2";
+ my $mock_json = Mojo::File->new("$SAMPLES/hentag/02_search_response.json")->slurp;
my @received_urls;
no warnings 'once', 'redefine';
@@ -144,20 +146,20 @@ note("06 - source url lookups");
fail("get_json_by_vault_id should not have been called");
return;
};
- local *LANraragi::Plugin::Metadata::HentagOnline::get_json_by_urls = sub($ua, $logger, @urls) {
+ local *LANraragi::Plugin::Metadata::HentagOnline::get_json_by_urls = sub ( $ua, $logger, @urls ) {
@received_urls = @urls;
return $mock_json;
};
- my %get_tags_params = ( archive_title => $archive_title, existing_tags => "sometag, source:$url1, source:$url2");
+ my %get_tags_params = ( archive_title => $archive_title, existing_tags => "sometag, source:$url1, source:$url2" );
- my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, 1 );
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
my $expected_title = "[Doi Sakazaki] Boin Tantei vs Kaitou Sanmensou [ENG]";
my $expected_tags =
- "artist:doi sakazaki, female:big breasts, female:maid, female:paizuri, language:english, source:https://hentag.com/vault/$expected_id";
- eq_array( \@received_urls, \($url1, $url2), "sent correct urls to get_json_by_urls");
+ "artist:doi sakazaki, female:big breasts, female:maid, female:paizuri, language:english, source:https://hentag.com/vault/$expected_id";
+ eq_array( \@received_urls, \( $url1, $url2 ), "sent correct urls to get_json_by_urls" );
is( $response{title}, $expected_title, "correct title" );
- is( $response{tags}, $expected_tags, "correct tags" );
+ is( $response{tags}, $expected_tags, "correct tags" );
}
note("07 - no allowed language");
@@ -174,10 +176,10 @@ note("07 - no allowed language");
return $mock_json;
};
- my %get_tags_params = ( archive_title => $archive_title);
+ my %get_tags_params = ( archive_title => $archive_title );
- my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, 1, "florp, flarp" );
- ok( exists($response{error}), "got an error");
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, "florp, flarp" );
+ ok( exists( $response{error} ), "got an error" );
}
note("08 - multiple hits in same language");
@@ -194,15 +196,58 @@ note("08 - multiple hits in same language");
return $mock_json;
};
- my %get_tags_params = ( archive_title => $archive_title);
+ my %get_tags_params = ( archive_title => $archive_title );
- my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params, 1 );
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
my $expected_title = "First hit";
- my $expected_tags =
- "artist:plop, female:bilbul, language:english, source:whatever";
+ my $expected_tags = "artist:plop, female:bilbul, language:english, source:whatever";
+ is( $response{title}, $expected_title, "correct title" );
+ is( $response{tags}, $expected_tags, "correct tags" );
+}
+
+note("08 - multiple hits, pick the best hit");
+{
+ my $archive_title = "some series 1";
+ my $received_title;
+ my $mock_json = Mojo::File->new("$SAMPLES/hentag/05_search_response_multiple_similar_titles.json")->slurp;
+
+ no warnings 'once', 'redefine';
+ local *LANraragi::Plugin::Metadata::HentagOnline::get_plugin_logger = sub { return get_logger_mock(); };
+ local *LANraragi::Plugin::Metadata::HentagOnline::get_json_by_title = sub {
+ my ( $ua, $our_archive_title ) = @_;
+ $received_title = $our_archive_title;
+ return $mock_json;
+ };
+
+ my %get_tags_params = ( archive_title => $archive_title );
+
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
+
+ my $expected_title = "(c20) [auth (circ)] some series 1 [peepee] [poopoo]";
+ is( $response{title}, $expected_title, "correct title" );
+}
+
+note("09 - multiple hits, pick the best hit, by similarity");
+{
+ my $archive_title = "some seris 1";
+ my $received_title;
+ my $mock_json = Mojo::File->new("$SAMPLES/hentag/05_search_response_multiple_similar_titles.json")->slurp;
+
+ no warnings 'once', 'redefine';
+ local *LANraragi::Plugin::Metadata::HentagOnline::get_plugin_logger = sub { return get_logger_mock(); };
+ local *LANraragi::Plugin::Metadata::HentagOnline::get_json_by_title = sub {
+ my ( $ua, $our_archive_title ) = @_;
+ $received_title = $our_archive_title;
+ return $mock_json;
+ };
+
+ my %get_tags_params = ( archive_title => $archive_title );
+
+ my %response = LANraragi::Plugin::Metadata::HentagOnline::get_tags( "", \%get_tags_params );
+
+ my $expected_title = "(c20) [auth (circ)] some series 1 [peepee] [poopoo]";
is( $response{title}, $expected_title, "correct title" );
- is( $response{tags}, $expected_tags, "correct tags" );
}
done_testing();
diff --git a/tests/LANraragi/Plugin/Metadata/Koromo.t b/tests/LANraragi/Plugin/Metadata/Koromo.t
index 1804c6bed..b1d5e7cc9 100644
--- a/tests/LANraragi/Plugin/Metadata/Koromo.t
+++ b/tests/LANraragi/Plugin/Metadata/Koromo.t
@@ -38,7 +38,7 @@ note("Koromo Tests");
my %ko_tags = trap { LANraragi::Plugin::Metadata::Koromo::get_tags( "", \%dummyhash, 1 ); };
my $expected_tags =
- "Teacher, Schoolgirl Outfit, Cheating, Hentai, Ahegao, Creampie, Uncensored, Condom, Unlimited, Heart Pupils, Love Hotel, series:Original Work, artist:â–² Chimaki, language:English, source:https://www.fakku.net/hentai/after-school-english_1632947200";
+ "Teacher, Schoolgirl Outfit, Cheating, Hentai, Ahegao, Creampie, Uncensored, Condom, Unlimited, Heart Pupils, Love Hotel, series:Original Work, artist:â–² Chimaki, magazine:Comic Bavel 2021-11, language:English, source:https://www.fakku.net/hentai/after-school-english_1632947200";
is( $ko_tags{title}, "After School", "Koromo parsing test 1/2" );
is( $ko_tags{tags}, $expected_tags, "Koromo parsing test 2/2" );
}
@@ -63,7 +63,7 @@ note("multiple artists json");
my %ko_tags = trap { LANraragi::Plugin::Metadata::Koromo::get_tags( "", \%dummyhash, 1 ); };
my $expected_tags =
- "Teacher, Schoolgirl Outfit, Cheating, Hentai, Ahegao, Creampie, Uncensored, Condom, Unlimited, Heart Pupils, Love Hotel, series:Original Work, artist:First, artist:Second, language:English, source:https://www.fakku.net/hentai/after-school-english_1632947200";
+ "Teacher, Schoolgirl Outfit, Cheating, Hentai, Ahegao, Creampie, Uncensored, Condom, Unlimited, Heart Pupils, Love Hotel, series:Original Work, artist:First, artist:Second, magazine:Comic Bavel 2021-11, language:English, source:https://www.fakku.net/hentai/after-school-english_1632947200";
is( $ko_tags{title}, "After School", "Koromo parsing test 1/2" );
is( $ko_tags{tags}, $expected_tags, "Koromo parsing test 2/2" );
}
diff --git a/tests/LANraragi/Plugin/Metadata/Ksk.t b/tests/LANraragi/Plugin/Metadata/Ksk.t
new file mode 100644
index 000000000..994134f3e
--- /dev/null
+++ b/tests/LANraragi/Plugin/Metadata/Ksk.t
@@ -0,0 +1,75 @@
+# LANraragi::Plugin::Metadata::Ksk
+use strict;
+use warnings;
+use utf8;
+use Data::Dumper;
+use File::Temp qw(tempfile);
+use File::Copy "cp";
+
+use Cwd qw( getcwd );
+
+use Test::Trap;
+use Test::More;
+use Test::Deep;
+
+my $cwd = getcwd();
+my $SAMPLES = "$cwd/tests/samples";
+require "$cwd/tests/mocks.pl";
+
+use_ok('LANraragi::Plugin::Metadata::Ksk');
+
+note("test not assuming language");
+{
+ my ( $fh, $filename ) = tempfile();
+ cp( $SAMPLES . "/ksk/fake.yaml", $fh );
+
+ no warnings 'once', 'redefine';
+ local *LANraragi::Plugin::Metadata::Ksk::get_plugin_logger = sub { return get_logger_mock(); };
+ local *LANraragi::Plugin::Metadata::Ksk::extract_file_from_archive = sub { $filename };
+ local *LANraragi::Plugin::Metadata::Ksk::is_file_in_archive = sub { 1 };
+
+ my %dummyhash = ( file_path => "test" );
+
+ my %ko_tags = LANraragi::Plugin::Metadata::Ksk::get_tags( "", \%dummyhash, 0 );
+ my $expected_tags =
+ "Harry Potter, Ebony Dark'ness Dementia Raven Way, Draco Malfoy, artist:xXMidnightEssenceXx, artist:bloodytearz666, series:Harry Potter, magazine:My Immortal - Genesis, source:https://www.fanfiction.net/s/6829556/1/My-Immortal";
+ is( $ko_tags{title}, "My Immortal", "Title is overwritten" );
+ is( $ko_tags{tags}, $expected_tags, "Language is missing" );
+}
+
+note("test assuming language");
+{
+ my ( $fh, $filename ) = tempfile();
+ cp( $SAMPLES . "/ksk/fake.yaml", $fh );
+
+ no warnings 'once', 'redefine';
+ local *LANraragi::Plugin::Metadata::Ksk::get_plugin_logger = sub { return get_logger_mock(); };
+ local *LANraragi::Plugin::Metadata::Ksk::extract_file_from_archive = sub { $filename };
+ local *LANraragi::Plugin::Metadata::Ksk::is_file_in_archive = sub { 1 };
+
+ my %dummyhash = ( file_path => "test" );
+
+ my %ko_tags = LANraragi::Plugin::Metadata::Ksk::get_tags( "", \%dummyhash, 1 );
+ my $expected_tags =
+ "Harry Potter, Ebony Dark'ness Dementia Raven Way, Draco Malfoy, artist:xXMidnightEssenceXx, artist:bloodytearz666, series:Harry Potter, magazine:My Immortal - Genesis, language:english, source:https://www.fanfiction.net/s/6829556/1/My-Immortal";
+ is( $ko_tags{title}, "My Immortal", "Title is overwritten" );
+ is( $ko_tags{tags}, $expected_tags, "Language is present" );
+}
+
+note("test support for info.yaml");
+{
+ my ( $fh, $filename ) = tempfile();
+ cp( $SAMPLES . "/ksk/fake.yaml", $fh );
+
+ no warnings 'once', 'redefine';
+ local *LANraragi::Plugin::Metadata::Ksk::get_plugin_logger = sub { return get_logger_mock(); };
+ local *LANraragi::Plugin::Metadata::Ksk::extract_file_from_archive = sub { $filename };
+ local *LANraragi::Plugin::Metadata::Ksk::is_file_in_archive = sub { my $fn = $_[1]; return $fn eq "info.yaml"; };
+
+ my %dummyhash = ( file_path => "test" );
+
+ my %ko_tags = LANraragi::Plugin::Metadata::Ksk::get_tags( "", \%dummyhash, 1 );
+ is( $ko_tags{title}, "My Immortal", "Loads data from info.yaml" );
+}
+
+done_testing();
diff --git a/tests/LANraragi/Utils/String.t b/tests/LANraragi/Utils/String.t
new file mode 100644
index 000000000..e4a470ae7
--- /dev/null
+++ b/tests/LANraragi/Utils/String.t
@@ -0,0 +1,53 @@
+use strict;
+use warnings;
+use utf8;
+use Data::Dumper;
+
+use Test::More;
+use Test::Deep;
+
+BEGIN { use_ok('LANraragi::Utils::String'); }
+
+note('testing trim...');
+{
+ my $input = "";
+ my $expected = "";
+ my $result = LANraragi::Utils::String::trim($input);
+
+ is( $result, $expected, "Empty string should result in empty string" );
+}
+
+{
+ my $input = "already trimmed";
+ my $expected = "already trimmed";
+ my $result = LANraragi::Utils::String::trim($input);
+
+ is( $result, $expected, "Pre-trimmed should do nothing" );
+}
+
+{
+ my $input = " trim everything ";
+ my $expected = "trim everything";
+ my $result = LANraragi::Utils::String::trim($input);
+
+ is( $result, $expected, "Trim should trim" );
+ is( $input, " trim everything ", "Trim doesn't modify the input variable" );
+}
+
+note('testing title cleanup...');
+{
+ my $input = "(C83) [Tetsubou Shounen (Natsushi)] So hold my hand one more time [English] [Yuri-ism Project]";
+ my $expected = "So hold my hand one more time";
+ my $result = LANraragi::Utils::String::clean_title($input);
+
+ is( $result, $expected, "Remove leading/trailing junk" );
+}
+
+note('testing string similarity detection...');
+{
+ is( LANraragi::Utils::String::most_similar( "orange", ( "door hinge", "sporange" ) ), 1, "Simple case" );
+ is( LANraragi::Utils::String::most_similar( "orange", () ), undef, "Empty set" );
+}
+
+done_testing();
+
diff --git a/tests/mocks.pl b/tests/mocks.pl
index cbad7564c..4cfd27e8c 100644
--- a/tests/mocks.pl
+++ b/tests/mocks.pl
@@ -40,7 +40,8 @@ sub setup_redis_mock {
"progress": 10,
"tags": "character:segata sanshiro, male:very cool",
"title": "Saturn Backup Cartridge - Japanese Manual",
- "file": "package.json"
+ "file": "package.json",
+ "lastreadtime": 1589038280
},
"e69e43e1355267f7d32a4f9b7f2fe108d2401ebg": {
"isnew": "false",
@@ -48,7 +49,8 @@ sub setup_redis_mock {
"progress": 34,
"tags": "character:segata, female:very cool too",
"title": "Saturn Backup Cartridge - American Manual",
- "file": "package.json"
+ "file": "package.json",
+ "lastreadtime": 1589038280
},
"e4c422fd10943dc169e3489a38cdbf57101a5f7e": {
"isnew": "true",
@@ -56,7 +58,8 @@ sub setup_redis_mock {
"progress": 0,
"tags": "parody: jojo's bizarre adventure",
"title": "Rohan Kishibe goes to Gucci",
- "file": "package.json"
+ "file": "package.json",
+ "lastreadtime": 0
},
"4857fd2e7c00db8b0af0337b94055d8445118630": {
"isnew": "false",
@@ -64,7 +67,8 @@ sub setup_redis_mock {
"progress": 34,
"tags": "artist:shirow masamune",
"title": "Ghost in the Shell 1.5 - Human-Error Processor vol01ch01",
- "file": "package.json"
+ "file": "package.json",
+ "lastreadtime": 1589038280
},
"2810d5e0a8d027ecefebca6237031a0fa7b91eb3": {
"isnew": "false",
@@ -72,7 +76,8 @@ sub setup_redis_mock {
"progress": 34,
"tags": "parody:fate grand order, character:abigail williams, character:artoria pendragon alter, character:asterios, character:ereshkigal, character:gilgamesh, character:hans christian andersen, character:hassan of serenity, character:hector, character:helena blavatsky, character:irisviel von einzbern, character:jeanne alter, character:jeanne darc, character:kiara sessyoin, character:kiyohime, character:lancer, character:martha, character:minamoto no raikou, character:mochizuki chiyome, character:mordred pendragon, character:nitocris, character:oda nobunaga, character:osakabehime, character:penthesilea, character:queen of sheba, character:rin tosaka, character:saber, character:sakata kintoki, character:scheherazade, character:sherlock holmes, character:suzuka gozen, character:tamamo no mae, character:ushiwakamaru, character:waver velvet, character:xuanzang, character:zhuge liang, group:wadamemo, artist:wada rco, artbook, full color",
"title": "Fate GO MEMO 2",
- "file": "package.json"
+ "file": "package.json",
+ "lastreadtime": 1589038280
},
"28697b96f0ac5858be2614ed10ca47742c9522fd": {
"isnew": "false",
@@ -80,8 +85,18 @@ sub setup_redis_mock {
"progress": 0,
"tags": "parody:fate grand order, group:wadamemo, artist:wada rco, artbook, full color, male:very cool too",
"title": "Fate GO MEMO",
- "file": "package.json"
- }
+ "file": "package.json",
+ "lastreadtime": 0
+ },
+ "TANK_1589141306": [
+ "Hello",
+ "2810d5e0a8d027ecefebca6237031a0fa7b91eb3",
+ "28697b96f0ac5858be2614ed10ca47742c9522fd"
+ ],
+ "TANK_1589138380":[
+ "World",
+ "28697b96f0ac5858be2614ed10ca47742c9522fd"
+ ]
})
};
@@ -107,6 +122,7 @@ sub setup_redis_mock {
$redis->mock( 'select', sub { 1 } );
$redis->mock( 'flushdb', sub { 1 } );
$redis->mock( 'zincrby', sub { 1 } );
+ $redis->mock( 'zrem', sub { 1 } );
$redis->mock( 'watch', sub { 1 } );
$redis->mock( 'hlen', sub { 1337 } );
$redis->mock( 'dbsize', sub { 1337 } );
@@ -184,6 +200,26 @@ sub setup_redis_mock {
}
);
+ # $redis->mock(
+ # 'zscore', # $redis->zscore => array position in list named by key in datamodel
+ # sub {
+ # my $self = shift;
+ # my ($key, $value) = @_;
+
+ # if ( !exists $datamodel{$key} ) {
+ # $datamodel{$key} = [];
+ # }
+
+ # for my $i ( 0 .. $#results ) {
+ # if ($element == $value) {
+ # return
+ # }
+ # }
+
+ # return scalar @{ $datamodel{$key} };
+ # }
+ # );
+
$redis->mock(
'zrangebylex', # $redis->zrangebylex => get all values of key in datamodel
sub {
@@ -199,6 +235,21 @@ sub setup_redis_mock {
}
);
+ $redis->mock(
+ 'zrangebyscore', # $redis->zrangebyscore => get all values of key in datamodel
+ sub {
+ my $self = shift;
+ my ( $key, $start, $end ) = @_;
+
+ if ( !exists $datamodel{$key} ) {
+ $datamodel{$key} = [];
+ }
+
+ # Return array, ordered alphabetically
+ return @{ $datamodel{$key} };
+ }
+ );
+
$redis->mock(
'zscan', # $redis->zscan => get all values of key in datamodel
sub {
diff --git a/tests/modules.t b/tests/modules.t
index a7fa866e0..323efbd1a 100644
--- a/tests/modules.t
+++ b/tests/modules.t
@@ -11,39 +11,38 @@ require $cwd . "/tests/mocks.pl";
setup_redis_mock();
my @modules = (
- "Shinobu", "LANraragi",
- "LANraragi::Utils::Archive", "LANraragi::Utils::Database",
- "LANraragi::Utils::Generic", "LANraragi::Utils::Plugins",
- "LANraragi::Utils::Routing", "LANraragi::Utils::TempFolder",
- "LANraragi::Utils::Logging", "LANraragi::Utils::Minion",
- "LANraragi::Utils::Tags", "LANraragi::Controller::Api::Archive",
- "LANraragi::Controller::Api::Search", "LANraragi::Controller::Api::Category",
- "LANraragi::Controller::Api::Database", "LANraragi::Controller::Api::Shinobu",
- "LANraragi::Controller::Api::Minion", "LANraragi::Controller::Api::Other",
- "LANraragi::Controller::Backup", "LANraragi::Controller::Batch",
- "LANraragi::Controller::Config", "LANraragi::Controller::Edit",
- "LANraragi::Controller::Index", "LANraragi::Controller::Logging",
- "LANraragi::Controller::Login", "LANraragi::Controller::Plugins",
- "LANraragi::Controller::Reader", "LANraragi::Controller::Stats",
- "LANraragi::Controller::Upload", "LANraragi::Controller::Category",
- "LANraragi::Model::Archive", "LANraragi::Model::Backup",
- "LANraragi::Model::Config", "LANraragi::Model::Plugins",
- "LANraragi::Model::Reader", "LANraragi::Model::Search",
- "LANraragi::Model::Stats", "LANraragi::Model::Category",
- "LANraragi::Model::Upload", "LANraragi::Model::Opds",
- "LANraragi::Plugin::Metadata::Chaika", "LANraragi::Plugin::Metadata::CopyTags",
- "LANraragi::Plugin::Metadata::DateAdded", "LANraragi::Plugin::Metadata::EHentai",
- "LANraragi::Plugin::Metadata::Eze", "LANraragi::Plugin::Metadata::Hdoujin",
- "LANraragi::Plugin::Metadata::Koromo", "LANraragi::Plugin::Metadata::MEMS",
- "LANraragi::Plugin::Metadata::nHentai", "LANraragi::Plugin::Metadata::RegexParse",
- "LANraragi::Plugin::Metadata::Fakku", "LANraragi::Plugin::Login::EHentai",
- "LANraragi::Plugin::Login::Fakku", "LANraragi::Plugin::Scripts::SourceFinder",
- "LANraragi::Plugin::Scripts::FolderToCat", "LANraragi::Plugin::Download::EHentai",
- "LANraragi::Plugin::Download::Chaika", "LANraragi::Plugin::Scripts::nHentaiSourceConverter",
- "LANraragi::Plugin::Scripts::BlacklistMigrate", "LANraragi::Plugin::Metadata::Hitomi",
- "LANraragi::Plugin::Metadata::Hentag", "LANraragi::Plugin::Metadata::HentagOnline",
- "LANraragi::Plugin::Metadata::ComicInfo",
- "LANraragi::Plugin::Metadata::ChaikaFile"
+ "Shinobu", "LANraragi",
+ "LANraragi::Utils::Archive", "LANraragi::Utils::Database",
+ "LANraragi::Utils::Generic", "LANraragi::Utils::Plugins",
+ "LANraragi::Utils::Routing", "LANraragi::Utils::TempFolder",
+ "LANraragi::Utils::Logging", "LANraragi::Utils::Minion",
+ "LANraragi::Utils::Tags", "LANraragi::Controller::Api::Archive",
+ "LANraragi::Controller::Api::Search", "LANraragi::Controller::Api::Category",
+ "LANraragi::Controller::Api::Database", "LANraragi::Controller::Api::Shinobu",
+ "LANraragi::Controller::Api::Minion", "LANraragi::Controller::Api::Other",
+ "LANraragi::Controller::Backup", "LANraragi::Controller::Batch",
+ "LANraragi::Controller::Config", "LANraragi::Controller::Edit",
+ "LANraragi::Controller::Index", "LANraragi::Controller::Logging",
+ "LANraragi::Controller::Login", "LANraragi::Controller::Plugins",
+ "LANraragi::Controller::Reader", "LANraragi::Controller::Stats",
+ "LANraragi::Controller::Upload", "LANraragi::Controller::Category",
+ "LANraragi::Model::Archive", "LANraragi::Model::Backup",
+ "LANraragi::Model::Config", "LANraragi::Model::Plugins",
+ "LANraragi::Model::Reader", "LANraragi::Model::Search",
+ "LANraragi::Model::Stats", "LANraragi::Model::Category",
+ "LANraragi::Model::Upload", "LANraragi::Model::Opds",
+ "LANraragi::Plugin::Metadata::Chaika", "LANraragi::Plugin::Metadata::CopyTags",
+ "LANraragi::Plugin::Metadata::DateAdded", "LANraragi::Plugin::Metadata::EHentai",
+ "LANraragi::Plugin::Metadata::Eze", "LANraragi::Plugin::Metadata::Hdoujin",
+ "LANraragi::Plugin::Metadata::Koromo", "LANraragi::Plugin::Metadata::MEMS",
+ "LANraragi::Plugin::Metadata::nHentai", "LANraragi::Plugin::Metadata::RegexParse",
+ "LANraragi::Plugin::Metadata::Fakku", "LANraragi::Plugin::Login::EHentai",
+ "LANraragi::Plugin::Login::Fakku", "LANraragi::Plugin::Scripts::SourceFinder",
+ "LANraragi::Plugin::Scripts::FolderToCat", "LANraragi::Plugin::Download::EHentai",
+ "LANraragi::Plugin::Download::Chaika", "LANraragi::Plugin::Scripts::nHentaiSourceConverter",
+ "LANraragi::Plugin::Metadata::Hitomi", "LANraragi::Plugin::Metadata::Hentag",
+ "LANraragi::Plugin::Metadata::HentagOnline", "LANraragi::Plugin::Metadata::ComicInfo",
+ "LANraragi::Plugin::Metadata::ChaikaFile", "LANraragi::Plugin::Metadata::Ksk",
);
# Test all modules load properly
diff --git a/tests/plugins.t b/tests/plugins.t
index 0373dd6f2..c43af527a 100644
--- a/tests/plugins.t
+++ b/tests/plugins.t
@@ -4,7 +4,6 @@ use utf8;
use Cwd;
use Mojo::Base 'Mojolicious';
-
use Test::More;
use Test::Trap;
use Test::Mojo;
@@ -80,7 +79,7 @@ note("Chaika Tests");
ok( length $title_by_id > 0, 'chaika.moe SHA-1 title test' );
}
-note("FAKKU Tests : Disabled due to cloudflare being used on FAKKU");
+note("FAKKU Tests : Disabled due to cloudflare being used");
# {
# my $f_title = "Kairakuten Cover Girl's Episode 009: Hamao";
@@ -98,7 +97,7 @@ note("FAKKU Tests : Disabled due to cloudflare being used on FAKKU");
note("Hitomi Tests");
{
- my $hi_gID = "2261881";
+ my $hi_gID = "2261881";
my %hi_hashdata = trap { LANraragi::Plugin::Metadata::Hitomi::get_tags_from_Hitomi( $hi_gID, 1 ); };
ok( length $hi_hashdata{tags} > 0, 'Hitomi API Tag retrieval test' );
diff --git a/tests/samples/hentag/05_search_response_multiple_similar_titles.json b/tests/samples/hentag/05_search_response_multiple_similar_titles.json
new file mode 100644
index 000000000..78a8d961b
--- /dev/null
+++ b/tests/samples/hentag/05_search_response_multiple_similar_titles.json
@@ -0,0 +1,47 @@
+[
+ {
+ "title": "(c20) [auth (circ)] some series 3 [peepee] [poopoo]",
+ "artists": [
+ "plop"
+ ],
+ "femaleTags": [
+ "bilbul"
+ ],
+ "language": "english",
+ "category": "manga",
+ "createdAt": 1255081730000,
+ "locations": [
+ "whatever"
+ ]
+ },
+ {
+ "title": "(c20) [auth (circ)] some series 1 [peepee] [poopoo]",
+ "artists": [
+ "the artist"
+ ],
+ "femaleTags": [
+ "penis"
+ ],
+ "language": "english",
+ "category": "manga",
+ "createdAt": 1255081730000,
+ "locations": [
+ "whatever 2"
+ ]
+ },
+ {
+ "title": "(c20) [auth (circ)] some series 2 [peepee] [poopoo]",
+ "artists": [
+ "the artist"
+ ],
+ "femaleTags": [
+ "penis"
+ ],
+ "language": "english",
+ "category": "manga",
+ "createdAt": 1255081730000,
+ "locations": [
+ "whatever 2"
+ ]
+ }
+]
diff --git a/tests/samples/ksk/fake.yaml b/tests/samples/ksk/fake.yaml
new file mode 100644
index 000000000..2db27f691
--- /dev/null
+++ b/tests/samples/ksk/fake.yaml
@@ -0,0 +1,20 @@
+Artist:
+- xXMidnightEssenceXx
+- bloodytearz666
+Description: The legendary fanfic, now illustrated
+ with a line break
+Magazine:
+- My Immortal - Genesis
+Pages: 420
+Parody:
+- Harry Potter
+Publisher:
+- FanFiction.net
+Released: Mon, 01 Jan 1990 11:30:01 GMT
+Tags:
+- Harry Potter
+- Ebony Dark'ness Dementia Raven Way
+- Draco Malfoy
+Thumb: https://placekitten.com/g/400/300
+Title: My Immortal
+URL: https://www.fanfiction.net/s/6829556/1/My-Immortal
\ No newline at end of file
diff --git a/tests/samples/opds/opds_sample.xml b/tests/samples/opds/opds_sample.xml
index 1bc86da72..4dc826e3a 100644
--- a/tests/samples/opds/opds_sample.xml
+++ b/tests/samples/opds/opds_sample.xml
@@ -96,7 +96,7 @@
+ href="/api/opds/2810d5e0a8d027ecefebca6237031a0fa7b91eb3/pse?page={pageNumber}" pse:count="34" pse:lastRead="34" pse:lastReadDate="2020-05-09T15:31:20Z" />
@@ -126,7 +126,7 @@
+ href="/api/opds/4857fd2e7c00db8b0af0337b94055d8445118630/pse?page={pageNumber}" pse:count="34" pse:lastRead="34" pse:lastReadDate="2020-05-09T15:31:20Z" />
@@ -186,7 +186,7 @@
+ href="/api/opds/e69e43e1355267f7d32a4f9b7f2fe108d2401ebg/pse?page={pageNumber}" pse:count="200" pse:lastRead="34" pse:lastReadDate="2020-05-09T15:31:20Z" />
@@ -216,7 +216,7 @@
+ href="/api/opds/e69e43e1355267f7d32a4f9b7f2fe108d2401ebf/pse?page={pageNumber}" pse:count="2" pse:lastRead="10" pse:lastReadDate="2020-05-09T15:31:20Z" />
diff --git a/tests/tankoubon.t b/tests/tankoubon.t
new file mode 100644
index 000000000..737abc9ea
--- /dev/null
+++ b/tests/tankoubon.t
@@ -0,0 +1,43 @@
+use strict;
+use warnings;
+use utf8;
+use Cwd;
+
+use Mojo::Base 'Mojolicious';
+
+use Test::More;
+use Test::Mojo;
+use Test::MockObject;
+use Mojo::JSON qw (decode_json);
+use Data::Dumper;
+
+use LANraragi::Model::Tankoubon;
+use LANraragi::Model::Config;
+use LANraragi::Model::Stats;
+
+# Mock Redis
+my $cwd = getcwd;
+require $cwd . "/tests/mocks.pl";
+setup_redis_mock();
+
+my $redis = LANraragi::Model::Config->get_redis;
+
+# Build search hashes
+LANraragi::Model::Stats::build_stat_hashes();
+
+# Search queries
+my ( $total, $filtered, @rgs );
+
+# Get Tankoubon
+my %tankoubon = LANraragi::Model::Tankoubon::get_tankoubon("TANK_1589141306", 0, 0);
+is($tankoubon{id}, "TANK_1589141306", 'ID test');
+is($tankoubon{name}, "Hello", 'Name test');
+ok($tankoubon{archives}[0] eq "28697b96f0ac5858be2614ed10ca47742c9522fd", 'Archives test');
+
+# List Tankoubon
+( $total, $filtered, @rgs ) = LANraragi::Model::Tankoubon::get_tankoubon_list(0);
+is($total, 2, 'Total Test');
+is($filtered, 2, 'Count Test');
+ok($rgs[0]{name} eq "World" && $rgs[1]{name} eq "Hello", 'Tank List test');
+
+done_testing();
diff --git a/tools/Documentation/.screenshots/batch.png b/tools/Documentation/.screenshots/batch.png
index 4bb29a69d..34922b7a9 100644
Binary files a/tools/Documentation/.screenshots/batch.png and b/tools/Documentation/.screenshots/batch.png differ
diff --git a/tools/Documentation/.screenshots/category_filtered.png b/tools/Documentation/.screenshots/category_filtered.png
index d83a46ee6..ec2c938b3 100644
Binary files a/tools/Documentation/.screenshots/category_filtered.png and b/tools/Documentation/.screenshots/category_filtered.png differ
diff --git a/tools/Documentation/.screenshots/karen-startmenu.png b/tools/Documentation/.screenshots/karen-startmenu.png
index 3f73effe9..5da0eb3be 100644
Binary files a/tools/Documentation/.screenshots/karen-startmenu.png and b/tools/Documentation/.screenshots/karen-startmenu.png differ
diff --git a/tools/Documentation/.screenshots/karen.jpg b/tools/Documentation/.screenshots/karen.jpg
index 565597ce8..c04865e98 100644
Binary files a/tools/Documentation/.screenshots/karen.jpg and b/tools/Documentation/.screenshots/karen.jpg differ
diff --git a/tools/Documentation/.screenshots/lrr_react.jpg b/tools/Documentation/.screenshots/lrr_react.jpg
new file mode 100644
index 000000000..3edfa3654
Binary files /dev/null and b/tools/Documentation/.screenshots/lrr_react.jpg differ
diff --git a/tools/Documentation/.screenshots/themes.png b/tools/Documentation/.screenshots/themes.png
index b953b4788..69c39d4a3 100644
Binary files a/tools/Documentation/.screenshots/themes.png and b/tools/Documentation/.screenshots/themes.png differ
diff --git a/tools/Documentation/advanced-usage/external-readers.md b/tools/Documentation/advanced-usage/external-readers.md
index 0704b0452..a30baf384 100644
--- a/tools/Documentation/advanced-usage/external-readers.md
+++ b/tools/Documentation/advanced-usage/external-readers.md
@@ -45,7 +45,14 @@ Here are some existing clients:
![Tachiyomi](<../.screenshots/tachiyomi.jpg>)
The open-source [Tachiyomi](https://tachiyomi.org) Android reader has a readymade plugin to consume the LANraragi API.
-You can download it [here.](https://github.com/inorichi/tachiyomi-extensions/blob/repo/apk/tachiyomi-all.lanraragi-v1.2.1.apk)
+You can download it [here.](https://github.com/tachiyomiorg/tachiyomi-extensions/blob/repo/apk/tachiyomi-all.lanraragi-v1.4.14.apk)
+
+### LRR React Web
+
+![LRR React-Web](../.screenshots/lrr_react.jpg)
+
+A React-based frontend PWA making use of the Client API. "Works best on mobile and tablet viewports, but the desktop experience is okay."
+Check it out [here.](https://github.com/hibikikuze4dan/lanraragi-react-web)
## Generic OPDS readers
diff --git a/tools/Documentation/api-documentation/archive-api.md b/tools/Documentation/api-documentation/archive-api.md
index 8a39ff219..dadbfea46 100644
--- a/tools/Documentation/api-documentation/archive-api.md
+++ b/tools/Documentation/api-documentation/archive-api.md
@@ -18,6 +18,7 @@ Get the Archive Index in JSON form. You can use the IDs of this JSON with the ot
"pagecount": 128,
"progress": 0,
"tags": "",
+ "lastreadtime": 1589038280,
"title": "Ghost in the Shell 01.5 - Human-Error Processor v01c01"
}, {
"arcid": "28697b96f0ac5858be2614ed10ca47742c9522fd",
@@ -26,6 +27,7 @@ Get the Archive Index in JSON form. You can use the IDs of this JSON with the ot
"pagecount": 34,
"progress": 3,
"tags": "parody:fate grand order, group:wadamemo, artist:wada rco, artbook, full color",
+ "lastreadtime": 1337038281,
"title": "Fate GO MEMO"
}, {
"arcid": "2810d5e0a8d027ecefebca6237031a0fa7b91eb3",
@@ -34,6 +36,7 @@ Get the Archive Index in JSON form. You can use the IDs of this JSON with the ot
"pagecount": 0,
"progress": 0,
"tags": "parody:fate grand order, character:abigail williams, character:artoria pendragon alter, character:asterios, character:ereshkigal, character:gilgamesh, character:hans christian andersen, character:hassan of serenity, character:hector, character:helena blavatsky, character:irisviel von einzbern, character:jeanne alter, character:jeanne darc, character:kiara sessyoin, character:kiyohime, character:lancer, character:martha, character:minamoto no raikou, character:mochizuki chiyome, character:mordred pendragon, character:nitocris, character:oda nobunaga, character:osakabehime, character:penthesilea, character:queen of sheba, character:rin tosaka, character:saber, character:sakata kintoki, character:scheherazade, character:sherlock holmes, character:suzuka gozen, character:tamamo no mae, character:ushiwakamaru, character:waver velvet, character:xuanzang, character:zhuge liang, group:wadamemo, artist:wada rco, artbook, full color",
+ "lastreadtime": 1337038282,
"title": "Fate GO MEMO 2"
}, {
"arcid": "e69e43e1355267f7d32a4f9b7f2fe108d2401ebf",
@@ -42,6 +45,7 @@ Get the Archive Index in JSON form. You can use the IDs of this JSON with the ot
"pagecount": 0,
"progress": 0,
"tags": "character:segata sanshiro",
+ "lastreadtime": 1337038234,
"title": "Saturn Backup Cartridge - Japanese Manual"
}, {
"arcid": "e4c422fd10943dc169e3489a38cdbf57101a5f7e",
@@ -50,6 +54,7 @@ Get the Archive Index in JSON form. You can use the IDs of this JSON with the ot
"pagecount": 0,
"progress": 0,
"tags": "parody: jojo's bizarre adventure",
+ "lastreadtime": 0,
"title": "Rohan Kishibe goes to Gucci"
}]
```
@@ -89,6 +94,7 @@ ID of the Archive to process.
"pagecount": 34,
"progress": 3,
"tags": "character:segata sanshiro",
+ "lastreadtime": 1337038234,
"title": "Saturn Backup Cartridge - Japanese Manual"
}
```
@@ -147,6 +153,29 @@ ID of the Archive to process.
{% endswagger-response %}
{% endswagger %}
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/archives/:id/tankoubons" method="get" summary="Get Archive Tankoubons" %}
+{% swagger-description %}
+Get all the Tankoubons which currently refer to this Archive ID.
+{% endswagger-description %}
+
+{% swagger-parameter name="id" type="string" required="true" in="path" %}
+ID of the Archive to process.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "operation": "find_arc_tankoubons",
+ "success": 1,
+ "tankoubons": [
+ "TANK_1688616437",
+ "TANK_1688693913"
+ ]
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/archives/:id/thumbnail" method="get" summary="Get Archive Thumbnail" %}
{% swagger-description %}
Get a Thumbnail image for a given Archive. This endpoint will queue generation of the thumbnail in the background if it doesn't already exist, and return a placeholder image.
@@ -309,6 +338,8 @@ ID of the Archive to process
{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/archives/:id/progress/:page" method="put" summary="Update Reading Progression" %}
{% swagger-description %}
Tell the server which page of this Archive you're currently showing/reading, so that it updates its internal reading progression accordingly.
+This endpoint will also update the date this Archive was last read, using the current server timestamp.
+
You should call this endpoint only when you're sure the user is currently reading the page you present.
**Don't** use it when preloading images off the server.
@@ -333,6 +364,7 @@ Current page to update the reading progress to. **Must** be a positive integer,
"id": "75d18ce470dc99f83dc355bdad66319d1f33c82b",
"operation": "update_progress",
"page": 34,
+ "lastreadtime": 123943543,
"success": 1
}
```
diff --git a/tools/Documentation/api-documentation/search-api.md b/tools/Documentation/api-documentation/search-api.md
index 1e43a2b67..625a34d64 100644
--- a/tools/Documentation/api-documentation/search-api.md
+++ b/tools/Documentation/api-documentation/search-api.md
@@ -14,80 +14,35 @@ ID of the category you want to restrict this search to.
{% endswagger-parameter %}
{% swagger-parameter name="filter" type="string" required="false" in="query" %}
-Search query. You can use the following special characters in it:
-
-\
-
-
-
-
-**Quotation Marks ("...")**
-
-\
-
+Search query. You can use the following special characters in it:
+**Quotation Marks ("...")**
Exact string search. Allows a search term to include spaces. Everything placed inside a pair of quotation marks is treated as a singular term. Wildcard characters are still interpreted as wildcards.
-**Question Mark (?), Underscore (_)**
-
-\
-
-
+**Question Mark (?), Underscore (_)**
Wildcard. Can match any single character.
-**Asterisk (*), Percentage Sign (%)**
-
-\
-
-
+**Asterisk (*), Percentage Sign (%)**
Wildcard. Can match any sequence of characters (including none).
-**Subtraction Sign (-)**
-
-\
-
-
+**Subtraction Sign (-)**
Exclusion. When placed before a term, prevents search results from including that term.
-**Dollar Sign ($)**
-
-\
-
-
+**Dollar Sign ($)**
Add at the end of a tag to perform an exact tag search rather than displaying all elements that start with the term. Only matches tags regardless of search parameters and can be used as an exclusion to ignore misc tags in the search query.
{% endswagger-parameter %}
{% swagger-parameter name="start" type="string" required="false" in="query" %}
-From which archive in the total result count this enumeration should start. The total number of archives displayed depends on the server-side
-
-_page size_
-
- preference.
-
-\
-
-
+From which archive in the total result count this enumeration should start. The total number of archives displayed depends on the server-side _page size_ preference.
From 0.8.2 onwards, you can use "-1" here to get the full, unpaged data.
{% endswagger-parameter %}
{% swagger-parameter name="sortby" type="string" required="false" in="query" %}
-Namespace by which you want to sort the results, or
-
-_title_
-
- if you want to sort by title. (Default value is title.)
+Namespace by which you want to sort the results, or _title_ if you want to sort by title. (Default value is title.)
{% endswagger-parameter %}
{% swagger-parameter name="order" type="string" required="false" in="query" %}
-Order of the sort, either
-
-`asc`
-
- or
-
-`desc`
-
-.
+Order of the sort, either `asc` or `desc`.
{% endswagger-parameter %}
{% swagger-response status="200" description="" %}
@@ -98,30 +53,35 @@ Order of the sort, either
"isnew": "none",
"extension": "zip",
"tags": "parody:fate grand order, group:wadamemo, artist:wada rco, artbook, full color",
+ "lastreadtime": 1337038234,
"title": "Fate GO MEMO"
}, {
"arcid": "2810d5e0a8d027ecefebca6237031a0fa7b91eb3",
"isnew": "none",
"extension": "rar",
"tags": "parody:fate grand order, character:abigail williams, character:artoria pendragon alter, character:asterios, character:ereshkigal, character:gilgamesh, character:hans christian andersen, character:hassan of serenity, character:hector, character:helena blavatsky, character:irisviel von einzbern, character:jeanne alter, character:jeanne darc, character:kiara sessyoin, character:kiyohime, character:lancer, character:martha, character:minamoto no raikou, character:mochizuki chiyome, character:mordred pendragon, character:nitocris, character:oda nobunaga, character:osakabehime, character:penthesilea, character:queen of sheba, character:rin tosaka, character:saber, character:sakata kintoki, character:scheherazade, character:sherlock holmes, character:suzuka gozen, character:tamamo no mae, character:ushiwakamaru, character:waver velvet, character:xuanzang, character:zhuge liang, group:wadamemo, artist:wada rco, artbook, full color",
+ "lastreadtime": 1337038234,
"title": "Fate GO MEMO 2"
}, {
"arcid": "4857fd2e7c00db8b0af0337b94055d8445118630",
"isnew": "none",
"extension": "pdf",
"tags": "artist:shirow masamune",
+ "lastreadtime": 1337038234,
"title": "Ghost in the Shell 1.5 - Human-Error Processor vol01ch01"
}, {
"arcid": "e4c422fd10943dc169e3489a38cdbf57101a5f7e",
"isnew": "none",
"extension": "epub",
"tags": "parody: jojo's bizarre adventure",
+ "lastreadtime": 0,
"title": "Rohan Kishibe goes to Gucci"
}, {
"arcid": "e69e43e1355267f7d32a4f9b7f2fe108d2401ebf",
"isnew": "none",
"extension": "lzma",
"tags": "character:segata sanshiro",
+ "lastreadtime": 1337038236,
"title": "Saturn Backup Cartridge - Japanese Manual"
}],
"draw": 0,
@@ -160,24 +120,28 @@ If the search doesn't return enough data to match your count, you will get the f
"isnew": "none",
"extension": "rar",
"tags": "parody:fate grand order, character:abigail williams, character:artoria pendragon alter, character:asterios, character:ereshkigal, character:gilgamesh, character:hans christian andersen, character:hassan of serenity, character:hector, character:helena blavatsky, character:irisviel von einzbern, character:jeanne alter, character:jeanne darc, character:kiara sessyoin, character:kiyohime, character:lancer, character:martha, character:minamoto no raikou, character:mochizuki chiyome, character:mordred pendragon, character:nitocris, character:oda nobunaga, character:osakabehime, character:penthesilea, character:queen of sheba, character:rin tosaka, character:saber, character:sakata kintoki, character:scheherazade, character:sherlock holmes, character:suzuka gozen, character:tamamo no mae, character:ushiwakamaru, character:waver velvet, character:xuanzang, character:zhuge liang, group:wadamemo, artist:wada rco, artbook, full color",
+ "lastreadtime": 1337038234,
"title": "Fate GO MEMO 2"
}, {
"arcid": "4857fd2e7c00db8b0af0337b94055d8445118630",
"isnew": "none",
"extension": "pdf",
"tags": "artist:shirow masamune",
+ "lastreadtime": 1337038234,
"title": "Ghost in the Shell 1.5 - Human-Error Processor vol01ch01"
}, {
"arcid": "e4c422fd10943dc169e3489a38cdbf57101a5f7e",
"isnew": "none",
"extension": "epub",
"tags": "parody: jojo's bizarre adventure",
+ "lastreadtime": 0,
"title": "Rohan Kishibe goes to Gucci"
}, {
"arcid": "e69e43e1355267f7d32a4f9b7f2fe108d2401ebf",
"isnew": "none",
"extension": "lzma",
"tags": "character:segata sanshiro",
+ "lastreadtime": 1337033234,
"title": "Saturn Backup Cartridge - Japanese Manual"
}
]
diff --git a/tools/Documentation/api-documentation/tankoubon-api.md b/tools/Documentation/api-documentation/tankoubon-api.md
new file mode 100644
index 000000000..fa01802b2
--- /dev/null
+++ b/tools/Documentation/api-documentation/tankoubon-api.md
@@ -0,0 +1,293 @@
+# Tankoubon API
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons" method="get" summary="Get all tankoubons" %}
+{% swagger-description %}
+Get list of Tankoubons paginated.
+{% endswagger-description %}
+
+{% swagger-parameter name="page" type="string" required="false" in="query" %}
+Page of the list of Tankoubons.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "filtered": 2,
+ "result": [
+ {
+ "archives": [
+ "28697b96f0ac5858be2614ed10ca47742c9522fd",
+ "4857fd2e7c00db8b0af0337b94055d8445118630",
+ "fa74bc15e7dd2b6ec0dc2e10cc7cd4942867318a"
+ ],
+ "id": "TANK_1688616437",
+ "name": "Test 1"
+ },
+ {
+ "archives": [
+ "fa74bc15e7dd2b6ec0dc2e10cc7cd4942867318a"
+ ],
+ "id": "TANK_1688693913",
+ "name": "Test 2"
+ }
+ ],
+ "total": 2
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons/:id" method="get" summary="Get a single tankoubon" %}
+{% swagger-description %}
+Get the details of the specified tankoubon ID, with the archives list paginated.
+{% endswagger-description %}
+
+{% swagger-parameter name="id" type="string" required="true" in="path" %}
+ID of the Tankoubon desired.
+{% endswagger-parameter %}
+
+{% swagger-parameter name="include_full_data" type="string" required="false" in="query" %}
+If set in 1, it appends a full_data array with Archive objects.
+{% endswagger-parameter %}
+
+{% swagger-parameter name="page" type="string" required="false" in="query" %}
+Page of the Archives list.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="include_full_data = 0" %}
+```javascript
+{
+ "filtered": 3,
+ "result": {
+ "archives": [
+ "fa74bc15e7dd2b6ec0dc2e10cc7cd4942867318a",
+ "28697b96f0ac5858be2614ed10ca47742c9522fd",
+ "4857fd2e7c00db8b0af0337b94055d8445118630"
+ ],
+ "id": "TANK_1688616437",
+ "name": "Test 1"
+ },
+ "total": 3
+}
+```
+{% endswagger-response %}
+
+{% swagger-response status="200" description="include_full_data = 1" %}
+```javascript
+{
+ "filtered": 3,
+ "result": {
+ "archives": [
+ "fa74bc15e7dd2b6ec0dc2e10cc7cd4942867318a",
+ "28697b96f0ac5858be2614ed10ca47742c9522fd",
+ "4857fd2e7c00db8b0af0337b94055d8445118630"
+ ],
+ "full_data": [
+ {
+ "arcid": "fa74bc15e7dd2b6ec0dc2e10cc7cd4942867318a",
+ "extension": "zip",
+ "isnew": "true",
+ "lastreadtime": 0,
+ "pagecount": 30,
+ "progress": 0,
+ "tags": "date_added:1688608157",
+ "lastreadtime": 0,
+ "title": "(C95) [wadamemo (WADA Rco)] Fate GO MEMO 3 (Fate Grand Order)"
+ },
+ {
+ "arcid": "28697b96f0ac5858be2614ed10ca47742c9522fd",
+ "extension": "zip",
+ "isnew": "true",
+ "lastreadtime": 0,
+ "pagecount": 30,
+ "progress": 0,
+ "tags": "date_added:1688608157",
+ "lastreadtime": 0,
+ "title": "FateGOMEMO"
+ },
+ {
+ "arcid": "4857fd2e7c00db8b0af0337b94055d8445118630",
+ "extension": "zip",
+ "isnew": "true",
+ "lastreadtime": 0,
+ "pagecount": 26,
+ "progress": 0,
+ "tags": "date_added:1688608157",
+ "lastreadtime": 0,
+ "title": "gits (2)"
+ }
+ ],
+ "id": "TANK_1688616437",
+ "name": "Test 1"
+ },
+ "total": 3
+}
+```
+{% endswagger-response %}
+
+{% swagger-response status="400" description="" %}
+```javascript
+{
+ "error": "The given tankoubon does not exist.",
+ "operation": "get_tankoubon",
+ "success": 0
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons" method="put" summary="🔑Create a Tankoubon" %}
+{% swagger-description %}
+Create a new Tankoubon or updated the name of an existing one.
+{% endswagger-description %}
+
+{% swagger-parameter name="name" type="string" required="true" in="query" %}
+Name of the Category.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "operation": "create_tankoubon",
+ "success": 1,
+ "tankoubon_id": "TANK_1690056313"
+}
+```
+{% endswagger-response %}
+
+{% swagger-response status="400" description="" %}
+```javascript
+{
+ "error": "Tankoubon name not specified.",
+ "operation": "create_tankoubon",
+ "success": 0
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons/:id/archive" method="put" summary="🔑Update a Tankoubon" %}
+{% swagger-description %}
+Modify a Tankoubon using an ordered array that can add new files, remove files, and update order.
+{% endswagger-description %}
+
+{% swagger-parameter name="id" type="string" required="true" in="path" %}
+ID of the Tankoubon to update.
+{% endswagger-parameter %}
+
+{% swagger-parameter name="archives" type="array" required="true" in="body" %}
+Ordered array with the IDs of the archives.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "error": "",
+ "operation": "update_archive_list",
+ "success": 1,
+ "successMessage": "Updated archives of tankoubon \"Test 1\"!"
+}
+```
+{% endswagger-response %}
+
+{% swagger-response status="400" description="" %}
+```javascript
+{
+ "error": "rr doesn't exist in the database!",
+ "operation": "update_archive_list",
+ "success": 0
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons/:id/:archive" method="put" summary="🔑Add an archive to a Tankoubon" %}
+{% swagger-description %}
+Append an archive at the final position of a Tankoubon.
+{% endswagger-description %}
+
+{% swagger-parameter name="id" type="string" required="true" in="path" %}
+ID of the Tankoubon to update.
+{% endswagger-parameter %}
+
+{% swagger-parameter name="archive" type="string" required="true" in="path" %}
+ID of the Archive to append.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "error": "",
+ "operation": "add_to_tankoubon",
+ "success": 1,
+ "successMessage": "Added \"(C95) [wadamemo (WADA Rco)] Fate GO MEMO 3 (Fate Grand Order)\" to tankoubon \"Test 1\"!"
+}
+```
+{% endswagger-response %}
+
+{% swagger-response status="400" description="" %}
+```javascript
+{
+ "error": "rr doesn't exist in the database!",
+ "operation": "add_to_tankoubon",
+ "success": 0
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons/:id/:archive" method="delete" summary="🔑Remove an archive from a Tankoubon" %}
+{% swagger-description %}
+Remove an archive from a Tankoubon.
+{% endswagger-description %}
+
+{% swagger-parameter name="id" type="string" required="true" in="path" %}
+ID of the Tankoubon to update.
+{% endswagger-parameter %}
+
+{% swagger-parameter name="archive" type="string" required="true" in="path" %}
+ID of the archive to remove.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "error": "",
+ "operation": "remove_from_tankoubon",
+ "success": 1,
+ "successMessage": "Removed \"(C95) [wadamemo (WADA Rco)] Fate GO MEMO 3 (Fate Grand Order)\" from tankoubon \"Test 1\"!"
+}
+```
+{% endswagger-response %}
+
+{% swagger-response status="400" description="" %}
+```javascript
+{
+ "error": "rr doesn't exist in the database!",
+ "operation": "remove_from_tankoubon",
+ "success": 0
+}
+```
+{% endswagger-response %}
+{% endswagger %}
+
+{% swagger baseUrl="http://lrr.tvc-16.science" path="/api/tankoubons/:id" method="delete" summary="🔑Delete a Tankoubon" %}
+{% swagger-description %}
+Remove a Tankoubon.
+{% endswagger-description %}
+
+{% swagger-parameter name="id" type="string" required="true" in="path" %}
+ID of the Tankoubon to delete.
+{% endswagger-parameter %}
+
+{% swagger-response status="200" description="" %}
+```javascript
+{
+ "error": "",
+ "operation": "delete_tankoubon",
+ "success": 1,
+ "successMessage": null
+}
+```
+{% endswagger-response %}
+{% endswagger %}
diff --git a/tools/Documentation/basic-operations/first-steps.md b/tools/Documentation/basic-operations/first-steps.md
index 8df1ba636..feaad1684 100644
--- a/tools/Documentation/basic-operations/first-steps.md
+++ b/tools/Documentation/basic-operations/first-steps.md
@@ -59,7 +59,7 @@ The following formats are supported by LRR for Archives:
* 7z/cb7
* xz
* pdf
-* epub (images only if viewed in the Web Client)\\
+* epub (images only if viewed in the Web Client or through the Client API, potentially out of order)\\
{% endhint %}
{% hint style="info" %}
diff --git a/tools/Documentation/extending-lanraragi/architecture.md b/tools/Documentation/extending-lanraragi/architecture.md
index 64b775ec7..fb83b6e6f 100644
--- a/tools/Documentation/extending-lanraragi/architecture.md
+++ b/tools/Documentation/extending-lanraragi/architecture.md
@@ -17,7 +17,8 @@ Those variables were introduced for the Homebrew package, but they can be declar
* `LRR_TEMP_DIRECTORY` - Temporary directory override. If this variable is set to a path, the temporary folder will be there instead of `/public/temp`.
* `LRR_LOG_DIRECTORY` - Log directory override. Changes the location of the `log` folder.
* `LRR_FORCE_DEBUG` - Debug Mode override. This will force Debug Mode to be enabled regardless of the user setting.
-* `LRR_NETWORK` - Network Interface. See the dedicated page in Advanced Operations.
+* `LRR_NETWORK` - Network Interface. See the dedicated page in Advanced Operations.
+* `LRR_REDIS_ADDRESS` - Redis address override. This has priority over the `redis_address` specified in `lrr.conf`.
## Coding Style
@@ -124,7 +125,8 @@ root/
|- lrr.conf <- Mojolicious configuration file
|- .perltidy.rc <- PerlTidy config file to match the coding style
|- .eslintrc.json <- ESLint config file to match the coding style
-+- package.json <- NPM file, contains front-end dependency listing and shortcuts
+|- package.json <- NPM file, contains front-end dependency listing and shortcuts
++- package-lock.json <- NPM lockfile used by installer/`npm ci` for reproducible builds
```
## Shinobu Architecture
diff --git a/tools/Documentation/extending-lanraragi/index.md b/tools/Documentation/extending-lanraragi/index.md
index 6bf29146c..ab2f39e22 100644
--- a/tools/Documentation/extending-lanraragi/index.md
+++ b/tools/Documentation/extending-lanraragi/index.md
@@ -20,3 +20,13 @@ Said development server can be ran with the `npm run dev-server` command.
The major difference is that this server will automatically reload when you modify any file within LANraragi. Background worker included!
You'll also probably want to enable **Debug Mode** in the LRR Options, as that will allow you to view debug-tier logs, alongside the raw Mojolicious logs.
+
+## Using Github Codespaces
+
+The LRR Git repository contains [devcontainer.json](https://github.com/Difegue/LANraragi/tree/dev/.devcontainer) configuration for [Codespaces](https://github.com/Difegue/LANraragi/codespaces), so you can easily spin up a development VM using that.
+Deployment might take some time, as the VM will download all dependencies.
+
+## Using Docker Compose
+
+You can use [Docker Compose](https://docs.docker.com/compose/) for quickly bringing up a LANraragi instance suitable for development.
+Run `docker compose up -d` inside `tools/build/docker` and hack away!
diff --git a/tools/Documentation/installing-lanraragi/community.md b/tools/Documentation/installing-lanraragi/community.md
index bb01d69e2..c66bd1aef 100644
--- a/tools/Documentation/installing-lanraragi/community.md
+++ b/tools/Documentation/installing-lanraragi/community.md
@@ -4,6 +4,11 @@
An UnRAID package based on the Docker images is available [here.](https://github.com/naipilk/LANraragi-unraid-template/)
+## Nix/NixOS
+
+If you're using [NixOS](https://nixos.org/) or the Nix package manager, a [LANraragi](https://search.nixos.org/packages?channel=unstable&show=lanraragi&from=0&size=50&sort=relevance&type=packages&query=lanraragi) package is available.
+Unlike the other options here, this one is also available for Darwin/macOS!
+
## Arch Linux
An installation package is provided [in the AUR](https://aur.archlinux.org/packages/lanraragi/) (Arch User Repository).
diff --git a/tools/Documentation/installing-lanraragi/methods.md b/tools/Documentation/installing-lanraragi/methods.md
index 99cc11da0..f758c8b45 100644
--- a/tools/Documentation/installing-lanraragi/methods.md
+++ b/tools/Documentation/installing-lanraragi/methods.md
@@ -17,7 +17,11 @@ Look at the methods below for something that fits your OS and usage.
{% content-ref url="macos.md" %}
[macos.md](macos.md)
-{% endcontent-ref %}
+{% endcontent-ref %}
+
+{% hint style="info" %}
+While not a part of the main repo, you can check out the [Nix](community.md) package as well if brew isn't to your taste.
+{% endhint %}
## Windows 10/11: _LRR for Windows_
diff --git a/tools/Documentation/plugin-docs/metadata.md b/tools/Documentation/plugin-docs/metadata.md
index af1e126e1..ef6e14ba1 100644
--- a/tools/Documentation/plugin-docs/metadata.md
+++ b/tools/Documentation/plugin-docs/metadata.md
@@ -52,6 +52,7 @@ Tags are expected to be separated by commas, like this:
Plugins can also modify the title of the archive:
`return ( tags => "some:tags", title=>"My new epic archive title" );`
This parameter is completely optional. \(The tags one isn't however, but it can very well be empty.\)
+If the Plugin's user has disabled "Plugins can modify archive titles" in their settings, you can still pass a new title - It'll simply do nothing.
If you couldn't obtain tags for some reason, you can tell LRR that an error occurred by returning a hash containing an "error" field:
diff --git a/tools/_screenshots/archive_list.png b/tools/_screenshots/archive_list.png
index 3a1647aed..b6a512a7b 100644
Binary files a/tools/_screenshots/archive_list.png and b/tools/_screenshots/archive_list.png differ
diff --git a/tools/_screenshots/archive_thumb.png b/tools/_screenshots/archive_thumb.png
index cfc6501ef..33bbb0ebe 100644
Binary files a/tools/_screenshots/archive_thumb.png and b/tools/_screenshots/archive_thumb.png differ
diff --git a/tools/_screenshots/cfg.png b/tools/_screenshots/cfg.png
index 5155a40a1..12740f9fc 100644
Binary files a/tools/_screenshots/cfg.png and b/tools/_screenshots/cfg.png differ
diff --git a/tools/_screenshots/reader.jpg b/tools/_screenshots/reader.jpg
index d9e0898af..8fc48e724 100644
Binary files a/tools/_screenshots/reader.jpg and b/tools/_screenshots/reader.jpg differ
diff --git a/tools/_screenshots/reader_overlay.jpg b/tools/_screenshots/reader_overlay.jpg
index 149cce81e..409c09815 100644
Binary files a/tools/_screenshots/reader_overlay.jpg and b/tools/_screenshots/reader_overlay.jpg differ
diff --git a/tools/build/docker/Dockerfile b/tools/build/docker/Dockerfile
index 175ce27c0..9759a0fb6 100644
--- a/tools/build/docker/Dockerfile
+++ b/tools/build/docker/Dockerfile
@@ -1,6 +1,7 @@
# DOCKER-VERSION 0.3.4
-FROM alpine:3.16
+FROM alpine:3.18
LABEL git="https://github.com/Difegue/LANraragi"
+ARG INSTALL_PARAMETER
ENV S6_KEEP_ENV 1
@@ -34,7 +35,9 @@ ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 \
# Enable automatic http proxy detection for mojo
MOJO_PROXY=1 \
# Allow Mojo to automatically pick up the X-Forwarded-For and X-Forwarded-Proto headers
- MOJO_REVERSE_PROXY=1
+ MOJO_REVERSE_PROXY=1 \
+ # Attempt to fix file permissions automatically
+ LRR_AUTOFIX_PERMISSIONS=1
RUN \
if [ $(getent group ${LRR_GID}) ]; then \
@@ -50,9 +53,10 @@ WORKDIR /home/koyomi/lanraragi
#This allows for Docker cache to preserve cpan dependencies
COPY --chown=koyomi:koyomi /tools/cpanfile /tools/install.pl /tools/build/docker/install-everything.sh tools/
COPY --chown=koyomi:koyomi /package.json package.json
+COPY --chown=koyomi:koyomi /package-lock.json package-lock.json
# Run the install script as root
-RUN sh ./tools/install-everything.sh
+RUN sh ./tools/install-everything.sh $INSTALL_PARAMETER
#Copy remaining LRR files from context
COPY --chown=koyomi:koyomi /lib lib
diff --git a/tools/build/docker/Dockerfile-dev b/tools/build/docker/Dockerfile-dev
new file mode 100644
index 000000000..ab4d53457
--- /dev/null
+++ b/tools/build/docker/Dockerfile-dev
@@ -0,0 +1,51 @@
+# DOCKER-VERSION 0.3.4
+FROM alpine:3.18
+
+#Default mojo server port
+EXPOSE 3000
+
+# Enable UTF-8 (might not do anything extra on alpine tho)
+ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 \
+ # rootless user id
+ LRR_UID=1000 LRR_GID=1000 \
+ # Environment variables overridable by the user on container deployment
+ LRR_NETWORK=http://*:3000 \
+ # extra variables
+ EV_EXTRA_DEFS=-DEV_NO_ATFORK \
+ # Enable automatic http proxy detection for mojo
+ MOJO_PROXY=1 \
+ # Allow Mojo to automatically pick up the X-Forwarded-For and X-Forwarded-Proto headers
+ MOJO_REVERSE_PROXY=1
+
+RUN \
+ if [ $(getent group ${LRR_GID}) ]; then \
+ adduser -D -u ${LRR_UID} koyomi; \
+ else \
+ addgroup -g ${LRR_GID} koyomi && \
+ adduser -D -u ${LRR_UID} -G koyomi koyomi; \
+fi
+
+WORKDIR /tmp/lrr
+
+#Copy cpanfile and install script before copying the entire context
+#This allows for Docker cache to preserve cpan dependencies
+COPY --chown=koyomi:koyomi /tools/cpanfile /tools/install.pl /tools/build/docker/install-everything.sh tools/
+COPY --chown=koyomi:koyomi /package.json package.json
+COPY --chown=koyomi:koyomi /package-lock.json package-lock.json
+
+# Run the install script as root, in dev mode to prevent wget etc from being uninstalled
+RUN sh ./tools/install-everything.sh -d
+
+RUN rm -rf /tmp/lrr
+
+RUN apk add npm
+
+# Add sudo to make dev more practical, and allow passwordless sudo
+RUN apk add --update sudo
+RUN echo "koyomi ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/koyomi && chmod 0440 /etc/sudoers.d/koyomi
+
+# We're done, since this is not a production build.
+
+WORKDIR /home/koyomi/lanraragi
+USER koyomi
+CMD ["npm", "run", "dev-server"]
diff --git a/tools/build/docker/Dockerfile-legacy b/tools/build/docker/Dockerfile-legacy
index f6ab11b8f..68fc3af73 100644
--- a/tools/build/docker/Dockerfile-legacy
+++ b/tools/build/docker/Dockerfile-legacy
@@ -53,6 +53,7 @@ WORKDIR /home/koyomi/lanraragi
#This allows for Docker cache to preserve cpan dependencies
COPY --chown=koyomi:koyomi /tools/cpanfile /tools/install.pl /tools/build/docker/install-everything.sh tools/
COPY --chown=koyomi:koyomi /package.json package.json
+COPY --chown=koyomi:koyomi /package-lock.json package-lock.json
# Run the install script as root
RUN sh ./tools/install-everything.sh
diff --git a/tools/build/docker/docker-compose.yml b/tools/build/docker/docker-compose.yml
new file mode 100644
index 000000000..2fbf95f05
--- /dev/null
+++ b/tools/build/docker/docker-compose.yml
@@ -0,0 +1,28 @@
+---
+# Docker compose file for dev environments.
+services:
+ lanraragi:
+ build:
+ dockerfile: tools/build/docker/Dockerfile-dev
+ context: ../../..
+ volumes:
+ - ../../../:/home/koyomi/lanraragi
+ ports:
+ - "3000:3000"
+ environment:
+ - "LRR_REDIS_ADDRESS=redis:6379"
+ networks:
+ - lrr
+
+ redis:
+ image: "docker.io/redis:7"
+ volumes:
+ - redis_data:/data
+ networks:
+ - lrr
+
+networks:
+ lrr:
+
+volumes:
+ redis_data:
diff --git a/tools/build/docker/install-everything.sh b/tools/build/docker/install-everything.sh
index 4fb6a3a33..9c4d9023d 100755
--- a/tools/build/docker/install-everything.sh
+++ b/tools/build/docker/install-everything.sh
@@ -1,5 +1,24 @@
#!/bin/sh
+usage() { echo "Usage: $0 [-d (devmode) -w (wsl cpan packages)]" 1>&2; exit 1; }
+
+DEV=0
+WSL=0
+
+while getopts "dw" o; do
+ case "${o}" in
+ d)
+ DEV=1
+ ;;
+ w)
+ WSL=1
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+
#Just do everything
apk update
apk add tzdata
@@ -7,25 +26,19 @@ apk add perl perl-io-socket-ssl perl-dev redis libarchive-dev libbz2 openssl-dev
apk add imagemagick imagemagick-perlmagick libwebp-tools libheif
apk add g++ make pkgconf gnupg wget curl file
apk add shadow s6 s6-portable-utils
+apk add nodejs npm s6-overlay libjxl
# Install cpanm
curl -L https://cpanmin.us | perl - App::cpanminus
-# Check for alpine version - 3.12 is used for the WSL version.
-if [ -f /etc/alpine-release ]; then
- alpine_version=$(cat /etc/alpine-release)
- if [ "$alpine_version" = "3.12.12" ]; then
- apk add nodejs-npm
-
- # Install Linux::Inotify 2.2 explicitly as 2.3 doesn't work properly on WSL:
- # WSL2 literally doesn't work for any form of filewatching,
- # WSL1 works with both default watcher and inotify 2.2, but crashes with inotify 2.3 ("can't open fd 4 as perl handle")
-
- # Doing the install here allows us to use 2.3 on non-WSL builds.
- cpanm https://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/Linux-Inotify2-2.2.tar.gz --reinstall
- else # Those packages don't exist on 3.12
- apk add nodejs npm s6-overlay libjxl
- fi
+# Check for windows to install specific versions of packages
+if [ $WSL -eq 1 ]; then
+ # Install Linux::Inotify 2.2 explicitly as 2.3 doesn't work properly on WSL:
+ # WSL2 literally doesn't work for any form of filewatching,
+ # WSL1 works with both default watcher and inotify 2.2, but crashes with inotify 2.3 ("can't open fd 4 as perl handle")
+
+ # Doing the install here allows us to use 2.3 on non-WSL builds.
+ cpanm https://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/Linux-Inotify2-2.2.tar.gz --reinstall
fi
#Alpine's libffi build comes with AVX instructions enabled
@@ -48,7 +61,9 @@ fi
cd tools && cpanm --notest --installdeps . -M https://cpan.metacpan.org && cd ..
npm run lanraragi-installer install-full
-#Cleanup to lighten the image
-apk del perl-dev g++ make gnupg wget curl nodejs npm openssl-dev file
-rm -rf public/js/vendor/*.map public/css/vendor/*.map
-rm -rf /root/.cpanm/* /root/.npm/ /usr/local/share/man/* node_modules /var/cache/apk/*
+if [ $DEV -eq 0 ]; then
+ #Cleanup to lighten the image
+ apk del perl-dev g++ make gnupg wget curl nodejs npm openssl-dev file
+ rm -rf public/js/vendor/*.map public/css/vendor/*.map
+ rm -rf /root/.cpanm/* /root/.npm/ /usr/local/share/man/* node_modules /var/cache/apk/*
+fi
diff --git a/tools/build/docker/redis.conf b/tools/build/docker/redis.conf
index 3505e7de2..eda3b8282 100644
--- a/tools/build/docker/redis.conf
+++ b/tools/build/docker/redis.conf
@@ -695,7 +695,7 @@ replica-lazy-flush no
#
# Please check http://redis.io/topics/persistence for more information.
-appendonly no
+appendonly yes
# The name of the append only file (default: "appendonly.aof")
diff --git a/tools/build/docker/s6/cont-init.d/01-lrr-setup b/tools/build/docker/s6/cont-init.d/01-lrr-setup
index 7d266df71..9152d37ba 100755
--- a/tools/build/docker/s6/cont-init.d/01-lrr-setup
+++ b/tools/build/docker/s6/cont-init.d/01-lrr-setup
@@ -2,6 +2,7 @@
USER_ID=${LRR_UID}
GROUP_ID=${LRR_GID}
+FIX_PERMS=${LRR_AUTOFIX_PERMISSIONS:-1}
echo "Starting LANraragi with UID/GID : $USER_ID/$GROUP_ID"
@@ -9,10 +10,7 @@ echo "Starting LANraragi with UID/GID : $USER_ID/$GROUP_ID"
#This solves permission problems on the content folder if the Docker user sets the same uid as the owner of the folder.
usermod -o -u $USER_ID koyomi
groupmod -o -g $GROUP_ID koyomi
-
-#Ensure LRR folder is writable
chown koyomi /home/koyomi/lanraragi
-chmod u+rwx /home/koyomi/lanraragi
#Crash with an error if content folder doesn't exist
if [ ! -d "/home/koyomi/lanraragi/content" ]; then
@@ -24,10 +22,19 @@ fi
chown -R koyomi /home/koyomi/lanraragi/database
chmod -R u+rwx /home/koyomi/lanraragi/database
-#Ensure thumbnail folder is writable
-chown -R koyomi /home/koyomi/lanraragi/content/thumb
-find /home/koyomi/lanraragi/content/thumb -type f -exec chmod u+rw {} \;
-find /home/koyomi/lanraragi/content/thumb -type d -exec chmod u+rwx {} \;
+if [ "$FIX_PERMS" -eq 1 ]; then
+ echo "Fixing permissions, hold on!"
+ #Ensure thumbnail folder is writable
+ chown -R koyomi /home/koyomi/lanraragi/content/thumb
+ find /home/koyomi/lanraragi/content/thumb -type f -exec chmod u+rw {} \;
+ find /home/koyomi/lanraragi/content/thumb -type d -exec chmod u+rwx {} \;
+
+ # Ensure the rest of the content folder is at least readable
+ find /home/koyomi/lanraragi/content -name thumb -prune -o -type f -exec chmod u+r {} \;
+ find /home/koyomi/lanraragi/content -name thumb -prune -o -type d -exec chmod u+rx {} \;
+else
+ echo "Not touching permissions"
+fi
#Ensure log folder is writable
mkdir /home/koyomi/lanraragi/log
diff --git a/tools/build/homebrew/Lanraragi.rb b/tools/build/homebrew/Lanraragi.rb
index 0bfa9b2b7..4d28c3f1f 100644
--- a/tools/build/homebrew/Lanraragi.rb
+++ b/tools/build/homebrew/Lanraragi.rb
@@ -3,14 +3,14 @@
class Lanraragi < Formula
desc "Web application for archival and reading of manga/doujinshi"
homepage "https://github.com/Difegue/LANraragi"
- # url "https://github.com/Difegue/LANraragi/archive/v.0.7.6.tar.gz"
- # sha256 "2c498cc6a18b9fbb77c52ca41ba329c503aa5d4ec648075c3ebb72bfa7102099"
+ # url "https://github.com/Difegue/LANraragi/archive/refs/tags/v.0.8.90.tar.gz"
+ # sha256 "290bd2299962f14667a279dd8e40a1f93d1e9e338c08342af5830a1ce119c93e"
url "https://github.com/Difegue/LANraragi.git",
revision: "COMMIT_HASH"
version "0.1994-dev"
license "MIT"
revision 1
- head "https://github.com/Difegue/LANraragi.git"
+ head "https://github.com/Difegue/LANraragi.git", branch: "dev"
depends_on "nettle" => :build
depends_on "pkg-config" => :build
@@ -28,16 +28,16 @@ class Lanraragi < Formula
uses_from_macos "libarchive"
- on_macos do
- resource "libarchive-headers" do
- url "https://opensource.apple.com/tarballs/libarchive/libarchive-83.100.2.tar.gz"
- sha256 "a0228f75792f881bc927196f8b794d0263a019aab741765e54550f75271258aa"
+ resource "libarchive-headers" do
+ on_macos do
+ url "https://github.com/apple-oss-distributions/libarchive/archive/refs/tags/libarchive-113.tar.gz"
+ sha256 "b422c37cc5f9ec876d927768745423ac3aae2d2a85686bc627b97e22d686930f"
end
end
resource "Image::Magick" do
- url "https://cpan.metacpan.org/authors/id/J/JC/JCRISTY/PerlMagick-7.0.10.tar.gz"
- sha256 "1d5272d71b5cb44c30cd84b09b4dc5735b850de164a192ba191a9b35568305f4"
+ url "https://cpan.metacpan.org/authors/id/J/JC/JCRISTY/Image-Magick-7.1.0-0.tar.gz"
+ sha256 "f90c975cbe21445777c40d19c17b7f79023d3064ef8fabcf348cf82654bc16eb"
end
def install
@@ -75,13 +75,13 @@ def install
end
end
- system "cpanm", "-v", "Config::AutoConf", "-l", libexec
+ system "cpanm", "Config::AutoConf", "--notest", "-l", libexec
system "npm", "install", *Language::Node.local_npm_install_args
system "perl", "./tools/install.pl", "install-full"
prefix.install "README.md"
(libexec/"lib").install Dir["lib/*"]
- libexec.install "script", "package.json", "public", "templates", "tests", "lrr.conf"
+ libexec.install "script", "package.json", "package-lock.json", "public", "templates", "tests", "lrr.conf"
cd "tools/build/homebrew" do
bin.install "lanraragi"
libexec.install "redis.conf"
@@ -105,7 +105,7 @@ def caveats
# but while we're at it, we can also check for the table flip! it's free real estate
# Make sure lanraragi writes files to a path allowed by the sandbox
- ENV["LRR_LOG_DIRECTORY"] = ENV["LRR_TEMP_DIRECTORY"] = testpath
+ ENV["LRR_LOG_DIRECTORY"] = ENV["LRR_TEMP_DIRECTORY"] = ENV["LRR_DATA_DIRECTORY"] = testpath
%w[server.pid shinobu.pid minion.pid].each { |file| touch file }
# Set PERL5LIB as we're not calling the launcher script
diff --git a/tools/build/homebrew/redis.conf b/tools/build/homebrew/redis.conf
index 3f1c213be..fcdda2f9e 100644
--- a/tools/build/homebrew/redis.conf
+++ b/tools/build/homebrew/redis.conf
@@ -695,7 +695,7 @@ replica-lazy-flush no
#
# Please check http://redis.io/topics/persistence for more information.
-appendonly no
+appendonly yes
# The name of the append only file (default: "appendonly.aof")
diff --git a/tools/build/windows/Karen b/tools/build/windows/Karen
index 6a63e5084..dd7cbb1a0 160000
--- a/tools/build/windows/Karen
+++ b/tools/build/windows/Karen
@@ -1 +1 @@
-Subproject commit 6a63e508499effed0a680e3984d96d8427383881
+Subproject commit dd7cbb1a0be95220688f3c9cc1d6f60b4625bcd6
diff --git a/tools/cpanfile b/tools/cpanfile
index 359c61fe0..b3d397701 100755
--- a/tools/cpanfile
+++ b/tools/cpanfile
@@ -8,6 +8,7 @@ requires 'Encode', 3.01;
requires 'Archive::Libarchive::Extract', 0.03;
requires 'Archive::Libarchive::Peek', 0.04;
requires 'Digest::SHA', 6.02;
+requires 'List::MoreUtils', 0.430;
# Not required by LRR itself but needs this version for Alpine support
requires 'Crypt::Rijndael', 1.14;
@@ -30,13 +31,14 @@ requires 'Logfile::Rotate', 1.04;
requires 'Compress::Zlib', 2.087;
# Test Utils
+requires 'App::Prove', 1.7046;
requires 'Test::Harness', 3.42;
requires 'Test::MockObject', 1.20200122;
requires 'Test::Trap', 0.3.4;
requires 'Test::Deep', 1.130;
# Mojo stuff
-requires 'Mojolicious', 9.30;
+requires 'Mojolicious', 9.34;
requires 'Mojolicious::Plugin::TemplateToolkit', 0.005;
requires 'Mojolicious::Plugin::RenderFile', 0.12;
requires 'Mojolicious::Plugin::Status', 1.15;
@@ -56,5 +58,11 @@ requires 'File::ChangeNotify', 0.31;
# Plugin system
requires 'Module::Pluggable', 5.2;
-# Eze plugin
+# Eze plugin/Timestamp calculation
requires 'Time::Local', 1.30;
+
+# Ksk plugin/YAML Support
+requires 'YAML::Syck', 1.34;
+
+# Hentag plugin
+requires 'String::Similarity', 1.04
diff --git a/tools/install.pl b/tools/install.pl
index 0cbb847dd..dbeb7c111 100755
--- a/tools/install.pl
+++ b/tools/install.pl
@@ -7,7 +7,7 @@
use Cwd;
use Config;
-use feature qw(say);
+use feature qw(say);
use File::Path qw(make_path);
#Vendor dependencies
@@ -156,7 +156,7 @@
say("\r\nObtaining remote Web dependencies...\r\n");
- if ( system("npm install") != 0 ) {
+ if ( system("npm ci") != 0 ) {
die "Something went wrong while obtaining node modules - Bailing out.";
}