dev 基于官方原版 f9b76513 汉化

This commit is contained in:
WindyMadman 2023-07-02 04:50:41 +00:00
parent bcc6c74a30
commit 4c8c2ff124
148 changed files with 7807 additions and 1111 deletions

View File

@ -8,7 +8,7 @@ ARG UPGRADE_PACKAGES="false"
ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8
# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies.
ARG USERNAME=koyomi
ARG USERNAME=root
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN export DEBIAN_FRONTEND=noninteractive \

View File

@ -41,5 +41,5 @@
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm run lanraragi-installer install-front && sudo service redis-server start",
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "koyomi"
"remoteUser": "root"
}

View File

@ -44,7 +44,7 @@ jobs:
- uses: actions/checkout@master
- name: Docker Build and export
run: |
docker build -t difegue/lanraragi -f ./tools/build/docker/Dockerfile-legacy .
docker build -t difegue/lanraragi -f ./tools/build/docker/Dockerfile --build-arg INSTALL_PARAMETER=-w .
docker create --name rootfs difegue/lanraragi
docker export --output=package.tar rootfs
- name: Upload rootfs

View File

@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@master
- name: Docker Build and export
run: |
docker build -t difegue/lanraragi -f ./tools/build/docker/Dockerfile-legacy .
docker build -t difegue/lanraragi -f ./tools/build/docker/Dockerfile --build-arg INSTALL_PARAMETER=-w .
docker create --name rootfs difegue/lanraragi
docker export --output=package.tar rootfs
- name: Upload rootfs

View File

