(Update) Auto-freeleech feature (#5229)

* add: autofreeleech user setting

* add: ui autofreeleech torrent section

* add: autofreeleech logic for torrent download

* fix: php lint styles

* fix: refactor code logic and validations

* fix: label for auto-freeleech-token setting

* fix; code style and schema dumping

* fix: freeleech guarded fields and mysql schema

* fix: mysql schema migration

* fix: auto freeleech migration batch
This commit is contained in:
nikoresu
2026-01-27 03:17:16 -05:00
committed by GitHub
parent 3b866d50df
commit 462061373c
8 changed files with 101 additions and 0 deletions
@@ -22,6 +22,8 @@ use App\Models\Scopes\ApprovedScope;
use App\Models\Torrent;
use App\Models\TorrentDownload;
use App\Models\User;
use App\Models\FreeleechToken;
use App\Services\Unit3dAnnounce;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
@@ -85,6 +87,27 @@ class TorrentDownloadController extends Controller
$torrentDownload->type = $rsskey ? 'RSS/API using '.$request->header('User-Agent') : 'Site using '.$request->header('User-Agent');
$torrentDownload->save();
// Auto-apply a freeleech token if the user has enabled the setting
$settings = $user->settings;
if (
$settings?->auto_freeleech_apply &&
$user->fl_tokens >= max(1, $settings->auto_freeleech_min_tokens) &&
!cache()->get("freeleech_token:{$user->id}:{$torrent->id}")
) {
FreeleechToken::query()->create([
'user_id' => $user->id,
'torrent_id' => $torrent->id,
]);
Unit3dAnnounce::addFreeleechToken($user->id, $torrent->id);
$user->decrement('fl_tokens');
cache()->put("freeleech_token:{$user->id}:{$torrent->id}", true);
$torrent->searchable();
}
return response()->streamDownload(
function () use ($id, $user, $torrent): void {
$dict = Bencode::bdecode(Storage::disk('torrent-files')->get($torrent->file_name));
@@ -146,6 +146,15 @@ class UpdateGeneralSettingRequest extends FormRequest
'required',
'boolean',
],
'auto_freeleech_apply' => [
'required',
'boolean',
],
'auto_freeleech_min_tokens' => [
'required',
'integer',
'min:0',
],
'show_adult_content' => [
'required',
'boolean',
+7
View File
@@ -39,6 +39,13 @@ final class FreeleechToken extends Model
/** @use HasFactory<\Database\Factories\FreeleechTokenFactory> */
use HasFactory;
/**
* The attributes that aren't mass assignable.
*
* @var list<string>
*/
protected $guarded = [];
/**
* Get the torrent the freeleech token was redeemed on.
*
+2
View File
@@ -339,6 +339,8 @@ final class User extends Authenticatable implements MustVerifyEmail
'torrent_sort_field' => 'bumped_at',
'torrent_search_autofocus' => false,
'show_adult_content' => true,
'auto_freeleech_apply' => false,
'auto_freeleech_min_tokens' => 0,
]);
}
+4
View File
@@ -56,6 +56,8 @@ use AllowDynamicProperties;
* @property ?string $custom_css
* @property ?string $standalone_css
* @property bool $show_poster
* @property bool $auto_freeleech_apply
* @property int $auto_freeleech_min_tokens
* @property bool $unbookmark_torrents_on_completion
* @property bool $show_adult_content
* @property \Illuminate\Support\Carbon|null $created_at
@@ -127,6 +129,8 @@ final class UserSetting extends Model
'online_block_position' => 'int',
'torrent_filters' => 'bool',
'show_poster' => 'bool',
'auto_freeleech_apply' => 'bool',
'auto_freeleech_min_tokens' => 'int',
'unbookmark_torrents_on_completion' => 'bool',
'show_adult_content' => 'bool',
];
@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class () extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('user_settings', function (Blueprint $table): void {
$table->boolean('auto_freeleech_apply')->default(false)->after('unbookmark_torrents_on_completion');
$table->unsignedInteger('auto_freeleech_min_tokens')->default(0)->after('auto_freeleech_apply');
});
}
};
+3
View File
@@ -2539,6 +2539,8 @@ CREATE TABLE `user_settings` (
`standalone_css` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`show_poster` tinyint(1) NOT NULL DEFAULT '0',
`unbookmark_torrents_on_completion` tinyint(1) NOT NULL,
`auto_freeleech_apply` tinyint(1) NOT NULL DEFAULT '0',
`auto_freeleech_min_tokens` int unsigned NOT NULL DEFAULT '0',
`show_adult_content` tinyint(1) NOT NULL DEFAULT '1',
`torrent_sort_field` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`torrent_search_autofocus` tinyint(1) NOT NULL DEFAULT '1',
@@ -3103,3 +3105,4 @@ INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (369,'2025_11_29_10
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (370,'2026_01_06_231535_remove_unnecessary_bigints',1);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (371,'2026_01_07_040502_mark_columns_as_unsigned',1);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (372,'2026_01_09_015532_alter_table_reports_make_verdict_nullable',1);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (373,'2026_01_14_120000_add_auto_freeleech_to_user_settings',1);
@@ -564,7 +564,40 @@
</label>
</p>
</div>
<p class="form__group">
<label class="form__label">
<input type="hidden" name="auto_freeleech_apply" value="0" />
<input
class="form__checkbox"
type="checkbox"
name="auto_freeleech_apply"
value="1"
@checked($user->settings->auto_freeleech_apply)
/>
Automatically apply freeleech tokens when applicable
</label>
</p>
<p class="form__group">
<input
id="auto_freeleech_min_tokens"
class="form__text"
inputmode="numeric"
name="auto_freeleech_min_tokens"
pattern="[0-9]*"
placeholder=" "
type="text"
required
value="{{ $user->settings->auto_freeleech_min_tokens }}"
/>
<label
class="form__label form__label--floating"
for="auto_freeleech_min_tokens"
>
Minimum tokens to keep when auto-applying freeleech
</label>
</p>
</fieldset>
<p class="form__group">
<button class="form__button form__button--filled">
{{ __('common.save') }}