support plugin nexusphp-hit-and-run

This commit is contained in:
xiaomlove
2022-10-01 00:11:22 +08:00
parent 65ba6442b1
commit 6de5cb2f21
20 changed files with 222 additions and 81 deletions

View File

@@ -14,6 +14,7 @@ use App\Models\HitAndRun;
use App\Models\Medal;
use App\Models\Peer;
use App\Models\SearchBox;
use App\Models\Setting;
use App\Models\Snatch;
use App\Models\Tag;
use App\Models\Torrent;
@@ -88,8 +89,7 @@ class Test extends Command
*/
public function handle()
{
$rep = new ToolRepository();
$r = $rep->transfer('C:\Users\CHENYU~1\AppData\Local\Temp/nexusphp.v1.5.beta5.20120707.web.20220918.053953.zip', 0);
$r = strstr('hr.*', '.', true);
dd($r);
}

View File

@@ -76,6 +76,7 @@ class EditSetting extends Page implements Forms\Contracts\HasForms
}
}
Setting::query()->upsert($data, ['name'], ['value']);
do_action("nexus_setting_update");
clear_setting_cache();
Filament::notify('success', __('filament::resources/pages/edit-record.messages.saved'), true);
}
@@ -85,13 +86,9 @@ class EditSetting extends Page implements Forms\Contracts\HasForms
$tabs = [];
$tabs[] = Forms\Components\Tabs\Tab::make(__('label.setting.hr.tab_header'))
->id('hr')
->schema([
Forms\Components\Radio::make('hr.mode')->options(HitAndRun::listModes(true))->inline(true)->label(__('label.setting.hr.mode')),
Forms\Components\TextInput::make('hr.inspect_time')->helperText(__('label.setting.hr.inspect_time_help'))->label(__('label.setting.hr.inspect_time'))->integer(),
Forms\Components\TextInput::make('hr.seed_time_minimum')->helperText(__('label.setting.hr.seed_time_minimum_help'))->label(__('label.setting.hr.seed_time_minimum'))->integer(),
Forms\Components\TextInput::make('hr.ignore_when_ratio_reach')->helperText(__('label.setting.hr.ignore_when_ratio_reach_help'))->label(__('label.setting.hr.ignore_when_ratio_reach'))->integer(),
Forms\Components\TextInput::make('hr.ban_user_when_counts_reach')->helperText(__('label.setting.hr.ban_user_when_counts_reach_help'))->label(__('label.setting.hr.ban_user_when_counts_reach'))->integer(),
])->columns(2);
->schema($this->getHitAndRunSchema())
->columns(2)
;
$tabs[] = Forms\Components\Tabs\Tab::make(__('label.setting.backup.tab_header'))
->id('backup')
@@ -135,4 +132,16 @@ class EditSetting extends Page implements Forms\Contracts\HasForms
return $tabs;
}
private function getHitAndRunSchema()
{
$default = [
Forms\Components\Radio::make('hr.mode')->options(HitAndRun::listModes(true))->inline(true)->label(__('label.setting.hr.mode')),
Forms\Components\TextInput::make('hr.inspect_time')->helperText(__('label.setting.hr.inspect_time_help'))->label(__('label.setting.hr.inspect_time'))->integer(),
Forms\Components\TextInput::make('hr.seed_time_minimum')->helperText(__('label.setting.hr.seed_time_minimum_help'))->label(__('label.setting.hr.seed_time_minimum'))->integer(),
Forms\Components\TextInput::make('hr.ignore_when_ratio_reach')->helperText(__('label.setting.hr.ignore_when_ratio_reach_help'))->label(__('label.setting.hr.ignore_when_ratio_reach'))->integer(),
Forms\Components\TextInput::make('hr.ban_user_when_counts_reach')->helperText(__('label.setting.hr.ban_user_when_counts_reach_help'))->label(__('label.setting.hr.ban_user_when_counts_reach'))->integer(),
];
return apply_filter("nexus_hit_and_run_setting_schema", $default);
}
}

View File