@ -6,57 +6,57 @@
[<img src="https://github.com/Difegue/LANraragi/actions/workflows/push-continuous-integration.yml/badge.svg">](https://github.com/Difegue/LANraragi/actions)
[<img src="https://img.shields.io/discord/612709831744290847">](https://discord.gg/aRQxtbg)
<img src="public/favicon.ico" width="128">
<img src="public/favicon.ico" width="128">
LANraragi
===========
LANraragi_CN
============
Open source server for archival of comics/manga, running on Mojolicious + Redis.
用于漫画存档的开源服务器,使用 Mojolicious + Redis 运行这是LANraragi的汉化版本相较与原版汉化了界面修复了chrome的js报错并且使用root账户代替koyomi解决群晖nas上面的无法访问挂载文件夹/home/koyomi/lanraragi/content目录的问题,我构建了一个docker镜像如果你是docker用户你需要将漫画文件夹挂载到/root/lanraragi/content数据库挂载到/root/lanraragi/database。
#### 💬 Talk with other fellow LANraragi Users on [Discord](https://discord.gg/aRQxtbg) or [GitHub Discussions](https://github.com/Difegue/LANraragi/discussions)
#### [📄 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)
#### docker用户使用指南
## Screenshots
|Main Page, Thumbnail View | Main Page, List View |
|---|---|
docker用户可以自行切换到 windycloud/lanraragi_cn:latest 镜像即可安装完成
#### 💬 在 [Discord](https://discord.gg/aRQxtbg) 或 [GitHub Discussions](https://github.com/Difegue/LANraragi/discussions) 与其他 LANraragi 用户交流
#### [📄 文档[英文]](https://sugoi.gitbook.io/lanraragi/v/dev) | [⏬ 下载](https://github.com/Difegue/LANraragi/releases/latest) | [🎞 演示](https://lrr.tvc-16.science) | [🪟🌃 Windows 版本](https://nightly.link/Difegue/LANraragi/workflows/push-continous-delivery/dev) | [💵 赞助以支持项目发展](https://ko-fi.com/T6T2UP5N)
## 截图
| 主页, 缩略视图 | 主页, 列表视图 |
| --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| [![archive_thumb](./tools/_screenshots/archive_thumb.png)](https://raw.githubusercontent.com/Difegue/LANraragi/dev/tools/_screenshots/archive_thumb.png) | [![archive_list](./tools/_screenshots/archive_list.png)](https://raw.githubusercontent.com/Difegue/LANraragi/dev/tools/_screenshots/archive_list.png) |
|Archive Reader | Reader with overlay |
|---|---|
| 档案阅读器 | 档案预览阅读器 |
| ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [![reader](./tools/_screenshots/reader.jpg)](https://raw.githubusercontent.com/Difegue/LANraragi/dev/tools/_screenshots/reader.jpg) | [![reader_overlay](./tools/_screenshots/reader_overlay.jpg)](https://raw.githubusercontent.com/Difegue/LANraragi/dev/tools/_screenshots/reader_overlay.jpg) |
|Configuration | Plugin Configuration |
|---|---|
| 配置页面 | 插件配置页面 |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| [![cfg](./tools/_screenshots/cfg.png)](https://raw.githubusercontent.com/Difegue/LANraragi/dev/tools/_screenshots/cfg.png) | [![cfg_plugin](./tools/_screenshots/cfg_plugin.png)](https://raw.githubusercontent.com/Difegue/LANraragi/dev/tools/_screenshots/cfg_plugin.png) |
## Features
## 特点
* Stores your comics in archive format. (zip/rar/targz/lzma/7z/xz/cbz/cbr/pdf supported, barebones support for epub)
* 以压缩或存档的形式预览你的漫画. 目前支持(zip/rar/targz/lzma/7z/xz/cbz/cbr/pdf supported, barebones support for epub)等格式。
* 直接从浏览器或专用客户端阅读漫画: 服务器内使用临时文件夹临时存放从压缩或存档里读取的数据
* 使用内置 OPDS 目录(现在支持 PSE在专用阅读器软件中阅读您的漫画
* 使用客户端 API 从其他程序与 LANraragi 交互 (适用于[许多平台!](https://sugoi.gitbook.io/lanraragi/v/dev/advanced-usage/external-readers))
* 1. 安卓客户端已提交中文支持https://f-droid.org/packages/com.utazukin.ichaival/
2. IOS客户端(用AltStore安装) https://github.com/Doraemoe/DuReader/releases
AltStore:https://altstore.io/
3. Windows客户端已提交中文支持 https://www.microsoft.com/zh-cn/p/lrreader/9mz6bwwvswjh
* 两个不同的用户界面:紧凑型档案列表,带有缩略图或缩略图视图。
* 从5个内置的CSS主题中进行选择或添加自己的CSS样式。
* 具有完整的命名空间Tags支持使用插件添加或从其他的来源导入它们。
* 档案存储在手动选定或动态类别中在将档案添加到lanraragi时可以自动使用插件对库内部的文档进行排序。
* 将档案直接从互联网下载到服务器的同时自动导入元数据。
* Read archives directly from your web browser: the server reads from within compressed files using temporary folders.
*将数据库备份为JSON以将Tags传递到另一个LANraragi实例。
* Read your archives in dedicated reader software using the built-in OPDS Catalog (now with PSE support!)
## 扫码直接查看教程
[<img src="https://user-images.githubusercontent.com/38988286/111801925-65776800-8908-11eb-8b13-283a4d21e41c.jpg">](http://yuanfangblog.xyz/technology/251.html)
* 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))
## Make a PR, get stickers™
* Two different user interfaces : compact archive list with thumbnails-on-hover, or thumbnail view.
* Choose from 5 preinstalled responsive library styles, or add your own with CSS.
* Full Tag support with Namespaces: Add your own or import them from other sources using Plugins.
* Store archives in either arbitary or dynamic Categories to sort your Library easily
* Import metadata using Plugins automatically when archives are added to LANraragi.
* Download archives from the Internet directly to the server, while using the aforementioned automatic metadata import
* Backup your database as JSON to carry your tags over to another LANraragi instance.
## Make a PR, get stickers™
Merged PRs to this repo(or $5+ donations) are eligible to get a dumb sticker pack [shipped on the house.](https://forms.office.com/Pages/ResponsePage.aspx?id=DQSIkWdsW0yxEjajBLZtrQAAAAAAAAAAAAN__osxt25URTdTUTVBVFRCTjlYWFJLMlEzRTJPUEhEVy4u)
Merged PRs to this repo(or $5+ donations) are eligible to get a dumb sticker pack [shipped on the house.](https://forms.office.com/Pages/ResponsePage.aspx?id=DQSIkWdsW0yxEjajBLZtrQAAAAAAAAAAAAN__osxt25URTdTUTVBVFRCTjlYWFJLMlEzRTJPUEhEVy4u)

5159
jquery.dataTables.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -65,41 +65,33 @@ sub startup {
eval { $self->LRR_CONF->get_redis->ping(); };
if ($@) {
say "(╯・_>・)╯︵ ┻━┻";
say "It appears your Redis database is currently not running.";
say "The program will cease functioning now.";
say "您的Redis数据库目前没有运行。";
say "程序将停止运行。";
die;
}
# Check old settings and migrate them if needed
if ( $self->LRR_CONF->get_redis->keys('LRR_*') ) {
say "Migrating old settings to new format...";
migrate_old_settings($self);
}
my $devmode;
# Catch Redis errors on our first connection. This is useful in case of temporary LOADING errors,
# Where Redis lets us send commands but doesn't necessarily reply to them properly.
# (https://github.com/redis/redis/issues/4624)
while (1) {
eval { $devmode = $self->LRR_CONF->enable_devmode; };
eval { $self->LRR_CONF->get_redis->keys('*') };
last unless ($@);
say "Redis error encountered: $@";
say "Trying again in 2 seconds...";
say "遇到Redis错误: $@";
say "将在2秒后重试...";
sleep 2;
}
# Enable AOF saving on the Redis server.
# This allows us to start creating an aof file using existing RDB snapshot data.
# Later LRR releases will then be able to set appendonly directly in redis.conf without fearing data loss.
say "Enabling AOF on Redis... This might take a while.";
$self->LRR_CONF->get_redis->config_set( "appendonly", "yes" );
# Check old settings and migrate them if needed
if ( $self->LRR_CONF->get_redis->keys('LRR_*') ) {
say "将旧版本设置迁移到新版本...";
migrate_old_settings($self);
}
if ($devmode) {
if ( $self->LRR_CONF->enable_devmode ) {
$self->mode('development');
$self->LRR_LOGGER->info("LANraragi $version (re-)started. (Debug Mode)");
$self->LRR_LOGGER->info("LANraragi $version (重新)启动。(调试模式)");
my $logpath = get_logdir . "/mojo.log";
@ -109,48 +101,50 @@ sub startup {
my ( $time, $level, @lines ) = @_;
open( my $fh, '>>', $logpath )
or die "Could not open file '$logpath' $!";
or die "无法打开文件 '$logpath' $!";
print $fh "[Mojolicious] " . $lines[0] . " " . $lines[1] . "\n";
my $l1 = $lines[0] // "";
my $l2 = $lines[1] // "";
print $fh "[Mojolicious] $l1 $l2 \n";
close $fh;
}
);
} else {
$self->mode('production');
$self->LRR_LOGGER->info("LANraragi $version started. (Production Mode)");
$self->LRR_LOGGER->info("LANraragi $version 已启动。(生产模式)");
}
#Plugin listing
my @plugins = get_plugins("metadata");
foreach my $pluginfo (@plugins) {
my $name = $pluginfo->{name};
$self->LRR_LOGGER->info( "Plugin Detected: " . $name );
$self->LRR_LOGGER->info( "检测到插件: " . $name );
}
@plugins = get_plugins("script");
foreach my $pluginfo (@plugins) {
my $name = $pluginfo->{name};
$self->LRR_LOGGER->info( "Script Detected: " . $name );
$self->LRR_LOGGER->info( "检测到脚本: " . $name );
}
@plugins = get_plugins("download");
foreach my $pluginfo (@plugins) {
my $name = $pluginfo->{name};
$self->LRR_LOGGER->info( "Downloader Detected: " . $name );
$self->LRR_LOGGER->info( "检测到下载器: " . $name );
}
# Enable Minion capabilities in the app
shutdown_from_pid( get_temp . "/minion.pid" );
my $miniondb = $self->LRR_CONF->get_redisad . "/" . $self->LRR_CONF->get_miniondb;
say "Minion will use the Redis database at $miniondb";
say "Minion将使用位于 $miniondb 的Redis数据库";
$self->plugin( 'Minion' => { Redis => "redis://$miniondb" } );
$self->LRR_LOGGER->info("Successfully connected to Minion database.");
$self->LRR_LOGGER->info("成功连接到Minion数据库。");
$self->minion->missing_after(5); # Clean up older workers after 5 seconds of unavailability
LANraragi::Utils::Minion::add_tasks( $self->minion );
$self->LRR_LOGGER->debug("Registered tasks with Minion.");
$self->LRR_LOGGER->debug("添加了Minion的任务");
# Rebuild stat hashes
# /!\ Enqueuing tasks must be done either before starting the worker, or once the IOLoop is started!
@ -174,7 +168,7 @@ sub startup {
);
LANraragi::Utils::Routing::apply_routes($self);
$self->LRR_LOGGER->info("Routing done! Ready to receive requests.");
$self->LRR_LOGGER->info("路由完成!可以接收外来请求。");
}
sub shutdown_from_pid {

View File

@ -206,6 +206,7 @@ sub update_progress {
# Just set the progress value.
$redis->hset( $id, "progress", $page );
$redis->hset( $id, "lastreadtime", time());
# Update total pages read statistic
$redis_cfg->incr("LRR_TOTALPAGESTAT");

View File

@ -102,10 +102,10 @@ sub add_to_category {
if ($result) {
my $successMessage = "Added $arcid to Category $catid!";
my %category = LANraragi::Model::Category::get_category($catid);
my $title = LANraragi::Model::Archive::get_title($arcid);
my %category = LANraragi::Model::Category::get_category($catid);
my $title = LANraragi::Model::Archive::get_title($arcid);
if (%category && defined($title)) {
if ( %category && defined($title) ) {
$successMessage = "Added \"$title\" to category \"$category{name}\"!";
}
@ -124,7 +124,15 @@ sub remove_from_category {
my ( $result, $err ) = LANraragi::Model::Category::remove_from_category( $catid, $arcid );
if ($result) {
render_api_response( $self, "remove_from_category" );
my $successMessage = "Removed $arcid from Category $catid!";
my %category = LANraragi::Model::Category::get_category($catid);
my $title = LANraragi::Model::Archive::get_title($arcid);
if ( %category && defined($title) ) {
$successMessage = "Removed \"$title\" from category \"$category{name}\"!";
}
render_api_response( $self, "remove_from_category", undef, $successMessage );
} else {
render_api_response( $self, "remove_from_category", $err );
}

View File

@ -43,7 +43,7 @@ sub socket {
my $logger = get_logger( "Batch Tagging", "lanraragi" );
$logger->info('Client connected to Batch Tagging service');
$logger->info('客户端连接到 Batch Tagging 服务');
# Increase inactivity timeout for connection a bit to account for clientside timeouts
$self->inactivity_timeout(80);
@ -59,10 +59,10 @@ sub socket {
my $id = $command->{"archive"};
unless ($id) {
$client->finish( 1001 => 'No archives provided.' );
$client->finish( 1001 => '没有提供档案.' );
return;
}
$logger->debug("Processing $id");
$logger->debug("运行 $id");
if ( $operation eq "plugin" ) {
@ -76,7 +76,7 @@ sub socket {
my @args = @{ $command->{"args"} };
if ( !@args ) {
$logger->debug("No user overrides given.");
$logger->debug("没有覆盖插件全局参数.");
# Try getting the saved defaults
@args = get_plugin_parameters($pluginname);
@ -118,7 +118,7 @@ sub socket {
if ( $operation eq "tagrules" ) {
$logger->debug("Applying tag rules to $id...");
$logger->debug("将标签规则应用于$id...");
my $tags = $redis->hget( $id, "tags" );
my @tagarray = split_tags_to_array($tags);
@ -127,7 +127,7 @@ sub socket {
# Merge array with commas
my $newtags = join( ', ', @tagarray );
$logger->debug("New tags: $newtags");
$logger->debug("新标签: $newtags");
set_tags( $id, $newtags );
$client->send(
@ -145,7 +145,7 @@ sub socket {
}
if ( $operation eq "delete" ) {
$logger->debug("Deleting $id...");
$logger->debug("正在删除 $id...");
my $delStatus = LANraragi::Utils::Database::delete_archive($id);
@ -177,7 +177,7 @@ sub socket {
# If the client doesn't respond, halt processing
finish => sub {
$logger->info('Client disconnected, halting remaining operations');
$logger->info('客户端断开连接,停止剩余操作');
$cancelled = 1;
$redis->quit();
}

View File

@ -1,7 +1,7 @@
package LANraragi::Controller::Category;
use Mojo::Base 'Mojolicious::Controller';
use utf8;
use URI::Escape;
use Redis;
use Encode;

View File

@ -1,7 +1,7 @@
package LANraragi::Controller::Index;
use Mojo::Base 'Mojolicious::Controller';
use utf8;
use URI::Escape;
use Redis;
use Encode;

View File

@ -157,7 +157,7 @@ sub process_upload {
if ( $filetext =~ /package LANraragi::Plugin::(Login|Metadata|Scripts|Download)::/ ) {
$plugintype = $1;
} else {
my $errormess = "Could not find a valid plugin package type in the plugin \"$filename\"!";
my $errormess = "在插件 \"$filename\" 中找不到有效的插件包类型!";
$logger->error($errormess);
$self->render(
@ -175,7 +175,7 @@ sub process_upload {
my $dir = getcwd() . ("/lib/LANraragi/Plugin/$plugintype/");
my $output_file = $dir . $filename;
$logger->info("Uploading new plugin $filename to $output_file ...");
$logger->info("将新插件 $filename 上传到 $output_file ...");
#Delete module if it already exists
if ( -e $output_file ) {
@ -198,7 +198,7 @@ sub process_upload {
};
if ($@) {
$logger->error("Could not instantiate plugin at namespace $pluginclass!");
$logger->error("无法在命名空间 $pluginclass 处实例化插件!");
$logger->error($@);
# Cleanup this shameful attempt

View File

@ -15,7 +15,8 @@ sub index {
if ( $self->req->param('id') ) {
# Allow adding to static categories
my @categories = LANraragi::Model::Category->get_static_category_list;
my @categories = LANraragi::Model::Category->get_static_category_list;
my @arc_categories = LANraragi::Model::Category::get_categories_containing_archive( $self->req->param('id') );
# Get query string from referrer URL, if there's one
my $referrer = $self->req->headers->referrer;
@ -26,15 +27,16 @@ sub index {
}
$self->render(
template => "reader",
title => $self->LRR_CONF->get_htmltitle,
use_local => $self->LRR_CONF->enable_localprogress,
id => $self->req->param('id'),
categories => \@categories,
csshead => generate_themes_header($self),
version => $self->LRR_VERSION,
ref_query => $query,
userlogged => $self->LRR_CONF->enable_pass == 0 || $self->session('is_logged')
template => "reader",
title => $self->LRR_CONF->get_htmltitle,
use_local => $self->LRR_CONF->enable_localprogress,
id => $self->req->param('id'),
arc_categories => \@arc_categories,
categories => \@categories,
csshead => generate_themes_header($self),
version => $self->LRR_VERSION,
ref_query => $query,
userlogged => $self->LRR_CONF->enable_pass == 0 || $self->session('is_logged')
);
} else {

View File

@ -2,7 +2,7 @@ package LANraragi::Model::Archive;
use strict;
use warnings;
use utf8;
use feature qw(signatures);
no warnings 'experimental::signatures';
@ -27,14 +27,14 @@ use LANraragi::Utils::Database
sub get_title($id) {
my $logger = get_logger( "Archives", "lanraragi" );
my $redis = LANraragi::Model::Config->get_redis;
my $redis = LANraragi::Model::Config->get_redis;
if ( $id eq "" ) {
$logger->debug("No archive ID provided.");
return ();
}
return $redis->hget( $id, "title" );
return redis_decode($redis->hget( $id, "title" ));
}
# Functions used when dealing with archives.
@ -105,7 +105,7 @@ sub serve_thumbnail {
my $subfolder = substr( $id, 0, 2 );
my $thumbname = "$thumbdir/$subfolder/$id.jpg";
if ( $page > 0 ) {
if ( $page - 1 > 0 ) {
$thumbname = "$thumbdir/$subfolder/$id/$page.jpg";
}

View File

@ -2,7 +2,7 @@ package LANraragi::Model::Backup;
use strict;
use warnings;
use utf8;
use Redis;
use Mojo::JSON qw(decode_json encode_json);
@ -17,6 +17,7 @@ use LANraragi::Utils::Logging qw(get_logger);
#Goes through the Redis archive IDs and builds a JSON string containing their metadata.
sub build_backup_JSON {
my $redis = LANraragi::Model::Config->get_redis;
my $logger = get_logger( "Backup/Restore", "lanraragi" );
# Basic structure of the backup object
my %backup = (
@ -49,6 +50,8 @@ sub build_backup_JSON {
push @{ $backup{categories} }, \%category;
};
$logger->trace("Backing up category $key: $@");
}
# Backup archives themselves next
@ -75,6 +78,9 @@ sub build_backup_JSON {
push @{ $backup{archives} }, \%arc;
};
$logger->trace("Backing up archive $id: $@");
}
$redis->quit();

View File

@ -2,7 +2,7 @@ package LANraragi::Model::Category;
use strict;
use warnings;
use utf8;
use Redis;
use Mojo::JSON qw(decode_json encode_json);

View File

@ -16,6 +16,9 @@ my $home = Mojo::Home->new;
$home->detect;
my $config = Mojolicious::Plugin::Config->register( Mojolicious->new, { file => $home . '/lrr.conf' } );
if ($ENV{LRR_REDIS_ADDRESS}) {
$config->{redis_address} = $ENV{LRR_REDIS_ADDRESS};
}
# Address and port of your redis instance.
sub get_redisad { return $config->{redis_address} }

View File

@ -2,7 +2,7 @@ package LANraragi::Model::Opds;
use strict;
use warnings;
use utf8;
use Redis;
use POSIX qw(strftime);
@ -117,6 +117,10 @@ sub get_opds_data {
$arcdata->{mimetype} = "application/x-cbz";
}
if ( $arcdata->{lastreadtime} > 0) {
$arcdata->{lastreaddate} = strftime( "%Y-%m-%dT%H:%M:%SZ", gmtime($arcdata->{lastreadtime}) );
}
for ( values %{$arcdata} ) { $_ = xml_escape($_); }
return $arcdata;

View File

@ -2,9 +2,9 @@ package LANraragi::Model::Plugins;
use strict;
use warnings;
use utf8;
use feature 'fc';
use feature 'fc';
use utf8;
use Redis;
use Encode;
use Mojo::JSON qw(decode_json encode_json);

View File

@ -2,7 +2,7 @@ package LANraragi::Model::Reader;
use strict;
use warnings;
use utf8;
use Redis;
use File::Basename;

View File

@ -2,8 +2,8 @@ package LANraragi::Model::Search;
use strict;
use warnings;
use utf8;
use utf8;
use List::Util qw(min);
use Redis;
use Storable qw/ nfreeze thaw /;
@ -19,14 +19,14 @@ use LANraragi::Model::Category;
# do_search (filter, category_id, page, key, order, newonly, untaggedonly)
# Performs a search on the database.
sub do_search {
my ( $filter, $category_id, $start, $sortkey, $sortorder, $newonly, $untaggedonly ) = @_;
my $redis = LANraragi::Model::Config->get_redis_search;
my $logger = get_logger( "Search Engine", "lanraragi" );
unless ( $redis->exists("LAST_JOB_TIME") ) {
$logger->error("Search engine is not initialized yet. Please wait a few seconds.");
$logger->error("搜索引擎尚未初始化。 请稍等几秒钟。");
return ( -1, -1, () );
}
@ -36,11 +36,12 @@ sub do_search {
# Look in searchcache first
my $sortorder_inv = $sortorder ? 0 : 1;
my $cachekey = redis_encode("$category_id-$filter-$sortkey-$sortorder-$newonly-$untaggedonly");
#print $cachekey . "\n";
my $cachekey_inv = redis_encode("$category_id-$filter-$sortkey-$sortorder_inv-$newonly-$untaggedonly");
my ( $cachehit, @filtered ) = check_cache( $cachekey, $cachekey_inv );
unless ($cachehit) {
$logger->debug("No cache available, doing a full DB parse.");
$logger->debug("没有可用的缓存进行完整的DB解析。");
@filtered = search_uncached( $category_id, $filter, $sortkey, $sortorder, $newonly, $untaggedonly );
# Cache this query in the search database
@ -69,10 +70,10 @@ sub check_cache {
my @filtered = ();
my $cachehit = 0;
$logger->debug("Search request: $cachekey");
$logger->debug("搜索请求: $cachekey");
if ( $redis->exists("LRR_SEARCHCACHE") && $redis->hexists( "LRR_SEARCHCACHE", $cachekey ) ) {
$logger->debug("Using cache for this query.");
$logger->debug("将缓存用于此查询。");
$cachehit = 1;
# Thaw cache and use that as the filtered list
@ -80,7 +81,7 @@ sub check_cache {
@filtered = @{ thaw $frozendata };
} elsif ( $redis->exists("LRR_SEARCHCACHE") && $redis->hexists( "LRR_SEARCHCACHE", $cachekey_inv ) ) {
$logger->debug("A cache key exists with the opposite sortorder.");
$logger->debug("与对面的排序订单存在缓存密钥.");
$cachehit = 1;
# Thaw cache, invert the list to match the sortorder and use that as the filtered list
@ -146,7 +147,7 @@ sub search_uncached {
my $isneg = $token->{isneg};
my $isexact = $token->{isexact};
$logger->debug("Searching for $tag, isneg=$isneg, isexact=$isexact");
$logger->debug("正在搜索 $tag, isneg=$isneg, isexact=$isexact");
# Encode tag as we'll use it in redis operations
$tag = redis_encode($tag);
@ -159,7 +160,7 @@ sub search_uncached {
my $operator = $1;
my $pagecount = $2;
$logger->debug("Searching for IDs with pages $operator $pagecount");
$logger->debug("搜索具有页面的ID $operator $pagecount");
# If no operator is specified, we assume it's an exact match
$operator = "=" if !$operator;
@ -183,7 +184,7 @@ sub search_uncached {
# Get the list of IDs for this tag
@ids = $redis->smembers("INDEX_$tag");
$logger->debug( "Found tag index for $tag, containing " . scalar @ids . " IDs" );
$logger->debug( "找到了 $tag 的索引,包含 " . scalar @ids . " ID" );
} else {
# Get index keys that match this tag.
@ -195,7 +196,7 @@ sub search_uncached {
# Get the list of IDs for each key
foreach my $key (@keys) {
my @keyids = $redis->smembers($key);
$logger->trace( "Found index $key for $tag, containing " . scalar @ids . " IDs" );
$logger->trace( "找到了 $tag 的索引 $key包含了 " . scalar @ids . " ID" );
push @ids, @keyids;
}
}
@ -207,7 +208,7 @@ sub search_uncached {
# First iteration
if ( $scan == -1 ) { $scan = 0; }
$logger->trace("Scanning for $namesearch, cursor=$scan");
$logger->trace("正在扫描 $namesearch, cursor=$scan");
my @result = $redis->zscan( "LRR_TITLES", $scan, "MATCH", $namesearch, "COUNT", 100 );
$scan = $result[0];
@ -215,7 +216,7 @@ sub search_uncached {
foreach my $title ( @{ $result[1] } ) {
if ( $title eq "0" ) { next; } # Skip scores
$logger->trace("Found title match: $title");
$logger->trace("找到标题匹配项: $title");
# Strip everything before \x00 to get the ID out of the key
my $id = substr( $title, index( $title, "\x00" ) + 1 );
@ -225,21 +226,21 @@ sub search_uncached {
if ( scalar @ids == 0 && !$isneg ) {
# No more results, we can end search here
$logger->trace("No results for this token, halting search.");
# 没有更多的结果,我们可以在这里结束搜索
$logger->trace("该标记没有结果,正在停止搜索。");
@filtered = ();
last;
} else {
$logger->trace( "Found " . scalar @ids . " results for this token." );
$logger->trace( "找到此标记的 " . scalar @ids . " 个结果." );
# Intersect the new list with the previous ones
# 将新列表与以前的列表相交
@filtered = intersect_arrays( \@ids, \@filtered, $isneg );
}
}
}
if ( $#filtered > 0 ) {
$logger->debug( "Found " . $#filtered . " results after filtering." );
$logger->debug( "筛选后找到了 " . $#filtered . " 个结果" );
if ( !$sortkey ) {
$sortkey = "title";
@ -257,7 +258,7 @@ sub search_uncached {
# Remove the titles from the keys, which are stored as "title\x00id"
@ordered = map { substr( $_, index( $_, "\x00" ) + 1 ) } @ordered;
$logger->trace( "Example element from ordered list: " . $ordered[0] );
$logger->trace( "有序列表中的示例元素: " . $ordered[0] );
# Just intersect the ordered list with the filtered one to get the final result
@filtered = intersect_arrays( \@filtered, \@ordered, 0 );
@ -371,7 +372,7 @@ sub compute_search_filter {
}
# Escape already present regex characters
$logger->debug("Pre-escaped tag: $tag");
$logger->debug("预转义标签: $tag");
remove_spaces($tag);

View File

@ -2,8 +2,8 @@ package LANraragi::Model::Stats;
use strict;
use warnings;
use utf8;
use utf8;
use Redis;
use File::Find;
use Mojo::JSON qw(encode_json);

View File

@ -2,7 +2,7 @@ package LANraragi::Model::Upload;
use strict;
use warnings;
use utf8;
use Redis;
use URI::Escape;
use File::Basename;
@ -34,11 +34,11 @@ sub handle_incoming_file {
my ( $tempfile, $catid, $tags ) = @_;
my ( $filename, $dirs, $suffix ) = fileparse( $tempfile, qr/\.[^.]*/ );
$filename = $filename . $suffix;
my $logger = get_logger( "File Upload/Download", "lanraragi" );
my $logger = get_logger( "文件上传/下载", "lanraragi" );
# Check if file is an archive
unless ( is_archive($filename) ) {
return ( 0, "deadbeef", $filename, "Unsupported File Extension ($filename)" );
return ( 0, "deadbeef", $filename, "不支持的文件扩展名 ($filename)" );
}
# Compute an ID here
@ -63,18 +63,18 @@ sub handle_incoming_file {
unlink $tempfile;
# The file already exists
my $suffix = " Enable replace duplicated archive in config to replace old ones.";
my $suffix = " 启用在配置中替换重复的存档以替换旧的档案。";
my $msg =
$isdupe
? "This file already exists in the Library." . $suffix
: "A file with the same name is present in the Library." . $suffix;
? "该文件已存在于库中。" . $suffix
: "库中存在具有相同名称的文件。" . $suffix;
return ( 0, $id, $filename, $msg );
}
# If we are replacing an existing one, just remove the old one first.
if ($replace_dupe) {
$logger->debug("Delete archive $id before replacing it.");
$logger->debug("更换之前删除存档 $id。");
LANraragi::Utils::Database::delete_archive( $id );
}
@ -97,9 +97,9 @@ sub handle_incoming_file {
# If the tag is a source: tag, add it to the URL index
if ( $t =~ /source:(.*)/i ) {
my $url = $1;
$logger->debug("Adding $url as an URL for $id");
$logger->debug("添加 $url 作为 $id 的 URL");
trim_url($url);
$logger->debug("Trimmed: $url");
$logger->debug("已修剪:$url");
# No need to encode the value, as URLs are already encoded by design
$redis_search->hset( "LRR_URLMAP", $url, $id );
@ -115,7 +115,7 @@ sub handle_incoming_file {
move( $output_file . ".upload", $output_file );
unless ( -e $output_file ) {
return ( 0, $id, $name, "The file couldn't be moved to your content folder!" );
return ( 0, $id, $name, "该文件无法移至您的内容文件夹!" );
}
# Now that the file has been copied, we can add the timestamp tag and calculate pagecount.
@ -125,25 +125,25 @@ sub handle_incoming_file {
$redis->quit();
$redis_search->quit();
$logger->debug("Running autoplugin on newly uploaded file $id...");
$logger->debug("在新上传的文件 $id 上运行自动插件...");
my ( $succ, $fail, $addedtags, $newtitle ) = LANraragi::Model::Plugins::exec_enabled_plugins_on_file($id);
my $successmsg = "$succ Plugins used successfully, $fail Plugins failed, $addedtags tags added. ";
my $successmsg = "$succ 插件使用成功,$fail 插件失败,$addedtags 标签已添加。 ";
if ( $newtitle ne "" ) {
$name = $newtitle;
}
if ($catid) {
$logger->debug("Adding uploaded file to category $catid");
$logger->debug("将上传的文件添加到类别 $catid");
my ( $catsucc, $caterr ) = LANraragi::Model::Category::add_to_category( $catid, $id );
if ($catsucc) {
my %category = LANraragi::Model::Category::get_category($catid);
my $catname = $category{name};
$successmsg .= "Added to Category '$catname'!";
$successmsg .= "添加到类别“$catname”";
} else {
$successmsg .= "Couldn't add to Category: $caterr";
$successmsg .= "无法添加到类别:$caterr";
}
}
@ -159,11 +159,11 @@ sub download_url {
my ( $url, $ua ) = @_;
my $logger = get_logger( "File Upload/Download", "lanraragi" );
my $logger = get_logger( "文件上传/下载", "lanraragi" );
# Download to a temp folder
die "Not a proper URL" unless $url;
$logger->info("Downloading URL $url...This will take some time.");
$logger->info("下载 URL $url...这将需要一些时间。");
my $tempdir = tempdir();
@ -172,7 +172,7 @@ sub download_url {
my $content_disp = $tx->result->headers->content_disposition;
my $filename = "Not_an_archive"; #placeholder;
$logger->debug("Content-Disposition Header: $content_disp");
$logger->debug("内容 Header: $content_disp");
if ( $content_disp =~ /.*filename=\"(.*)\".*/gim ) {
$filename = $1;
} elsif ( $content_disp =~ /.*filename\*=UTF-8''(.*)/gim ) {
@ -187,7 +187,7 @@ sub download_url {
$filename = $1;
}
$logger->debug("Filename: $filename");
$logger->debug("文件名: $filename");
# remove invalid Windows chars
$filename =~ s@[\\/:"*?<>|]+@@g;
@ -202,7 +202,7 @@ sub download_url {
$filename = substr( $filename, 0, -1 );
}
$filename = $filename . $ext;
$logger->debug("Filename post clean: $filename");
$logger->debug("处理后的文件名: $filename");
$tx->result->save_to("$tempdir\/$filename");
# Update $tempfile to the exact reference created by the host filesystem

View File

@ -14,7 +14,7 @@ sub plugin_info {
namespace => "chaikadl",
author => "Difegue",
version => "1.0",
description => "Downloads the given chaika.moe URL and adds it to LANraragi. No support for gallery links for now!",
description => "下载给定的 chaika.moe URL 并将其添加到 LANraragi。 暂时不支持图库链接!",
# Downloader-specific metadata
# https://panda.chaika.moe/archive/_____/

View File

@ -21,7 +21,7 @@ sub plugin_info {
author => "Difegue",
version => "1.0",
description =>
"Downloads the given e*hentai URL and adds it to LANraragi. This uses GP to call the archiver, so make sure you have enough!",
"下载给定的 e*hentai URL 并将其添加到 LANraragi。 这将使用 GP 调用存档因此请确保您有足够的GP!",
# Downloader-specific metadata
url_regex => "https?:\/\/e(-|x)hentai.org\/g\/.*\/.*"
@ -74,7 +74,7 @@ sub provide_url {
# Use archiver key in archiver.php
# https://exhentai.org/archiver.php?gid=1638076&token=817f55f6fd&or=441617--08433a31606bc6c730e260c7fcbb2e71699949ce
my $archiverurl = "$domain\/archiver.php?gid=$gID&token=$gToken&or=$archKey";
$logger->info("Archiver URL: $archiverurl");
$logger->info("存档 URL: $archiverurl");
# Do a quick GET to check for potential errors
my $archiverHtml = $lrr_info->{user_agent}->max_redirects(5)->get($archiverurl)->result->body;
@ -95,11 +95,11 @@ sub provide_url {
)->result;
$content = $response->body;
$logger->debug("/archiver.php result: $content");
$logger->debug("/archiver.php 返回内容: $content");
if ($content =~ /.*Insufficient funds.*/gim) {
$logger->debug("Not enough GP, aborting download.");
return ( error => "You do not have enough GP to download this URL." );
$logger->debug("GP 不够,正在中止下载。");
return ( error => "您没有足够的 GP 来下载此 URL。" );
}
my $finalURL = URI->new();
@ -107,7 +107,7 @@ sub provide_url {
# Parse that to get the final URL
if ( $content =~ /.*document.location = "(.*)".*/gim ) {
$finalURL = URI->new($1);
$logger->info("Final URL obtained: $finalURL");
$logger->info("获得的最终URL $finalURL");
}
};

View File

@ -0,0 +1,97 @@
package LANraragi::Plugin::Download::Koushoku;
use strict;
use warnings;
no warnings 'uninitialized';
use URI;
use Mojo::UserAgent;
use LANraragi::Utils::Logging qw(get_logger);
# Meta-information about your plugin.
sub plugin_info {
return (
# Standard metadata
name => "Koushoku Downloader",
type => "download",
namespace => "kskdl",
#login_from => "ehlogin",
author => "Difegue",
version => "1.0",
description => "Downloads the given KSK URL and adds it to LANraragi.",
# Downloader-specific metadata
# https://ksk.moe/view/____/_________
url_regex => "https?:\/\/ksk.moe\/view\/.*\/.*"
);
}
# Mandatory function to be implemented by your downloader
sub provide_url {
shift;
my $lrr_info = shift;
my $logger = get_logger( "KSK Downloader", "plugins" );
# Get the URL to download
# We don't really download anything here, we just use the E-H URL to get an archiver URL that can be downloaded normally.
my $url = $lrr_info->{url};
my $ua = $lrr_info->{user_agent};
my $gID = "";
my $gToken = "";
$logger->debug($url);
if ( $url =~ /.*\/view\/([0-9]*)\/([0-z]*)\/*.*/ ) {
$gID = $1;
$gToken = $2;
} else {
return ( error => "Not a valid Koushoku URL!" );
}
$logger->debug("gID: $gID, gToken: $gToken");
# Sadly, we need to look at the original page to get the hash key to get a download URL. (and get cookies in case those are needed?)
# It's DOM parsing time again!
my $response = $ua->max_redirects(5)->get($url)->result;
my $content = $response->body;
my $dom = Mojo::DOM->new($content);
my $hash = "";
eval {
# Hash is stuck in the value of the "Original" DL button.
$hash = $dom->at(".original")->attr('value');
};
if ( $hash eq "" ) {
return ( error => "Couldn't retrieve download hash from URL $gID/$gToken" );
}
# POST to the download endpoint to get the download URL
# https://ksk.moe/download/11537/d951ca197324
my $downloadURL = "https:\/\/ksk.moe\/download\/$gID\/$gToken";
$logger->info("下载表单 URL: $downloadURL, hash: $hash");
# First redirect should be our download URL.
my $finalURL = URI->new();
eval {
$response = $ua->max_redirects(0)->post( $downloadURL => form => { hash => $hash } )->result;
$content = $response->body;
if ( $response->code == 302 ) {
$logger->debug( "重定向/位置 header: " . $response->headers->location );
$finalURL = URI->new( $response->headers->location );
}
};
if ( $@ || $finalURL eq "" ) {
return ( error => "Couldn't proceed with an original size download: <pre>$content</pre>" );
}
# All done!
return ( download_url => $finalURL->as_string );
}
1;

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Login::EHentai;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use Mojo::UserAgent;
use LANraragi::Utils::Logging qw(get_logger);
@ -18,12 +18,12 @@ sub plugin_info {
author => "Difegue",
version => "2.3",
description =>
"Handles login to E-H. If you have an account that can access fjorded content or exhentai, adding the credentials here will make more archives available for parsing.",
"处理E-H登录。 如果您有一个可以访问 fjorded 内容或 exhentai 的帐户,则在此处添加凭据将使更多档案可用于解析.",
parameters => [
{ type => "int", desc => "ipb_member_id cookie" },
{ type => "string", desc => "ipb_pass_hash cookie" },
{ type => "string", desc => "star cookie (optional, if present you can view fjorded content without exhentai)" },
{ type => "string", desc => "igneous cookie(optional, if present you can view exhentai without Europe and America IP)" }
{ type => "string", desc => "star cookie (可选,如果存在,您可以在没有 exhentai 的情况下查看 fjorded 内容)" },
{ type => "string", desc => "igneous cookie可选如果有的话您可以在没有欧洲和美国IP的情况下查看Newentai" }
]
);
@ -50,7 +50,7 @@ sub get_user_agent {
my $ua = Mojo::UserAgent->new;
if ( $ipb_member_id ne "" && $ipb_pass_hash ne "" ) {
$logger->info("Cookies provided ($ipb_member_id $ipb_pass_hash $star $igneous)!");
$logger->info("提供Cookie ($ipb_member_id $ipb_pass_hash $star $igneous)!");
#Setup the needed cookies with both domains
#They should translate to exhentai cookies with the igneous value generated
@ -135,7 +135,7 @@ sub get_user_agent {
)
);
} else {
$logger->info("No cookies provided, returning blank UserAgent.");
$logger->info("未提供 Cookie返回空白 UserAgent。");
}
return $ua;

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Login::Fakku;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use Mojo::UserAgent;
use LANraragi::Utils::Logging qw(get_logger);
@ -16,7 +16,7 @@ sub plugin_info {
author => "Nodja",
version => "0.1",
description =>
"Handles login to fakku. The cookie is only valid for 7 days so don't forget to update it.",
"处理fakku登录。cookie的有效期只有 7 天,所以不要忘记更新它.",
parameters => [
{ type => "string", desc => "fakku_sid cookie value" }
]

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Login::nHentai;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use Mojo::UserAgent;
use LANraragi::Utils::Logging qw(get_logger);
@ -18,11 +18,11 @@ sub plugin_info {
author => "Pheromir",
version => "0.1",
description =>
"Bypasses the Cloudflare Javascript-challenge by re-using cookies from your browser. Both CF cookies and the user-agent must originate from the same webbrowser.",
"通过重新使用浏览器中的 cookie 绕过Cloudflare的js。 CF cookie 和用户代理必须来自同一个网络浏览器.",
parameters => [
{ type => "string", desc => "Browser UserAgent string (Can be found at http://useragentstring.com/ for your browser)" },
{ type => "string", desc => "csrftoken cookie for domain nhentai.net" },
{ type => "string", desc => "cf_clearance cookie for domain nhentai.net" }
{ type => "string", desc => "浏览器 UserAgent 字符串(可以在 http://useragentstring.com/ 找到您的浏览器)" },
{ type => "string", desc => "域名nhentai.net的csrftoken cookie" },
{ type => "string", desc => "域名nhentai.net的cf_clearance cookie" }
]
);

View File

@ -2,7 +2,7 @@ package LANraragi::Plugin::Metadata::Chaika;
use strict;
use warnings;
use utf8;
use URI::Escape;
use Mojo::UserAgent;
use Mojo::DOM;
@ -20,16 +20,16 @@ sub plugin_info {
namespace => "trabant",
author => "Difegue",
version => "2.3",
description => "Searches chaika.moe for tags matching your archive. This will try to use the thumbnail first, and fallback to a default text search.",
description => "在 chaika.moe 中搜索与您的档案匹配的标签。 这将首先尝试使用缩略图,然后回退到默认文本搜索.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nB3RJTUUH4wYCFQocjU4r+QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH\nAAAEZElEQVQ4y42T3WtTdxzGn/M7J+fk5SRpTk7TxMZkXU84tTbVNrUT3YxO7HA4pdtQZDe7cgx2\ns8vBRvEPsOwFYTDYGJUpbDI2wV04cGXCGFLonIu1L2ptmtrmxeb1JDkvv121ZKVze66f74eH7/f5\nMmjRwMCAwrt4/9KDpflMJpPHvyiR2DPcJklJ3TRDDa0xk36cvrm8vDwHAAwAqKrqjjwXecPG205w\nHBuqa9rk77/d/qJYLD7cCht5deQIIczbgiAEKLVAKXWUiqVV06Tf35q8dYVJJBJem2A7Kwi2nQzD\nZig1CG93+PO5/KN6tf5NKpVqbsBUVVVFUUxwHJc1TXNBoxojS7IbhrnLMMx9pVJlBqFQKBKPxwcB\nkJYgjKIo3QCE1nSKoghbfJuKRqN2RVXexMaQzWaLezyeEUEQDjscjk78PxFFUYRkMsltJgGA3t7e\nyMLCwie6rr8iCILVbDbvMgwzYRjGxe0o4XC4s1AoHPP5fMP5/NNOyzLKAO6Ew+HrDADBbre/Ryk9\nnzx81FXJNlEpVpF+OqtpWu2MpmnXWmH9/f2umZmZi4cOHXnLbILLzOchhz1YerJAs9m1GwRAg2GY\nh7GYah488BJYzYW+2BD61AFBlmX/1nSNRqN9//792ujoaIPVRMjOKHoie3DytVGmp2fXCAEAjuMm\nu7u7Umosho6gjL/u/QHeEgvJZHJ2K/D+/fuL4+PjXyvPd5ldkShy1UXcmb4DnjgQj/fd5gDA6/XS\nYCAwTwh9oT3QzrS1+VDVi+vd3Tsy26yQVoFF3dAXJVmK96p9EJ0iLNOwKKU3CQCk0+lSOpP5WLDz\nF9Q9kZqyO0SloOs6gMfbHSU5NLRiUOuax2/HyZPHEOsLw2SbP83eu/fLxrkNp9P554XxCzVa16MC\n7+BPnTk9cfmH74KJE8nmga7Xy5JkZ8VKifGIHpoBb1VX8hNTd3/t/7lQ3OeXfFPvf/jBRw8ezD/a\n7M/aWq91cGgnJaZ2VcgSdnV1XRNNd3vAoBVVYusmnEQS65hfgSG6c+zy3Kre7nF/KrukcMW0Zg8O\nD08DoJutDxxOEb5IPUymwrq8ft1gLKfkFojkkRxemERCAQUACPFWRazYLJcrFGwQhyufbQQ7rFpy\nLMkCwGZC34qPIuwp+XPOjBFwazQ/txrdFS2GGS/Xuj+pUKLGk1Kjvlded3s72lyGW+PLbGVcmrAA\ngN0wTk1NWYODg9XOKltGtpazi5GigzroUnHN5nUHG1ylRsG7rDXHmnEpu4CeEtEKkqNc6QqlLc/M\n8uT5lLH5eq0aGxsju1O7GQB498a5s/0x9dRALPaQEDZnYwnhWJtMCCNrjeb0UP34Z6e/PW22zjPP\n+vwXBwfPvbw38XnXjk7GsiwKAIQQhjAMMrlsam45d+zLH6/8o6vkWcBcrXbVKQhf6bpucCwLjmUB\nSmmhXC419eblrbD/TAgAkUjE987xE0c7ZDmk66ajUCnq+cL63fErl25s5/8baQPaWLhx6goAAAAA\nSUVORK5CYII=",
parameters => [
{ type => "bool", desc => "Save archive title" },
{ type => "bool", desc => "Add the following tags if available: download URL, gallery ID, category, timestamp" },
{ type => "bool", desc => "Add tags without a namespace to the 'other:' namespace instead, mirroring E-H's behavior of namespacing everything" },
{ type => "string", desc => "Add a custom 'source:' tag to your archive. Example: chaika. Will NOT add a tag if blank" }
{ type => "bool", desc => "保存存档标题" },
{ type => "bool", desc => "添加以下标签如果可用下载URLGallery ID类别时间戳" },
{ type => "bool", desc => "将没有名称空间的标签添加到“另一个”名称空间反映了E-H的命名空间的行为" },
{ type => "string", desc => "将自定义的“源”标签添加到您的存档中。示例chaika。如果空白不会添加标签" }
],
oneshot_arg => "Chaika Gallery or Archive URL (Will attach matching tags to your archive)"
oneshot_arg => "Chaika Gallery或存档URL将在您的档案中附加匹配标签"
);
}

View File

@ -4,7 +4,7 @@ use strict;
use warnings;
use Mojo::JSON qw(from_json);
use utf8;
use LANraragi::Utils::Logging qw(get_plugin_logger);
use LANraragi::Utils::Archive qw(is_file_in_archive extract_file_from_archive);

View File

@ -4,7 +4,7 @@ use strict;
use warnings;
use Mojo::DOM;
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);

View File

@ -2,7 +2,7 @@ package LANraragi::Plugin::Metadata::CopyTags;
use strict;
use warnings;
use utf8;
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_logger);
@ -16,10 +16,10 @@ sub plugin_info {
namespace => "copytags",
author => "Difegue",
version => "2.1",
description => "Apply custom tag modifications.",
description => "应用自定义标签修改.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nB3RJTUUH4wYCFQ05iQtpeQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH\nAAAD8ElEQVQ4y4WUW2yURRTHfzPfty2UWrZbqdrdhktowQAJiQ/iDUwkaFJ5IAQfGjWBByMhwYAm\nBH3xqT5ArARS9cUgJC1qjCDxCY1JEy6lLVJrW9lKq6Wlgcqy2W7b/S4zx4fdbstFneRMZjLJb/7n\nf86MOn78+MlEIvE6gIhgRRARECGTmaS0tJT6+vrvo7HKxserq6f4v9Hc3PyxiBh5yBgYGJBUKiW/\n9vZKV/eVb7s6OyN79uxhbGwMKVx8f2gRUUEQEAQhfhDg+wGeHxAaA8DZs2e50tVNZ+flJ3v7B8ra\n29uJx+M0NTXhed6DCg8dPtzs+77xfV883xfP8yVXCM/zxA9CCcNQzv3402+bX96yuK2tjd27dxOP\nx2loaCCdTj+gkIJlICAFLz0vx/RMjmx2kunpaXK5nF5au3RJb29fzdq162ouX+p4ZHh4mO3bt98j\n0DU2n5oUZqUUvudz8cIFEvEEoQkRIBarXLFr584frLVmdHRUj4yNXu3r69tbVVV1u7W1lcbGxjxQ\njMzjKxAw1rJoURlr1q7B9wMEQaFKBerDwMfzPKKLo6t+uXp12Z07d16pq6tL79ixg0gkgjamkCv5\nvItKUfkrFCilmN0orZmayrJgQSlDQ0NPHz3WskhrTXd3NwBaxBR8m007v7aza+a8RQTXcaipTTAx\nMYHn+2SnJ4nFYgwODuaBRmxB3FylEEGsLRKliBZcHSFVkSFVOUWiOk5uxiObzZJKpfJAa8wciPvA\nzIflzxSKW+EtDgx8wKUbXVSYcuM4TtEWba1VSkGkJILruvmIuFibh2gNjtI4SuNqB6XBVQ7jFTdo\nK/+GiWemNmmt59omFouNfXf6dLsIalZZGJrI6lV1zwIcOP8hQ871YsE0mpRJUVFWTnZ5WjpSF09t\n+WhbJdf4DMDdv2/foYMHDx46c+YMW7dupba2lutDw1UrV674G+B3/xr9VT1gVLFMWjk4SoOg/ope\nZyo9/elzq1/QQIs7v8u11oyMjFBTU6OszKas0I4D6t4nG1qDAqwWJnWG0IbrAdz737ZSCmsNUvAw\nmAnxJsxcHyEoV+FUgDiWhXfL2RS89FXdtSfeYss8oDEGz/Ow1mKMQReq9vXmE4SSVyPAAl3KiT9b\n2X/7XZZMPcbz9sWTl94/9+bn63vUXvaKCxCGIclkkmQyCcCxlhZJ/jHI3XR60hqjpdinloiUSJ/0\nlZQuLC/Z0L9B4n2V73zR08ORXUcEyFd2fHycTCZT7KWLHR3q5s3xyslMxlhrlYjklVvLuv6V/tE3\nTr29vGzZxlffe+q1jV82hObRwFZXVxONRvnXn/e/ounCJzU/z5yPPOzsH4cGnEj6mhLzAAAAAElF\nTkSuQmCC",
parameters => [ { type => "string", desc => "Tags to copy, separated by commas." } ]
parameters => [ { type => "string", desc => "要复制的标签,以逗号分隔." } ]
);
}

View File

@ -2,7 +2,7 @@ package LANraragi::Plugin::Metadata::DateAdded;
use strict;
use warnings;
use utf8;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use Mojo::UserAgent;
@ -21,7 +21,7 @@ sub plugin_info {
author => "Utazukin",
version => "1.0",
description =>
"Adds a timestamp tag to your archive. <br> This plugin follows the server settings for the timestamp tag and will use file modification time if the server setting is set to 'Use Last modified Time'.",
"将时间戳标记添加到您的存档。 <br> 此插件遵循时间戳标签的服务器设置,如果服务器设置设置为“使用上次修改时间”,则将使用文件修改时间.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nB3RJTUUH4wYCFQY4HfiAJAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH\nAAADKUlEQVQ4y6WVsUtrVxzHP+fmkkiqJr2CQWKkvCTwJgkJDpmyVAR1cVOhdq04tHNB7BD8A97S\nXYkO3dRRsMSlFoIOLYFEohiDiiTNNeaGpLn5dRDv06ev75V+4SyH8/2c3/n+zuEoEeFTqtfrb5RS\nJZ/P98m1iMirI5fLMT8/L+FwWEKhkIRCIXn79q2srKxIpVL5qE/7cINms8ny8rIkEgkpl8skk0lm\nZ2eZmZkhHo+TzWYJBoOyvr4u7Xb7RYHq6ZEvLi6Ynp6WVqvFwsIC4+PjRCIRDMNAKcXNzQ2lUols\nNsvOzg6xWIxMJqOeRuEAq9UqqVRKhoaGmJubY2pqCl3XiUajXF5e0t/fz+DgIIVCAbfbzdbWFtvb\n24yMjLC/v6+eZWjbNqurq5JIJGRtbU0syxLbtsU0TXmqXq8njUZDRERubm4knU6LYRiSyWScDBER\nGo0G4XBYFhcX5fz8XP4yTbGLf0hnd0s+plqtJru7u7K0tCSRSEQ6nc77ppycnFCv10kmk4yOjoII\n2kiIv3//lfbGu1dvh1KKVCrF2NgYmqaRy+UAHoCHh4f4fD4mJiZwuVz4fT74YhDvTz/TPv2TX378\ngWKx+Azo9/sZGBhAKYVhGBSLxa8doGmaABiGQT6fp9VqPbg0jcr897w7+I3FxUVs23aAlmVxe3tL\nPB7n/v6eWq22D6A/lq+UotlsEo1G8Xg8jvFNOMzCN99iGF/icrmc+b6+PrxeL6enp7hcLpR6aLT+\nuEDTNEqlErFYDMuy8Hq9AHg8HpaXv3uRYbfbRdM0TNNE096/Dweo6zoHBwfE43F0XXeAjyf4UJVK\nhUql8iwGJ8NHeb1e9vb2CAaDADQajRcgy7IACAQCHB0d/TtQ0zQuLi7Y3Nzk+vqacrkMwNXVFXd3\nd7Tbbc7Ozuh0OmxsbHB1dfViQ/21+3V8fIxpmkxOTmKaJrZt0263sW0b27ZJp9M0m010XX8RhwN8\nNPV6PQCKxSL5fB7DMAgEAnS7XarVKtVqFbfbjVIK27ZRSjkeB9jtdikUChQKBf6vlIg4Gb3Wzc/V\n8PDwV36//1x9zhfwX/QPryPQMvGWTdEAAAAASUVORK5CYII=",
parameters => [],

View File

@ -10,7 +10,7 @@ use URI::Escape;
use Mojo::JSON qw(decode_json encode_json);
use Mojo::Util qw(html_unescape);
use Mojo::UserAgent;
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);
@ -27,20 +27,20 @@ sub plugin_info {
author => "Difegue and others",
version => "2.5.1",
description =>
"Searches g.e-hentai for tags matching your archive. <br/><i class='fa fa-exclamation-circle'></i> This plugin will use the source: tag of the archive if it exists.",
"搜索 g.e-hentai 以查找与您的存档匹配的标签. <br/><i class='fa fa-exclamation-circle'></i> 此插件将使用存档的 source: tag (如果存在)",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wYBFg0JvyFIYgAAAB1pVFh0Q29tbWVudAAAAAAAQ3Jl\nYXRlZCB3aXRoIEdJTVBkLmUHAAAEo0lEQVQ4y02UPWhT7RvGf8/5yMkxMU2NKaYIFtKAHxWloYNU\ncRDeQTsUFPwAFwUHByu4ODq4Oghdiri8UIrooCC0Lx01ONSKfYOioi1WpWmaxtTm5PTkfNzv0H/D\n/9oeePjdPNd13Y8aHR2VR48eEUURpmmiaRqmaXbOAK7r4vs+IsLk5CSTk5P4vo9hGIgIsViMra0t\nCoUCRi6XY8+ePVSrVTRN61yybZuXL1/y7t078vk8mUyGvXv3cuLECWZnZ1lbW6PdbpNIJHAcB8uy\nePr0KYZlWTSbTRKJBLquo5TCMAwmJia4f/8+Sini8Ti1Wo0oikin09i2TbPZJJPJUK/XefDgAefO\nnWNlZQVD0zSUUvi+TxAE6LqOrut8/fqVTCaDbdvkcjk0TSOdTrOysoLrujiOw+bmJmEYMjAwQLVa\nJZVKYXR1ddFut/F9H9M0MU0T3/dZXV3FdV36+/vp7u7m6NGj7Nq1i0qlwuLiIqVSib6+Pubn5wGw\nbZtYLIaxMymVSuH7PpZlEUURSina7TZBEOD7Pp8/fyYMQ3zfZ25ujv3795NOp3n48CE9PT3ouk4Q\nBBi/fv3Ctm0cx6Grq4utrS26u7sREQzDIIoifv78SU9PD5VKhTAMGRoaYnV1leHhYa5evUoQBIRh\niIigiQhRFKHrOs1mE9u2iaKIkydPYhgGAKZp8v79e+LxOPl8Htd1uXbtGrdv3yYMQ3ZyAODFixeb\nrVZLvn//Lq7rSqVSkfX1dREROXz4sBw/flyUUjI6OipXrlyRQ4cOSbPZlCiKxHVdCcNQHMcRz/PE\ndV0BGL53756sra1JrVaT9fV1cRxHRESGhoakr69PUqmUvHr1SsrlsuzI931ptVriuq78+fNHPM+T\nVqslhoikjh075p09e9ba6aKu6/T39zM4OMjS0hIzMzM0Gg12794N0LEIwPd9YrEYrusShiEK4Nmz\nZ41yudyVy+XI5/MMDAyQzWap1+tks1lEhIWFBQqFArZto5QiCAJc1+14t7m5STweRwOo1WoSBAEj\nIyMUi0WSySQiQiqV6lRoYWGhY3673e7sfRAEiAjZbBbHcbaBb9++5cCBA2SzWZLJJLZt43kesViM\nHX379g1d1wnDsNNVEQEgCAIajQZ3797dBi4tLWGaJq7rYpompVKJmZkZ2u12B3j58mWUUmiahoiw\nsbFBEASdD2VsbIwnT55gACil+PHjB7Ozs0xPT/P7929u3ryJZVmEYUgYhhQKBZRSiAie52EYBkop\nLMvi8ePHTE1NUSwWt0OZn5/3hoeHzRs3bqhcLseXL1+YmJjowGzbRtO07RT/F8jO09+8ecP58+dJ\nJBKcPn0abW5uThWLRevOnTv/Li4u8vr1a3p7e9E0jXg8zsePHymVSnz69Kmzr7quY9s2U1NTXLp0\nCc/zOHLkCPv27UPxf6rX63+NjIz8IyKMj48zPT3NwYMHGRwcpLe3FwARodVqcf36dS5evMj4+DhB\nEHDmzBkymQz6DqxSqZDNZr8tLy//DYzdunWL5eVlqtUqHz58IJVKkUwmaTQalMtlLly4gIjw/Plz\nTp06RT6fZ2Njg/8AqMV7tO07rnsAAAAASUVORK5CYII=",
parameters => [
{ type => "string", desc => "Forced language to use in searches (Japanese won't work due to EH limitations)" },
{ type => "bool", desc => "Save archive title" },
{ type => "bool", desc => "Fetch using thumbnail first (falls back to title)" },
{ type => "bool", desc => "Search using gID from title (falls back to title)" },
{ type => "bool", desc => "Use ExHentai (enable to search for fjorded content without star cookie)" },
{ type => "string", desc => "在搜索中强制使用语言(由于 EH 限制,日语无法使用)" },
{ type => "bool", desc => "保存档案名称" },
{ type => "bool", desc => "首先使用缩略图获取(否则使用标题)" },
{ type => "bool", desc => "使用标题的GID搜索返回标题" },
{ type => "bool", desc => "使用 ExHentai可以在没有星形 cookie 的情况下搜索fjorded内容" },
{ type => "bool",
desc => "Save the original title when available instead of the English or romanised title"
desc => "如果可用,请保存原始标题,而不是英文或罗马拼音标题"
},
{ type => "bool", desc => "Fetch additional timestamp (time posted) and uploader metadata" },
{ type => "bool", desc => "Search only expunged galleries" },
{ type => "bool", desc => "获取额外的时间戳(发布时间)和上传者元数据" },
{ type => "bool", desc => "搜索已删除的图库" },
],
oneshot_arg => "E-H Gallery URL (Will attach tags matching this exact gallery to your archive)",
@ -55,7 +55,7 @@ sub get_tags {
shift;
my $lrr_info = shift; # Global info hash
my $ua = $lrr_info->{user_agent};
my ( $lang, $savetitle, $usethumbs, $search_gid, $enablepanda, $jpntitle, $additionaltags, $expunged ) = @_; # Plugin parameters
my ( $lang, $savetitle, $usethumbs, $search_gid, $enablepanda, $jpntitle, $additionaltags, $expunged ) = @_; # Plugin parameters
# Use the logger to output status - they'll be passed to a specialized logfile and written to STDOUT.
my $logger = get_plugin_logger();
@ -133,11 +133,7 @@ sub lookup_gallery {
$logger->info("Reverse Image Search Enabled, trying now.");
#search with image SHA hash
$URL =
$domain
. "?f_shash="
. $thumbhash
. "&fs_similar=on&fs_covers=on";
$URL = $domain . "?f_shash=" . $thumbhash . "&fs_similar=on&fs_covers=on";
$logger->debug("Using URL $URL (archive thumbnail hash)");
@ -149,12 +145,9 @@ sub lookup_gallery {
}
# Search using gID if present in title name
my ( $title_gid ) = $title =~ /\[([0-9]+)\]/g;
my ($title_gid) = $title =~ /\[([0-9]+)\]/g;
if ( $search_gid && $title_gid ) {
$URL =
$domain
. "?f_search="
. uri_escape_utf8("gid:$title_gid");
$URL = $domain . "?f_search=" . uri_escape_utf8("gid:$title_gid");
$logger->debug("Found gID: $title_gid, Using URL $URL (gID from archive title)");
@ -166,18 +159,17 @@ sub lookup_gallery {
}
# Regular text search (advanced options: Disable default filters for: Language, Uploader, Tags)
$URL =
$domain
. "?advsearch=1&f_sfu=on&f_sft=on&f_sfl=on"
. "&f_search="
. uri_escape_utf8( qw(") . $title . qw(") );
$URL = $domain . "?advsearch=1&f_sfu=on&f_sft=on&f_sfl=on" . "&f_search=" . uri_escape_utf8( qw(") . $title . qw(") );
my $has_artist = 0;
# Add artist tag from the OG tags if it exists
# Add artist tag from the OG tags if it exists (and only contains ASCII characters)
if ( $tags =~ /.*artist:\s?([^,]*),*.*/gi ) {
$URL = $URL . "+" . uri_escape_utf8("artist:$1");
$has_artist = 1;
my $artist = $1;
if ( $artist =~ /^[\x00-\x7F]*$/ ) {
$URL = $URL . "+" . uri_escape_utf8("artist:$artist");
$has_artist = 1;
}
}
# Add the language override, if it's defined.
@ -186,7 +178,7 @@ sub lookup_gallery {
}
# Search expunged galleries if the option is enabled.
if ( $expunged ) {
if ($expunged) {
$URL = $URL . "&f_sh=on";
}

View File

@ -8,7 +8,7 @@ use warnings;
use Mojo::JSON qw(from_json);
use File::Basename;
use Time::Local qw(timegm_modern);
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Database;
@ -27,15 +27,15 @@ sub plugin_info {
author => "Difegue",
version => "2.3",
description =>
"Collects metadata from eze-style info.json files ({'gallery_info': {xxx} } syntax), either embedded in your archive or in the same folder with the same name. ({archive_name}.json)",
"从 eze 样式的 info.json 文件 ({'gallery_info': {xxx} } syntax)中收集元数据, 这些文件嵌入在您的存档中或具有相同名称的同一文件夹中. ({archive_name}.json)",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nB3RJTUUH4wYCFDYBnHlU6AAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH\nAAAETUlEQVQ4y22UTWhTWRTHf/d9JHmNJLFpShMcKoRIqxXE4sKpjgthYLCLggU/wI1CUWRUxlmU\nWblw20WZMlJc1yKKKCjCdDdYuqgRiygq2mL8aJpmQot5uabv3XdnUftG0bu593AOv3M45/yvGBgY\n4OrVqwRBgG3bGIaBbduhDSClxPM8tNZMTEwwMTGB53lYloXWmkgkwqdPnygUCljZbJbW1lYqlQqG\nYYRBjuNw9+5dHj16RD6fJ51O09bWxt69e5mammJ5eZm1tTXi8Tiu6xKNRrlx4wZWNBqlXq8Tj8cx\nTRMhBJZlMT4+zuXLlxFCEIvFqFarBEFAKpXCcRzq9TrpdJparcbIyAiHDh1icXERyzAMhBB4nofv\n+5imiWmavHr1inQ6jeM4ZLNZDMMglUqxuLiIlBLXdfn48SNKKXp6eqhUKiQSCaxkMsna2hqe52Hb\nNsMdec3n8+Pn2+vpETt37qSlpYVyucz8/DzT09Ns3bqVYrEIgOM4RCIRrI1MiUQCz/P43vE8jxcv\nXqCUwvM8Zmdn2bJlC6lUitHRUdrb2zFNE9/3sd6/f4/jOLiuSzKZDCH1wV/EzMwM3d3dNN69o729\nnXK5jFKKPXv2sLS0RF9fHydOnMD3fZRSaK0xtNYEQYBpmtTr9RC4b98+LMsCwLZtHj9+TCwWI5/P\nI6Xk5MmTXLhwAaUUG3MA4M6dOzQaDd68eYOUkqHIZj0U2ay11mzfvp1du3YhhGBgYIDjx4/T3d1N\nvV4nCAKklCilcF2XZrOJlBIBcOnSJc6ePYsQgj9yBf1l//7OJcXPH1Y1wK/Ff8SfvT995R9d/SA8\nzyMaja5Xq7Xm1q1bLCwssLS09M1Atm3bFr67urq+8W8oRUqJlBJLCMHNmze5d+8e2Ww2DPyrsSxq\ntRqZTAattZibm6PZbHJFVoUQgtOxtAbwfR8A13WJxWIYANVqFd/36e/v/ypzIpEgCAKEEMzNzYXN\n34CN/FsSvu+jtSaTyeC67jrw4cOHdHZ2kslkQmCz2SQSiYT269evMU0zhF2RVaH1ejt932dlZYXh\n4eF14MLCArZtI6UMAb+1/qBPx9L6jNOmAY4dO/b/agBnnDb9e1un3vhQzp8/z/Xr19eBQgjevn3L\n1NTUd5WilKJQKGAYxje+lpYWrl27xuTk5PqKARSLRfr6+hgaGiKbzfLy5UvGx8dRSqGUwnEcDMNA\nKYUQIlRGNBplZmaGw4cPE4/HOXDgAMbs7Cy9vb1cvHiR+fl5Hjx4QC6XwzAMYrEYz549Y3p6mufP\nn4d6NU0Tx3GYnJzk6NGjNJtNduzYQUdHB+LL8mu1Gv39/WitGRsb4/79+3R1dbF7925yuVw4/Uaj\nwalTpzhy5AhjY2P4vs/BgwdJp9OYG7ByuUwmk6FUKgFw7tw5SqUSlUqFp0+fkkgk2LRpEysrKzx5\n8oTBwUG01ty+fZv9+/eTz+dZXV3lP31rAEu+yXjEAAAAAElFTkSuQmCC",
parameters => [
{ type => "bool", desc => "Save archive title" },
{ type => "bool", desc => "保存档案名称" },
{ type => "bool",
desc => "Save the original title when available instead of the English or romanised title"
desc => "如果可用,请保存原始标题,而不是英文或罗马拼音标题"
},
{ type => "bool", desc => "Fetch additional timestamp (time posted) and uploader metadata" },
{ type => "bool", desc => "获取额外的时间戳(发布时间)和上传者元数据" },
]
);

View File

@ -9,7 +9,7 @@ use URI::Escape;
use Mojo::JSON qw(decode_json);
use Mojo::UserAgent;
use Mojo::DOM;
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);
@ -27,12 +27,12 @@ sub plugin_info {
author => "Difegue, Nodja",
version => "0.8",
description =>
"Searches FAKKU for tags matching your archive. If you have an account, don't forget to enter the matching cookie in the login plugin to be able to access controversial content. <br/><br/>
<i class='fa fa-exclamation-circle'></i> <b>This plugin can and will return invalid results depending on what you're searching for!</b> <br/>The FAKKU search API isn't very precise and I recommend you use the Chaika.moe plugin when possible.",
"FAKKU 中搜索与您的档案匹配的标签 如果您有帐户请不要忘记在登录插件中输入匹配的 cookie 才能访问有争议的内容 <br/><br/>
<i class='fa fa-exclamation-circle'></i> <b>此插件可以并且将根据您搜索的内容返回无效结果!</b> <br/>FAKKU 搜索 API 不是很精确我建议您尽可能使用 Chaika.moe 插件.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAACZSURBVDhPlY+xDYQwDEWvZgRGYA22Y4frqJDSZhFugiuuo4cqPGT0iTjAYL3C+fGzktc3hEcsQvJq6HtjE2Jdv4viH4a4pWnL8q4A6g+ET9P8YhS2/kqwIZXWnwqChDxPfCFfD76wOzJ2IOR/0DSwnuRKYAKUW3gq2OsJTYM0jr7QVRVwlabJEaw3ARYBcmFXeomxphIeEMIMmh3lOLQR+QQAAAAASUVORK5CYII=",
parameters => [ { type => "bool", desc => "Save archive title" } ],
oneshot_arg => "FAKKU Gallery URL (Will attach tags matching this exact gallery to your archive)"
parameters => [ { type => "bool", desc => "保存档案名称" } ],
oneshot_arg => "FAKKU 图库 URL将与此确切图库匹配的标签附加到您的档案中"
);
}

View File

@ -6,7 +6,7 @@ use warnings;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use Mojo::JSON qw(from_json);
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);
@ -22,7 +22,7 @@ sub plugin_info {
namespace => "Hdoujinplugin",
author => "Pao",
version => "0.5",
description => "Collects metadata embedded into your archives by HDoujin Downloader's json or txt files.",
description => "通过 HDoujin 下载器的 json 或 txt 文件收集嵌入到您的档案中的元数据.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wYDFB0m9797jwAAAB1pVFh0Q29tbWVudAAAAAAAQ3Jl\nYXRlZCB3aXRoIEdJTVBkLmUHAAAEbklEQVQ4y1WUPW/TUBSGn3uvHdv5cBqSOrQJgQ4ghqhCAgQM\nIIRAjF2Y2JhA/Q0g8R9YmJAqNoZKTAwMSAwdQEQUypeQEBEkTdtUbdzYiW1sM1RY4m5Hunp1znmf\n94jnz5+nAGmakiQJu7u7KKWwbRspJWma0m63+fHjB9PpFM/z6Ha7FAoFDMNga2uLx48fkyQJ29vb\nyCRJSNMUz/PY2dnBtm0qlQpKKZIkIQgCer0eW1tbDIdDJpMJc3NzuK5Lt9tF13WWl5dJkoRyuYyU\nUrK3t0ccx9TrdQzD4F/HSilM08Q0TWzbplqtUqvVKBaLKKVoNpt8/vyZKIq4fv064/EY2ev1KBQK\n2LadCQkhEEJkteu6+L6P7/tMJhOm0ylKKarVKjdu3GA6nXL+/HmSJEHWajV0Xf9P7N8TQhDHMWEY\nIoRgOBzieR4At2/f5uTJk0RRRLFYZHZ2liNHjqBFUcRoNKJarSKlRAiRmfPr1y/SNMVxHI4dO8aF\nCxfI5/O4rotSirdv33L16lV+//7Nly9fUEqh5XI5dF0nTdPMaSEEtm3TaDSwLAvLstB1nd3dXUql\nEqZpYlkW6+vrdLtdHjx4wPb2NmEYHgpalkUQBBwcHLC2tsbx48cpFos4jkMQBIRhyGQyYTgcsrGx\nQavVot1uc+LECcbjMcPhkFKpRC6XQ0vTlDAMieOYQqGA4zhcu3YNwzDQdR3DMA4/ahpCCPL5fEbC\nvXv3WFlZ4c+fP7TbbZaWlpBRFGXjpmnK/Pw8QRAwnU6RUqJpGp7nMRqNcF0XwzCQUqKUolwus7y8\njO/7lMtlFhcX0YQQeJ6XMXfq1Cn29/epVCrouk4QBNi2TalUIoqizLg0TQEYjUbU63VmZmYOsdE0\nDd/3s5HH4zG6rtNsNrEsi0qlQqFQYH19nVevXjEej/8Tm0wmlMtlhBAMBgOkaZo0Gg329vbY2dkh\nCIJsZ0oplFK8efOGp0+fcvHiRfL5PAAHBweEYcj8/HxGydevX5FxHDMajajVanz69Ik4jkmSBF3X\n0TSNzc1N7t69S6vV4vXr10gp8X2f4XBIpVLJghDHMRsbG2jT6TRLxuLiIr1eDwBN09A0jYcPHyKE\n4OjRo8RxTBRF9Pt95ubmMud93+f79+80m03k/v4+UspDKDWNRqPBu3fvSNOUtbU16vU6ly5dwnEc\ncrkcrutimib5fD4zxzRNVldXWVpaQqysrKSdTofLly8zmUwoFAoIIfjXuW3bnD17NkuJlBLHcdA0\nDYAgCHj27BmO47C6uopM05RyucyLFy/QNA3XdRFCYBgGQRCwubnJhw8fGAwGANRqNTRNI0kSXr58\nyc2bN6nX64RhyP379xFPnjxJlVJIKTl37hydTocoiuh0OszOzmJZFv1+n8FgwJ07d7hy5Qrj8ZiP\nHz/S7/c5ffo0CwsL9Ho9ZmZmEI8ePUoNwyBJEs6cOcPCwgLfvn3j/fv35PN5bNtGKZUdjp8/f3Lr\n1q3svLVaLTzPI4oiLMviL7opJdyaltNwAAAAAElFTkSuQmCC",
parameters => []

View File

@ -6,7 +6,7 @@ use warnings;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use Mojo::JSON qw(from_json);
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);

View File

@ -8,7 +8,7 @@ no warnings 'experimental::signatures';
use URI::Escape;
use Mojo::JSON qw(from_json);
use Mojo::UserAgent;
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@ use warnings;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use Mojo::JSON qw(from_json);
use utf8;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);
@ -22,10 +22,10 @@ sub plugin_info {
namespace => "koromoplugin",
author => "CirnoT, Difegue",
version => "2.0",
description => "Collects metadata embedded into your archives as Koromo-style Info.json files. ( {'Tags': [xxx] } syntax)",
description => " 在Koromo 风格的 Info.json 文件收集作为嵌入到档案中的元数据. ( {'Tags': [xxx] } syntax)",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw1AUhU9TpVoqDmYQcchQnSyIijhKFYtgobQVWnUweekfNDEkKS6OgmvBwZ/FqoOLs64OroIg+APi4uqk6CIl3pcUWsR44fE+zrvn8N59gNCoMs3qGgc03TbTibiUy69IoVeE0QsRAYgys4xkZiEL3/q6pz6quxjP8u/7s/rUgsWAgEQ8ywzTJl4nnt60Dc77xCIryyrxOfGYSRckfuS64vEb55LLAs8UzWx6jlgklkodrHQwK5sa8RRxVNV0yhdyHquctzhr1Rpr3ZO/MFLQlzNcpzWMBBaRRAoSFNRQQRU2YrTrpFhI03ncxz/k+lPkUshVASPHPDagQXb94H/we7ZWcXLCS4rEge4Xx/kYAUK7QLPuON/HjtM8AYLPwJXe9m80gJlP0uttLXoE9G8DF9dtTdkDLneAwSdDNmVXCtISikXg/Yy+KQ8M3ALhVW9urXOcPgBZmtXSDXBwCIyWKHvN5909nXP7t6c1vx8dzXKFeWpUawAAAAZiS0dEAOwAEABqpSa6lwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+MKCRQBJSKMeg0AAAGVSURBVDjLpZMxa9tQFIXPeaiyhxiZzKFjBme1JFfYgYAe9Bd0yA8JIaQhkJLBP6T/wh3qpZYzm2I8dyilJJMTW7yTIVGRFasE8uAt93K+d+5991IS8Ybj1SVIer24ty8Jk2wyl5S/GkDSi+O4s9PaOYOQh91wSHK2DeLViVut1pmkTwAQtAPUQcz/xCRBEpKOg3ZwEnbDDklvK6AQ+77fds4tSJbBcM7Nm83GbhXiVcXj8fiHpO/WWgfgHAAkXYxGoy8k/UG/nzxDnsqRxF7cO0iS5AhAQxKLm6bpVZqmn8sxAI3kQ2KjKDqQ9GRFEqDNfpQcukrMkDRF3ADAJJvM1+v1n0G/n5D0AcBaew3gFMCFtfbyuVT/cHCYrFarX1mWLQCgsAWSXtgNO81mY/ed7380xpyUn3XOXefr/Ntyufw9vZn+LL7zn21J+fRmOru/f/hrjNmThFLOGWPeV8UvBklSTnIWdsNh0A4g6RiAI/n17vZuWBVvncQNSBAYEK5OvNGDbSMdRdE+AJdl2aJumfjWdX4EIwDvDt7UjSEAAAAASUVORK5CYII=",
parameters => [ { type => "bool", desc => "Save archive title" } ]
parameters => [ { type => "bool", desc => "保存档案名称" } ]
);
}

View File

@ -0,0 +1,188 @@
package LANraragi::Plugin::Metadata::Koushoku;
use strict;
use warnings;
use utf8;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use URI::Escape;
use Mojo::JSON qw(decode_json);
use Mojo::UserAgent;
use Mojo::DOM;
#You can also use the LRR Internal API when fitting.
use LANraragi::Model::Plugins;
use LANraragi::Utils::Logging qw(get_plugin_logger);
use LANraragi::Utils::Generic qw(remove_spaces);
#Meta-information about your plugin.
sub plugin_info {
return (
#Standard metadata
name => "Koushoku",
type => "metadata",
namespace => "kskmetadata",
author => "Difegue",
version => "1.0",
description =>
"Searches KSK for tags matching your archive. <br/><i class='fa fa-exclamation-circle'></i> This plugin will use the source: tag of the archive if it exists.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAANkSURBVDhPJZJpU5NXGIbf/9Ev0g+MM7Udp9WWDsVOsRYQKEVZQ4BsZnt9sy9shgShBbTYaTVCKY1B1pBEQggGFOogKEvYdOoXfszVQ/rhmTkz59zXc9/PeaRO12163DZCbgc+8y06HTJ+h5UOp4xLvoXdoOFBf5Auu4LS3obc0oJDp8VhNtLlcyN1uRWcZj13vS5cBi1+mwWPYiLY6cYjG+lxKoR8LgHpw9BQz+OBAbS1tch6DR1uO1Kox4dWVcfdDg9uswGnVSc66wn47QJmwtreTEPFVZxCoKosJ3hbRmlpRt8kNEIrdfscNN+o4tfeHhz6VhHBgqG1nsHeDpxGDV6zDkWjIvxLH25tK2+WUkzcG8JrNdJ/x4803NuJrr4G7Y/X8+UWIl1TDUGfgsfUjl2nwm/WMjrUh72tEXXFNYoKP+b74ks4FQOStuEnVNVlWBtv8kBYcmhVBJwWLOo6vKY2fvbaSD0ZxdnWxKWCj1CVXiEyPIBVuAz6bUiySc0dj0zAbsZtaM1fRH4fwm/RMDYYYCP2lNnfBsn89ZghxcIjMfmxng5GQ92ExIwkj6Kn5UYF6uofhMUG2mvLycYi7GaTnKwvk0vH+XctzXE6weupCFvRCP9MjLMx+Tfdulak4s8KqSr5kppvLmNT3WRQWN5Oz7ObibObnmMnMSXECxwtxdidi7L+Z5jlP0bYnJnEKX5PUpeVshqdINzl475dZnN+kqPsIocrApCa5fVchP3kDAeLc3nQ1vQTNqcjbCZncbQ3It1XZLLhR7wUtTMZZWd2Ugj+f3yYjpFLzbC/OM1BZoHcygJ7KeFEuHu7lsJmViN5G+o4jsd5+fAhKyMjecDJUoK9xDTH4uG753E+bCxxtJpkX5xzmQS5FyniU2MYNCKCsbo8b/84GWf7aZSt2Wi+81kdPU+wPj1OOOAhIHbi3Yu0GGqS07evqCv7llCXA+n6VxcpKTzHwsgwH1bTvBf0g7NOwu7J6jPGQn4iQ4H8XPZErNPNdYIWPZfPn6OvUwDUlVe59vknfHe+gLGAn9PtNQ7XnpHLJjgUdQZ6vy4iCMDxaiq/D8WFBXx9oZCA+DFJI3agougiVV9cyEOqij6l32UkFr6Xz7yfibG3PM/eSoLs1Di2+loaS0uovFIkFlDhPxYUixj0Cgg3AAAAAElFTkSuQmCC",
parameters => [ { type => "bool", desc => "Save archive title" } ],
oneshot_arg => "Koushoku Gallery URL (Will attach tags matching this exact gallery to your archive)"
);
}
#Mandatory function to be implemented by your plugin
sub get_tags {
shift;
my $lrr_info = shift; # Global info hash
my $ua = $lrr_info->{user_agent};
my ($savetitle) = @_; # Plugin parameters
my $logger = get_plugin_logger();
# Work your magic here - You can create subs below to organize the code better
my $ksk_URL = "";
# If the user specified a oneshot argument, use it as-is.
# We could stand to pre-check it to see if it really is a FAKKU URL but meh
if ( $lrr_info->{oneshot_param} ) {
$ksk_URL = $lrr_info->{oneshot_param};
} elsif ( $lrr_info->{existing_tags} =~ /.*source:\s*ksk\.moe\/view\/([0-9]*)\/([0-z]*)\/*.*/gi ) {
my $gID = $1;
my $gToken = $2;
$ksk_URL = "https://ksk.moe/view/$gID/$gToken";
$logger->debug("Skipping search and using $gID / $gToken from source tag");
} else {
# Search for a KSK URL if the user didn't specify one
$ksk_URL = search_for_ksk_url( $lrr_info->{archive_title}, $ua );
}
# Do we have a URL to grab data from?
if ( $ksk_URL ne "" ) {
$logger->debug("Detected Koushoku URL: $ksk_URL");
} else {
$logger->info("No matching Koushoku Gallery Found!");
return ( error => "No matching Koushoku Gallery Found!" );
}
my ( $newtags, $newtitle );
eval { ( $newtags, $newtitle ) = get_tags_from_ksk( $ksk_URL, $ua ); };
if ($@) {
return ( error => $@ );
}
$logger->info("Sending the following tags to LRR: $newtags");
#Return a hash containing the new metadata - it will be integrated in LRR.
if ( $savetitle && $newtags ne "" ) { return ( tags => $newtags, title => $newtitle ); }
else { return ( tags => $newtags ); }
}
######
## KSK-Specific Methods
######
# search_for_ksk_url(title, useragent)
# Uses the website's search to find a gallery and returns its gallery ID.
sub search_for_ksk_url {
my ( $title, $ua ) = @_;
my $dom = get_search_result_dom( $title, $ua );
# Get the first link on the page that has rel="bookmark"
my $path = $dom->at('a[rel="bookmark"]')->attr('href');
if ( $path ne "" ) {
return "https://ksk.moe" . $path;
} else {
return "";
}
}
sub get_search_result_dom {
my ( $title, $ua ) = @_;
my $logger = get_plugin_logger();
# Use the regular search page.
my $URL = "https://ksk.moe/browse?s=" . uri_escape_utf8($title);
$logger->debug("Using URL $URL to search.");
my $res = $ua->max_redirects(5)->get($URL)->result;
$logger->debug( "Got this HTML: " . $res->body );
return $res->dom;
}
# get_tags_from_ksk(fURL, useragent)
# Parses a KSK URL for tags.
sub get_tags_from_ksk {
my ( $url, $ua ) = @_;
my $logger = get_plugin_logger();
my $dom = get_dom_from_ksk( $url, $ua );
# Title is the first h1 block
my $title = $dom->at('h1')->text;
remove_spaces($title);
$logger->debug("Parsed title: $title");
# Get all the links with rel="tag"
my @tags = ();
my @tags_dom = $dom->find('a[rel="tag"]')->each;
# Use the href to get the tag name and namespace.
@tags_dom = map { $_->attr('href') } @tags_dom;
foreach my $href (@tags_dom) {
# "/tags/blahblah" => "blahblah", "/artists/blah%20blah" => "artist:blah blah"
if ( $href =~ /\/(.*)\/(.*)/ ) {
$logger->debug("Matching tag: $1 / $2");
# url-decode it before pushing
my $tag = uri_unescape($2);
remove_spaces($tag);
if ( $1 eq "artists" ) {
$tag = "artist:" . $tag;
}
if ( $1 eq "parodies" ) {
$tag = "parody:" . $tag;
}
if ( $1 eq "magazines" ) {
$tag = "magazine:" . $tag;
}
push( @tags, lc $tag );
}
}
return ( join( ', ', @tags ), $title );
}
sub get_dom_from_ksk {
my ( $url, $ua ) = @_;
my $logger = get_plugin_logger();
my $res = $ua->max_redirects(5)->get($url)->result;
$logger->trace( "Got this HTML: " . $res->body );
my $dom = $res->dom;
}
1;

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Metadata::MEMS;
use strict;
use warnings;
use LANraragi::Utils::Logging qw(get_plugin_logger);
use utf8;
# Meta-information about the plugin.
sub plugin_info {
@ -15,8 +15,8 @@ sub plugin_info {
login_from => "ehlogin",
author => 'Mayriad',
version => '1.1.1',
description => 'Accurately retrieves metadata from e-hentai.org using the identifiers appeneded to the '
. 'filenames of archives downloaded by Mayriad\'s EH Master Script.',
description => '使用附加到 的标识符准确地从 e-hentai.org 检索元数据 '
. '下载档案的文件名通过 Mayriad\'s EH 的主脚本提供.',
icon => 'data:image/png;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAA'
. 'AAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD'
. '///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wARBmb/EQZm/xEGZv8RBmb/EQZm/'
@ -36,12 +36,12 @@ sub plugin_info {
# Custom arguments:
parameters => [
{ type => 'bool',
desc => 'Save the original Japanese title when available instead of the English or ' . 'romanised title'
desc => '如果可用,请保存原始日文标题,而不是英文或 ' . '罗马化标题'
},
{ type => 'bool', desc => 'Save additional timestamp (time posted) and uploader metadata' },
{ type => 'bool', desc => 'Use ExHentai link for source instead of E-Hentai link' }
{ type => 'bool', desc => '保存额外的时间戳(发布时间)和上传者元数据' },
{ type => 'bool', desc => '使用 ExHentai 链接作为源而不是 E-Hentai 链接' }
],
oneshot_arg => 'Enter a valid EH gallery URL to copy metadata from this EH gallery to this LANraragi archive',
oneshot_arg => '输入有效的 EH 库 URL 以将此 EH 库中的元数据复制到此 LANraragi 存档',
cooldown => 4
);
}

View File

@ -2,7 +2,7 @@ package LANraragi::Plugin::Metadata::RegexParse;
use strict;
use warnings;
use utf8;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use Mojo::JSON qw(from_json);
@ -26,10 +26,10 @@ sub plugin_info {
author => "Difegue",
version => "1.0",
description =>
"Derive tags from the filename of the given archive. <br>Follows the doujinshi naming standard (Release) [Artist] TITLE (Series) [Language].",
"从给定档案的文件名派生标签. <br>遵循同人志命名标准(发布)[艺术家]TITLE系列[语言].",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAL1JREFUOI1jZMABpNbH/sclx8DAwPAscDEjNnEMQUIGETIYhUOqYdgMhTPINQzdUEZqGIZsKBM1DEIGTOiuexqwCKdidDl0vtT62P9kuZCJEWuKYWBgYGBgRHbh04BFDNIb4jAUbbSrZTARUkURg6lD10OUC/0PNaMYgs1Skgwk1jCSDCQWoBg46dYmhite0+D8pwGLCMY6uotRDOy8toZBkI2HIhcO/pxCm8KBUkOxFl/kGoq3gCXFYFxVAACeoU/8xSNybwAAAABJRU5ErkJggg==",
parameters => [ { type => "bool", desc => "Save archive title", default_value => "1" } ]
parameters => [ { type => "bool", desc => "保存档案名称", default_value => "1" } ]
);
}

View File

@ -2,7 +2,7 @@ package LANraragi::Plugin::Metadata::nHentai;
use strict;
use warnings;
use utf8;
#Plugins can freely use all Perl packages already installed on the system
#Try however to restrain yourself to the ones already installed for LRR (see tools/cpanfile) to avoid extra installations by the end-user.
use URI::Escape;
@ -24,12 +24,12 @@ sub plugin_info {
login_from => "nhentaicfbypass",
author => "Difegue and others",
version => "1.7.2",
description => "Searches nHentai for tags matching your archive.
<br>Supports reading the ID from files formatted as \"{Id} Title\" and if not, tries to search for a matching gallery.
<br><i class='fa fa-exclamation-circle'></i> This plugin will use the source: tag of the archive if it exists.",
description => "nHentai 中搜索与您的档案匹配的标签.
<br>支持从格式为以下的文件中读取 ID \"{Id} Title\" 如果没有尝试搜索匹配的图库.
<br><i class='fa fa-exclamation-circle'></i> 此插件将使用 source: tag 的标签如果存在.",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nB3RJTUUH4wYCFA8s1yKFJwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH\nAAACL0lEQVQ4y6XTz0tUURQH8O+59773nLFcaGWTk4UUVCBFiJs27VxEQRH0AyRo4x8Q/Qtt2rhr\nU6soaCG0KYKSwIhMa9Ah+yEhZM/5oZMG88N59717T4sxM8eZCM/ycD6Xwznn0pWhG34mh/+PA8mk\n8jO5heziP0sFYwfgMDFQJg4IUjmquSFGG+OIlb1G9li5kykgTgvzSoUCaIYlo8/Igcjpj5wOkARp\n8AupP0uzJLijCY4zzoXOxdBLshAgABr8VOp7bpAXDEI7IBrhdksnjNr3WzI4LaIRV9fk2iAaYV/y\nA1dPiYjBAALgpQxnhV2XzTCAGWGeq7ACBvCdzKQyTH+voAm2hGlpcmQt2Bc2K+ymAhWPxTzPDQLt\nOKo1FiNBQaArq9WNRQwEgKl7XQ1duzSRSn/88vX0qf7DPQddx1nI5UfHxt+m0sLYPiP3shRAG8MD\nok1XEEXR/EI2ly94nrNYWG6Nx0/2Hp2b94dv34mlZge1e4hVCJ4jc6tl9ZP803n3/i4lpdyzq2N0\n7M3DkSeF5ZVYS8v1qxcGz5+5eey4nPDbmGdE9FpGeWErVNe2tTabX3r0+Nk3PwOgXFkdfz99+exA\nMtFZITEt9F23mpLG0hYTVQCKpfKPlZ/rqWKpYoAPcTmpginW76QBbb0OBaBaDdjaDbNlJmQE3/d0\nMYoaybU9126oPkrEhpr+U2wjtoVVGBowkslEsVSupRKdu0Mduq7q7kqExjSS3V2dvwDLavx0eczM\neAAAAABJRU5ErkJggg==",
parameters => [ { type => "bool", desc => "Save archive title" } ],
parameters => [ { type => "bool", desc => "保存档案名称" } ],
oneshot_arg => "nHentai Gallery URL (Will attach tags matching this exact gallery to your archive)"
);

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Scripts::BlacklistMigrate;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use LANraragi::Utils::Logging qw(get_plugin_logger);
use LANraragi::Utils::Database qw(save_computed_tagrules);
use LANraragi::Utils::Tags qw(tags_rules_to_array restore_CRLF);
@ -21,7 +21,7 @@ sub plugin_info {
namespace => "blist2rule",
author => "Difegue",
version => "1.0",
description => "Migrate your blacklist from LANraragi < 0.8.0 databases to the new Tag Rules system."
description => "将您的黑名单从 LANraragi < 0.8.0 的数据库迁移到新的标签规则系统."
);
}

View File

@ -5,7 +5,7 @@ use warnings;
use File::Find;
use File::Basename;
use Data::Dumper;
use utf8;
use LANraragi::Utils::Logging qw(get_logger);
use LANraragi::Utils::Generic qw(is_archive);
use LANraragi::Utils::Database qw(compute_id);
@ -24,10 +24,10 @@ sub plugin_info {
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAuJJREFUOI3FlE1sVFUUx3/nvVdaSqd0sAmElDYopOWjsKiEnYkLowU2uMGw0ajBhS5oqAtwo3FTaIQNCz7CBldEE01M+AglJMACUyBQrI6iQ2groNNxpjPz5n3MnXddvOnrfACNK09yk/fuved3//933j3wf8Thw6O6q6tHd3X16FOnTusX7ZW7I7H0kuUrV6hCtmHxt7UnOXHiDInEJAAzM49kscMtw2xesWHfKOTGASNa+GnmHfYP7gSgr28TY2PnF4UBWAD88Tlk7kFVyuDbX0ew43vzU/6bnc+12vnqx4OrX//i4gIQXS2uJkZGvqRXD3Q/V9LKXdjmSxcmjq7ahi6vtRazMKAHGua8oolbsHDyFk7iF4r/3IOyGl9QKI1u+vo2kUhMsmZ3T8Pa5c+E5vYYzbFWWkQTW23R+XKc+9/+eKUB+MbBHZWqhpW9MGSjtdDes57OzRtZ2hFD4tshcEAVkHIeVIapse8wDPNQxbKBDuDhxHKODd5myZ44698dBTQgUbEkex0CFzJXIfDC58CDwCP3Z1ZtPpAaD4FWnJIv2Nkm+j85AroE/jRoHwI/SgoBbt27h+54DS3je0VEh7VtimOnm2mKxRcguhpUDXvGUDb9bd3fh14rCtNPWuh9/6s6RfWq6mEetG0le/cb5KPbpajKActwChaIVNR5ddAqeLkCmt9TLjCbzEVFtQDstENTW0c4M58cJbiNsPmxtBs7eQ03p87VANP3J+n94CjiPKj76N4z7M4f6IPKk35YAFMORUCzpRU3/VdoV82BytUm+jMQlEArlBJmEyncORdnroTypxCRt7YMp5IRUBVzv/cPnV0n+VshyH8MgYuycyjHJjPt4GbyONki5VIAItfQnBeTG62YD1458DTF8EJXscSw1lEu4s0m8TJ/k/o5iZuZIygHlb+ZHwzkUoC+2T+cuiNSd08/re1qMjFa25YM5D0xjVtGe8fUhg9/zfMf41+ZdKPYI8TqHgAAAABJRU5ErkJggg==",
description =>
"Scan your Content Folder and automatically create Static Categories for each subfolder.<br>This Script will create a category for each subfolder with archives as direct children.",
"扫描您的内容文件夹并自动为每个子文件夹创建静态分类。<br>此脚本将为每个子文件夹创建一个类别,并将存档作为直接子文件夹.",
parameters => [
{ type => "bool", desc => "Delete all your static categories before creating the ones matching your subfolders" },
{ type => "bool", desc => "Use top level subfolders only to create categories" }
{ type => "bool", desc => "在创建与子文件夹匹配的静态类别之前,请删除所有静态类别" },
{ type => "bool", desc => "仅使用顶级子文件夹创建类别" }
]
);
@ -46,12 +46,12 @@ sub run_script {
my $dirname;
if ($delete_old_cats) {
$logger->info("Deleting all Static Categories before folder walking as instructed.");
$logger->info("按照指示,在文件夹步行之前删除所有静态类别。");
my @categories = LANraragi::Model::Category->get_static_category_list;
for my $category (@categories) {
my $cat_id = %{$category}{"id"};
$logger->debug("Deleting '$cat_id'");
$logger->debug("删除 '$cat_id'");
LANraragi::Model::Category::delete_category($cat_id);
}
}
@ -85,7 +85,7 @@ sub run_script {
$userdir
);
$logger->debug( "Find routine results: " . Dumper %subfolders );
$logger->debug( "找到常规结果: " . Dumper %subfolders );
# For each subfolder with file, create a category bearing its name and containing all its files
for my $folder ( keys %subfolders ) {

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Scripts::SourceFinder;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use Mojo::UserAgent;
use LANraragi::Utils::Logging qw(get_plugin_logger);
use LANraragi::Model::Stats;
@ -19,10 +19,10 @@ sub plugin_info {
namespace => "urlfinder",
author => "Difegue",
version => "2.0",
description => "Looks in the database if an archive has a 'source:' tag matching the given URL.",
description => "在数据库中查找匹配给定链接 'source:' 的标签 .",
icon =>
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABZSURBVDhPzY5JCgAhDATzSl+e/2irOUjQSFzQog5hhqIl3uBEHPxIXK7oFXwVE+Hj5IYX4lYVtN6MUW4tGw5jNdjdt5bLkwX1q2rFU0/EIJ9OUEm8xquYOQFEhr9vvu2U8gAAAABJRU5ErkJggg==",
oneshot_arg => "URL to search."
oneshot_arg => "要搜索的网址."
);
}

View File

@ -3,7 +3,7 @@ package LANraragi::Plugin::Scripts::nHentaiSourceConverter;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use LANraragi::Utils::Logging qw(get_plugin_logger);
use LANraragi::Utils::Database qw(invalidate_cache set_tags);
use LANraragi::Model::Config;
@ -18,7 +18,7 @@ sub plugin_info {
namespace => "nhsrcconv",
author => "Guerra24",
version => "1.0",
description => "Converts \"source:{id}\" tags with 6 or less digits into \"source:nhentai.net/g/{id}\""
description => "转换 \"source:{id}\" 6 位或更少位数的标签 \"source:nhentai.net/g/{id}\""
);
}

View File

@ -2,7 +2,7 @@ package LANraragi::Utils::Archive;
use strict;
use warnings;
use utf8;
use feature qw(say);
use feature qw(signatures);
@ -167,13 +167,13 @@ sub extract_thumbnail ( $thumbdir, $id, $page, $use_hq ) {
my @filelist = @$images;
my $requested_image = $filelist[ $page > 0 ? $page - 1 : 0 ];
die "Requested image not found" unless $requested_image;
die "Requested image not found: $requested_image" unless $requested_image;
$logger->debug("Extracting thumbnail for $id page $page from $requested_image");
# Extract first image to temp dir
my $arcimg = extract_single_file( $file, $requested_image, $temppath );
if ( $page > 0 ) {
if ( $page - 1 > 0 ) {
# Non-cover thumbnails land in a dedicated folder.
$thumbname = "$thumbdir/$subfolder/$id/$page.jpg";
@ -183,6 +183,7 @@ sub extract_thumbnail ( $thumbdir, $id, $page, $use_hq ) {
# For cover thumbnails, grab the SHA-1 hash for tag research.
# That way, no need to repeat a costly extraction later.
my $shasum = shasum( $arcimg, 1 );
$logger->debug("Setting thumbnail hash: $shasum");
$redis->hset( $id, "thumbhash", $shasum );
$redis->quit();
}
@ -340,17 +341,16 @@ sub extract_single_file ( $archive, $filepath, $destination ) {
}
# Variant for plugins.
# Extracts the file with a timestamp to a folder in /temp/plugin.
# Extracts the file to a folder in /temp/plugin.
sub extract_file_from_archive ( $archive, $filename ) {
# Timestamp extractions in microseconds
my ( $seconds, $microseconds ) = gettimeofday;
my $stamp = "$seconds-$microseconds";
my $path = get_temp . "/plugin/$stamp";
mkdir get_temp . "/plugin";
my $path = get_temp . "/plugin";
mkdir $path;
return extract_single_file( $archive, $filename, $path );
my $tmp = File::Temp->new( DIR => $path );
$tmp->unlink_on_destroy(0);
return extract_single_file( $archive, $filename, $tmp->filename );
}
1;

View File

@ -2,11 +2,11 @@ package LANraragi::Utils::Database;
use strict;
use warnings;
use utf8;
use feature qw(signatures);
no warnings 'experimental::signatures';
use utf8;
use Digest::SHA qw(sha256_hex);
use Mojo::JSON qw(decode_json);
use Encode;
@ -171,7 +171,7 @@ sub build_json ( $id, %hash ) {
# It's not a new archive, but it might have never been clicked on yet,
# so grab the value for $isnew stored in redis.
my ( $name, $title, $tags, $file, $isnew, $progress, $pagecount ) = @hash{qw(name title tags file isnew progress pagecount)};
my ( $name, $title, $tags, $file, $isnew, $progress, $pagecount, $lastreadtime) = @hash{qw(name title tags file isnew progress pagecount lastreadtime)};
# Return undef if the file doesn't exist.
return unless ( defined($file) && -e $file );
@ -191,7 +191,8 @@ sub build_json ( $id, %hash ) {
isnew => $isnew ? $isnew : "false",
extension => lc( ( split( /\./, $file ) )[-1] ),
progress => $progress ? int($progress) : 0,
pagecount => $pagecount ? int($pagecount) : 0
pagecount => $pagecount ? int($pagecount) : 0,
lastreadtime => $lastreadtime ? int($lastreadtime) : 0
};
return $arcdata;

View File

@ -2,10 +2,10 @@ package LANraragi::Utils::Generic;
use strict;
use warnings;
use utf8;
use feature "switch";
no warnings 'experimental';
use utf8;
use Storable qw(store);
use Digest::SHA qw(sha256_hex);
use Mojo::Log;
@ -123,7 +123,7 @@ sub start_minion {
my $logger = get_logger( "Minion", "minion" );
my $numcpus = Sys::CpuAffinity::getNumCpus();
$logger->info("Starting new Minion worker in subprocess with $numcpus parallel jobs.");
$logger->info("在子进程中使用 $numcpus 并行作业启动新的 Minion 工作进程。");
my $worker = $mojo->app->minion->worker;
$worker->status->{jobs} = $numcpus;
@ -133,9 +133,9 @@ sub start_minion {
my $proc = Proc::Simple->new();
$proc->start(
sub {
$logger->info("Minion worker $$ started");
$logger->info("Minion 工作线程 $$ 开始运行");
$worker->run;
$logger->info("Minion worker $$ stopped");
$logger->info("Minion 工作线程 $$ 停止运行");
return 1;
}
);
@ -153,7 +153,7 @@ sub _spawn {
my ( $job, $pid ) = @_;
my ( $id, $task ) = ( $job->id, $job->task );
my $logger = get_logger( "Minion Worker", "minion" );
$job->app->log->debug(qq{Process $pid is performing job "$id" with task "$task"});
$job->app->log->debug(qq{进程 $pid 正在执行作业 "$id" 和任务 "$task"});
}
# Start Shinobu and return its Proc::Background object.
@ -164,7 +164,7 @@ sub start_shinobu {
$proc->start( $^X, "./lib/Shinobu.pm" );
$proc->kill_on_destroy(0);
$mojo->LRR_LOGGER->debug( "Shinobu Worker new PID is " . $proc->pid );
$mojo->LRR_LOGGER->debug( "Shinobu 工作进程新的 PID 为 " . $proc->pid );
# Freeze the process object in the PID file
store \$proc, get_temp() . "/shinobu.pid";
@ -189,7 +189,7 @@ sub shasum {
};
if ($@) {
$logger->error( "Error building hash for " . $_[0] . " -- " . $@ );
$logger->error( "创建哈希时出错" . $_[0] . " -- " . $@ );
return "";
}

View File

@ -2,7 +2,7 @@ package LANraragi::Utils::Logging;
use strict;
use warnings;
use utf8;
use feature 'say';
use POSIX;
@ -56,7 +56,7 @@ sub get_logger {
$log->level('debug');
}
# Step down into trace if we're launched from npm run dev-server
# Step down into trace if we're launched from npm run dev-server-verbose
if ( $ENV{LRR_DEVSERVER} ) {
$log->level('trace');
}

View File

@ -27,10 +27,21 @@ sub add_tasks {
my ( $job, @args ) = @_;
my ( $thumbdir, $id, $page ) = @args;
my $logger = get_logger( "Minion", "minion" );
# Non-cover thumbnails are rendered in low quality by default.
my $use_hq = $page eq 0 || LANraragi::Model::Config->get_hqthumbpages;
my $thumbname = extract_thumbnail( $thumbdir, $id, $page, $use_hq );
$job->finish($thumbname);
my $thumbname = "";
eval { $thumbname = extract_thumbnail( $thumbdir, $id, $page, $use_hq ); };
if ($@) {
my $msg = "Error building thumbnail: $@";
$logger->error($msg);
$job->fail( { errors => [$msg] } );
} else {
$job->finish($thumbname);
}
}
);
@ -44,14 +55,14 @@ sub add_tasks {
my @keys = $redis->keys('????????????????????????????????????????');
$redis->quit();
$logger->info("Starting thumbnail regen job (force = $force)");
$logger->info("开始缩略图重新生成作业 (强制模式 = $force)");
my @errors = ();
my $numCpus = Sys::CpuAffinity::getNumCpus();
my $pl = Parallel::Loops->new($numCpus);
$pl->share( \@errors );
$logger->debug("Number of available cores for processing: $numCpus");
$logger->debug("可用于处理的核心数量: $numCpus");
my @sections = split_workload_by_cpu( $numCpus, @keys );
# Regen thumbnails for errythang if $force = 1, only missing thumbs otherwise
@ -66,12 +77,12 @@ sub add_tasks {
unless ( $force == 0 && -e $thumbname ) {
eval {
$logger->debug("Regenerating for $id...");
$logger->debug("正在重新生成:$id...");
extract_thumbnail( $thumbdir, $id, 0, 1 );
};
if ($@) {
$logger->warn("Error while generating thumbnail: $@");
$logger->warn("生成缩略图时出错: $@");
push @errors, $@;
}
}
@ -116,7 +127,7 @@ sub add_tasks {
or die "Bullshit! File path could not be converted back to a byte sequence!"
; # This error happening would not make any sense at all so it deserves the EYE reference
$logger->info("Processing uploaded file $file...");
$logger->info("正在处理上传的文件 $file...");
# Since we already have a file, this goes straight to handle_incoming_file.
my ( $status, $id, $title, $message ) = LANraragi::Model::Upload::handle_incoming_file( $file, $catid, "" );
@ -139,20 +150,20 @@ sub add_tasks {
my $ua = Mojo::UserAgent->new;
my $logger = get_logger( "Minion", "minion" );
$logger->info("Downloading url $url...");
$logger->info("正在下载 $url...");
# Keep a clean copy of the url for display and tagging
my $og_url = $url;
trim_url($og_url);
# If the URL is already recorded, abort the download
# 如果已记录URL请流产下载
my $recorded_id = LANraragi::Model::Stats::is_url_recorded($og_url);
if ($recorded_id) {
$job->finish(
{ success => 0,
url => $og_url,
id => $recorded_id,
message => "URL already downloaded!"
message => "链接已被下载!"
}
);
return;
@ -163,7 +174,7 @@ sub add_tasks {
if ($downloader) {
$logger->info( "Found downloader " . $downloader->{namespace} );
$logger->info( "发现下载器 " . $downloader->{namespace} );
# Use the downloader to transform the URL
my $plugname = $downloader->{namespace};
@ -183,15 +194,15 @@ sub add_tasks {
$ua = $plugin_result->{user_agent};
$url = $plugin_result->{download_url};
$logger->info("URL transformed by plugin to $url");
$logger->info("插件将 URL 转换为 $url");
} else {
$logger->debug("No downloader found, trying direct URL.");
$logger->debug("找不到下载器,尝试直接下载 URL.");
}
# Download the URL
eval {
my $tempfile = LANraragi::Model::Upload::download_url( $url, $ua );
$logger->info("URL downloaded to $tempfile");
$logger->info("URL将会被保存为 $tempfile ");
# Add the url as a source: tag
my $tag = "source:$og_url";
@ -229,7 +240,7 @@ sub add_tasks {
my ( $namespace, $id, $scriptarg ) = @args;
my $logger = get_logger( "Minion", "minion" );
$logger->info("Running plugin $namespace...");
$logger->info("运行插件 $namespace...");
my ( $pluginfo, $plugin_result ) = use_plugin( $namespace, $id, $scriptarg );

View File

@ -2,7 +2,7 @@ package LANraragi::Utils::Plugins;
use strict;
use warnings;
use utf8;
use Mojo::JSON qw(decode_json);
use LANraragi::Utils::Database qw(redis_decode);

View File

@ -2,7 +2,7 @@ package LANraragi::Utils::Routing;
use strict;
use warnings;
use utf8;
use Mojolicious::Plugin::Status;
use Mojolicious::Plugin::Minion::Admin;

View File

@ -2,7 +2,7 @@ package LANraragi::Utils::Tags;
use strict;
use warnings;
use utf8;
use feature "switch";
no warnings 'experimental';

View File

@ -2,7 +2,7 @@ package LANraragi::Utils::TempFolder;
use strict;
use warnings;
use utf8;
use Cwd 'abs_path';
use FindBin;

View File

@ -10,7 +10,7 @@ package Shinobu;
use strict;
use warnings;
use utf8;
use feature qw(say signatures);
no warnings 'experimental::signatures';
@ -47,7 +47,7 @@ my $inotifysub = sub {
my $e = shift;
my $name = $e->path;
my $type = $e->type;
$logger->debug("Received inotify event $type on $name");
$logger->debug("收到 $name 上的 inotify 事件 $type");
if ( $type eq "create" || $type eq "modify" ) {
new_file_callback($name);
@ -63,11 +63,11 @@ sub initialize_from_new_process {
my $userdir = LANraragi::Model::Config->get_userdir;
$logger->info("Shinobu File Watcher started.");
$logger->info("Content folder is $userdir.");
$logger->info("Shinobu文件监视器启动.");
$logger->info("内容文件夹为: $userdir.");
update_filemap();
$logger->info("Initial scan complete! Adding watcher to content folder to monitor for further file edits.");
$logger->info("初始扫描完成! 将观监视器添加到内容文件夹以监视进一步的文件变动。");
# Add watcher to content directory
my $contentwatcher = File::ChangeNotify->instantiate_watcher(
@ -78,13 +78,13 @@ sub initialize_from_new_process {
);
my $class = ref($contentwatcher);
$logger->debug("Watcher class is $class");
$logger->debug("文件监视器类名为: $class");
# Add watcher to tempfolder
my $tempwatcher = File::ChangeNotify->instantiate_watcher( directories => [ get_temp() ] );
# manual event loop
$logger->info("All done! Now dutifully watching your files. ");
$logger->info("全部初始化已经完成,文件监视器正在全力监测文件变动。");
while (1) {
@ -106,7 +106,7 @@ sub initialize_from_new_process {
# This computes IDs for all new archives and henceforth can get rather expensive!
sub update_filemap {
$logger->info("Scanning content folder for changes...");
$logger->info("正在扫描内容文件夹以查找更改...");
my $redis = LANraragi::Model::Config->get_redis_config;
# Clear hash
@ -135,13 +135,13 @@ sub update_filemap {
my @newfiles = grep { !$filemaphash{$_} } @files;
my @deletedfiles = grep { !$fshash{$_} } @filemapfiles;
$logger->info( "Found " . scalar @newfiles . " new files." );
$logger->info( scalar @deletedfiles . " files were found on the filemap but not on the filesystem." );
$logger->info( "找到 " . scalar @newfiles . " 个新文件." );
$logger->info( scalar @deletedfiles . " 个文件在数据库里找到文件,但在文件系统上找不到文件。" );
# Delete old files from filemap
foreach my $deletedfile (@deletedfiles) {
$logger->debug("Removing $deletedfile from filemap.");
$redis->hdel( "LRR_FILEMAP", $deletedfile ) || $logger->warn("Couldn't delete previous filemap data.");
$logger->debug("正在从数据库中删除 $deletedfile");
$redis->hdel( "LRR_FILEMAP", $deletedfile ) || $logger->warn("无法从数据库中删除以前的文件数据。");
}
$redis->quit();
@ -150,7 +150,7 @@ sub update_filemap {
my $numCpus = Sys::CpuAffinity::getNumCpus();
my $pl = Parallel::Loops->new($numCpus);
$logger->debug("Number of available cores for processing: $numCpus");
$logger->debug("可用于处理的核心数量: $numCpus");
my @sections = split_workload_by_cpu( $numCpus, @newfiles );
# Eval the parallelized file crawl to avoid taking down the entire process in case one of the forked processes dies
@ -165,7 +165,7 @@ sub update_filemap {
eval { add_to_filemap( $redis, $file ); };
if ($@) {
$logger->error("Error scanning $file: $@");
$logger->error("扫描 $file 文件时出现错误: $@");
}
}
$redis->quit();
@ -174,7 +174,7 @@ sub update_filemap {
};
if ($@) {
$logger->error("Error while scanning content folder: $@");
$logger->error("扫描内容文件夹时出错: $@");
}
}
@ -183,14 +183,14 @@ sub add_to_filemap ( $redis_cfg, $file ) {
my $redis_arc = LANraragi::Model::Config->get_redis;
if ( is_archive($file) ) {
$logger->debug("Adding $file to Shinobu filemap.");
$logger->debug("将 $file 添加到 Shinobu 数据库。");
#Freshly created files might not be complete yet.
#We have to wait before doing any form of calculation.
while (1) {
last unless -e $file; # Sanity check to avoid sticking in this loop if the file disappears
last if open( my $handle, '<', $file );
$logger->debug("Waiting for file to be openable");
$logger->debug("等待文件允许被打开");
sleep(1);
}
@ -198,7 +198,7 @@ sub add_to_filemap ( $redis_cfg, $file ) {
my $cnt = 0;
while (1) {
last if ( ( ( -s $file ) >= 512000 ) || $cnt >= 5 );
$logger->debug("Waiting for file to be fully written");
$logger->debug("等待文件完全写入磁盘");
sleep(1);
$cnt++;
}
@ -208,23 +208,23 @@ sub add_to_filemap ( $redis_cfg, $file ) {
eval { $id = compute_id($file); };
if ($@) {
$logger->error("Couldn't open $file for ID computation: $@");
$logger->error("Giving up on adding it to the filemap.");
$logger->error("无法打开 $file 进行ID计算: $@");
$logger->error("放弃将文件添加到数据库.");
return;
}
$logger->debug("Computed ID is $id.");
$logger->debug("计算出的ID为: $id.");
# If the id already exists on the server, throw a warning about duplicates
if ( $redis_cfg->hexists( "LRR_FILEMAP", $file ) ) {
my $filemap_id = $redis_cfg->hget( "LRR_FILEMAP", $file );
$logger->debug("$file was logged but is already in the filemap!");
$logger->debug("$file 文件已经存在于数据库中!");
if ( $filemap_id ne $id ) {
$logger->debug("$file has a different ID than the one in the filemap! ($filemap_id)");
$logger->info("$file has been modified, updating its ID from $filemap_id to $id.");
$logger->debug("$file 文件的ID与数据库中现有的ID不同! ($filemap_id)");
$logger->info("$file 文件已被修改,已将其在数据库中的ID从 $filemap_id 修改为 $id.");
LANraragi::Utils::Database::change_archive_id( $filemap_id, $id );
@ -232,7 +232,7 @@ sub add_to_filemap ( $redis_cfg, $file ) {
$redis_cfg->hset( "LRR_FILEMAP", $file, $id );
} else {
$logger->debug(
"$file has the same ID as the one in the filemap. Duplicate inotify events? Cleaning cache just to make sure");
"$file 文件的ID与数据库内的ID一致. 可能是重复的 inotify 事件触发? 为了防止出现其他意外情况现在开始清理缓存");
invalidate_cache();
}
@ -250,19 +250,19 @@ sub add_to_filemap ( $redis_cfg, $file ) {
#Update the real file path and title if they differ from the saved one
#This is meant to always track the current filename for the OS.
unless ( $file eq $filecheck ) {
$logger->debug("File name discrepancy detected between DB and filesystem!");
$logger->debug("Filesystem: $file");
$logger->debug("Database: $filecheck");
$logger->debug("在数据库和文件系统之间检测到文件名差异!");
$logger->debug("文件系统: $file");
$logger->debug("数据库内: $filecheck");
my ( $name, $path, $suffix ) = fileparse( $file, qr/\.[^.]*/ );
$redis_arc->hset( $id, "file", $file );
$redis_arc->hset( $id, "name", redis_encode($name) );
$redis_arc->hset( $id, " 所属文件: ", $file );
$redis_arc->hset( $id, " 所属名字: ", redis_encode($name) );
$redis_arc->wait_all_responses;
invalidate_cache();
}
# Set pagecount in case it's not already there
unless ( $redis_arc->hget( $id, "pagecount" ) ) {
$logger->debug("Pagecount not calculated for $id, doing it now!");
$logger->debug("未计算 $id 的页数,立即执行!");
LANraragi::Utils::Database::add_pagecount( $redis_arc, $id );
}
@ -273,7 +273,7 @@ sub add_to_filemap ( $redis_cfg, $file ) {
invalidate_cache();
}
} else {
$logger->debug("$file not recognized as archive, skipping.");
$logger->debug("$file 未被识别为存档,正在跳过。");
}
$redis_arc->quit;
}
@ -282,7 +282,7 @@ sub add_to_filemap ( $redis_cfg, $file ) {
# "handles the addition of new subdirectories by adding them to the watch list"
sub new_file_callback($name) {
$logger->debug("New file detected: $name");
$logger->debug("检测到新文件: $name");
unless ( -d $name ) {
my $redis = LANraragi::Model::Config->get_redis_config;
@ -290,7 +290,7 @@ sub new_file_callback($name) {
$redis->quit();
if ($@) {
$logger->error("Error while handling new file: $@");
$logger->error("处理新文件时出错: $@");
}
}
}
@ -299,7 +299,7 @@ sub new_file_callback($name) {
# Deleted subdirectories trigger deleted events for every file deleted.
sub deleted_file_callback($name) {
$logger->info("$name was deleted from the content folder!");
$logger->info("$name 已从内容文件夹中删除!");
unless ( -d $name ) {
my $redis = LANraragi::Model::Config->get_redis_config;
@ -316,7 +316,7 @@ sub deleted_file_callback($name) {
sub add_new_file ( $id, $file ) {
my $redis = LANraragi::Model::Config->get_redis;
$logger->info("Adding new file $file with ID $id");
$logger->info("添加 ID 为 $id 的新文件 $file");
eval {
LANraragi::Utils::Database::add_archive_to_redis( $id, $file, $redis );
@ -328,7 +328,7 @@ sub add_new_file ( $id, $file ) {
};
if ($@) {
$logger->error("Error while adding file: $@");
$logger->error("添加文件时出错: $@");
}
$redis->quit;
}

View File

@ -1,8 +1,8 @@
{
"name": "lanraragi",
"version": "0.8.90",
"version_name": "The Hearts Filthy Lesson",
"description": "I'm under Japanese influence and my honor's at stake!",
"version": "0.9.0",
"version_name": "哈罗太空男孩",
"description": "我一世英名恐怕要毁在日本文化的影响下了!",
"scripts": {
"test": "prove -r -l -v tests/",
"lanraragi-installer": "perl ./tools/install.pl",
@ -11,10 +11,10 @@
"dev-server": "perl ./script/launcher.pl -m -v ./script/lanraragi",
"dev-server-verbose": "export LRR_DEVSERVER=1 && perl ./script/launcher.pl -m -v ./script/lanraragi",
"kill-workers": "(kill -15 `cat ./public/temp/shinobu.pid-s6` || true) && (kill -15 `cat ./public/temp/minion.pid-s6` || true) && (pkill -9 -f ./script/lanraragi || true)",
"docker-build": "docker build -t difegue/lanraragi -f ./tools/build/docker/Dockerfile .",
"docker-build": "docker build -t windycloud/lanraragi_cn:dev -f ./tools/build/docker/Dockerfile .",
"critic": "perlcritic ./lib/* ./script/* ./tools/install.pl",
"backup-db": "perl ./script/backup",
"get-version": "perl -Mojo -E \"my \\$conf = j(f(qw(package.json))->slurp); say %\\$conf{version} .q/ - '/. %\\$conf{version_name} .q/'/ \""
"get-version": "perl ./script/get_version"
},
"repository": {
"type": "git",

View File

@ -28,7 +28,7 @@ Batch.initializeAll = function () {
// Load all archives, showing a spinner while doing so
$("#arclist").hide();
Server.callAPI("/api/archives", "GET", null, "Couldn't load the complete archive list! Please reload the page.",
Server.callAPI("/api/archives", "GET", null, "无法加载完整的存档列表! 请重新加载页面.",
(data) => {
// Parse the archive list and add <li> elements to arclist
data.forEach((archive) => {
@ -75,7 +75,7 @@ Batch.showOverride = function () {
* Check untagged archives, using the matching API endpoint.
*/
Batch.checkUntagged = function () {
Server.callAPI("api/archives/untagged", "GET", null, "Error getting untagged archives!",
Server.callAPI("api/archives/untagged", "GET", null, "获取未加标签的存档时出错!",
(data) => {
// Check untagged archives
data.forEach((id) => {
@ -97,11 +97,11 @@ Batch.checkUntagged = function () {
Batch.startBatchCheck = function () {
if (Batch.currentOperation === "delete") {
LRR.showPopUp({
text: "Are you sure you want to delete the selected archives?",
text: "您确定要删除选定的档案吗?",
icon: "warning",
showCancelButton: true,
focusConfirm: false,
confirmButtonText: "Yes, delete it!",
confirmButtonText: "是的,删除!",
reverseButtons: true,
confirmButtonColor: "#d33",
}).then((result) => {
@ -121,7 +121,7 @@ Batch.startBatchCheck = function () {
Batch.startBatch = function () {
$(".tag-options").hide();
$("#log-container").html("Started Batch Operation...\n************\n");
$("#log-container").html("开始批量获取标签操作...\n************\n");
$("#cancel-job").show();
$("#restart-job").hide();
$(".job-status").show();
@ -188,7 +188,7 @@ Batch.startBatch = function () {
}
if (timeout !== 0) {
$("#log-container").append(`Sleeping for ${timeout} seconds.\n`);
$("#log-container").append(`休眠 ${timeout}.\n`);
}
// Wait timeout and pass next archive
setTimeout(() => {
@ -212,32 +212,32 @@ Batch.updateBatchStatus = function (event) {
const msg = JSON.parse(event.data);
if (msg.success === 0) {
$("#log-container").append(`Error while processing ID ${msg.id} (${msg.message})\n\n`);
$("#log-container").append(`处理 ID ${msg.id} (${msg.message})时发生插件错误\n\n`);
} else {
switch (Batch.currentOperation) {
case "plugin":
$("#log-container").append(`Processed ID ${msg.id} with "${Batch.currentPlugin}" (Added tags: ${msg.tags})\n\n`);
$("#log-container").append(`处理 ID ${msg.id} "${Batch.currentPlugin}" (添加标签: ${msg.tags})\n\n`);
break;
case "delete":
$("#log-container").append(`Deleted ID ${msg.id} (Filename: ${msg.filename})\n\n`);
$("#log-container").append(`删除 ID ${msg.id} (文件名: ${msg.filename})\n\n`);
break;
case "tagrules":
$("#log-container").append(`Replaced tags for ID ${msg.id} (New tags: ${msg.tags})\n\n`);
$("#log-container").append(`修改 ID ${msg.id} (新标签: ${msg.tags})\n\n`);
break;
case "addcat":
// Append the message at the end of this log,
// as it can contain the warning about the ID already being in the category
$("#log-container").append(`Added ID ${msg.id} to category ${msg.category}! ${msg.message} \n\n`);
$("#log-container").append(`已添加 ID ${msg.id} 到分类 ${msg.category}! ${msg.message} \n\n`);
break;
case "clearnew": {
$("#log-container").append(`Cleared new flag for ID ${msg.id}\n\n`);
$("#log-container").append(`清除了NEW标志 ID ${msg.id}\n\n`);
// Remove last character from matching row
const t = $(`#${msg.id}`).next().text().replace("🆕", "");
$(`#${msg.id}`).next().text(t);
break;
}
default:
$("#log-container").append(`Unknown operation ${Batch.currentOperation} (${msg.message})\n\n`);
$("#log-container").append(`未知操作 ${Batch.currentOperation} (${msg.message})\n\n`);
break;
}
@ -245,7 +245,7 @@ Batch.updateBatchStatus = function (event) {
$(`#${msg.id}`)[0].checked = false;
if (msg.title !== undefined && msg.title !== "") {
$("#log-container").append(`Changed title to: ${msg.title}\n`);
$("#log-container").append(`修改标题为: ${msg.title}\n`);
}
}
@ -263,12 +263,12 @@ Batch.updateBatchStatus = function (event) {
* Handle websocket errors.
*/
Batch.batchError = function () {
$("#log-container").append("************\nError! Terminating session.\n");
$("#log-container").append("************\n错误! 终止会话。\n");
Batch.scrollLogs();
LRR.toast({
heading: "An error occured during batch tagging!",
text: "Please check application logs.",
heading: "在批量添加标签时出错",
text: "请检查错误日志.",
icon: "error",
hideAfter: false,
});
@ -287,17 +287,17 @@ Batch.endBatch = function (event) {
Batch.scrollLogs();
LRR.toast({
heading: "Batch Operation complete!",
heading: "批量添加标签完成!",
icon: status,
});
// Delete the search cache after a finished session
Server.callAPI("api/search/cache", "DELETE", null, "Error while deleting cache! Check Logs.", null);
Server.callAPI("api/search/cache", "DELETE", null, "删除缓存时出错! 请检查日志。", null);
$("#cancel-job").hide();
if (Batch.currentOperation === "delete") {
$("#log-container").append("Reloading page in 5 seconds to account for deleted archives...\n");
$("#log-container").append("已删除该档案,将在 5 秒内重新加载页面...\n");
setTimeout(() => { window.location.reload(); }, 5000);
} else {
$("#restart-job").show();

View File

@ -22,9 +22,9 @@ Category.initializeAll = function () {
Category.addNewCategory = function (isDynamic) {
LRR.showPopUp({
title: "Enter a name for the new category",
title: "输入一个分类的名称",
input: "text",
inputPlaceholder: "My Category",
inputPlaceholder: "我的分类",
inputAttributes: {
autocapitalize: "off",
},
@ -32,7 +32,7 @@ Category.addNewCategory = function (isDynamic) {
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return "Please enter a category name.";
return "请输入一个分类的名称.";
}
return undefined;
},
@ -42,7 +42,7 @@ Category.addNewCategory = function (isDynamic) {
const searchtag = isDynamic ? "language:english" : "";
// Make an API request to create category, search is empty -> static, otherwise dynamic
Server.callAPI(`/api/categories?name=${result.value}&search=${searchtag}`, "PUT", `Category "${result.value}" created!`, "Error creating category:",
Server.callAPI(`/api/categories?name=${result.value}&search=${searchtag}`, "PUT", `分类 "${result.value}" 已创建!`, "创建分类出错:",
(data) => {
// Reload categories and select the newly created ID
Category.loadCategories(data.category_id);
@ -63,7 +63,7 @@ Category.loadCategories = function (selectedID) {
const catCombobox = document.getElementById("category");
catCombobox.options.length = 0;
// Add default
catCombobox.options[catCombobox.options.length] = new Option("-- No Category --", "", true, false);
catCombobox.options[catCombobox.options.length] = new Option("-- 无分类 --", "", true, false);
// Add categories, select if the ID matches the optional argument
data.forEach((c) => {
@ -73,7 +73,7 @@ Category.loadCategories = function (selectedID) {
// Update form with selected category details
Category.updateCategoryDetails();
})
.catch((error) => LRR.showErrorToast("Error getting categories from server", error));
.catch((error) => LRR.showErrorToast("从服务器获取分类出错", error));
};
Category.updateCategoryDetails = function () {
@ -139,7 +139,7 @@ Category.saveCurrentCategoryDetails = function () {
Category.indicateSaving();
// PUT update with name and search (search is empty if this is a static category)
Server.callAPI(`/api/categories/${categoryID}?name=${catName}&search=${searchtag}&pinned=${pinned}`, "PUT", null, "Error updating category:",
Server.callAPI(`/api/categories/${categoryID}?name=${catName}&search=${searchtag}&pinned=${pinned}`, "PUT", null, "更新分类时出错:",
(data) => {
// Reload categories and select the newly created ID
Category.indicateSaved();
@ -152,7 +152,7 @@ Category.updateArchiveInCategory = function (id, checked) {
const categoryID = document.getElementById("category").value;
Category.indicateSaving();
// PUT/DELETE api/categories/catID/archiveID
Server.callAPI(`/api/categories/${categoryID}/${id}`, checked ? "PUT" : "DELETE", null, "Error adding/removing archive to category",
Server.callAPI(`/api/categories/${categoryID}/${id}`, checked ? "PUT" : "DELETE", null, "添加/移除文件到分类时出错",
() => {
// Reload categories and select the archive list properly
Category.indicateSaved();
@ -164,16 +164,16 @@ Category.updateArchiveInCategory = function (id, checked) {
Category.deleteSelectedCategory = function () {
const categoryID = document.getElementById("category").value;
LRR.showPopUp({
text: "The category will be deleted permanently.",
text: "该类别将被永久删除.",
icon: "warning",
showCancelButton: true,
focusConfirm: false,
confirmButtonText: "Yes, delete it!",
confirmButtonText: "是的,删除!",
reverseButtons: true,
confirmButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
Server.callAPI(`/api/categories/${categoryID}`, "DELETE", "Category deleted!", "Error deleting category",
Server.callAPI(`/api/categories/${categoryID}`, "DELETE", "分类已删除!", "删除分类出错",
() => {
// Reload categories to show the archive list properly
Category.loadCategories();
@ -184,18 +184,18 @@ Category.deleteSelectedCategory = function () {
};
Category.indicateSaving = function () {
document.getElementById("status").innerHTML = "<i class=\"fas fa-spin fa-2x fa-compact-disc\"></i> Saving your modifications...";
document.getElementById("status").innerHTML = "<i class=\"fas fa-spin fa-2x fa-compact-disc\"></i> 保存您的修改中...";
};
Category.indicateSaved = function () {
document.getElementById("status").innerHTML = "<i class=\"fas fa-2x fa-check-circle\"></i> Saved!";
document.getElementById("status").innerHTML = "<i class=\"fas fa-2x fa-check-circle\"></i> 已保存!";
};
Category.predicateHelp = function () {
LRR.toast({
toastId: "predicateHelp",
heading: "Writing a Predicate",
text: "Predicates follow the same syntax as searches in the Archive Index. Check the <a href=\"https://sugoi.gitbook.io/lanraragi/basic-operations/searching\">Documentation</a> for more information.",
heading: "填入关键词",
text: "关键词遵循与“存档索引”中的搜索相同的语法。参考 <a href=\"https://sugoi.gitbook.io/lanraragi/basic-operations/searching\">此文件</a> 获取更多信息.",
icon: "info",
hideAfter: 20000,
});

View File

@ -42,7 +42,7 @@ Config.initializeAll = function () {
Config.rebootShinobu = function () {
$("#restart-button").prop("disabled", true);
Server.callAPI("/api/shinobu/restart", "POST", "Background Worker restarted!", "Error while restarting Worker:",
Server.callAPI("/api/shinobu/restart", "POST", "后台工作已重启!", "重启后台工作失败:",
() => {
$("#restart-button").prop("disabled", false);
Config.shinobuStatus();
@ -52,7 +52,7 @@ Config.rebootShinobu = function () {
Config.rescanContentFolder = function () {
$("#rescan-button").prop("disabled", true);
Server.callAPI("/api/shinobu/rescan", "POST", "Content folder rescan started!", "Error while restarting Worker:",
Server.callAPI("/api/shinobu/rescan", "POST", "开始重新扫描内容文件夹!", "重启工作时出错:",
() => {
$("#rescan-button").prop("disabled", false);
Config.shinobuStatus();
@ -62,7 +62,7 @@ Config.rescanContentFolder = function () {
// Update the status of the background worker.
Config.shinobuStatus = function () {
Server.callAPI("/api/shinobu", "GET", null, "Error while querying Shinobu status:",
Server.callAPI("/api/shinobu", "GET", null, "查询 Shinobu 状态时出错:",
(data) => {
if (data.is_alive) {
$("#shinobu-ok").show();

View File

@ -22,7 +22,7 @@ Edit.initializeAll = function () {
// Hide tag input while statistics load
Edit.hideTags();
Server.callAPI("/api/database/stats?minweight=2", "GET", null, "Couldn't load tag statistics",
Server.callAPI("/api/database/stats?minweight=2", "GET", null, "无法加载Tags统计信息",
(data) => {
Edit.suggestions = data.reduce((res, tag) => {
let label = tag.text;
@ -74,8 +74,8 @@ Edit.focusTagInput = function () {
Edit.showHelp = function () {
LRR.toast({
toastId: "pluginHelp",
heading: "About Plugins",
text: "You can use plugins to automatically fetch metadata for this archive. <br/> Just select a plugin from the dropdown and hit Go! <br/> Some plugins might provide an optional argument for you to specify. If that's the case, a textbox will be available to input said argument.",
heading: "关于插件",
text: "您可以使用插件自动获取此存档的元数据。 <br/> 只需从下拉菜单中选择一个插件即可点击! <br/> 一些插件可能会提供可选的参数供您指定。如果是这样,将提供一个文本框来输入所述参数。",
icon: "info",
hideAfter: 33000,
});
@ -106,18 +106,18 @@ Edit.saveMetadata = function () {
formData.append("title", $("#title").val());
return fetch(`api/archives/${id}/metadata`, { method: "PUT", body: formData })
.then((response) => (response.ok ? response.json() : { success: 0, error: "Response was not OK" }))
.then((response) => (response.ok ? response.json() : { success: 0, error: "反应不好" }))
.then((data) => {
if (data.success) {
LRR.toast({
heading: "Metadata saved!",
heading: "元数据保存了!",
icon: "success",
});
} else {
throw new Error(data.message);
}
})
.catch((error) => LRR.showErrorToast("Error while saving archive data :", error))
.catch((error) => LRR.showErrorToast("保存存档数据时错误:", error))
.finally(() => {
Edit.showTags();
});
@ -125,11 +125,11 @@ Edit.saveMetadata = function () {
Edit.deleteArchive = function () {
LRR.showPopUp({
text: "Are you sure you want to delete this archive?",
text: "您确定要删除此档案吗?",
icon: "warning",
showCancelButton: true,
focusConfirm: false,
confirmButtonText: "Yes, delete it!",
confirmButtonText: "是的,删除它!",
reverseButtons: true,
confirmButtonColor: "#d33",
}).then((result) => {
@ -145,12 +145,12 @@ Edit.getTags = function () {
const pluginID = $("select#plugin option:checked").val();
const archivID = $("#archiveID").val();
const pluginArg = $("#arg").val();
Server.callAPI(`../api/plugins/use?plugin=${pluginID}&id=${archivID}&arg=${pluginArg}`, "POST", null, "Error while fetching tags :",
Server.callAPI(`../api/plugins/use?plugin=${pluginID}&id=${archivID}&arg=${pluginArg}`, "POST", null, "获取标签时错误 :",
(result) => {
if (result.data.title && result.data.title !== "") {
$("#title").val(result.data.title);
LRR.toast({
heading: "Archive title changed to :",
heading: "存档标题更改为 :",
text: result.data.title,
icon: "info",
});
@ -163,14 +163,14 @@ Edit.getTags = function () {
});
LRR.toast({
heading: "Added the following tags :",
heading: "添加了以下标签 :",
text: result.data.new_tags,
icon: "info",
hideAfter: 7000,
});
} else {
LRR.toast({
heading: "No new tags added!",
heading: "没有添加新标签!",
text: result.data.new_tags,
icon: "info",
});

View File

@ -74,10 +74,10 @@ Index.initializeAll = function () {
Index.updateCarousel();
},
items: {
random: { name: "Randomly Picked", icon: "fas fa-random" },
inbox: { name: "New Archives", icon: "fas fa-envelope-open-text" },
untagged: { name: "Untagged Archives", icon: "fas fa-edit" },
// ondeck: { name: "On Deck", icon: "fas fa-book-reader" },
random: { name: "随机", icon: "fas fa-random" },
inbox: { name: "新档案", icon: "fas fa-envelope-open-text" },
untagged: { name: "无标签档案", icon: "fas fa-edit" },
// ondeck: { name: "列表", icon: "fas fa-book-reader" },
},
}),
});
@ -87,15 +87,15 @@ Index.initializeAll = function () {
localStorage.sawContextMenuToast = true;
LRR.toast({
heading: `Welcome to LANraragi ${Index.serverVersion}!`,
text: "If you want to perform advanced operations on an archive, remember to just right-click its name. Happy reading!",
heading: `欢迎使用 LANraragi ${Index.serverVersion}!`,
text: "如果要对存档执行高级操作,请记住只需右键单击其名称。 祝您阅读愉快!",
icon: "info",
hideAfter: 13000,
});
}
// Get some info from the server: version, debug mode, local progress
Server.callAPI("/api/info", "GET", null, "Error getting basic server info!",
Server.callAPI("/api/info", "GET", null, "获取服务器基础信息时出错!",
(data) => {
Index.serverVersion = data.version;
Index.debugMode = data.debug_mode === "1";
@ -108,8 +108,8 @@ Index.initializeAll = function () {
Index.fetchChangelog();
} else {
LRR.toast({
heading: "<i class=\"fas fa-bug\"></i> You're running in Debug Mode!",
text: "Advanced server statistics can be viewed <a href=\"./debug\">here.</a>",
heading: "<i class=\"fas fa-bug\"></i> 您正在调试模式下运行!",
text: "可以在<a href=\"./debug\">此处.</a>查看高级服务器统计信息",
icon: "warning",
});
}
@ -221,11 +221,11 @@ Index.toggleCategory = function (button) {
*/
Index.promptCustomColumn = function (column) {
LRR.showPopUp({
title: "Enter a tag namespace for this column",
text: "Enter a full namespace without the colon, e.g \"artist\".\nIf you have multiple tags with the same namespace, only the last one will be shown in the column.",
title: "输入要在此列中显示的标签的命名空间",
text: "输入不带冒号的完整命名空间, 例如 \"artist\".\n如果您有多个具有相同命名空间的标签则该列中只会显示最后一个.",
input: "text",
inputValue: localStorage.getItem(`customColumn${column}`),
inputPlaceholder: "Tag namespace",
inputPlaceholder: "标签名称空间",
inputAttributes: {
autocapitalize: "off",
},
@ -233,7 +233,7 @@ Index.promptCustomColumn = function (column) {
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return "Please enter a namespace.";
return "请输入一个命名空间.";
}
return undefined;
},
@ -322,28 +322,28 @@ Index.updateCarousel = function (e) {
switch (localStorage.carouselType) {
case "random":
$("#carousel-icon")[0].classList = "fas fa-random";
$("#carousel-title").text("Randomly Picked");
$("#carousel-title").text("随机");
endpoint = `/api/search/random?filter=${IndexTable.currentSearch}&category=${Index.selectedCategory}&count=15`;
break;
case "inbox":
$("#carousel-icon")[0].classList = "fas fa-envelope-open-text";
$("#carousel-title").text("New Archives");
$("#carousel-title").text("新档案");
endpoint = `/api/search?filter=${IndexTable.currentSearch}&category=${Index.selectedCategory}&newonly=true&sortby=date_added&order=desc&start=-1`;
break;
case "untagged":
$("#carousel-icon")[0].classList = "fas fa-edit";
$("#carousel-title").text("Untagged Archives");
$("#carousel-title").text("无标签档案");
endpoint = `/api/search?filter=${IndexTable.currentSearch}&category=${Index.selectedCategory}&untaggedonly=true&sortby=date_added&order=desc&start=-1`;
break;
default:
$("#carousel-icon")[0].classList = "fas fa-pastafarianism";
$("#carousel-title").text("What???");
$("#carousel-title").text("未定义");
endpoint = `/api/search?filter=${IndexTable.currentSearch}&category=${Index.selectedCategory}`;
break;
}
if (Index.carouselInitialized) {
Server.callAPI(endpoint, "GET", null, "Error getting carousel data!",
Server.callAPI(endpoint, "GET", null, "获取轮播数据时出错!",
(results) => {
Index.swiper.virtual.removeAllSlides();
const slides = results.data
@ -411,8 +411,8 @@ Index.checkVersion = function () {
if (latestVersion > currentVersion) {
LRR.toast({
heading: `A new version of LANraragi (${data.tag_name}) is available !`,
text: `<a href="${data.html_url}">Click here to check it out.</a>`,
heading: `新的 LANraragi (${data.tag_name}) 可用 !`,
text: `<a href="${data.html_url}">点击此处查看.</a>`,
icon: "info",
closeOnClick: false,
draggable: false,
@ -421,7 +421,7 @@ Index.checkVersion = function () {
}
})
// eslint-disable-next-line no-console
.catch((error) => console.log("Error checking latest version.", error));
.catch((error) => console.log("检查最新版本时出错.", error));
};
/**
@ -432,7 +432,7 @@ Index.fetchChangelog = function () {
localStorage.lrrVersion = Index.serverVersion;
fetch("https://api.github.com/repos/difegue/lanraragi/releases/latest", { method: "GET" })
.then((response) => (response.ok ? response.json() : { error: "Response was not OK" }))
.then((response) => (response.ok ? response.json() : { error: "响应不正确" }))
.then((data) => {
if (data.error) throw new Error(data.error);
@ -453,7 +453,7 @@ Index.fetchChangelog = function () {
$("#updateOverlay").css("display", "block");
});
})
.catch((error) => { LRR.showErrorToast("Error getting changelog for new version", error); });
.catch((error) => { LRR.showErrorToast("获取新版本的变更日志时出错", error); });
}
};
@ -463,7 +463,7 @@ Index.fetchChangelog = function () {
* @returns Categories
*/
Index.loadContextMenuCategories = function (id) {
return Server.callAPI(`/api/archives/${id}/categories`, "GET", null, `Error finding categories for ${id}!`,
return Server.callAPI(`/api/archives/${id}/categories`, "GET", null, `查找以下类别出现错误 ${id}!`,
(data) => {
const items = {};
@ -473,7 +473,7 @@ Index.loadContextMenuCategories = function (id) {
}
if (Object.keys(items).length === 0) {
items.noop = { name: "This archive isn't in any category.", icon: "far fa-sad-cry" };
items.noop = { name: "该档案不存在于任何分类。", icon: "far fa-sad-cry" };
}
return items;
@ -506,11 +506,11 @@ Index.handleContextMenu = function (option, id) {
break;
case "delete":
LRR.showPopUp({
text: "Are you sure you want to delete this archive?",
text: "你确定删除该档案吗?",
icon: "warning",
showCancelButton: true,
focusConfirm: false,
confirmButtonText: "Yes, delete it!",
confirmButtonText: "是的,删除!",
reverseButtons: true,
confirmButtonColor: "#d33",
}).then((result) => {
@ -535,7 +535,7 @@ Index.handleContextMenu = function (option, id) {
*/
Index.loadTagSuggestions = function () {
// Query the tag cloud API to get the most used tags.
Server.callAPI("/api/database/stats?minweight=2", "GET", null, "Couldn't load tag suggestions",
Server.callAPI("/api/database/stats?minweight=2", "GET", null, "无法加载标签建议",
(data) => {
// Get namespaces objects in the data array to fill the namespace-sortby combobox
const namespacesSet = new Set(data.map((element) => (element.namespace === "parody" ? "series" : element.namespace)));
@ -578,7 +578,7 @@ Index.loadTagSuggestions = function () {
* Query the category API to build the filter buttons.
*/
Index.loadCategories = function () {
Server.callAPI("/api/categories", "GET", null, "Couldn't load categories",
Server.callAPI("/api/categories", "GET", null, "无法加载分类",
(data) => {
// Sort by LastUsed + pinned
// Pinned categories are shown at the beginning
@ -598,7 +598,7 @@ Index.loadCategories = function () {
const div = `<div style='display:inline-block'>
<input class='favtag-btn ${((category.id === Index.selectedCategory) ? "toggled" : "")}'
type='button' id='${category.id}' value='${catName}'
onclick='Index.toggleCategory(this)' title='Click here to display the archives contained in this category.'/>
onclick='Index.toggleCategory(this)' title='单击此处显示此类别中包含的档案.'/>
</div>`;
html += div;
@ -639,8 +639,8 @@ Index.migrateProgress = function () {
const localProgressKeys = Object.keys(localStorage).filter((x) => x.endsWith("-reader")).map((x) => x.slice(0, -7));
if (localProgressKeys.length > 0) {
LRR.toast({
heading: "Your Reading Progression is now saved on the server!",
text: "You seem to have some local progression hanging around -- Please wait warmly while we migrate it to the server for you. ☕",
heading: "您的阅读进度现已保存在服务器上!",
text: "您似乎有一些本地进度未上传 -- 我们正在为您将其迁移到服务器,请耐心等待。 ☕",
icon: "info",
hideAfter: 23000,
});
@ -657,7 +657,7 @@ Index.migrateProgress = function () {
&& data !== undefined
&& data !== null
&& progress > data.progress) {
Server.callAPI(`api/archives/${id}/progress/${progress}?force=1`, "PUT", null, "Error updating reading progress!", null);
Server.callAPI(`api/archives/${id}/progress/${progress}?force=1`, "PUT", null, "更新阅读进度时出错!", null);
}
// Clear out localStorage'd progress
@ -667,14 +667,14 @@ Index.migrateProgress = function () {
});
Promise.all(promises).then(() => LRR.toast({
heading: "Reading Progression has been fully migrated! 🎉",
text: "You'll have to reopen archives in the Reader to see the migrated progression values.",
heading: "阅读进度已完全迁移! 🎉",
text: "您需要在阅读器中重新打开档案以查看已迁移的进度值",
icon: "success",
hideAfter: 13000,
}));
} else {
// eslint-disable-next-line no-console
console.log("No local reading progression to migrate");
console.log("没有本地阅读进度可迁移");
}
};

View File

@ -57,8 +57,8 @@ IndexTable.initializeAll = function () {
order: [[0, "asc"]],
dom: "<\"top\"ip>rt<\"bottom\"p><\"clear\">",
language: {
info: "Showing _START_ to _END_ of _TOTAL_ ancient chinese lithographies.",
infoEmpty: "<h1><br/><i class=\"fas fa-4x fa-toilet-paper-slash\"></i><br/><br/>No archives to show you! Try <a href=\"upload\">uploading some</a>?</h1><br/>",
info: "展示 _START_ 到 _END_ 共 _TOTAL_ 作品.",
infoEmpty: "<h1><br/><i class=\"fas fa-4x fa-toilet-paper-slash\"></i><br/><br/>当前没有档案! 试试 <a href=\"upload\">上传一些</a>?</h1><br/>",
processing: "<div id=\"progress\" class=\"indeterminate\"\"><div class=\"bar-container\"><div class=\"bar\" style=\" width: 80%; \"></div></div></div>",
},
preDrawCallback: IndexTable.initializeThumbView, // callbacks for thumbnail view

View File

@ -28,7 +28,7 @@ Logs.showLog = function (type) {
$("#log-container").scrollTop($("#log-container").prop("scrollHeight"));
Logs.lastType = type;
})
.catch((error) => LRR.showErrorToast("Error getting logs from server", error));
.catch((error) => LRR.showErrorToast("从服务器获取日志时出错", error));
};
Logs.refreshLog = function () {

View File

@ -15,14 +15,14 @@ Plugins.initializeAll = function () {
done(e, data) {
if (data.result.success) {
LRR.toast({
heading: "Plugin successfully uploaded!",
text: `The plugin "${data.result.name}" has been successfully added. Refresh the page to see it.`,
heading: "插件上传成功!",
text: `该插件 "${data.result.name}" 已添加成功. 刷新页面即可查看.`,
icon: "info",
hideAfter: 10000,
});
} else {
LRR.toast({
heading: "Error uploading plugin",
heading: "上传插件出错",
text: data.result.error,
icon: "error",
hideAfter: false,

View File

@ -43,7 +43,39 @@ Reader.initializeAll = function () {
window.location.href = `./reader?id=${Reader.id}&force_reload`;
});
$(document).on("click.edit-metadata", "#edit-archive", () => LRR.openInNewTab(`./edit?id=${Reader.id}`));
$(document).on("click.add-category", "#add-category", () => Server.addArchiveToCategory(Reader.id, $("#category").val()));
$(document).on("click.delete-archive", "#delete-archive", () => {
LRR.closeOverlay();
LRR.showPopUp({
text: "Are you sure you want to delete this archive?",
icon: "warning",
showCancelButton: true,
focusConfirm: false,
confirmButtonText: "Yes, delete it!",
reverseButtons: true,
confirmButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
Server.deleteArchive(Reader.id, () => { document.location.href = "./"; });
}
});
});
$(document).on("click.add-category", "#add-category", () => {
if ($("#category").val() === "" || $(`#archive-categories a[data-id="${$("#category").val()}"]`).length !== 0) { return; }
Server.addArchiveToCategory(Reader.id, $("#category").val());
const html = `<div class="gt" style="font-size:14px; padding:4px">
<a href="/?c=${$("#category").val()}">
<span class="label">${$("#category option:selected").text()}</span>
<a href="#" class="remove-category" data-id="${$("#category").val()}"
style="margin-left:4px; margin-right:2px">×</a>
</a>`;
$("#archive-categories").append(html);
});
$(document).on("click.remove-category", ".remove-category", (e) => {
Server.removeArchiveFromCategory(Reader.id, $(e.target).attr("data-id"));
$(e.target).parent().remove();
});
$(document).on("click.set-thumbnail", "#set-thumbnail", () => Server.callAPI(`/api/archives/${Reader.id}/thumbnail?page=${Reader.currentPage + 1}`,
"PUT", `Successfully set page ${Reader.currentPage + 1} as the thumbnail!`, "Error updating thumbnail!", null));
@ -70,10 +102,10 @@ Reader.initializeAll = function () {
Reader.currentPage = (+params.get("p") || 1) - 1;
// Remove the "new" tag with an api call
Server.callAPI(`/api/archives/${Reader.id}/isnew`, "DELETE", null, "Error clearing new flag! Check Logs.", null);
Server.callAPI(`/api/archives/${Reader.id}/isnew`, "DELETE", null, "清除NEW标签时出错 请检查日志.", null);
// Get basic metadata
Server.callAPI(`/api/archives/${Reader.id}/metadata`, "GET", null, "Error getting basic archive info!",
Server.callAPI(`/api/archives/${Reader.id}/metadata`, "GET", null, "获取存档基本信息时出错!",
(data) => {
let { title } = data;
@ -84,6 +116,7 @@ Reader.initializeAll = function () {
}
$("#archive-title").html(title);
$("#archive-title-overlay").html(title);
if (data.pagecount) { $(".max-page").html(data.pagecount); }
document.title = title;
@ -107,7 +140,7 @@ Reader.initializeAll = function () {
};
Reader.loadImages = function () {
Server.callAPI(`/api/archives/${Reader.id}/files?force=${Reader.force}`, "GET", null, "Error getting the archive's imagelist!",
Server.callAPI(`/api/archives/${Reader.id}/files?force=${Reader.force}`, "GET", null, "获取存档的图像列表时出错!",
(data) => {
Reader.pages = data.pages;
Reader.maxPage = Reader.pages.length - 1;
@ -154,13 +187,13 @@ Reader.loadImages = function () {
data.job,
false,
() => Reader.initializeArchiveOverlay(),
() => LRR.showErrorToast("The extraction job didn't conclude properly. Your archive might be corrupted."),
() => LRR.showErrorToast("提取未成功. 档案可能损坏."),
);
},
).finally(() => {
if (Reader.pages === undefined) {
$("#img").attr("src", "img/flubbed.gif");
$("#display").append("<h2>I flubbed it while trying to open the archive.</h2>");
$("#display").append("<h2>我在尝试打开存档时搞砸了.</h2>");
}
});
};
@ -342,16 +375,16 @@ Reader.checkFiletypeSupport = function (extension) {
if ((extension === "rar" || extension === "cbr") && !localStorage.rarWarningShown) {
localStorage.rarWarningShown = true;
LRR.toast({
heading: "This archive seems to be in RAR format!",
text: "RAR archives might not work properly in LANraragi depending on how they were made. If you encounter errors while reading, consider converting your archive to zip.",
heading: "这个存档似乎是 RAR 格式!",
text: "RAR 档案在 LANraragi 中可能无法正常工作,具体取决于它们的制作方式。 如果您在阅读时遇到错误,请考虑将您的存档转换为 zip。",
icon: "warning",
hideAfter: 23000,
});
} else if (extension === "epub" && !localStorage.epubWarningShown) {
localStorage.epubWarningShown = true;
LRR.toast({
heading: "EPUB support in LANraragi is minimal",
text: "EPUB books will only show images in the Web Reader. If you want text support, consider pairing LANraragi with an <a href='https://sugoi.gitbook.io/lanraragi/advanced-usage/external-readers#generic-opds-readers'>OPDS reader.</a>",
heading: "LANraragi对EPUB的支持很基础",
text: "EPUB 图书将仅在网络阅读器中显示图像。 如果您需要文本支持,请考虑将 LANraragi 与 <a href='https://sugoi.gitbook.io/lanraragi/advanced-usage/external-readers#generic-opds-readers'>OPDS阅读器搭配使用.</a>",
icon: "warning",
hideAfter: 20000,
closeOnClick: false,
@ -363,7 +396,7 @@ Reader.checkFiletypeSupport = function (extension) {
Reader.toggleHelp = function () {
LRR.toast({
toastId: "readerHelp",
heading: "Navigation Help",
heading: "导航帮助",
text: $("#reader-help").children().first().html(),
icon: "info",
hideAfter: 60000,
@ -437,7 +470,7 @@ Reader.goToPage = function (page) {
Reader.showingSinglePage = false;
if (Reader.infiniteScroll) {
$("#display img").get(page).scrollIntoView({ behavior: "smooth" });
$("#display img").get(Reader.currentPage).scrollIntoView({ behavior: "smooth" });
} else {
$("#img_doublepage").attr("src", "");
$("#display").removeClass("double-mode");
@ -492,7 +525,7 @@ Reader.updateProgress = function () {
if (Reader.trackProgressLocally) {
localStorage.setItem(`${Reader.id}-reader`, Reader.currentPage + 1);
} else {
Server.callAPI(`api/archives/${Reader.id}/progress/${Reader.currentPage + 1}`, "PUT", null, "Error updating reading progress!", null);
Server.callAPI(`api/archives/${Reader.id}/progress/${Reader.currentPage + 1}`, "PUT", null, "更新阅读进度时出错!", null);
}
};
@ -680,7 +713,7 @@ Reader.initializeArchiveOverlay = function () {
const thumbCss = (localStorage.cropthumbs === "true") ? "id3" : "id3 nocrop";
const thumbnail = `
<div class='${thumbCss} quick-thumbnail' page='${index}' style='display: inline-block; cursor: pointer'>
<span class='page-number'>Page ${page}</span>
<span class='page-number'>页面 ${page}</span>
<img src="./img/wait_warmly.jpg" id="${index}_thumb" />
<i id="${index}_spinner" class="fa fa-4x fa-circle-notch fa-spin ttspinner" style="display:flex;justify-content: center; align-items: center;"></i>
</div>`;

View File

@ -17,7 +17,7 @@ Server.isScriptRunning = false;
*/
Server.callAPI = function (endpoint, method, successMessage, errorMessage, successCallback) {
return fetch(endpoint, { method })
.then((response) => (response.ok ? response.json() : { success: 0, error: "Response was not OK" }))
.then((response) => (response.ok ? response.json() : { success: 0, error: "响应不正确" }))
.then((data) => {
if (Object.prototype.hasOwnProperty.call(data, "success") && !data.success) {
throw new Error(data.error);
@ -52,7 +52,7 @@ Server.callAPI = function (endpoint, method, successMessage, errorMessage, succe
*/
Server.checkJobStatus = function (jobId, useDetail, callback, failureCallback) {
fetch(useDetail ? `/api/minion/${jobId}/detail` : `/api/minion/${jobId}`, { method: "GET" })
.then((response) => (response.ok ? response.json() : { success: 0, error: "Response was not OK" }))
.then((response) => (response.ok ? response.json() : { success: 0, error: "响应不正确" }))
.then((data) => {
if (data.error) throw new Error(data.error);
@ -70,7 +70,7 @@ Server.checkJobStatus = function (jobId, useDetail, callback, failureCallback) {
callback(data);
}
})
.catch((error) => { LRR.showErrorToast("Error checking Minion job status", error); failureCallback(error); });
.catch((error) => { LRR.showErrorToast("检查Minion工作状态时出错", error); failureCallback(error); });
};
/**
@ -83,25 +83,25 @@ Server.saveFormData = function (formSelector) {
const postData = new FormData($(formSelector)[0]);
return fetch(window.location.href, { method: "POST", body: postData })
.then((response) => (response.ok ? response.json() : { success: 0, error: "Response was not OK" }))
.then((response) => (response.ok ? response.json() : { success: 0, error: "响应不正确" }))
.then((data) => {
if (data.success) {
LRR.toast({
heading: "Saved Successfully!",
heading: "保存成功!",
icon: "success",
});
} else {
throw new Error(data.message);
}
})
.catch((error) => LRR.showErrorToast("Error while saving", error));
.catch((error) => LRR.showErrorToast("保存出错", error));
};
Server.triggerScript = function (namespace) {
const scriptArg = $(`#${namespace}_ARG`).val();
if (Server.isScriptRunning) {
LRR.showErrorToast("A script is already running.", "Please wait for it to terminate.");
LRR.showErrorToast("一个脚本已在运行.", "请等待它终止.");
return;
}
@ -111,7 +111,7 @@ Server.triggerScript = function (namespace) {
// Save data before triggering script
Server.saveFormData("#editPluginForm")
.then(Server.callAPI(`/api/plugins/queue?plugin=${namespace}&arg=${scriptArg}`, "POST", null, "Error while executing Script :",
.then(Server.callAPI(`/api/plugins/queue?plugin=${namespace}&arg=${scriptArg}`, "POST", null, "执行脚本时出错 :",
(data) => {
// Check minion job state periodically while we're on this page
Server.checkJobStatus(
@ -124,7 +124,7 @@ Server.triggerScript = function (namespace) {
if (d.result.success === 1) {
LRR.toast({
heading: "Script result",
heading: "脚本效果",
text: `<pre>${JSON.stringify(d.result.data, null, 4)}</pre>`,
icon: "info",
hideAfter: 10000,
@ -144,7 +144,7 @@ Server.triggerScript = function (namespace) {
};
Server.cleanTemporaryFolder = function () {
Server.callAPI("/api/tempfolder", "DELETE", "Temporary Folder Cleaned!", "Error while cleaning Temporary Folder :",
Server.callAPI("/api/tempfolder", "DELETE", "临时文件夹已清理!", "清理临时文件夹时出错 :",
(data) => {
$("#tempsize").html(data.newsize);
},
@ -152,26 +152,26 @@ Server.cleanTemporaryFolder = function () {
};
Server.invalidateCache = function () {
Server.callAPI("/api/search/cache", "DELETE", "Threw away the Search Cache!", "Error while deleting cache! Check Logs.", null);
Server.callAPI("/api/search/cache", "DELETE", "丢弃搜索缓存!", "删除缓存时出错! 请检查日志.", null);
};
Server.clearAllNewFlags = function () {
Server.callAPI("/api/database/isnew", "DELETE", "All archives are no longer new!", "Error while clearing flags! Check Logs.", null);
Server.callAPI("/api/database/isnew", "DELETE", "所有档案都不再是新的!", "清理NEW标签时出错 请检查日志.", null);
};
Server.dropDatabase = function () {
LRR.showPopUp({
title: "This is a (very) destructive operation! ",
text: "Are you sure you want to wipe the database?",
title: "这是一个(非常)破坏性的操作! ",
text: "您确定要擦除数据库吗?",
icon: "warning",
showCancelButton: true,
focusConfirm: false,
confirmButtonText: "Yes, do it!",
confirmButtonText: "是的,这样做!",
reverseButtons: true,
confirmButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
Server.callAPI("/api/database/drop", "POST", "Sayonara! Redirecting you...", "Error while resetting the database? Check Logs.",
Server.callAPI("/api/database/drop", "POST", "再见! 重定向...", "重置数据库时出错? 请检查日志.",
() => {
setTimeout(() => { document.location.href = "./"; }, 1500);
},
@ -181,18 +181,18 @@ Server.dropDatabase = function () {
};
Server.cleanDatabase = function () {
Server.callAPI("/api/database/clean", "POST", null, "Error while cleaning the database! Check Logs.",
Server.callAPI("/api/database/clean", "POST", null, "清理数据库时出错! 请检查日志.",
(data) => {
LRR.toast({
heading: `Successfully cleaned the database and removed ${data.deleted} entries!`,
heading: `成功清理数据库并删除 ${data.deleted}!`,
icon: "success",
hideAfter: 7000,
});
if (data.unlinked > 0) {
LRR.toast({
heading: `${data.unlinked} other entries have been unlinked from the database and will be deleted on the next cleanup!`,
text: "Do a backup now if some files disappeared from your archive index.",
heading: `${data.unlinked} 其他条目已从数据库中取消链接,将在下次清理时删除!`,
text: "如果某些文件从存档索引中消失,请立即进行备份.",
icon: "warning",
hideAfter: 16000,
});
@ -204,8 +204,8 @@ Server.cleanDatabase = function () {
Server.regenerateThumbnails = function (force) {
const forceparam = force ? 1 : 0;
Server.callAPI(`/api/regen_thumbs?force=${forceparam}`, "POST",
"Queued up a job to regenerate thumbnails! Stay tuned for updates or check the Minion console.",
"Error while sending job to Minion:",
"正在排队处理重新生成缩略图工作! 请继续关注更新或检查 Minion 控制台.",
"向 Minion 发送作业时出错:",
(data) => {
// Disable the buttons to avoid accidental double-clicks.
$("#genthumb-button").prop("disabled", true);
@ -219,7 +219,7 @@ Server.regenerateThumbnails = function (force) {
$("#genthumb-button").prop("disabled", false);
$("#forcethumb-button").prop("disabled", false);
LRR.toast({
heading: "All thumbnails generated! Encountered the following errors:",
heading: "所有缩略图生成! 但遇到以下错误:",
text: d.result.errors,
icon: "success",
hideAfter: 15000,
@ -230,7 +230,7 @@ Server.regenerateThumbnails = function (force) {
(error) => {
$("#genthumb-button").prop("disabled", false);
$("#forcethumb-button").prop("disabled", false);
LRR.showErrorToast("The thumbnail regen job failed!", error);
LRR.showErrorToast("缩略图重建失败!", error);
},
);
},
@ -239,12 +239,12 @@ Server.regenerateThumbnails = function (force) {
// Adds an archive to a category. Basic implementation to use everywhere.
Server.addArchiveToCategory = function (arcId, catId) {
Server.callAPI(`/api/categories/${catId}/${arcId}`, "PUT", `Added ${arcId} to Category ${catId}!`, "Error adding/removing archive to category", null);
Server.callAPI(`/api/categories/${catId}/${arcId}`, "PUT", `添加 ${arcId}${catId}!`, "将档案添加/移除到类别时出错", null);
};
// Ditto, but for removing.
Server.removeArchiveFromCategory = function (arcId, catId) {
Server.callAPI(`/api/categories/${catId}/${arcId}`, "DELETE", `Removed ${arcId} from Category ${catId}!`, "Error adding/removing archive to category", null);
Server.callAPI(`/api/categories/${catId}/${arcId}`, "DELETE", `${catId}移除${arcId}!`, "将档案添加/移除到类别时出错", null);
};
/**
@ -255,12 +255,12 @@ Server.removeArchiveFromCategory = function (arcId, catId) {
*/
Server.deleteArchive = function (arcId, callback) {
fetch(`/api/archives/${arcId}`, { method: "DELETE" })
.then((response) => (response.ok ? response.json() : { success: 0, error: "Response was not OK" }))
.then((response) => (response.ok ? response.json() : { success: 0, error: "响应不正确" }))
.then((data) => {
if (data.success === "0") {
LRR.toast({
heading: "Couldn't delete archive file. <br> (Maybe it has already been deleted beforehand?)",
text: "Archive metadata has been deleted properly. <br> Please delete the file manually before returning to Library View.",
heading: "无法删除存档文件. <br> (或许已被删除?)",
text: "存档元数据已完整删除. <br> 请在返资源库之前手动删除文件.",
icon: "warning",
hideAfter: 20000,
});
@ -268,7 +268,7 @@ Server.deleteArchive = function (arcId, callback) {
$("#goback").show();
} else {
LRR.toast({
heading: "Archive successfully deleted. Redirecting you ...",
heading: "存档已成功删除,重定向 ...",
text: `File name : ${data.filename}`,
icon: "success",
hideAfter: 7000,
@ -276,5 +276,5 @@ Server.deleteArchive = function (arcId, callback) {
setTimeout(callback, 1500);
}
})
.catch((error) => LRR.showErrorToast("Error while deleting archive", error));
.catch((error) => LRR.showErrorToast("删除存档时出错", error));
};

View File

@ -7,7 +7,7 @@ Stats.initializeAll = function () {
// bind events to DOM
$(document).on("click.goback", "#goback", () => { window.location.replace("./"); });
Server.callAPI("/api/database/stats?minweight=2", "GET", null, "Couldn't load tag statistics",
Server.callAPI("/api/database/stats?minweight=2", "GET", null, "无法加载标签统计数据",
(data) => {
$("#statsLoading").hide();
$("#tagcount").html(data.length);

View File

@ -29,7 +29,7 @@ Upload.initializeAll = function () {
<a href="#" id="${data.result.job}-name" title="${data.result.name}">${data.result.name}</a>
</td>
<td><i id="${data.result.job}-icon" class='fa fa-spinner fa-spin' style='margin-left:20px; margin-right: 10px;'></i>
<a href="#" id="${data.result.job}-link">Processing file... (Job #${data.result.job})</a>
<a href="#" id="${data.result.job}-link">处理文件... (Job #${data.result.job})</a>
</td>
</tr>`;
}
@ -72,7 +72,7 @@ Upload.initializeAll = function () {
// Handle updating the upload counters.
Upload.updateUploadCounters = function () {
$("#progressCount").html(`🤔 Processing: ${processingArchives} 🙌 Completed: ${completedArchives} 👹 Failed: ${failedArchives}`);
$("#progressCount").html(`🤔 处理中: ${processingArchives} 🙌 完成: ${completedArchives} 👹 失败: ${failedArchives}`);
let icon;
if (completedArchives === totalUploads) {
@ -82,7 +82,7 @@ Upload.updateUploadCounters = function () {
} else {
icon = "fa fa-spinner fa-spin";
}
$("#progressTotal").html(`<i class="${icon}"></i> Total:${completedArchives + failedArchives}/${totalUploads}`);
$("#progressTotal").html(`<i class="${icon}"></i> 共计:${completedArchives + failedArchives}/${totalUploads}`);
// At the end of the upload job, dump the search cache!
if (processingArchives === 0) { Server.invalidateCache(); }
@ -99,11 +99,11 @@ Upload.handleCompletedUpload = function (jobID, d) {
}
if (d.result.success) {
$(`#${jobID}-link`).html(`Click here to edit metadata.<br>(${d.result.message})`);
$(`#${jobID}-link`).html(`点击此处编辑元数据.<br>(${d.result.message})`);
$(`#${jobID}-icon`).attr("class", "fa fa-check-circle");
completedArchives += 1;
} else {
$(`#${jobID}-link`).html(`Error while processing archive.<br>(${d.result.message})`);
$(`#${jobID}-link`).html(`处理档案时发生错误.<br>(${d.result.message})`);
$(`#${jobID}-icon`).attr("class", "fa fa-exclamation-circle");
failedArchives += 1;
}
@ -113,7 +113,7 @@ Upload.handleCompletedUpload = function (jobID, d) {
};
Upload.handleFailedUpload = function (jobID, d) {
$(`#${jobID}-link`).html(`Error while processing file.<br>(${d})`);
$(`#${jobID}-link`).html(`处理文件时出错.<br>(${d})`);
$(`#${jobID}-icon`).attr("class", "fa fa-exclamation-circle");
failedArchives += 1;
@ -147,7 +147,7 @@ Upload.downloadUrl = function () {
<a href="#" id="${data.job}-name" title="${data.url}">${data.url}</a>
</td>
<td><i id="${data.job}-icon" class='fa fa-spinner fa-spin' style='margin-left:20px; margin-right: 10px;'></i>
<a href="#" id="${data.job}-link">Downloading file... (Job #${data.job})</a>
<a href="#" id="${data.job}-link">下载文件... (Job #${data.job})</a>
</td>
</tr>`;
@ -168,7 +168,7 @@ Upload.downloadUrl = function () {
throw new Error(data.message);
}
})
.catch((error) => LRR.showErrorToast("Error while adding download job", error));
.catch((error) => LRR.showErrorToast("添加下载作业时出错", error));
});
};

View File

@ -544,22 +544,26 @@ div.id1 {
display: inline-block;
margin: 3px 2px 2px 3px;
padding-top: 3px;
height: 335px;
vertical-align: top;
min-height: 335px;
}
div.id2 {
height: 30px;
margin: auto;
overflow: hidden;
text-align: center;
vertical-align: middle;
line-height: 15px;
width: 97%;
}
div.id2 a {
font-weight: bold;
text-decoration: none;
overflow: hidden;
/* Multi-line title support */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
div.id3 {

View File

@ -545,22 +545,26 @@ div.id1 {
display: inline-block;
margin: 3px 2px 2px 3px;
padding-top: 3px;
height: 335px;
vertical-align: top;
min-height: 335px;
}
div.id2 {
height: 30px;
margin: auto;
overflow: hidden;
text-align: center;
vertical-align: middle;
line-height: 15px;
width: 97%;
}
div.id2 a {
font-weight: bold;
text-decoration: none;
overflow: hidden;
/* Multi-line title support */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
div.id3 {

View File

@ -538,23 +538,26 @@ div.id1 {
display: inline-block;
margin: 3px 2px 2px 3px;
padding-top: 3px;
height: 335px;
vertical-align: top;
min-height: 335px;
}
div.id2 {
height: 30px;
min-height: 32px;
margin: auto;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 97%;
}
div.id2 a {
font-weight: bold;
text-decoration: none;
overflow: hidden;
/* Multi-line title support */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
div.id3 {

View File

@ -651,20 +651,22 @@ div.id1 {
}
div.id2 {
height: 20px;
overflow: hidden;
min-height: 32px;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 97%;
}
div.id2 a {
font-weight: bold;
text-decoration: none;
overflow: hidden;
color: #FCFCFC;
font-size: 12px;
/* Multi-line title support */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
div.id2 a:hover {

View File

@ -603,26 +603,29 @@ div.id1 {
display: inline-block;
margin: 3px 5px 5px 3px;
padding-top: 3px;
height: 335px;
vertical-align: top;
min-height: 335px;
}
div.id2 {
border-bottom: 2px dotted #414135;
height: 20px;
min-height: 20px;
margin: auto auto 10px;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 97%;
}
div.id2 a {
font-weight: bold;
text-decoration: none;
overflow: hidden;
color: #414135;
font-size: 12px;
/* Multi-line title support */
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
div.id2 a:hover {

12
script/get_version Normal file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use Mojo::JSON qw(j);
use Mojo::File;
my $conf = j( Mojo::File->new(qw(package.json))->slurp );
say %$conf{version} . " - '" . %$conf{version_name} . "'"

View File

@ -9,6 +9,7 @@ use Mojo::Server::Morbo;
use Mojo::Server::Prefork;
use Mojo::Util qw(extract_usage getopt);
use File::Path qw(make_path);
use utf8;
getopt
'm|morbo' => \my $morbo,
@ -55,7 +56,7 @@ if ($morbo) {
$backend->daemon->listen(@listen);
$backend->run($app);
} else {
print "Server PID will be at " . $hypno_pid . "\n";
print "服务器PID存放在 " . $hypno_pid . "\n";
$backend = Mojo::Server::Prefork->new( keep_alive_timeout => 30 );
$backend->pid_file($hypno_pid);

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Database Backup/Restore</title>
<title>[% title %] - 数据库备份/恢复</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -35,14 +35,14 @@
<body>
<div class='ido' style='text-align:center'>
<h2 class='ih' style='text-align:center'>Database Backup/Restore</h2>
<h2 class='ih' style='text-align:center'>数据库备份/恢复</h2>
<br>
You can backup your existing database here, or restore an existing backup.<br><br>
Backuping allows you to download a JSON file containing all your categories and archive IDs, and their matching
metadata.<br>
Restoring from a backup will restore this metadata, <b>for IDs which already exist in your database.</b><br>
(Categories will always be restored)</br>
您可以在此处备份现有数据库,或还原现有备份。<br><br>
通过备份您可以下载一个包含所有类别和档案ID以及它们匹配的元数据的JSON
文件。<br>
从备份还原将针对数据库中已存在的 <b>ID还原此元数据。</b><br>
(分类将始终被恢复)</br>
<table style='margin:auto; font-size:9pt; margin-top:25px; text-align:center;'>
<tbody id='files'>
@ -50,13 +50,13 @@
<td>
<span id='do-backup' class="stdbtn" style="height:50px; display:inline-block">
<i style="padding-top:6px; padding-bottom: 5px" class="fa fa-download fa-2x"></i><br>
<span>Backup Database</span>
<span>备份数据库</span>
</span>
</td>
<td>
<span class="stdbtn fileinput-button" style="height:50px; display:inline-block;">
<i style="padding-top:6px; padding-bottom: 5px" class="fa fa-upload fa-2x"></i><br>
<span>Restore Backup</span>
<span>恢复备份</span>
<input type="file" id="fileupload" multiple="" name="file">
</span>
</td>
@ -68,7 +68,7 @@
<div id='processing' style='display:none'>
<i class='fa fa-3x fa-compact-disc fa-spin' style='margin-top:20px' id='tag-spinner'></i>
<h3>Restoring your backup ... </h3>
<h3>恢复备份中 ... </h3>
</div>
<h3 id='result'></h3>
@ -77,7 +77,7 @@
<br><br><br>
<input id='return' class='stdbtn' type='button' value='Return to Library' />
<input id='return' class='stdbtn' type='button' value='返回资料库' />
<br><br>

View File

@ -3,7 +3,7 @@
<html>
<head>
<title>[% title %] - Batch Operations</title>
<title>[% title %] - 批量操作</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -33,11 +33,11 @@
<body>
<div class='ido' style='text-align:center'>
<h2 class='ih' style='text-align:center'>Batch Operations</h2>
<h2 class='ih' style='text-align:center'>批量操作</h2>
You can apply modifications to multiple archives in one go here.<br><br>
Select what you'd like to do, check archives you want to use it on, and get rolling! <br>
Archives with no tags have been pre-checked.<br><br>
您可以在此处通过一项操作在多个档案中使用插件.<br><br>
选择您的插件,检查要使用的存档,然后滚动! <br>
没有标签的档案已被预先检查.<br><br>
<div style='margin-left:auto; margin-right:auto;'>
<div style='text-align:left; width:400px !important' class='left-column'>
@ -47,15 +47,15 @@
<tbody>
<tr>
<td>
<h2>Task :</h2>
<h2>任务 :</h2>
</td>
<td>
<select id="batch-operation" class="favtag-btn" style="font-size:20px; height:30px">
<option value="plugin">🧩 Use Plugin</option>
<option value="clearnew">🆕 Remove New Flag</option>
<option value="tagrules">📏 Apply Tag Rules</option>
<option value="addcat">📚 Add To Category</option>
<option value="delete">🗑️ Delete Archive</option>
<option value="plugin">🧩 调用插件</option>
<option value="clearnew">🆕 移除NEW标签</option>
<option value="tagrules">📏 应用标签规则</option>
<option value="addcat">📚 添加到分类</option>
<option value="delete">🗑️ 删除档案</option>
</select>
</td>
</tr>
@ -67,7 +67,7 @@
<table>
<tbody>
<tr class="operation plugin-operation">
<td>Use plugin :</td>
<td>使用插件 :</td>
<td>
<select id="plugin" class="favtag-btn">
[% FOREACH plugins %]
@ -77,20 +77,20 @@
</td>
</tr>
<tr class="operation plugin-operation">
<td>Timeout (max 20s):</td>
<td>超时 (最大 20 秒):</td>
<td>
<input type="number" id="timeout" min="0" max="20" value="0"> seconds
</td>
</tr>
<tr class="operation plugin-operation">
<td colspan="2">
<h3>This plugin recommends a cooldown of <span id="cooldown">-1</span> seconds.
<h3>此插件建议冷却时间为 <span id="cooldown">-1</span> 秒.
</h3>
<i class="fas fa-exclamation-triangle"></i> Some external services may temporarily
ban
your machine for excessive loads if you call a plugin too many times! <br>
Make sure to set a suitable <b>timeout</b> between archives using this picker if
the plugin you want to use is concerned. <br><br>
<i class="fas fa-exclamation-triangle"></i> 某些外部服务可能会暂时
Ban
掉你的设备, 如果您频繁调用插件! <br>
确保在使用此插件的档案间隔设置合适的 <b>超时时间</b> 如果
您要使用的插件存在相关问题. <br><br>
</td>
</tr>
@ -98,17 +98,17 @@
<tr class="operation plugin-operation">
<td colspan="2">
<input type="checkbox" id="override">
<label for="override">Override Plugin Global Arguments</label>
<label for="override">覆盖插件全局参数</label>
</td>
</tr>
<tr class="operation tagrules-operation">
<td style="vertical-align: top;">This will apply the following Tag Rules to the selected
Archives.<br><br>
You can edit your Tag Rules in Server Configuration.<br><br>
<td style="vertical-align: top;">这会将以下标签规则应用于选定的
档案.<br><br>
您可以在服务器配置中编辑您的标签规则.<br><br>
<input id='server-config' class='stdbtn' type='button'
value='Server Configuration' />
value='服务器配置' />
</td>
<td>
<textarea class="stdinput" size="20" style='height:196px'
@ -119,13 +119,13 @@
<tr class="operation clearnew-operation">
<td colspan="2" style="text-align: center;">
This removes the "new" flag from the selected archives.
这将从所选档案中删除“NEW”标志.
<br>
</td>
</tr>
<tr class="operation addcat-operation">
<td>Add to Category :</td>
<td>添加到分类 :</td>
<td>
<select id="category" class="favtag-btn">
[% FOREACH categories %]
@ -144,8 +144,8 @@
<tr class="operation delete-operation">
<td colspan="2" style="text-align: center;">
<h3>This will delete both metadata and matching files from your system!
Please use with caution.
<h3>这将从您的系统中删除元数据和匹配文件!
请谨慎使用.
</h3>
<br>
</td>
@ -177,19 +177,19 @@
<div class="tag-options" style="text-align:center">
<br /><br />
<input type='button' id="check-uncheck" value='Check/Uncheck all' class='stdbtn' checked='false'>
<input type='button' id="start-batch" value='Start Task' class='stdbtn'>
<input type='button' id="check-uncheck" value='选中/取消全部' class='stdbtn' checked='false'>
<input type='button' id="start-batch" value='开始标记' class='stdbtn'>
</div>
<div class="job-status" style="display:none; text-align:center">
<input id="cancel-job" type='button' value='Cancel' class='stdbtn'>
<input id="restart-job" type='button' value='Start another job' class='stdbtn'>
<input id="cancel-job" type='button' value='取消' class='stdbtn'>
<input id="restart-job" type='button' value='开始其他任务' class='stdbtn'>
<div id="progress" style="padding-top:6px; padding-bottom:6px">
<div class="bar"></div>
Processed <span id="arcs"></span> out of <span id="totalarcs"></span>
当前运行 <span id="arcs"></span> 共 <span id="totalarcs"></span>
</div>
<div class="id1" style="padding:4px; height:auto; width:97%;">
<pre id="log-container" class="log-panel" />
@ -206,14 +206,14 @@
<div id="loading-placeholder"
style="align-content: center;top: 150px; position: relative; margin-left: auto; margin-right: auto; width: 90%;">
<i class="fas fa-8x fa-spin fa-compact-disc"></i><br><br>
<h2>Preparing your data.</h2>
<h2>准备数据.</h2>
</div>
</div>
<br><br>
</div>
<input id='plugin-config' class='stdbtn' type='button' value='Plugin Configuration' />
<input id='return' class='stdbtn' type='button' value='Return to Library' />
<input id='plugin-config' class='stdbtn' type='button' value='插件配置' />
<input id='return' class='stdbtn' type='button' value='回到资料库' />
</div>
[% INCLUDE footer %]

View File

@ -3,7 +3,7 @@
<html>
<head>
<title>[% title %] - Categories </title>
<title>[% title %] - 分类 </title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -33,55 +33,55 @@
<body>
<div class='ido' style='text-align:center'>
<h2 class='ih' style='text-align:center'>Categories</h2>
<h2 class='ih' style='text-align:center'>分类</h2>
<br><br>
<div style='margin-left:auto; margin-right:auto;'>
<div style='text-align:left; font-size: 9pt; width:400px !important ' class='left-column'>
Categories appear at the top of your window when browsing the Library.<br>
There are two distinct kinds:
浏览“资源库”时,分类显示在窗口的顶部。<br>
有两种不同的分类:
<ul>
<li><i class="fas fa-2x fa-folder-open" style="margin-left: -30px; width:30px"></i>
Static Categories are arbitrary collections of
Archives, where you can add as many items as you want.
静态类别是档案的任意集合,
您可以在其中添加任意数量的项。
</li>
<li><i class="fas fa-2x fa-bolt" style="margin-left: -25px; width:25px"></i>
Dynamic Categories contain all archives matching a given predicate, and
automatically update alongside your library.
动态类别包含与给定词匹配的所有档案, 将
自动与您的资料库一起更新。
</li>
</ul>
You can create new categories here or edit existing ones. </br></br>
您可以在此处创建新分类或编辑现有分类。 </br></br>
<div style="text-align:center">
<input id='new-static' type='button' value='New Static Category' class='stdbtn'>
<input id='new-dynamic' type='button' value='New Dynamic Category' class='stdbtn'>
<input id='new-static' type='button' value='新的静态分类' class='stdbtn'>
<input id='new-dynamic' type='button' value='新的动态分类' class='stdbtn'>
</div> <br>
Select a category in the combobox below to edit its name, the archives it contains, or its predicate.
<br> <b>All your modifications are saved automatically.</b> <br></br>
在下面的组合框中选择一个类别,以编辑其名称,包含在存档或给定关键词中
<br> <b>您所有的修改都会自动保存。</b> <br></br>
<table>
<tbody>
<tr>
<td>
<h2>Category:</h2>
<h2>分类:</h2>
</td>
<td>
<select id="category" class="favtag-btn" style="font-size:20px; height:30px">
<option disabled selected value> -- No Category -- </option>
<option disabled selected value> -- 无分类 -- </option>
</select>
</td>
</tr>
<tr class="tag-options">
<td style="text-align: right;">Name:</td>
<td style="text-align: right;">名称:</td>
<td>
<input id="catname" value="" />
</td>
</tr>
<tr id="predicatefield" class="tag-options">
<td style="text-align: right;">Predicate:</td>
<td style="text-align: right;">关键词:</td>
<td>
<input id="catsearch" value="" />
<i id="predicate-help" style="cursor:pointer" class="fas fa-question-circle"></i>
@ -91,12 +91,12 @@
<td></td>
<td>
<input id="pinned" name="pinned" class="fa" type="checkbox">
<label for="pinned">Pin this Category</label>
<label for="pinned">加密该分类</label>
</td>
</tr>
<tr class="tag-options">
<td></td>
<td><input id="delete" type='button' value='Delete Category' class='stdbtn'>
<td><input id="delete" type='button' value='删除分类' class='stdbtn'>
</td>
</tr>
<tr class="tag-options">
@ -115,8 +115,8 @@
<div id="dynamicplaceholder"
style="align-content: center;top: 150px; position: relative; margin-left: auto; margin-right: auto; width: 90%;">
<i class="fas fa-8x fa-air-freshener"></i><br><br>
<h2>If you select a Static Category, your archives will appear here so you can add/remove them from
the category.</h2>
<h2>如果选择静态类别,则归档将显示在此处,因此您可以从分类中添加/删除
它们。</h2>
</div>
<ul id="archivelist" class='checklist' style="display:none">
@ -126,7 +126,7 @@
<br><br>
</div>
<input id='return' class='stdbtn' type='button' value='Return to Library' />
<input id='return' class='stdbtn' type='button' value='回到资料库' />
</div>
[% INCLUDE footer %]

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Settings</title>
<title>[% title %] - 设置</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@ -35,21 +35,24 @@
<body>
<div class="ido">
<h2 class="ih" style="text-align:center">Admin Settings</h2>
<h2 class="ih" style="text-align:center">管理员设置</h2>
<br>
<div class="left-column">
<img class="logo-container" src="./img/logo.png">
<br>
<h1 style="margin-bottom: 2px">LANraragi</h1>
Version [% version %], "[% vername %]"
版本 [% version %], "[% vername %]"
<br>
<h2>Select a category to show the matching settings.</h2>
汉化:<a href="http://yuanfangblog.xyz"> 昭君 </a>
<br>
汉化:<a href="http://bs.windycloud.cn"> WindyMadman </a>
<h2>选择一个分类以显示相关设置。</h2>
<br />
<input id='save' class='stdbtn' type='button' value='Save Settings' /><br />
<input id='plugin-config' class='stdbtn' type='button' value='Plugin Configuration' />
<input id='backup' class='stdbtn' type='button' value='Database Backup/Restore' />
<input id='return' class='stdbtn' type='button' value='Return to Library' />
<input id='save' class='stdbtn' type='button' value='保存配置' /><br />
<input id='plugin-config' class='stdbtn' type='button' value='插件配置' />
<input id='backup' class='stdbtn' type='button' value='数据库备份/恢复' />
<input id='return' class='stdbtn' type='button' value='返回资料库' />
</div>
<form class="right-column" name="editConfigForm" id="editConfigForm" enctype="multipart/form-data" method="post"
@ -58,7 +61,7 @@
<ul class="collapsible extensible with-right-caret">
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-cubes" aria-hidden="true"></i> Global Settings
<i class="fa fa-cubes" aria-hidden="true"></i> 全局设置
</div>
<div class="collapsible-body">
<table style="margin:auto; font-size:9pt;">
@ -70,7 +73,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-paint-brush" aria-hidden="true"></i> Theme
<i class="fa fa-paint-brush" aria-hidden="true"></i> 主题
</div>
<div class="collapsible-body">
<table style="margin:auto; font-size:9pt;">
@ -82,7 +85,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-shield-alt" aria-hidden="true"></i> Security
<i class="fa fa-shield-alt" aria-hidden="true"></i> 安全
</div>
<div class="collapsible-body">
<table style="margin:auto; font-size:9pt;">
@ -94,7 +97,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-file-archive" aria-hidden="true"></i> Archive Files
<i class="fa fa-file-archive" aria-hidden="true"></i> 档案文件
</div>
<div class="collapsible-body">
<table style="margin:auto; font-size:9pt;">
@ -106,7 +109,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-tags" aria-hidden="true"></i> Tags and Thumbnails
<i class="fa fa-tags" aria-hidden="true"></i> 标签和缩略图
</div>
<div class="collapsible-body">
<table style="margin:auto; font-size:9pt;">
@ -118,7 +121,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-satellite" aria-hidden="true"></i> Background Workers
<i class="fa fa-satellite" aria-hidden="true"></i> 后台进程
</div>
<div class="collapsible-body">
<table style="margin:auto; font-size:9pt;">

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Edit Mode</title>
<title>[% title %] - 编辑模式</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@ -37,9 +37,9 @@
<div class='ido' style='text-align:center'>
[% IF artist %]
<h2 class='ih' style='text-align:center'>Editing [% arctitle %] by [% artist %] </h2>
<h2 class='ih' style='text-align:center'>修改 [% arctitle %] 通过 [% artist %] </h2>
[% ELSE %]
<h2 class='ih' style='text-align:center'>Editing [% arctitle %]</h2>
<h2 class='ih' style='text-align:center'>编辑 [% arctitle %]</h2>
[% END %]
<form name='editArchiveForm' id='editArchiveForm' enctype='multipart/form-data' method='post' autocomplete="off"
@ -47,7 +47,7 @@
<table style='margin:auto; font-size:8pt;'>
<tbody>
<tr>
<td style='text-align:left; width:100px'>Current File Name:</td>
<td style='text-align:left; width:100px'>当前文件名:</td>
<td>
<input class='stdinput edit-mode-stdinput' type='text' readonly='' size='20'
value="[% file %]" name='filename'>
@ -63,7 +63,7 @@
</tr>
<tr>
<td style='text-align:left; width:100px'>Title:</td>
<td style='text-align:left; width:100px'>标题:</td>
<td>
<input id='title' class='stdinput edit-mode-stdinput' type='text' maxlength='255' size='20'
value="[% arctitle %]" name='title'>
@ -71,9 +71,9 @@
</tr>
<tr>
<td style='text-align:left; width:100px; vertical-align:top'>Tags <span
style="font-size:6pt">(separated by
hyphens, i.e : tag1, tag2)</span> :
<td style='text-align:left; width:100px; vertical-align:top'>标签 <span
style="font-size:6pt">(用连字符
分隔, 例如 : tag1, tag2)</span> :
</td>
<td>
<textarea id='tagText' class='stdinput' name='tags' autocomplete="off"
@ -85,8 +85,8 @@
</tr>
<tr>
<td style='text-align:left; width:100px; vertical-align:top'>Import Tags from Plugin : <br />
<input type='button' name='tag_import' value='Help' id="show-help" class='stdbtn'
<td style='text-align:left; width:100px; vertical-align:top'>从插件导入标签 : <br />
<input type='button' name='tag_import' value='帮助' id="show-help" class='stdbtn'
style='min-width:90px;'></input>
</td>
<td id="plugin_table" style="text-align: left">
@ -107,18 +107,18 @@
<br />
<i class='fa fa-2x fa-exclamation-circle' style='margin-top:4px'></i> Using a Plugin will
save any modifications to
archive metadata
you might have made !
<i class='fa fa-2x fa-exclamation-circle' style='margin-top:4px'></i> 使用插件将
保存对存档
元数据所做的
任何修改!
</td>
</tr>
<tr>
<td colspan='2' style='text-align:center'> <br />
<input class='stdbtn' type='button' id="save-metadata" value='Save Metadata' />
<input class='stdbtn' type='button' id="delete-archive" value='Delete Archive' />
<input id='goback' class='stdbtn' type='button' value='Return to Library' />
<input class='stdbtn' type='button' id="save-metadata" value='保存元数据' />
<input class='stdbtn' type='button' id="delete-archive" value='删除档案' />
<input id='goback' class='stdbtn' type='button' value='返回资料库' />
<br />
</td>
</tr>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>LANraragi Server Error</title>
<title>LANraragi 服务器错误</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -13,13 +13,13 @@
<img src='/img/flubbed.gif' />
<br />
<h2>I flubbed it while rendering your page!</h2>
It's likely there's a bug with the server at this point.<br />
<h2>服务器在渲染页面时出现了错误!</h2>
可能是由于服务器上出现了一个BUG导致的此问题。<br />
<p>
<%= $exception->message %>
</p>
<h3>Some more info below if available:</h3>
<h3>下面还有一些可能有用的信息,请交给服务器管理员查看:</h3>
<pre><%= dumper $snapshot %></pre>
</body>

View File

@ -5,5 +5,7 @@
[% descstr %]
<br>
[% END %]
Powered by <a href="https://github.com/Difegue/LANraragi"> LANraragi.</a>
使用 <a href="https://github.com/Difegue/LANraragi"> LANraragi </a> ❤ 稳定运行.
<br>
汉化由 <a href="https://bs.windycloud.cn"> LANraragi_CN_Windy </a> ⚡ 强力驱动.
</p>

View File

@ -49,29 +49,29 @@
[% IF userlogged %]
<p id="nb">
<i class="fa fa-caret-right"></i>
<a href="./upload">Add Archives</a>
<a href="./upload">上传档案</a>
<span style="margin-left:5px"></span>
<i class="fa fa-caret-right"></i>
<a href="./batch">Batch Operations</a>
<a href="./batch">批量操作</a>
<span style="margin-left:5px"></span>
<i class="fa fa-caret-right"></i>
<a href="./config">Settings</a>
<a href="./config">设置</a>
<span style="margin-left:5px"></span>
<i class="fa fa-caret-right"></i>
<a href="./config/categories">Modify Categories</a>
<a href="./config/categories">修改分类</a>
<span style="margin-left:5px"></span>
<i class="fa fa-caret-right"></i>
<a href="./stats">Statistics</a>
<a href="./stats">统计</a>
<i class="fa fa-caret-right"></i>
<a href="./logs">Logs</a>
<a href="./logs">日志</a>
</p>
[% ELSE %]
<p id="nb">
<i class="fa fa-caret-right"></i>
<a href="./login">Admin Login</a>
<a href="./login">管理员登录</a>
<span style="margin-left:5px"></span>
<i class="fa fa-caret-right"></i>
<a href="./stats">Statistics</a>
<a href="./stats">统计</a>
</p>
[% END %]
@ -83,9 +83,9 @@
<!-- Categories go here -->
</div>
<input type='text' id='search-input' class='search stdinput' size='90' style='width:95%'
placeholder='Search Title, Artist, Series, Language or Tags' />
<input id='apply-search' class='searchbtn stdbtn' type='button' value='Apply Filter' />
<input id='clear-search' class='searchbtn stdbtn' type='button' value='Clear Filter' />
placeholder='搜索 标题, 艺术家, 系列, 语言或标签' />
<input id='apply-search' class='searchbtn stdbtn' type='button' value='应用筛选' />
<input id='clear-search' class='searchbtn stdbtn' type='button' value='清除筛选' />
</div>
<ul class="collapsible index-carousel with-right-caret">
@ -95,13 +95,13 @@
<i id="carousel-icon" class="fa"></i>
<div id="carousel-title"
style="display:inline;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-left: 8px;"
title="Click to show archives from the current search with the specified filter">...</div>
title="单击以显示具有当前搜索的关键词的档案">...</div>
</div>
<div class="collapsible-right">
<a class="fa fa-2x fa-sync-alt" style="margin-bottom: -4px; display:none" id="reload-carousel"
href="#" title="Refresh Selection"></a>
href="#" title="刷新选区"></a>
<a class="fa fa-2x fa-ellipsis-h" style="margin-bottom: -4px; margin-left: 12px"
id="carousel-mode-menu" href="#" title="Carousel Options"></a>
id="carousel-mode-menu" href="#" title="轮播选项"></a>
</div>
<div class="collapsible-body" style="flex: 1 0 100%;overflow: hidden;box-sizing: border-box;">
@ -125,25 +125,25 @@
</ul>
<div class="table-options" style="display: none;">
<div class="thumbnail-options">Sort by:
<div class="thumbnail-options">排序:
<select class="favtag-btn" id="namespace-sortby">
<option selected value="title">Title</option>
<option selected value="date_added">Date</option>
<option selected value="title">标题</option>
<option selected value="date_added">日期</option>
</select>
<a class="fa fa-sort-alpha-down fa-2x table-option" id="order-sortby" href="#"
title="Sort Order"></a>
title="排列顺序"></a>
<input id="thumbnail-crop" class="fa table-option" type="checkbox"
title="If enabled, thumbnails that don't fit a regular A4 page will be cropped to only show the left side.">
<label for="thumbnail-crop" style="vertical-align: middle; padding-top:6px">Crop thumbnails</label>
title="如果启用不适合常规A4页面的缩略图将被裁剪为仅显示左边部分.">
<label for="thumbnail-crop" style="vertical-align: middle; padding-top:6px">缩略图裁切</label>
</div>
<div style="margin-left:auto">Go to Page:
<div style="margin-left:auto">跳转到:
<select class="favtag-btn" id="page-select">
</select>
<a class="fa fa-list fa-2x mode-toggle thumbnail-toggle table-option" href="#"
title="Switch to Compact Mode"></a>
title="紧凑模式"></a>
<a class="fa fa-table fa-2x mode-toggle compact-toggle table-option" href="#"
title="Switch to Thumbnail Mode"></a>
title="缩略图模式"></a>
</div>
</div>
@ -151,20 +151,20 @@
<thead class="list" style="display: none;">
<tr>
<th id="titleheader">
<a>Title</a>
<a>标题</a>
</th>
<th id="customheader1">
<i id="edit-header-1" class="fas fa-pencil-alt edit-header-btn"
title="Edit this column"></i>
<a id="header-1">Artist</a>
title="编辑此列"></i>
<a id="header-1">艺术家</a>
</th>
<th id="customheader2">
<i id="edit-header-2" class="fas fa-pencil-alt edit-header-btn"
title="Edit this column"></i>
<a id="header-2">Series</a>
title="编辑此列"></i>
<a id="header-2">系列</a>
</th>
<th id="tagsheader">
<a>Tags</a>
<a>标签</a>
</th>
</tr>
</thead>
@ -174,11 +174,11 @@
<div id="json-error" style="display:none">
<h1 style="color: red">
<i class="fas fa-bomb"></i> I don't know everything, but I sure as hell know this database's busted
lads
<i class="fas fa-bomb"></i> 我确定数据库已经崩溃,除此之外啥也不清楚
伙计
<i class="fas fa-bomb"></i>
</h1>
<h2>The database cache is corrupt, and as such LANraragi is unable to display your archive list.</h2>
<h2>数据库缓存已损坏因此LANraragi无法显示您的存档列表。</h2>
</div>
</div>
@ -194,10 +194,10 @@
[% IF usingdefpass %]
//If the json has the "default password" flag, flash a friendly notification inviting the user to change his password
LRR.toast({
heading: 'You\'re using the default password and that\'s super baka of you',
text: '<a href="login">Login</a> with password "kamimamita" and <a href="config">change that shit</a> on the double.<br/>...Or just disable it! <br/>Why not check the configuration options afterwards, while you\'re at it? ',
heading: '你\'正在使用默认密码\',这样真的非常危险!!!!',
text: ' 使用默认密码 "kamimamita" <a href="login">点此登录</a><br>马上去 <a href="config">修改它</a>!<br/>当然你也可以把密码禁用掉! <br/>但是所有人都可以修改服务器的设置项?',
icon: 'warning',
hideAfter: 25000,
hideAfter: 25000,
closeOnClick: false,
draggable: false,
});
@ -212,25 +212,25 @@
Index.handleContextMenu(key, $(this).attr("id"));
},
items: {
"read": { name: "Read", icon: "fas fa-book" },
"download": { name: "Download", icon: "fas fa-save" },
"read": { name: "阅读", icon: "fas fa-book" },
"download": { name: "下载", icon: "fas fa-save" },
[% IF userlogged %]
"sep1": "---------",
"edit": { name: "Edit Metadata", icon: "fas fa-pencil-alt" },
"delete": { name: "Delete", icon: "fas fa-trash-alt" },
"edit": { name: "编辑元数据", icon: "fas fa-pencil-alt" },
"delete": { name: "删除", icon: "fas fa-trash-alt" },
"category": {
"name": "Add to Category",
"name": "添加到分类",
"icon": "fas fa-search-plus",
"items": {
[% IF categories.size > 0 %][% FOREACH categories %]
"category-[% id %]": { "name": "[% name %]", "icon": "fas fa-stream" },
[% END %][% ELSE %]
"noop": { "name": "No Categories yet...", "icon": "fas fa-ghost" }
"noop": { "name": "暂无分类...", "icon": "fas fa-ghost" }
[% END %]
}
},
"categoryremove": {
"name": "Remove from Category",
"name": "从分类中移除",
"icon": "fas fa-search-minus",
"items": Index.loadContextMenuCategories($trigger.attr("id"))
}
@ -245,7 +245,7 @@
<div id="overlay-shade"> </div>
<div id="updateOverlay" class="id1 base-overlay small-overlay" style="display:none">
<h2 class="ih" style="text-align:center">New Version Release Notes</h2>
<h2 class="ih" style="text-align:center">新版本发行说明</h2>
<div id="changelog"></div>
</div>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Login</title>
<title>[% title %] - 登录</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -18,14 +18,14 @@
<body>
<div class='ido' style='text-align:center'>
<p>This page requires you to log on.</p>
<p>需要登录才能访问该页面。</p>
<form name='loginForm' method='post'>
<table style='margin:auto; text-align:left; font-size:8pt;'>
<tbody>
<tr>
<td>Admin Password:</td>
<td>密码:</td>
<td>
<input autofocus id='pw_field' class='stdinput' type='password' style='width:90%' value=''
maxlength='255' size='20' name='password'>
@ -33,14 +33,14 @@
</tr>
<tr>
<td style='padding-top:5px; text-align:center; vertical-align:middle' colspan='2'>
<input class='stdbtn' type='submit' value='Login' style='width:60px'>
<input class='stdbtn' type='submit' value='登入' style='width:60px'>
</td>
</tr>
[% IF wrongpass %]
<tr style='font-size:23px'>
<td colspan='2' style='padding-top:5px; text-align:center; vertical-align:middle '>Wrong
Password. </td>
<td colspan='2' style='padding-top:5px; text-align:center; vertical-align:middle '>密码
错误. </td>
</tr>
[% END %]
</tbody>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Logs</title>
<title>[% title %] - 日志</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -28,29 +28,32 @@
<body>
<div class='ido' style='text-align:center'>
<h2 class='ih' style='text-align:center'>Application Logs</h2>
<h2 class='ih' style='text-align:center'>软件日志</h2>
<br>
You can check LANraragi logs here for debugging purposes.<br>
By default, this view only shows the last 100 lines of each logfile, newest lines last. <br><br>
您可以在此处检查LANraragi日志以进行调试。<br>
默认情况下此视图仅显示每个日志文件的最后100行最后一行显示最新行。 <br><br>
<ul>
<li>General Logs pertain to the main application. </li>
<li>Shinobu Logs correspond to the Background Worker.</li>
<li>Plugin Logs are reserved for metadata plugins only. </li>
<li>Mojolicious logs won't tell much unless you're running Debug Mode. </li>
<li>Redis logs won't be available from here if you're running from source! </li>
<li>常规日志与主应用程序有关。 </li>
<li>Shinobu日志对应于后台监视进程。</li>
<li>插件日志仅针对元数据插件。 </li>
<li>除非您正在运行“调试模式”否则Mojolicious日志不会告诉您太多信息。 </li>
<li>如果您从源代码运行则Redis日志将无法在此处使用 </li>
</ul>
<br>历代汉化:昭君。访问<a href="http://yuanfangblog.xyz"> 我的博客 </a>和<a href="https://space.bilibili.com/6976331"> Bilibili空间 </a>获取更多信息和教程<br>
<br>接手汉化WindyMadman。访问<a href="https://bs.windycloud.cn"> 我的论坛 </a>获取一站式的教程和服务<br>
<br>点击下载 <a href="https://f-droid.org/packages/com.utazukin.ichaival"> 安卓客户端汉化版 </a>、<a href="https://github.com/Doraemoe/DuReader/releases"> IOS客户端 </a>、<a href="https://www.microsoft.com/zh-cn/p/lrreader/9mz6bwwvswjh"> Windows客户端 .</a><br>
<br><br>
<h1 class='ih' style='float:left; margin-left: 5%;'>Currently Viewing: <span id="indicator">general</span></h1>
<h1 class='ih' style='float:left; margin-left: 5%;'>当前视图: <span id="indicator">通常</span></h1>
<div style="margin-right: 5%;float: right;">
<a id="refresh" href="#" title="Refresh">
<a id="refresh" href="#" title="刷新">
<i style="padding-right: 10px;" class="fa fa-sync-alt fa-2x"></i>
</a>
Lines: <input type="number" min="0" value="100" id="loglines" style="width: 60px;">
显示行: <input type="number" min="0" value="100" id="loglines" style="width: 60px;">
</div>
@ -68,18 +71,18 @@
<br><br>
<span id='buttonstagging'>
<input id="show-general" type='button' value='View LANraragi Logs' class='stdbtn'>
<input id="show-general" type='button' value='查看 LANraragi 日志' class='stdbtn'>
<input id="show-shinobu" type='button' value='View Shinobu Logs' class='stdbtn'>
<input id="show-shinobu" type='button' value='查看 Shinobu 日志' class='stdbtn'>
<input id="show-plugins" type='button' value='View Plugin Logs' class='stdbtn'>
<input id="show-plugins" type='button' value='查看 插件 日志' class='stdbtn'>
<input id="show-mojo" type='button' value='View Mojolicious Logs' class='stdbtn'>
<input id="show-mojo" type='button' value='查看 Mojolicious 日志' class='stdbtn'>
<input id="show-redis" type='button' value='View Redis Logs' class='stdbtn'>
<input id="show-redis" type='button' value='查看 Redis 日志' class='stdbtn'>
<br><br>
<input id='return' class='stdbtn' type='button' value='Return to Library' />
<input id='return' class='stdbtn' type='button' value='返回资料库' />
</span>
@ -88,4 +91,4 @@
[% INCLUDE footer %]
</body>
</html>
</html>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>Page Not Found</title>
<title>找不到网页</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

View File

@ -62,7 +62,9 @@
<link rel="http://opds-spec.org/acquisition" href="/api/archives/[% arc.arcid %]/download[% api_key_query %]" title="Download/Read"
type="[% arc.mimetype %]" />
<link rel="http://vaemendis.net/opds-pse/stream" type="image/jpeg"
href="/api/opds/[% arc.arcid %]/pse?page={pageNumber}[% api_key_and %]" pse:count="[% arc.pagecount %]" [% IF arc.progress %] pse:lastRead="[% arc.progress %]" [% END %]/>
href="/api/opds/[% arc.arcid %]/pse?page={pageNumber}[% api_key_and %]" pse:count="[% arc.pagecount %]"
[% IF arc.progress %] pse:lastRead="[% arc.progress %]" [% END %]
[% IF arc.lastreaddate %] pse:lastReadDate="[% arc.lastreaddate %]" [% END %]/>
<link type="text/html" rel="alternate" title="Open in LANraragi" href="/reader?id=[% arc.arcid %][% api_key_and %]" />
</entry>
[% END %]

View File

@ -33,7 +33,9 @@
<link rel="http://opds-spec.org/acquisition" href="/api/archives/[% arc.arcid %]/download[% api_key_query %]" title="Download/Read"
type="[% arc.mimetype %]" />
<link rel="http://vaemendis.net/opds-pse/stream" type="image/jpeg"
href="/api/opds/[% arc.arcid %]/pse?page={pageNumber}[% api_key_and %]" pse:count="[% arc.pagecount %]" [% IF arc.progress %] pse:lastRead="[% arc.progress %]" [% END %]/>
href="/api/opds/[% arc.arcid %]/pse?page={pageNumber}[% api_key_and %]" pse:count="[% arc.pagecount %]"
[% IF arc.progress %] pse:lastRead="[% arc.progress %]" [% END %]
[% IF arc.lastreaddate %] pse:lastReadDate="[% arc.lastreaddate %]" [% END %] />
<link type="text/html" rel="alternate" title="Open in LANraragi" href="/reader?id=[% arc.arcid %][% api_key_and %]" />
</entry>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Plugin Configuration</title>
<title>[% title %] - 插件配置</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@ -38,11 +38,11 @@
<body>
<div class="ido" style="text-align:center;">
<h1 class="ih" style="text-align:center">Plugin Configuration</h1>
<br /> Enable/Disable Auto-Plugin on metadata plugins by checking the toggles.
<br /> Plugins will be automatically used on new archives if they're toggled here.
<br /> If they have configuration variables, you can set them here as well.
<br /> You can also trigger Scripts here. Triggering a script will save your Plugin settings beforehand.
<h1 class="ih" style="text-align:center">插件配置</h1>
<br /> 切换该选项,在元数据插件上启用/禁用 Auto-Plugin。
<br /> 如果在这里切换插件,它们将自动用于新档案。
<br /> 如果它们具有配置变量,则也可以在此处进行设置。
<br /> 您也可以在此处触发脚本。 触发脚本将事先保存您的插件设置。
<br />
<form name="editPluginForm" id="editPluginForm" enctype="multipart/form-data" method="post">
@ -51,7 +51,7 @@
<ul class="collapsible extensible with-right-caret">
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-plug" aria-hidden="true"></i> Login Plugins
<i class="fa fa-plug" aria-hidden="true"></i> 登录插件
</div>
<div class="collapsible-body">
[% INCLUDE pluginlist plugins = logins %]
@ -59,7 +59,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fas fa-cloud-download-alt" aria-hidden="true"></i> Downloaders
<i class="fas fa-cloud-download-alt" aria-hidden="true"></i> 下载器
</div>
<div class="collapsible-body">
[% INCLUDE pluginlist plugins = downloaders %]
@ -67,7 +67,7 @@
</li>
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-scroll" aria-hidden="true"></i> Scripts
<i class="fa fa-scroll" aria-hidden="true"></i> 脚本
</div>
<div class="collapsible-body">
[% INCLUDE pluginlist plugins = scripts %]
@ -80,7 +80,7 @@
<ul class="collapsible extensible with-right-caret">
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-digital-tachograph" aria-hidden="true"></i> Metadata Plugins
<i class="fa fa-digital-tachograph" aria-hidden="true"></i> 元数据插件
</div>
<div class="collapsible-body">
[% INCLUDE pluginlist plugins = metadata %]
@ -93,15 +93,15 @@
<h1 style="text-align:center">
<span class="script-running" style="display:none">
<i aria-hidden="true" class="fa fa-3x fa-atom fa-spin"></i> <br>
A script is running...
一个脚本正在运行...
</span>
<input id='save' class='stdbtn' type='button' value='Save Plugin Configuration' />
<input id='save' class='stdbtn' type='button' value='保存插件配置' />
<span id="plugin-upload" class='stdbtn fileinput-button'
style="margin-bottom: -10px; font-weight:normal">
<span style="position:absolute; top:5px; left:25%">Upload Plugin</span>
<span style="position:absolute; top:5px; left:25%">上传插件</span>
<input type='file' name='file' multiple id='fileupload'>
</span>
<input id='return' class='stdbtn' type='button' value='Return to Library' />
<input id='return' class='stdbtn' type='button' value='返回资料库' />
</h1>
</form>
</div>
@ -126,14 +126,14 @@
<div style="float:right; text-align: right;">
[% IF plugin.type == "metadata" %]
<h1 class="ih" style="display:inline"> Run Automatically: </h1>
<h1 class="ih" style="display:inline"> 自动运行: </h1>
<input id="[% plugin.namespace %]" name="[% plugin.namespace %]" class="fa" type="checkbox" [% IF plugin.enabled
%] checked [% END %]>
<br />
[% END %]
[% IF plugin.login_from %]
<i class="fa fa-plug" aria-hidden="true"></i> This plugin depends on the login plugin "[% plugin.login_from %]".
<i class="fa fa-plug" aria-hidden="true"></i> 该插件依赖登录插件 "[% plugin.login_from %]".
[% END %]
</div>
@ -141,7 +141,7 @@
<br />
[% IF plugin.type == "download" %]
<pre title="This plugin will trigger on URLs matching this regex!"> [% plugin.url_regex %]</pre>
<pre title="此插件将在与该正则表达式匹配的URL上触发"> [% plugin.url_regex %]</pre>
[% END %]
[% plugin.description %]
<br />
@ -163,7 +163,7 @@
<tr>
<td colspan="2">
<input class='stdbtn' type='button' onclick="Server.triggerScript('[% plugin.namespace %]');"
value='Trigger Script' />
value='触发脚本' />
</td>
</tr>
</tbody>
@ -174,7 +174,7 @@
<div class="collapsible-title" style="padding: 5px 0 0 5px">
<a>
<i class="fas fa-sliders-h fa-2x" style="margin-right: 4px" aria-hidden="true"></i>
<b style="vertical-align: super;">Plugin Settings</b>
<b style="vertical-align: super;">插件设置</b>
</a>
</div>
<div class="collapsible-body" style="padding:5px 0 0 0">

View File

@ -60,7 +60,7 @@
<div id="i5">
<div class="sb">
<a href="./?[% ref_query %]" id="return-to-index" title="Done reading? Go back to Archive Index">
<a href="./?[% ref_query %]" id="return-to-index" title="看完了吗? 返回档案索引">
<i class="fa fa-angle-down fa-3x"></i>
</a>
</div>
@ -68,9 +68,11 @@
<div id="i7" class="if">
<i class="fa fa-caret-right fa-lg"></i>
<a id="imgLink" style="cursor:pointer;">View full-size image</a>
<a id="imgLink" style="cursor:pointer;">查看原图</a>
<i class="fa fa-caret-right fa-lg"></i>
<a href="./random">Switch to another random archive</a>
<a href="./random">切换到下一个随机档案</a>
<i class="fa fa-caret-right fa-lg"></i>
<a href="./">返回资料库</a>
</div>
</div>
@ -82,7 +84,7 @@
<div id="overlay-shade"></div>
<div id="archivePagesOverlay" class="id1 base-overlay page-overlay" style="display:none" loaded="false">
<h2 class="ih" style="text-align:center">Archive Overview</h2>
<h2 class="ih" id="archive-title-overlay" style="text-align:center">档案预览</h2>
<div id="tagContainer" class="caption caption-tags caption-reader">
<br>
<div style="margin-bottom:16px;">
@ -93,25 +95,41 @@
[% IF userlogged %]
<div style="display:inline-block; vertical-align: middle;">
<h2>Admin Options</h2>
<h2>管理员设置</h2>
<input class="stdbtn" type='button' id="set-thumbnail" value="Set this Page as Thumbnail"
title="Set the currently opened page as the thumbnail for this archive." />
<input class="stdbtn" type='button' id="set-thumbnail" value="将此页面设置为缩略图"
style="width:160px" title="将当前打开的页面设置为此档案的缩略图." />
<input id="regenerate-cache" class='stdbtn' type='button' value='清理缓存'
style="width:160px" />
<br>
<input id="regenerate-cache" class='stdbtn' type='button' value='Clean Archive Cache' />
<br>
<input id="edit-archive" class='stdbtn' type='button' value='Edit Archive Metadata' />
<input id="edit-archive" class='stdbtn' type='button' value='编辑元数据'
style="width:160px" />
<input id="delete-archive" class='stdbtn' type='button' value='删除'
style="width:160px" />
<h2>Add this archive to a Category</h2>
<h2>类别</h2>
<div id="archive-categories" style="display:inline-block">
[% FOREACH arc_categories %]
<div class="gt" style="font-size:14px; padding:4px">
<a href="/?c=[% id %]">
<span class="label">[% name %]</span>
<a href="#" class="remove-category" data-id="[% id %]"
style="margin-left:4px; margin-right:2px">×</a>
</a>
</div>
[% END %]
</div>
<br />
<span>Add to : </span>
<select id="category" class="favtag-btn" style="width:200px; margin-right: 8px">
<option selected value=""> -- No Category -- </option>
<option selected value=""> -- 无分类 -- </option>
[% FOREACH categories %]
<option value="[% id %]">[% name %]</option>
[% END %]
</select>
<br>
<input value="Add Archive" class="stdbtn" id="add-category" type="button">
<a class="fas fa-plus" id="add-category" href="#" title="添加该档案到分类"></a>
</div>
[% END %]
</div>
@ -120,13 +138,13 @@
<br><br>
<h2 class="ih" style="text-align:center">Pages</h2>
<h2 class="ih" style="text-align:center">档案总览</h2>
<div id="extract-spinner" style="width: 80%; margin-left: auto; margin-right: auto">
<p class="loading-spinner">
<i id="spinner" class="fa fa-dharmachakra fa-4x fa-spin"></i>
</p>
Working on it...
工作中...
</div>
</div>
</div>
@ -139,23 +157,23 @@
<div id="reader-help" style="display: none;">
<div class="navigation-help-toast">
You can navigate between pages using:
您可以使用在页面之间导航:
<ul>
<li>The arrow icons</li>
<li>The a/d keys</li>
<li>Your keyboard arrows (and the spacebar)</li>
<li>Touching the left/right side of the image.</li>
<li>箭头图标</li>
<li>A/D 键</li>
<li>键盘上的箭头(和空格键)</li>
<li>点击图像的左侧/右侧.</li>
</ul>
<br>Other keyboard shortcuts:
<br>其他键盘快捷键:
<ul>
<li>M: toggle manga mode (right-to-left reading)</li>
<li>O: show advanced reader options.</li>
<li>P: toggle double page mode</li>
<li>Q: bring up the thumbnail index and archive options.</li>
<li>R: open a random archive.</li>
<li>F: toggle fullscreen mode</li>
<li>M: 切换漫画模式(从右到左阅读)</li>
<li>O: 显示高级阅读器选项.</li>
<li>P: 切换双页模式</li>
<li>Q: 调出缩略图索引和存档选项.</li>
<li>R: 打开随机存档.</li>
<li>F: 切换全屏模式</li>
</ul>
<br>To return to the archive index, touch the arrow pointing down or use Backspace.
<br>要返回存档索引,请触摸向下的箭头或使用 Backspace.
</div>
</div>
@ -171,72 +189,72 @@
<!-- -->
[% BLOCK config %]
<h2 class="ih" style="text-align:center">Reader Options</h2>
<h2 class="ih" style="text-align:center">阅读器选项</h2>
<h1 class="ih config-panel">Those options save automatically -- Click around and find out!</h1>
<h1 class="ih config-panel">这些选项会自动保存-单击启用!</h1>
<div id="fit-mode">
<h2 class="config-panel"> Fit display to </h2>
<input id="fit-container" class="favtag-btn config-btn" type="button" value="Container">
<input id="fit-width" class="favtag-btn config-btn" type="button" value="Width">
<input id="fit-height" class="favtag-btn config-btn" type="button" value="Height">
<h2 class="config-panel"> 缩放显示到 </h2>
<input id="fit-container" class="favtag-btn config-btn" type="button" value="自适应">
<input id="fit-width" class="favtag-btn config-btn" type="button" value="适应宽度">
<input id="fit-height" class="favtag-btn config-btn" type="button" value="适应高度">
</div>
<div id="container-width">
<h2 class="config-panel"> Container Width (in pixels or percentage)</h2>
<h2 class="config-panel"> 显示宽度 (像素或百分比)</h2>
<input id="container-width-input" class="stdinput" style="display:inline; width: 70%;"
placeholder="The default value is 1200px, or 90% in Double Page Mode.">
<input id="container-width-apply" class="favtag-btn config-btn" type="button" style="display:inline;" value="Apply">
placeholder="默认值为1200像素或在双页模式下缩放为90大小.">
<input id="container-width-apply" class="favtag-btn config-btn" type="button" style="display:inline;" value="应用">
</div>
<div id="toggle-double-mode">
<h2 class="config-panel"> Page Rendering </h2>
<input id="single-page" class="favtag-btn config-btn" type="button" value="Single">
<input id="double-page" class="favtag-btn config-btn" type="button" value="Double">
<h2 class="config-panel"> 页面渲染 </h2>
<input id="single-page" class="favtag-btn config-btn" type="button" value="单页">
<input id="double-page" class="favtag-btn config-btn" type="button" value="双页">
</div>
<div id="toggle-manga-mode">
<h2 class="config-panel"> Reading Direction </h2>
<h2 class="config-panel"> 阅读方向 </h2>
<span class="config-panel"></span>
<input id="normal-mode" class="favtag-btn config-btn" type="button" value="Left to Right">
<input id="manga-mode" class="favtag-btn config-btn" type="button" value="Right to Left">
<input id="normal-mode" class="favtag-btn config-btn" type="button" value="从左到右">
<input id="manga-mode" class="favtag-btn config-btn" type="button" value="从右到左">
</div>
<div id="preload-images">
<h2 class="config-panel"> How many images to preload</h2>
<input id="preload-input" class="stdinput" style="display:inline" placeholder="The default is two images.">
<input id="preload-apply" class="favtag-btn config-btn" type="button" style="display:inline;" value="Apply">
<h2 class="config-panel"> 预加载图片张数</h2>
<input id="preload-input" class="stdinput" style="display:inline" placeholder="默认为两张图片.">
<input id="preload-apply" class="favtag-btn config-btn" type="button" style="display:inline;" value="应用">
</div>
<div id="toggle-header">
<h2 class="config-panel"> Header </h2>
<input id="show-header" class="favtag-btn config-btn" type="button" value="Visible">
<input id="hide-header" class="favtag-btn config-btn" type="button" value="Hidden">
<h2 class="config-panel"> 标题栏 </h2>
<input id="show-header" class="favtag-btn config-btn" type="button" value="显示">
<input id="hide-header" class="favtag-btn config-btn" type="button" value="隐藏">
</div>
<div id="toggle-overlay">
<h2 class="config-panel"> Show Archive Overlay by default </h2>
<span class="config-panel">This will show the overlay with thumbnails every time you open a new Reader page.
<h2 class="config-panel"> 默认显示预览 </h2>
<span class="config-panel">这将在您每次打开新的阅读器页面时显示带有缩略图的叠加层.
</span>
<input id="show-overlay" class="favtag-btn config-btn" type="button" value="Enabled">
<input id="hide-overlay" class="favtag-btn config-btn" type="button" value="Disabled">
<input id="show-overlay" class="favtag-btn config-btn" type="button" value="启用">
<input id="hide-overlay" class="favtag-btn config-btn" type="button" value="停用">
</div>
<div id="toggle-progress">
<h2 class="config-panel"> Progression Tracking </h2>
<span class="config-panel">Disabling tracking will restart reading from page one every time you reopen the reader.
<h2 class="config-panel"> 进度追踪 </h2>
<span class="config-panel">每次您重新打开阅读器时,禁用跟踪都会从第一页重新开始阅读.
</span>
<input id="track-progress" class="favtag-btn config-btn" type="button" value="Enabled">
<input id="untrack-progress" class="favtag-btn config-btn" type="button" value="Disabled">
<input id="track-progress" class="favtag-btn config-btn" type="button" value="启用">
<input id="untrack-progress" class="favtag-btn config-btn" type="button" value="禁用">
</div>
<div id="toggle-infinite-scroll">
<h2 class="config-panel"> Infinite Scrolling </h2>
<span class="config-panel">Display all images in a vertical view in the same page.
<h2 class="config-panel"> 无限滚动 </h2>
<span class="config-panel">在同一页面中以垂直视图显示所有图像。
</span>
<input id="infinite-scroll-on" class="favtag-btn config-btn" type="button" value="Enabled">
<input id="infinite-scroll-off" class="favtag-btn config-btn" type="button" value="Disabled">
<input id="infinite-scroll-on" class="favtag-btn config-btn" type="button" value="启用">
<input id="infinite-scroll-off" class="favtag-btn config-btn" type="button" value="禁用">
</div>
[% END %]
@ -258,14 +276,14 @@
<!-- -->
[% BLOCK pagesel %]
<div class="absolute-options absolute-left">
<a class="fa fa-cog fa-2x" id="toggle-settings-overlay" href="#" title="Reader Settings"></a>
<a class="fa fa-question-circle fa-2x" id="toggle-help" href="#" title="Help"></a>
<a class="fa fa-cog fa-2x" id="toggle-settings-overlay" href="#" title="阅读设置"></a>
<a class="fa fa-question-circle fa-2x" id="toggle-help" href="#" title="帮助"></a>
</div>
<div class="absolute-options absolute-right">
<a class="fa fa-arrow-right fa-2x reading-direction" href="#" title="Reading Direction"></a>
<a class="fa fa-th fa-2x" id="toggle-archive-overlay" href="#" title="Archive Overview"></a>
<a class="fa fa-compress fa-2x" id="toggle-full-screen" href="#" title="FullScreen"></a>
<a class="fa fa-arrow-right fa-2x reading-direction" href="#" title="阅读方向"></a>
<a class="fa fa-th fa-2x" id="toggle-archive-overlay" href="#" title="档案预览"></a>
<a class="fa fa-compress fa-2x" id="toggle-full-screen" href="#" title="全屏模式"></a>
</div>
[% END %]
<!-- -->

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<title>[% title %] - Library Statistics</title>
<title>[% title %] - 资料库统计</title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -35,7 +35,7 @@
<body>
<div class='ido' style='text-align:center'>
<h2 class="ih" style="text-align:center">Library Statistics</h2>
<h2 class="ih" style="text-align:center">资料库统计</h2>
<br>
<br>
@ -44,23 +44,23 @@
<h1 class="ih">
<i class="fa fa-book fa-2x" aria-hidden="true"></i> <span style="font-size: 20px"> [% archivecount %]
</span>
Archives on record
个档案文件
<br><br>
<i class="fa fa-tags fa-2x" aria-hidden="true"></i> <span style="font-size: 20px" id="tagcount">
<i id="spinner" class="fa fa-virus fa-spin"></i> </span>
Different
tags existing
个不同
的标签
<br><br>
<i class="fa fa-folder-open fa-2x" aria-hidden="true"></i> <span style="font-size: 20px"> [% arcsize %]
GB </span>
in content folder
空间占用
<br><br>
<i class="fa fa-book-reader fa-2x" aria-hidden="true"></i> <span style="font-size: 20px"> [% pagestat %]
</span>
pages read
页已读
<br><br><br>
Tag Cloud <br>
标签云 <br>
</h1>
</div>
@ -71,7 +71,7 @@
<p class="loading-spinner">
<i id="spinner" class="fa fa-dharmachakra fa-4x fa-spin"></i>
</p>
Asking the great powers that be for your tag statistics...
探索标签统计信息的强大功能...
</div>
<div id="tagCloud" style="width: 80%; height: 500px; margin-left: auto; margin-right: auto">
@ -81,19 +81,20 @@
style="display: none; width:80%; margin-left: auto; margin-right: auto">
<li class="option-flyout">
<div class="collapsible-title caret-right">
<i class="fa fa-chart-bar" aria-hidden="true"></i> Detailed Stats
<i class="fa fa-chart-bar" aria-hidden="true"></i> 详细统计
</div>
<div class="collapsible-body">
<div id="tagList"
style="max-width: 80vw; display: flex; height:calc(2048px - 25vw); flex-direction: column; flex-wrap:wrap; align-items:flex-start; overflow:auto">
</div><br>
(These statistics only show tags that appear at least twice in your database.)
(这些统计信息仅显示在您的数据库中至少出现两次的标签.)
</div>
</li>
</ul>
<br>
<input id="goback" type="button" value="Return to Library" class="stdbtn">
<br>
<input id="goback" type="button" value="返回资料库" class="stdbtn">
</div>
[% INCLUDE footer %]

View File

@ -1,26 +1,26 @@
<tr>
<td class="option-td">
<h2 class="ih"> Archive Directory </h2>
<h2 class="ih"> 档案文件夹 </h2>
</td>
<td class="config-td">
<input class="stdinput" style="width:100%" maxlength="255" size="20" value="[% dirname %]" name="dirname"
type="text" [% IF forceddirname %] disabled title="This option is enforced by an environment variable." [%
type="text" [% IF forceddirname %] disabled title="此选项由环境变量强制执行。" [%
END %]>
<br> Directory where the archives will be located. It will be created if it doesn't exist.
<br>Make sure the OS user running LANraragi has read access to this directory. <br>
<br> 档案将被放置的目录,如果不存在,将被自动创建.
<br>确保运行 LANraragi 的系统的用户对该目录具有读取权限. <br>
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> Synology eCryptFS Compatibility Mode </h2>
<h2 class="ih"> 群晖 eCryptFS 兼容模式 </h2>
</td>
<td class="config-td">
[% IF enablecryptofs %]
<input id="enablecryptofs" name="enablecryptofs" class="fa" type="checkbox" checked> [% ELSE %]
<input id="enablecryptofs" name="enablecryptofs" class="fa" type="checkbox"> [% END %]
<label for="enablecryptofs">
<br>If enabled, LANraragi will cutoff archive filenames to 143 bytes, which is the max accepted by eCryptFS.
<br>如果启用LANraragi 会将存档文件名截断为 143 字节,这是 eCryptFS 接受的最大值.
</label>
</td>
</tr>
@ -29,35 +29,35 @@
<tr>
<td class="option-td">
<input id="rescan-button" class='stdbtn' type='button' value='Rescan Archive Directory' />
<input id="rescan-button" class='stdbtn' type='button' value='重新扫描存档目录' />
</td>
<td class="config-td">
Click this button to trigger a rescan of the Archive Directory in case you're missing files, <br>
or some data such as total page counts. <br>
单击此按钮以触发存档目录的重新扫描,以防丢失文件, <br>
或一些数据,例如总页数. <br>
<br>
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> Maximum <br>Temporary Folder Size </h2>
<h2 class="ih"> 最大 <br>临时存档占用 </h2>
</td>
<td class="config-td">
<input class="stdinput" style="width:100%" maxlength="255" size="20" value="[% tempmaxsize %]"
name="tempmaxsize" type="text">
<br>In MBs. The temporary folder contains recently opened archives, for faster subsequent reading. <br>
It is automatically emptied when it grows past this specified size.
<br>以MB为单位。 临时文件夹包含最近打开的档案,以便于后续读取。 <br>
当它超过此指定大小时,将自动清空。
</td>
</tr>
<tr>
<td class="option-td">
<input id='clean-temp' class='stdbtn' type='button' value='Clean Temporary Folder' />
<input id='clean-temp' class='stdbtn' type='button' value='清理临时文件夹' />
</td>
<td class="config-td">
Current Size:
当前大小:
<h2 style="display:inline"><span id="tempsize"> [%tempsize%] </span> MBs </h2>
<br>Empty the temporary folder manually by clicking this button.
<br>单击此按钮手动清空临时文件夹。
</td>
</tr>
@ -65,11 +65,11 @@
<tr>
<td class="option-td">
<input id='reset-search-cache' class='stdbtn' type='button' value='Reset Search Cache' />
<input id='reset-search-cache' class='stdbtn' type='button' value='重置搜索缓存' />
</td>
<td class="config-td">
The last searches done in the archive index are cached for faster loads. <br>
If something went wrong with said cache, you can reset it by clicking this button. <br>
存档索引中最后一次执行的搜索将被缓存以加快加载速度。 <br>
如果上述缓存出了问题,您可以通过单击此按钮将其重置。 <br>
<br>
</td>
</tr>
@ -78,28 +78,26 @@
<tr>
<td class="option-td">
<input id='clear-new-tags' class='stdbtn' type='button' value='Clear NEW flags' />
<input id='clear-new-tags' class='stdbtn' type='button' value='清理“NEW”标签' />
</td>
<td class="config-td">
Newly uploaded archives are marked as "new" in the index until you've opened them. <br>
If you want to clear those flags, click this button. <br>
在您打开新归档文件之前它们会在索引中标记为“NEW”。<br>
如果要清除这些标志,请单击此按钮。 <br>
<br>
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih">Replace duplicated archives</h2>
<h2 class="ih">更换重复的档案</h2>
</td>
<td class="config-td">
[% IF replacedupe %]
<input id="replacedupe" name="replacedupe" class="fa" type="checkbox" checked> [% ELSE %]
<input id="replacedupe" name="replacedupe" class="fa" type="checkbox"> [% END %]
<label for="replacedupe">
<br>If enabled, LANraragi will overwrite old archives when a newer one (with the same name) is uploaded
through the Web Uploader or the Download System.
<br> <i class="fas fa-exclamation-triangle" style="color:red"></i> This will delete metadata for old files
when they're replaced! Use with caution.
<br>如果启用了当通过Web Uploader或下载系统上载的新档案具有相同名称Lanraragi将覆盖旧档案。
<br> <i class="fas fa-exclamation-triangle" style="color:red"></i> 旧文件更换时,这将删除元数据!谨慎使用。
</label>
</td>
</tr>

View File

@ -1,101 +1,101 @@
<tr>
<td class="option-td">
<h2 class="ih"> Site Title </h2>
<h2 class="ih"> 站点名称 </h2>
</td>
<td class="config-td">
<input class="stdinput" style="width:100%" maxlength="255" size="20" value="[% title %]" name="htmltitle"
type="text">
<br>The site title appears on most pages as...their title.
<br>网站标题在大多数页面上显示为...标题。
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> MOTD </h2>
<h2 class="ih"> 座右铭 </h2>
</td>
<td class="config-td">
<input id="motd" class="stdinput" style="width:100%" maxlength="255" size="20" value="[% motd %]" name="motd"
type="text">
<br>Slang for Message of the Day. Appears on top of the main Library view.
<br>每日的座右铭,出现在主资料库的顶部。
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> Archives per page </h2>
<h2 class="ih"> 每页显示数量 </h2>
</td>
<td class="config-td">
<input class="stdinput" style="width:100%" maxlength="255" size="20" value="[% pagesize %]" name="pagesize"
type="number">
<br> Number of archives shown on a page in the main list.
<br> 单页面上显示的档案数量。
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> Resize Images in Reader </h2>
<h2 class="ih"> 在阅读器中缩放图像大小 </h2>
</td>
<td class="config-td">
[% IF enableresize %]
<input id="enableresize" name="enableresize" class="fa" type="checkbox" checked> [% ELSE %]
<input id="enableresize" name="enableresize" class="fa" type="checkbox"> [% END %]
<label for="enableresize">
<br> If enabled, pages exceeding a certain size will be resized when viewed to save bandwidth.
<br> <i class="fas fa-exclamation-triangle" style="color:red"></i> This option can potentially consume a lot
of RAM if enabled and used on large images! Use with caution.
<br> 如果启用,超过一定大小的页面将在查看时调整大小以节省带宽。
<br> <i class="fas fa-exclamation-triangle" style="color:red"></i> 如果在较大图像上启用并使用此选项,
则可能会消耗大量内存! 请谨慎使用。
</label>
</td>
</tr>
<tr class="resizefields">
<td class="option-td">
<h2 class="ih"> Image Size Threshold </h2>
<h2 class="ih"> 图像尺寸阈值 </h2>
</td>
<td class="config-td">
<input id="sizethreshold" class="stdinput" type="number" style="width:100%" maxlength="255" size="20"
value="[% sizethreshold %]" name="sizethreshold">
<br>(in KBs.) Maximum size an image can reach before being resized.
<br>(以 KBs.) 调整大小之前,图像可以达到的最大尺寸。
</td>
</tr>
<tr class="resizefields">
<td class="option-td">
<h2 class="ih"> Resize Quality </h2>
<h2 class="ih"> 调整质量 </h2>
</td>
<td class="config-td">
<input id="readerquality" class="stdinput" type="number" min="0" max="100" style="width:100%" maxlength="255"
size="20" value="[% readerquality %]" name="readerquality">
<br> Quality of the resized images. Less quality = Smaller image. (0-100)
<br> 调整大小后的图像的质量。 低质量 = 小容量图片。 (0-100)
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> Clientside Progress Tracking </h2>
<h2 class="ih"> 客户端进度跟踪 </h2>
</td>
<td class="config-td">
[% IF localprogress %]
<input id="localprogress" name="localprogress" class="fa" type="checkbox" checked> [% ELSE %]
<input id="localprogress" name="localprogress" class="fa" type="checkbox"> [% END %]
<label for="localprogress">
<br>Enabling this option will save reading progression on the browser (through localStorage) instead of the
server. <br />
Consider toggling this option if you're sharing the LANraragi instance with multiple users!
<br>启用此选项将保存浏览器上的阅读进度到本地,而不是
服务器. <br />
如果您与多个用户共用 LANraragi 服务器,请考虑切换此选项!
</label>
</td>
</tr>
<tr>
<td class="option-td">
<h2 class="ih"> Debug Mode </h2>
<h2 class="ih"> 调试模式 </h2>
</td>
<td class="config-td">
<td>
[% IF devmode %]
<input id="devmode" name="devmode" class="fa" type="checkbox" checked> [% ELSE %]
<input id="devmode" name="devmode" class="fa" type="checkbox"> [% END %]
<label for="devmode">
<br>Enabling Debug Mode will show more logs and disable update nagging. <br />Fully effective after
restarting LANraragi.
<br>启用调试模式将显示更多日志并禁用更新设置。 <br />重启后将
完全生效.
</label>
</td>
</tr>
@ -103,19 +103,19 @@
<tr>
<td class="option-td">
<input id='clean-db' class='stdbtn' type='button' value='Clean Database' />
<input id='clean-db' class='stdbtn' type='button' value='清理数据库' />
</td>
<td class="config-td">
Cleaning the database will remove entries that aren't on your filesystem.
清理数据库将删除文件系统上没有的条目。
</td>
</tr>
<tr>
<td class="option-td">
<input id='drop-db' class='stdbtn' type='button' value='Reset Database' />
<input id='drop-db' class='stdbtn' type='button' value='重置数据库' />
</td>
<td class="config-td">
<span style="color:red"><i class="fas fa-exclamation-triangle"></i> Danger zone!</span> <br>
Clicking this button will reset the entire database and delete all settings and metadata. <br>
<span style="color:red"><i class="fas fa-exclamation-triangle"></i> 危险!</span> <br>
单击此按钮将重置整个数据库并删除所有设置和元数据。 <br>
</td>
</tr>

View File

@ -1,38 +1,38 @@
<tr>
<td class="option-td">
<h2 class="ih"> Shinobu Status </h2>
<h2 class="ih"> 运行状态 </h2>
</td>
<td class="config-td">
<span id="shinobu-ok">The Shinobu File Watcher is currently <h2 class="ih"
<span id="shinobu-ok">当前后台监视进程工作 <h2 class="ih"
style="display:inline; color:rgb(26, 165, 26)">👍
OK!</h2> </span>
<span id="shinobu-ko">The Shinobu File Watcher is currently <h2 class="ih"
正常!</h2> </span>
<span id="shinobu-ko">当前后台监视进程工作 <h2 class="ih"
style="display:inline; color:rgb(207, 37, 37)">👹
Kaput! </h2></span>
异常! </h2></span>
(PID: <span id="pid"></span>)
<br>This File Watcher is responsible for monitoring your content directory and automatically handling new
archives as
they come. <br>
<br>该进程负责监视您的内容目录,并在
新档案出现时
自动进行处理。 <br>
</td>
</tr>
<tr>
<td class="option-td">
<input id="restart-button" class='stdbtn' type='button' value='Restart File Watcher' />
<input id="restart-button" class='stdbtn' type='button' value='重启后台文件监视进程' />
</td>
<td class="config-td">
If Shinobu is dead or unresponsive, you can reboot her by clicking this button.
如果进程已死或无响应,您可以通过单击此按钮来重新启动它。
</td>
</tr>
<tr>
<td class="option-td">
<input id='open-minion' class='stdbtn' type='button' value='Open Minion Console' />
<input id='open-minion' class='stdbtn' type='button' value='打开Minion控制台' />
</td>
<td class="config-td">
The Minion Worker handles spare tasks that are too long to execute within the request/response lifecycle of web
applications.<br>
The console shows currently running and concluded tasks.
Minion Worker 处理的备用任务太长无法在Web的请求/响应生命周期内
执行。<br>
控制台显示当前正在运行和已结束的任务。
</td>
</tr>

Some files were not shown because too many files have changed in this diff Show More