diff --git a/app/Filament/Resources/System/TrackerUrlResource.php b/app/Filament/Resources/System/TrackerUrlResource.php new file mode 100644 index 00000000..7b4ef1d6 --- /dev/null +++ b/app/Filament/Resources/System/TrackerUrlResource.php @@ -0,0 +1,116 @@ +schema([ + Forms\Components\TextInput::make('url')->required(), + Forms\Components\Radio::make('is_default') + ->label(__('label.is_default')) + ->options(self::getYesNoOptions()) + ->required(true) + ->inline() + , + Forms\Components\Radio::make('enabled') + ->label(__('label.enabled')) + ->options(self::getEnableDisableOptions(1, 0)) + ->required(true) + ->inline() + , + Forms\Components\TextInput::make('priority') + ->label(__('label.priority'))->numeric() + ->default(0) + ->helperText(__('label.priority_help')) + , + ]); + } + + public static function getEloquentQuery(): Builder + { + return TrackerUrl::query() + ->orderBy('is_default', 'desc') + ->orderBy('priority', 'desc') + ->orderBy('id', 'desc') + ; + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('id') + , + Tables\Columns\TextColumn::make('url') + , + Tables\Columns\IconColumn::make('is_default') + ->label(__('label.is_default')) + ->boolean() + , + Tables\Columns\IconColumn::make('enabled') + ->label(__('label.enabled')) + ->boolean() + , + Tables\Columns\TextColumn::make('priority') + ->label(__('label.priority')) + , + Tables\Columns\TextColumn::make('updated_at') + ->label(__('label.updated_at')) + , + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ManageTrackerUrls::route('/'), + ]; + } +} diff --git a/app/Filament/Resources/System/TrackerUrlResource/Pages/ManageTrackerUrls.php b/app/Filament/Resources/System/TrackerUrlResource/Pages/ManageTrackerUrls.php new file mode 100644 index 00000000..722e07ff --- /dev/null +++ b/app/Filament/Resources/System/TrackerUrlResource/Pages/ManageTrackerUrls.php @@ -0,0 +1,20 @@ +is_default == 1) { + self::query()->where("id", "!=", $model->id)->update(["is_default" => 0]); + } + //添加 id 与 URL 映射 + $redis = NexusDB::redis(); + $redis->del(self::TRACKER_URL_CACHE_KEY); + $list = self::listAll(); + $first = $list->first(); + $hasDefault = false; + foreach ($list as $item) { + $redis->hset(self::TRACKER_URL_CACHE_KEY, $item->id, $item->url); + if ($item->is_default == 1) { + $hasDefault = true; + $redis->set(self::TRACKER_URL_DEFAULT_CACHE_KEY, $item->url); + } + } + if (!$hasDefault && $first) { + $redis->set(self::TRACKER_URL_DEFAULT_CACHE_KEY, $first->url); + } + }); + static::saving(function (TrackerUrl $model) { + if ($model->is_default == 1) { + $model->enabled = 1; + } + }); + } + + public static function listAll() + { + return self::query() + ->where("enabled", 1) + ->orderBy("is_default", "desc") + ->orderBy("priority", "desc") + ->get(); + } + + public static function getById(int $trackerUrlId) + { + $redis = NexusDB::redis(); + if ($trackerUrlId == 0) { + return $redis->get(self::TRACKER_URL_DEFAULT_CACHE_KEY); + } + $result = $redis->hget(self::TRACKER_URL_CACHE_KEY, $trackerUrlId); + if (!$result) { + $result = $redis->get(self::TRACKER_URL_DEFAULT_CACHE_KEY); + } + return $result; + } +} diff --git a/database/migrations/2025_06_19_194137_create_tracker_urls_table.php b/database/migrations/2025_06_19_194137_create_tracker_urls_table.php new file mode 100644 index 00000000..a901202f --- /dev/null +++ b/database/migrations/2025_06_19_194137_create_tracker_urls_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('url'); + $table->tinyInteger('enabled')->default(1); + $table->tinyInteger('is_default')->default(0); + $table->integer('priority')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tracker_urls'); + } +}; diff --git a/database/migrations/2025_06_19_194434_add_tracker_url_id_to_users_table.php b/database/migrations/2025_06_19_194434_add_tracker_url_id_to_users_table.php new file mode 100644 index 00000000..17ee7fe6 --- /dev/null +++ b/database/migrations/2025_06_19_194434_add_tracker_url_id_to_users_table.php @@ -0,0 +1,28 @@ +integer('tracker_url_id')->default(0); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('tracker_url_id'); + }); + } +}; diff --git a/include/constants.php b/include/constants.php index 791eb03e..8535a5f4 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ '登记', 'checkbox_pm_on_topic_reply' => '论坛帖子有新回复时通知我', 'checkbox_pm_on_hr_reached' => 'H&R 达标时通知我', + 'row_tracker_url' => 'Tracker URL', + 'row_tracker_url_help' => '注意:选择后只能向选中的链接汇报。默认只能向列表中的第 1 个默认链接汇报。', ); ?> diff --git a/lang/cht/lang_usercp.php b/lang/cht/lang_usercp.php index d6674cc8..19164494 100644 --- a/lang/cht/lang_usercp.php +++ b/lang/cht/lang_usercp.php @@ -254,6 +254,8 @@ $lang_usercp = array 'add_seed_box_btn' => '登記', 'checkbox_pm_on_topic_reply' => '論壇帖子有新回復時通知我', 'checkbox_pm_on_hr_reached' => 'H&R 達標時通知我', + 'row_tracker_url' => 'Tracker URL', + 'row_tracker_url_help' => '注意:選擇後只能向選中的鏈接匯報。默認只能向列表中的第 1 個默認鏈接匯報。', ); ?> diff --git a/lang/en/lang_usercp.php b/lang/en/lang_usercp.php index 7f60d108..cc43446c 100644 --- a/lang/en/lang_usercp.php +++ b/lang/en/lang_usercp.php @@ -256,6 +256,8 @@ $lang_usercp = array 'add_seed_box_btn' => 'Register', 'checkbox_pm_on_topic_reply' => 'Notify me when there are new replies to forum posts', 'checkbox_pm_on_hr_reached' => 'Notify me when H&R reaches target', + 'row_tracker_url' => 'Tracker URL', + 'row_tracker_url_help' => 'Note: Once selected, announce can only be sent to the selected link. By default, announce can only be sent to the first default link in the list.', ); ?> diff --git a/nexus/Install/Update.php b/nexus/Install/Update.php index 240ca144..ea2af3bf 100644 --- a/nexus/Install/Update.php +++ b/nexus/Install/Update.php @@ -15,6 +15,7 @@ use App\Models\Setting; use App\Models\Tag; use App\Models\Torrent; use App\Models\TorrentTag; +use App\Models\TrackerUrl; use App\Models\User; use App\Models\UserBanLog; use App\Repositories\AttendanceRepository; @@ -361,6 +362,19 @@ class Update extends Install Artisan::call("upgrade:migrate_snatched_hr_id"); Artisan::call("upgrade:migrate_snatched_buy_log_id"); } + if (!Schema::hasTable("tracker_urls")) { + $this->runMigrate("database/migrations/2025_06_19_194137_create_tracker_urls_table.php"); + $announceUrl = get_setting("security.https_announce_url"); + if (empty($announceUrl)) { + $announceUrl = get_setting("basic.announce_url"); + } + TrackerUrl::query()->create([ + "url" => $announceUrl, + "enabled" => 1, + "is_default" => 1, + ]); + NexusDB::cache_del("nexus_plugin_store_all"); + } } diff --git a/public/announce.php b/public/announce.php index 4a88aa30..0a364ca8 100644 --- a/public/announce.php +++ b/public/announce.php @@ -111,7 +111,7 @@ $seeder = ($left == 0) ? "yes" : "no"; // check passkey if (!$az = $Cache->get_value('user_passkey_'.$passkey.'_content')){ - $res = sql_query("SELECT id, username, downloadpos, enabled, uploaded, downloaded, class, parked, clientselect, showclienterror, passkey, donor, donoruntil, seedbonus FROM users WHERE passkey=". sqlesc($passkey)." LIMIT 1"); + $res = sql_query("SELECT id, username, downloadpos, enabled, uploaded, downloaded, class, parked, clientselect, showclienterror, passkey, donor, donoruntil, seedbonus, tracker_url_id FROM users WHERE passkey=". sqlesc($passkey)." LIMIT 1"); $az = mysql_fetch_array($res); do_log("[check passkey], currentUser: " . nexus_json_encode($az)); $Cache->cache_value('user_passkey_'.$passkey.'_content', $az, 3600); @@ -133,6 +133,13 @@ $CURUSER = $GLOBALS["CURUSER"] = $az; $isDonor = is_donor($az); $az['__is_donor'] = $isDonor; $log = "user: $userid, isDonor: $isDonor, seeder: $seeder, ip: $ip, ipv4: $ipv4, ipv6: $ipv6"; +//check tracker url +$trackerUrl = \App\Models\TrackerUrl::getById($az['tracker_url_id']); +$currentUrl = getSchemeAndHttpHost(); +if (!str_contains($trackerUrl, $currentUrl)) { + do_log("announce check tracker url, trackerUrl: $trackerUrl does not contains: $currentUrl"); + warn("you should announce to: $trackerUrl"); +} //3. CHECK IF CLIENT IS ALLOWED //$clicheck_res = check_client($peer_id,$agent,$client_familyid); diff --git a/public/download.php b/public/download.php index 12df53eb..06d1556f 100644 --- a/public/download.php +++ b/public/download.php @@ -84,9 +84,9 @@ if ($CURUSER['downloadpos']=="no") { denyDownload(); } -$trackerSchemaAndHost = get_tracker_schema_and_host(); -$ssl_torrent = $trackerSchemaAndHost['ssl_torrent']; -$base_announce_url = $trackerSchemaAndHost['base_announce_url']; +//$trackerSchemaAndHost = get_tracker_schema_and_host(); +//$ssl_torrent = $trackerSchemaAndHost['ssl_torrent']; +//$base_announce_url = $trackerSchemaAndHost['base_announce_url']; $res = sql_query("SELECT torrents.name, torrents.filename, torrents.save_as, torrents.size, torrents.owner, torrents.banned, torrents.approval_status, torrents.price, categories.mode as search_box_id FROM torrents left join categories on torrents.category = categories.id WHERE torrents.id = ".sqlesc($id)) or sqlerr(__FILE__, __LINE__); $row = mysql_fetch_assoc($res); @@ -140,7 +140,7 @@ if (strlen($CURUSER['passkey']) != 32) { sql_query("UPDATE users SET passkey=".sqlesc($CURUSER['passkey'])." WHERE id=".sqlesc($CURUSER['id'])); } $dict = \Rhilip\Bencode\Bencode::load($fn); -$dict['announce'] = $ssl_torrent . $base_announce_url . "?passkey=" . $CURUSER['passkey']; +$dict['announce'] = \App\Models\TrackerUrl::getById($CURUSER['tracker_url_id']) . "?passkey=" . $CURUSER['passkey']; $dict['comment'] = getSchemeAndHttpHost(true) . "/details.php?id=" . $id; do_log(sprintf("[ANNOUNCE_URL], user: %s, torrent: %s, url: %s", $CURUSER['id'] ?? '', $id, $dict['announce'])); /** diff --git a/public/settings.php b/public/settings.php index 4dd7f104..b310383e 100644 --- a/public/settings.php +++ b/public/settings.php @@ -369,7 +369,7 @@ elseif ($action == 'securitysettings') //security settings print ("
"); tr($lang_settings['row_enable_ssl']," ".$lang_settings['text_yes']. " ".$lang_settings['text_no']. " ".$lang_settings['text_optional']."
".$lang_settings['text_ssl_note'], 1); tr($lang_settings['row_enable_ssl_tracker']," ".$lang_settings['text_yes']. " ".$lang_settings['text_no']. " ".$lang_settings['text_optional']."
".$lang_settings['text_ssl_note'], 1); - tr($lang_settings['row_https_announce_url']," ".$lang_settings['text_https_announce_url_note'] . $_SERVER["HTTP_HOST"]."/announce.php", 1); +// tr($lang_settings['row_https_announce_url']," ".$lang_settings['text_https_announce_url_note'] . $_SERVER["HTTP_HOST"]."/announce.php", 1); yesorno($lang_settings['row_enable_image_verification'], 'iv', $SECURITY["iv"], $lang_settings['text_image_verification_note']); yesorno($lang_settings['row_allow_email_change'], 'changeemail', $SECURITY["changeemail"], $lang_settings['text_email_change_note']); tr($lang_settings['row_cheater_detection_level']," ".$lang_settings['text_cheater_detection_level_note']."
".$lang_settings['text_never_suspect'].classlist('nodetect',$AUTHORITY['staffmem'],$SECURITY['nodetect']).$lang_settings['text_or_above'].get_user_class_name(UC_UPLOADER,false,true,true).".", 1); @@ -507,7 +507,7 @@ elseif ($action == 'basicsettings') // basic settings print (""); tr($lang_settings['row_site_name']," ".$lang_settings['text_site_name_note'], 1); tr($lang_settings['row_base_url']," ".$lang_settings['text_it_should_be'] . $_SERVER["HTTP_HOST"] . $lang_settings['text_base_url_note'], 1); - tr($lang_settings['row_announce_url']," ".$lang_settings['text_it_should_be'] . $_SERVER["HTTP_HOST"].DEFAULT_TRACKER_URI, 1); +// tr($lang_settings['row_announce_url']," ".$lang_settings['text_it_should_be'] . $_SERVER["HTTP_HOST"].DEFAULT_TRACKER_URI, 1); // tr($lang_settings['row_mysql_host']," ".$lang_settings['text_mysql_host_note'], 1); // tr($lang_settings['row_mysql_user']," ".$lang_settings['text_mysql_user_note'], 1); // tr($lang_settings['row_mysql_password']," ".$lang_settings['text_mysql_password_note'], 1); diff --git a/public/usercp.php b/public/usercp.php index fd93be73..80886565 100644 --- a/public/usercp.php +++ b/public/usercp.php @@ -129,6 +129,7 @@ if ($action){ // $updateset[] = "tzoffset = " . sqlesc($tzoffset); $updateset[] = "info = " . sqlesc($info); + $updateset[] = "tracker_url_id = " . sqlesc($_POST["tracker_url_id"]); //notifs if (!empty($_POST['notifs'])) { @@ -145,10 +146,12 @@ if ($action){ } $query = "UPDATE users SET " . implode(",", $updateset) . " WHERE id = ".sqlesc($CURUSER["id"]); $result = sql_query($query); - if (!$result) - sqlerr(__FILE__,__LINE__); - else - header("Location: usercp.php?action=personal&type=saved"); + if (!$result) { + sqlerr(__FILE__,__LINE__); + } else { + clear_user_cache($CURUSER["id"], $CURUSER['passkey']); + header("Location: usercp.php?action=personal&type=saved"); + } } stdhead($lang_usercp['head_control_panel'].$lang_usercp['head_personal_settings'],true); @@ -156,11 +159,18 @@ if ($action){ $ct_r = sql_query("SELECT id,name FROM countries ORDER BY name") or die; while ($ct_a = mysql_fetch_array($ct_r)) $countries .= "\n"; - $isplist = "\n"; + + $trackerUrls = "\n"; + $trackerUrlList = \App\Models\TrackerUrl::listAll(); + foreach ($trackerUrlList as $item) { + $trackerUrls .= "\n"; + } + $isplist = "\n"; $isp_r = sql_query("SELECT id,name FROM isp ORDER BY id ASC") or die; while ($isp_a = mysql_fetch_array($isp_r)) $isplist .= "\n"; - $downloadspeed = "\n"; + + $downloadspeed = "\n"; $ds_a = sql_query("SELECT id,name FROM downloadspeed ORDER BY id") or die; while ($ds_b = mysql_fetch_array($ds_a)) $downloadspeed .= "\n"; @@ -199,7 +209,8 @@ if ($action){ tr_small($lang_usercp['row_gender'], "".$lang_usercp['radio_not_available']." ".$lang_usercp['radio_male']."".$lang_usercp['radio_female'],1); - tr_small($lang_usercp['row_country'], "",1); + tr_small($lang_usercp['row_tracker_url'], "" . "
".$lang_usercp['row_tracker_url_help']."",1); + tr_small($lang_usercp['row_country'], "",1); //School select if ($showschool == 'yes'){ $schools = "n"; diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index 401e4aff..8841be55 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -47,6 +47,7 @@ return [ 'queue_monitor' => 'Queue monitor', 'user_modify_logs' => 'User modify logs', 'message_templates' => 'Message templates', + 'tracker_url' => 'Tracker URL', ], 'resources' => [ 'agent_allow' => [ diff --git a/resources/lang/en/label.php b/resources/lang/en/label.php index eff3d96f..71e2e345 100644 --- a/resources/lang/en/label.php +++ b/resources/lang/en/label.php @@ -48,6 +48,7 @@ return [ 'text_code' => "CODE", 'language' => 'Language', 'content' => 'Content', + 'is_default' => 'Is default', 'setting' => [ 'nav_text' => 'Setting', 'backup' => [ diff --git a/resources/lang/zh_CN/admin.php b/resources/lang/zh_CN/admin.php index 8e8d9f1a..2728e957 100644 --- a/resources/lang/zh_CN/admin.php +++ b/resources/lang/zh_CN/admin.php @@ -45,6 +45,7 @@ return [ 'queue_monitor' => '队列监控', 'user_modify_logs' => '修改记录', 'message_templates' => '消息模板', + 'tracker_url' => 'Tracker URL', ], 'resources' => [ 'agent_allow' => [ diff --git a/resources/lang/zh_CN/label.php b/resources/lang/zh_CN/label.php index 6cdd7fcb..62bbfafc 100644 --- a/resources/lang/zh_CN/label.php +++ b/resources/lang/zh_CN/label.php @@ -48,6 +48,7 @@ return [ 'text_code' => "代码", 'language' => '语言', 'content' => '内容', + 'is_default' => '是否默认', 'setting' => [ 'nav_text' => '设置', 'backup' => [ diff --git a/resources/lang/zh_TW/admin.php b/resources/lang/zh_TW/admin.php index 52427cc1..69834a0a 100644 --- a/resources/lang/zh_TW/admin.php +++ b/resources/lang/zh_TW/admin.php @@ -47,6 +47,7 @@ return [ 'queue_monitor' => '隊列監控', 'user_modify_logs' => '修改記錄', 'message_templates' => '消息模板', + 'tracker_url' => 'Tracker URL', ], 'resources' => [ 'agent_allow' => [ diff --git a/resources/lang/zh_TW/label.php b/resources/lang/zh_TW/label.php index 2a64db3f..328b1047 100644 --- a/resources/lang/zh_TW/label.php +++ b/resources/lang/zh_TW/label.php @@ -48,6 +48,7 @@ return [ 'text_code' => "代碼", 'language' => '語言', 'content' => '內容', + 'is_default' => '是否默認', 'setting' => [ 'nav_text' => '設置', 'backup' => [