@@ -2,6 +2,8 @@
namespace App\Models;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidArgumentException;
use Illuminate\Database\Eloquent\Casts\Attribute;
class HitAndRun extends NexusModel
@@ -17,7 +19,7 @@ class HitAndRun extends NexusModel
const STATUS_UNREACHED = 3;
const STATUS_PARDONED = 4;
public static $status = [
public static array $status = [
self::STATUS_INSPECTING => ['text' => 'Inspecting'],
self::STATUS_REACHED => ['text' => 'Reached'],
self::STATUS_UNREACHED => ['text' => 'Unreached'],
@@ -39,17 +41,37 @@ class HitAndRun extends NexusModel
protected function seedTimeRequired(): Attribute
{
return new Attribute(
get: fn($value, $attributes) => $this->status == self::STATUS_INSPECTING ? mkprettytime(3600 * Setting::get('hr.seed_time_minimum') - $this->snatch->seedtime) : '---'
get: fn($value, $attributes) => $this->doGetSeedTimeRequired()
);
}
protected function inspectTimeLeft(): Attribute
{
return new Attribute(
get: fn($value, $attributes) => $this->status == self::STATUS_INSPECTING ? mkprettytime(\Carbon\Carbon::now()->diffInSeconds($this->snatch->completedat->addHours(Setting::get('hr.inspect_time')))) : '---'
get: fn($value, $attributes) => $this->doGetInspectTimeLeft()
);
}
private function doGetInspectTimeLeft(): string
{
if ($this->status != self::STATUS_INSPECTING) {
return '---';
}
$inspectTime = HitAndRun::getConfig('inspect_time', $this->torrent->basic_category->mode);
$diffInSeconds = Carbon::now()->diffInSeconds($this->snatch->completedat->addHours($inspectTime));
return mkprettytime($diffInSeconds);
}
private function doGetSeedTimeRequired(): string
{
if ($this->status != self::STATUS_INSPECTING) {
return '---';
}
$seedTimeMinimum = HitAndRun::getConfig('seed_time_minimum', $this->torrent->basic_category->mode);
$diffInSeconds = 3600 * $seedTimeMinimum - $this->snatch->seedtime;
return mkprettytime($diffInSeconds);
}
public function getStatusTextAttribute()
{
return nexus_trans('hr.status_' . $this->status);
@@ -87,8 +109,29 @@ class HitAndRun extends NexusModel
public static function getIsEnabled(): bool
{
$result = Setting::get('hr.mode');
return $result && in_array($result, [self::MODE_GLOBAL, self::MODE_MANUAL]);
$enableSpecialSection = Setting::get('main.spsct') == 'yes';
$browseMode = self::getConfig('mode', Setting::get('main.browsecat'));
$browseEnabled = $browseMode && in_array($browseMode, [self::MODE_GLOBAL, self::MODE_MANUAL]);
if (!$enableSpecialSection) {
do_log("Not enable special section, browseEnabled: $browseEnabled");
return $browseEnabled;
}
$specialMode = self::getConfig('mode', Setting::get('main.specialcat'));
$specialEnabled = $specialMode && in_array($specialMode, [self::MODE_GLOBAL, self::MODE_MANUAL]);
$result = $browseEnabled || $specialEnabled;
do_log("Enable special section, browseEnabled: $browseEnabled, specialEnabled: $specialEnabled, result: $result");
return $result;
}
public static function getConfig($name, $searchBoxId)
{
if ($name == '*') {
$key = "hr";
} else {
$key = "hr.$name";
}
$default = Setting::get($key);
return apply_filter("nexus_setting_get", $default, $name, ['mode' => $searchBoxId]);
}
public function torrent(): \Illuminate\Database\Eloquent\Relations\BelongsTo

View File

@@ -18,6 +18,14 @@ class SearchBox extends NexusModel
'extra' => 'object'
];
const SECTION_BROWSE = 'browse';
const SECTION_SPECIAL = 'special';
public static array $sections = [
self::SECTION_BROWSE => ['text' => 'Browse'],
self::SECTION_SPECIAL => ['text' => 'Special'],
];
const EXTRA_DISPLAY_COVER_ON_TORRENT_LIST = 'display_cover_on_torrent_list';
const EXTRA_DISPLAY_SEED_BOX_ICON_ON_TORRENT_LIST = 'display_seed_box_icon_on_torrent_list';
@@ -35,6 +43,21 @@ class SearchBox extends NexusModel
return $result;
}
public static function listSections($field = null): array
{
$result = [];
foreach (self::$sections as $key => $value) {
$value['text'] = nexus_trans("searchbox.sections.$key");
$value['mode'] = Setting::get("main.{$key}cat");
if ($field !== null && isset($value[$field])) {
$result[$key] = $value[$field];
} else {
$result[$key] = $value;
}
}
return $result;
}
public function getCustomFieldsAttribute($value): array
{
if (!is_array($value)) {

View File

@@ -289,7 +289,8 @@ class Torrent extends NexusModel
public function getHrAttribute(): string
{
$hrMode = Setting::get('hr.mode');
// $hrMode = Setting::get('hr.mode');
$hrMode = HitAndRun::getConfig('mode', $this->basic_category->mode);
if ($hrMode == HitAndRun::MODE_GLOBAL) {
return self::HR_YES;
}

View File

@@ -3,13 +3,16 @@ namespace App\Repositories;
use App\Models\HitAndRun;
use App\Models\Message;
use App\Models\SearchBox;
use App\Models\Setting;
use App\Models\User;
use App\Models\UserBanLog;
use Carbon\Carbon;
use Elasticsearch\Endpoints\Search;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Nexus\Database\NexusDB;
class HitAndRunRepository extends BaseRepository
{
@@ -87,12 +90,23 @@ class HitAndRunRepository extends BaseRepository
return $query;
}
public function cronjobUpdateStatus($uid = null, $torrentId = null, $ignoreTime = false): bool|int
public function cronjobUpdateStatus($uid = null, $torrentId = null, $ignoreTime = false)
{
do_log("uid: $uid, torrentId: $torrentId, ignoreTime: " . var_export($ignoreTime, true));
$enableSpecialSection = Setting::get('main.spsct') == 'yes';
$browseMode = Setting::get('main.browsecat');
$specialMode = Setting::get('main.specialcat');
$this->doCronjobUpdateStatus($browseMode, $uid, $torrentId, $ignoreTime);
if ($enableSpecialSection && $browseMode != $specialMode) {
$this->doCronjobUpdateStatus($specialMode, $uid, $torrentId, $ignoreTime, $specialMode);
}
}
private function doCronjobUpdateStatus($searchBoxId, $uid = null, $torrentId = null, $ignoreTime = false)
{
do_log("searchBoxId: $searchBoxId, uid: $uid, torrentId: $torrentId, ignoreTime: " . var_export($ignoreTime, true));
$setting = HitAndRun::getConfig('*', $searchBoxId);
$size = 1000;
$page = 1;
$setting = Setting::get('hr');
if (empty($setting['mode'])) {
do_log("H&R not set.");
return false;
@@ -108,7 +122,7 @@ class HitAndRunRepository extends BaseRepository
$query = HitAndRun::query()
->where('status', HitAndRun::STATUS_INSPECTING)
->with([
'torrent' => function ($query) {$query->select(['id', 'size', 'name']);},
'torrent' => function ($query) {$query->select(['id', 'size', 'name', 'category']);},
'snatch',
'user' => function ($query) {$query->select(['id', 'username', 'lang', 'class', 'donoruntil', 'enabled']);},
'user.language',
@@ -122,6 +136,9 @@ class HitAndRunRepository extends BaseRepository
if (!$ignoreTime) {
$query->where('created_at', '<', Carbon::now()->subHours($setting['inspect_time']));
}
$query->whereHas('torrent.basic_category', function (Builder $query) use ($searchBoxId) {
return $query->where('mode', $searchBoxId);
});
$successCounts = 0;
$disabledUsers = [];
while (true) {
@@ -164,7 +181,7 @@ class HitAndRunRepository extends BaseRepository
$requireSeedTime = bcmul($setting['seed_time_minimum'], 3600);
do_log("$currentLog, targetSeedTime: $targetSeedTime, requireSeedTime: $requireSeedTime");
if ($targetSeedTime >= $requireSeedTime) {
$result = $this->reachedBySeedTime($row);
$result = $this->reachedBySeedTime($row, $searchBoxId);
if ($result) {
$successCounts++;
}
@@ -176,7 +193,7 @@ class HitAndRunRepository extends BaseRepository
$requireShareRatio = $setting['ignore_when_ratio_reach'];
do_log("$currentLog, targetShareRatio: $targetShareRatio, requireShareRatio: $requireShareRatio");
if ($targetShareRatio >= $requireShareRatio) {
$result = $this->reachedByShareRatio($row);
$result = $this->reachedByShareRatio($row, $searchBoxId);
if ($result) {
$successCounts++;
}
@@ -185,7 +202,7 @@ class HitAndRunRepository extends BaseRepository
//unreached
if ($row->created_at->addHours($setting['inspect_time'])->lte(Carbon::now())) {
$result = $this->unreached($row, !isset($disabledUsers[$row->uid]));
$result = $this->unreached($row, $searchBoxId, !isset($disabledUsers[$row->uid]));
if ($result) {
$successCounts++;
$disabledUsers[$row->uid] = true;
@@ -194,7 +211,7 @@ class HitAndRunRepository extends BaseRepository
}
$page++;
}
do_log("[CRONJOB_UPDATE_HR_DONE]");
do_log("searchBoxId: $searchBoxId, [CRONJOB_UPDATE_HR_DONE]");
return $successCounts;
}
@@ -212,15 +229,15 @@ class HitAndRunRepository extends BaseRepository
];
}
private function reachedByShareRatio(HitAndRun $hitAndRun): bool
private function reachedByShareRatio(HitAndRun $hitAndRun, $searchBoxId): bool
{
do_log(__METHOD__);
$comment = nexus_trans('hr.reached_by_share_ratio_comment', [
'now' => Carbon::now()->toDateTimeString(),
'seed_time_minimum' => Setting::get('hr.seed_time_minimum'),
'seed_time_minimum' => HitAndRun::getConfig('seed_time_minimum', $searchBoxId),
'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1),
'share_ratio' => get_hr_ratio($hitAndRun->snatch->uploaded, $hitAndRun->snatch->downloaded),
'ignore_when_ratio_reach' => Setting::get('hr.ignore_when_ratio_reach'),
'ignore_when_ratio_reach' => HitAndRun::getConfig('ignore_when_ratio_reach', $searchBoxId),
], $hitAndRun->user->locale);
$update = [
'comment' => $comment
@@ -228,13 +245,13 @@ class HitAndRunRepository extends BaseRepository
return $this->inspectingToReached($hitAndRun, $update, __FUNCTION__);
}
private function reachedBySeedTime(HitAndRun $hitAndRun): bool
private function reachedBySeedTime(HitAndRun $hitAndRun, $searchBoxId): bool
{
do_log(__METHOD__);
$comment = nexus_trans('hr.reached_by_seed_time_comment', [
'now' => Carbon::now()->toDateTimeString(),
'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1),
'seed_time_minimum' => Setting::get('hr.seed_time_minimum')
'seed_time_minimum' => HitAndRun::getConfig('seed_time_minimum', $searchBoxId)
], $hitAndRun->user->locale);
$update = [
'comment' => $comment
@@ -271,16 +288,16 @@ class HitAndRunRepository extends BaseRepository
return true;
}
private function unreached(HitAndRun $hitAndRun, $disableUser = true): bool
private function unreached(HitAndRun $hitAndRun, $searchBoxId, $disableUser = true): bool
{
do_log(sprintf('hitAndRun: %s, disableUser: %s', $hitAndRun->toJson(), var_export($disableUser, true)));
$comment = nexus_trans('hr.unreached_comment', [
'now' => Carbon::now()->toDateTimeString(),
'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1),
'seed_time_minimum' => Setting::get('hr.seed_time_minimum'),
'seed_time_minimum' => HitAndRun::getConfig('seed_time_minimum', $searchBoxId),
'share_ratio' => get_hr_ratio($hitAndRun->snatch->uploaded, $hitAndRun->snatch->downloaded),
'torrent_size' => mksize($hitAndRun->torrent->size),
'ignore_when_ratio_reach' => Setting::get('hr.ignore_when_ratio_reach')
'ignore_when_ratio_reach' => HitAndRun::getConfig('ignore_when_ratio_reach', $searchBoxId)
], $hitAndRun->user->locale);
$update = [
'status' => HitAndRun::STATUS_UNREACHED,
@@ -319,7 +336,7 @@ class HitAndRunRepository extends BaseRepository
/** @var User $user */
$user = $hitAndRun->user;
$counts = $user->hitAndRuns()->where('status', HitAndRun::STATUS_UNREACHED)->count();
$disableCounts = Setting::get('hr.ban_user_when_counts_reach');
$disableCounts = HitAndRun::getConfig('ban_user_when_counts_reach', $searchBoxId);
do_log("user: {$user->id}, H&R counts: $counts, disableCounts: $disableCounts", 'notice');
if ($counts >= $disableCounts) {
do_log("[DISABLE_USER_DUE_TO_H&R_UNREACHED]", 'notice');
@@ -347,23 +364,48 @@ class HitAndRunRepository extends BaseRepository
public function getStatusStats($uid, $formatted = true)
{
$results = HitAndRun::query()->where('uid', $uid)
->selectRaw('status, count(*) as counts')
->groupBy('status')
->get()
->pluck('counts', 'status');
if ($formatted) {
return sprintf(
'%s/%s/%s',
$results->get(HitAndRun::STATUS_INSPECTING, 0),
$results->get(HitAndRun::STATUS_UNREACHED, 0),
Setting::get('hr.ban_user_when_counts_reach')
);
$enableSpecialSection = Setting::get('main.spsct') == 'yes';
if ($enableSpecialSection) {
$sql = "select hit_and_runs.status, categories.mode, count(*) as counts from hit_and_runs left join torrents on torrents.id = hit_and_runs.torrent_id left join categories on categories.id = torrents.category where hit_and_runs.uid = $uid group by hit_and_runs.status, categories.mode";
} else {
$sql = "select hit_and_runs.status, count(*) as counts from hit_and_runs where uid = $uid group by status";
}
$results = NexusDB::select($sql);
if (!$formatted) {
return $results;
}
if ($enableSpecialSection) {
$grouped = [];
foreach ($results as $item) {
$grouped[$item['mode']][$item['status']] = $item['counts'];
}
$out = [];
foreach (SearchBox::listSections() as $key => $info) {
$out[] = sprintf(
'%s: %s/%s/%s',
$info['text'],
$grouped[$info['mode']][HitAndRun::STATUS_INSPECTING] ?? 0,
$grouped[$info['mode']][HitAndRun::STATUS_UNREACHED] ?? 0,
HitAndRun::getConfig('ban_user_when_counts_reach', $info['mode'])
);
}
return implode(" ", $out);
} else {
foreach (SearchBox::listSections() as $key => $info) {
if ($key == SearchBox::SECTION_BROWSE) {
return sprintf(
'%s/%s/%s',
$results[HitAndRun::STATUS_INSPECTING] ?? 0,
$results[HitAndRun::STATUS_UNREACHED] ?? 0,
HitAndRun::getConfig('ban_user_when_counts_reach', $info['mode'])
);
}
}
}
return $results;
}
public function listStatus(): array
{
$results = [];
@@ -409,4 +451,14 @@ class HitAndRunRepository extends BaseRepository
{
return [HitAndRun::STATUS_INSPECTING, HitAndRun::STATUS_UNREACHED];
}
public function renderOnUploadPage($value, $searchBoxId): string
{
if (HitAndRun::getConfig('mode', $searchBoxId) == \App\Models\HitAndRun::MODE_MANUAL && user_can('torrent_hr')) {
$hrRadio = sprintf('<label><input type="radio" name="hr[%s]" value="0"%s />NO</label>', $searchBoxId, $value == 0 ? ' checked' : '');
$hrRadio .= sprintf('<label><input type="radio" name="hr[%s]" value="1"%s />YES</label>', $searchBoxId, $value == 1 ? ' checked' : '');
return tr('H&R', $hrRadio, 1, "mode_$searchBoxId", true);
}
return '';
}
}

View File

@@ -1092,7 +1092,8 @@ class TrackerRepository extends BaseRepository
if ($user->isDonating()) {
return;
}
$hrMode = Setting::get('hr.mode');
// $hrMode = Setting::get('hr.mode');
$hrMode = HitAndRun::getConfig('mode', $torrent->basic_category->mode);
if ($hrMode == HitAndRun::MODE_DISABLED) {
return;
}