dev 基于官方原版 f9b76513 汉化
This commit is contained in:
parent
bcc6c74a30
commit
4c8c2ff124
@ -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 \
|
||||
|
@ -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"
|
||||
}
|
@ -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
|
||||
|
2
.github/workflows/release-delivery.yml
vendored
2
.github/workflows/release-delivery.yml
vendored
@ -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
|
||||
|
76
README.md
76
README.md
@ -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
5159
jquery.dataTables.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
@ -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");
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package LANraragi::Controller::Category;
|
||||
use Mojo::Base 'Mojolicious::Controller';
|
||||
|
||||
use utf8;
|
||||
|
||||
use URI::Escape;
|
||||
use Redis;
|
||||
use Encode;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package LANraragi::Controller::Index;
|
||||
use Mojo::Base 'Mojolicious::Controller';
|
||||
|
||||
use utf8;
|
||||
|
||||
use URI::Escape;
|
||||
use Redis;
|
||||
use Encode;
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -2,7 +2,7 @@ package LANraragi::Model::Category;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
|
||||
use Redis;
|
||||
use Mojo::JSON qw(decode_json encode_json);
|
||||
|
@ -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} }
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -2,7 +2,7 @@ package LANraragi::Model::Reader;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
|
||||
use Redis;
|
||||
use File::Basename;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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/_____/
|
||||
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
||||
|
97
lib/LANraragi/Plugin/Download/Koushoku.pm
Normal file
97
lib/LANraragi/Plugin/Download/Koushoku.pm
Normal 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;
|
@ -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;
|
||||
|
@ -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" }
|
||||
]
|
||||
|
@ -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" }
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -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 => "添加以下标签(如果可用):下载URL,Gallery 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(将在您的档案中附加匹配标签)"
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 => "要复制的标签,以逗号分隔." } ]
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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 => [],
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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 => "获取额外的时间戳(发布时间)和上传者元数据" },
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -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(将与此确切图库匹配的标签附加到您的档案中)"
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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 => []
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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 => "保存档案名称" } ]
|
||||
);
|
||||
|
||||
}
|
||||
|
188
lib/LANraragi/Plugin/Metadata/Koushoku.pm
Normal file
188
lib/LANraragi/Plugin/Metadata/Koushoku.pm
Normal 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;
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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" } ]
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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)"
|
||||
);
|
||||
|
||||
|
@ -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 的数据库迁移到新的标签规则系统."
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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 ) {
|
||||
|
@ -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 => "要搜索的网址."
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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}\""
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 "";
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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);
|
||||
|
@ -2,7 +2,7 @@ package LANraragi::Utils::Routing;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
|
||||
use Mojolicious::Plugin::Status;
|
||||
use Mojolicious::Plugin::Minion::Admin;
|
||||
|
@ -2,7 +2,7 @@ package LANraragi::Utils::Tags;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use feature "switch";
|
||||
no warnings 'experimental';
|
||||
|
||||
|
@ -2,7 +2,7 @@ package LANraragi::Utils::TempFolder;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
|
||||
use Cwd 'abs_path';
|
||||
use FindBin;
|
||||
|
@ -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;
|
||||
}
|
||||
|
10
package.json
10
package.json
@ -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",
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -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();
|
||||
|
@ -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",
|
||||
});
|
||||
|
@ -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("没有本地阅读进度可迁移");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 () {
|
||||
|
@ -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,
|
||||
|
@ -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>`;
|
||||
|
@ -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));
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
12
script/get_version
Normal 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} . "'"
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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 %]
|
||||
|
@ -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 %]
|
||||
|
@ -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;">
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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 %]
|
||||
|
@ -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>
|
@ -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">
|
||||
|
@ -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 %]
|
||||
<!-- -->
|
||||
|
@ -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 %]
|
||||
|
@ -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>
|
@ -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>
|
@ -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
Loading…
Reference in New Issue
Block a user