diff --git a/.cspell/brands.txt b/.cspell/brands.txt index 4c5948c65..e1b6c2287 100644 --- a/.cspell/brands.txt +++ b/.cspell/brands.txt @@ -10,6 +10,7 @@ limewire mal mediainfo phpstorm +rottentomatoes shareaza tmdb tvdb diff --git a/app/Console/Commands/AutoRemoveTimedTorrentBuffs.php b/app/Console/Commands/AutoRemoveTimedTorrentBuffs.php index 37d1c3a27..ce52d6e1e 100644 --- a/app/Console/Commands/AutoRemoveTimedTorrentBuffs.php +++ b/app/Console/Commands/AutoRemoveTimedTorrentBuffs.php @@ -71,9 +71,13 @@ class AutoRemoveTimedTorrentBuffs extends Command Unit3dAnnounce::addTorrent($torrent); } - Torrent::query()->whereNotNull('bumped_at')->where('bumped_at', '<', now()->subWeek())->update([ - 'bumped_at' => DB::raw('created_at'), - ]); + Torrent::query() + ->whereNotNull('bumped_at') + ->where('bumped_at', '<', now()->subWeek()) + ->whereColumn('bumped_at', '!=', 'created_at') + ->update([ + 'bumped_at' => DB::raw('created_at'), + ]); $this->comment('Automated Removal Of Expired Torrent Buffs Command Complete'); } diff --git a/app/DTO/TorrentSearchFiltersDTO.php b/app/DTO/TorrentSearchFiltersDTO.php index 33d37211b..d607825d3 100644 --- a/app/DTO/TorrentSearchFiltersDTO.php +++ b/app/DTO/TorrentSearchFiltersDTO.php @@ -448,7 +448,10 @@ readonly class TorrentSearchFiltersDTO $filters[] = 'user.username = '.json_encode($this->uploader); if (!$group->is_modo) { - $filters[] = 'anon = false'; + $filters[] = [ + 'anon = false', + 'user.username = '.json_encode($this->user->username), + ]; } } diff --git a/app/Helpers/Bbcode.php b/app/Helpers/Bbcode.php index fcd9ef9a9..9ddbaa797 100755 --- a/app/Helpers/Bbcode.php +++ b/app/Helpers/Bbcode.php @@ -183,8 +183,8 @@ class Bbcode 'code' => [ 'openBbcode' => '/^\[code\]/i', 'closeBbcode' => '[/code]', - 'openHtml' => '
',
-            'closeHtml'   => '
', + 'openHtml' => '
',
+            'closeHtml'   => '
', 'block' => true, ], 'pre' => [ diff --git a/app/Helpers/Helpers.php b/app/Helpers/Helpers.php index ab4928489..0064c30a5 100644 --- a/app/Helpers/Helpers.php +++ b/app/Helpers/Helpers.php @@ -56,6 +56,16 @@ if (!\function_exists('href_request')) { } } +if (!\function_exists('href_rottentomatoes')) { + function href_rottentomatoes(string|null $title, string|null $date): string + { + $year = substr($date ?? '', 0, 4); + $query = "{$title} ({$year}) site:rottentomatoes.com"; + + return "https://html.duckduckgo.com/html/?q=\\".rawurlencode($query); + } +} + if (!\function_exists('href_poll')) { function href_poll(App\Models\Poll $poll): string { diff --git a/app/Helpers/TorrentTools.php b/app/Helpers/TorrentTools.php index 5c1fd8938..7c0f476b8 100644 --- a/app/Helpers/TorrentTools.php +++ b/app/Helpers/TorrentTools.php @@ -48,6 +48,7 @@ class TorrentTools $result['info']['source'] = config('torrent.source'); $result['info']['private'] = 1; + $result['info']['entropy'] = bin2hex(random_bytes(64)); if (config('torrent.created_by_append') && \array_key_exists('created by', $result)) { $result['created by'] = trim((string) $result['created by'], '. ').'. '.config('torrent.created_by', ''); diff --git a/app/Http/Controllers/API/ChatController.php b/app/Http/Controllers/API/ChatController.php index 2436a1c5e..718e99cbd 100644 --- a/app/Http/Controllers/API/ChatController.php +++ b/app/Http/Controllers/API/ChatController.php @@ -420,7 +420,7 @@ class ChatController extends Controller } /* USERS */ - public function updateUserChatStatus(Request $request): \Illuminate\Http\JsonResponse + public function updateUserChatStatus(Request $request): \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response { $user = $request->user(); $user->load(['chatStatus', 'chatroom', 'group', 'echoes']); @@ -432,7 +432,7 @@ class ChatController extends Controller $user->chatStatus()->associate($status); $user->save(); - return response()->json($user); + return response('success'); } public function updateUserRoom(Request $request): \Illuminate\Http\JsonResponse diff --git a/app/Http/Controllers/API/QuickSearchController.php b/app/Http/Controllers/API/QuickSearchController.php index 5d6da196a..a65181206 100644 --- a/app/Http/Controllers/API/QuickSearchController.php +++ b/app/Http/Controllers/API/QuickSearchController.php @@ -27,7 +27,7 @@ class QuickSearchController extends Controller { public function index(Request $request): \Illuminate\Http\JsonResponse { - $query = $request->input('query'); + $query = $request->input('query', ''); $filters = [ 'deleted_at IS NULL', diff --git a/app/Http/Controllers/API/TorrentController.php b/app/Http/Controllers/API/TorrentController.php index 71af7d46c..3abe1773c 100644 --- a/app/Http/Controllers/API/TorrentController.php +++ b/app/Http/Controllers/API/TorrentController.php @@ -671,7 +671,6 @@ class TorrentController extends BaseController 'media_info' => $hit['mediainfo'], 'bd_info' => $hit['bdinfo'], 'description' => $hit['description'], - 'info_hash' => $hit['info_hash'], 'size' => $hit['size'], 'num_file' => $hit['num_file'], 'files' => $hit['files'], diff --git a/app/Http/Controllers/API/TorrentRequestController.php b/app/Http/Controllers/API/TorrentRequestController.php new file mode 100644 index 000000000..8199a835f --- /dev/null +++ b/app/Http/Controllers/API/TorrentRequestController.php @@ -0,0 +1,70 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Controllers\API; + +use App\Http\Controllers\Controller; +use App\Http\Resources\TorrentRequestResource; +use App\Models\TorrentRequest; +use Illuminate\Http\Request; + +class RequestController extends Controller +{ + /** + * Request search filter. + */ + public function filter(Request $request): \Illuminate\Http\JsonResponse + { + $query = TorrentRequest::query() + ->with(['user', 'claim.user', 'filler']) + ->withSum('bounties', 'seedbonus') + ->when($request->filled('name'), fn ($query) => $query->where('name', 'LIKE', '%'.str_replace(' ', '%', $request->input('name')).'%')) + ->when($request->filled('category_id'), fn ($query) => $query->whereIntegerInRaw('category_id', (array) $request->input('category_id'))) + ->when($request->filled('type_id'), fn ($query) => $query->whereIntegerInRaw('type_id', (array) $request->input('type_id'))) + ->when($request->filled('resolution_id'), fn ($query) => $query->whereIntegerInRaw('resolution_id', (array) $request->input('resolution_id'))) + ->when($request->filled('tmdb'), fn ($query) => $query->whereAny(['tmdb_movie_id', 'tmdb_tv_id'], '=', $request->integer('tmdb'))) + ->when($request->filled('imdb'), fn ($query) => $query->where('imdb', '=', $request->integer('imdb'))) + ->when($request->filled('tvdb'), fn ($query) => $query->where('tvdb', '=', $request->integer('tvdb'))) + ->when($request->filled('mal'), fn ($query) => $query->where('mal', '=', $request->integer('mal'))) + ->when($request->filled('filled'), fn ($query) => $request->boolean('filled') + ? $query->whereNotNull('filled_by') + : $query->whereNull('filled_by')) + ->when($request->filled('claimed'), fn ($query) => $request->boolean('claimed') + ? $query->whereNotNull('claim') + : $query->whereNull('claim')); + + $perPage = min($request->integer('perPage', 25), 100); + $page = max($request->integer('page', 1), 1); + $requests = $query->paginate( + perPage: $perPage, + page: $page + ); + + return TorrentRequestResource::collection($requests)->response(); + } + + /** + * View a single request. + */ + public function show(int $id): \Illuminate\Http\JsonResponse + { + $request = TorrentRequest::with(['user', 'claim.user', 'filler']) + ->withSum('bounties', 'seedbonus') + ->findOrFail($id); + + return new TorrentRequestResource($request)->response(); + } +} diff --git a/app/Http/Controllers/RequestController.php b/app/Http/Controllers/RequestController.php index 69e6aa915..e282a4210 100644 --- a/app/Http/Controllers/RequestController.php +++ b/app/Http/Controllers/RequestController.php @@ -58,7 +58,7 @@ class RequestController extends Controller public function show(Request $request, TorrentRequest $torrentRequest): \Illuminate\Contracts\View\Factory|\Illuminate\View\View { return view('requests.show', [ - 'torrentRequest' => $torrentRequest->load(['category', 'claim' => ['user'], 'bounties', 'torrent']), + 'torrentRequest' => $torrentRequest->load(['category', 'claim.user.group', 'bounties.user.group', 'torrent']), 'user' => $request->user(), 'canEdit' => $request->user()->group->is_modo || TorrentRequest::query() ->whereDoesntHave('bounties', fn ($query) => $query->where('user_id', '!=', $request->user()->id)) diff --git a/app/Http/Controllers/Staff/DonationController.php b/app/Http/Controllers/Staff/DonationController.php index d8db0852d..657eeecca 100644 --- a/app/Http/Controllers/Staff/DonationController.php +++ b/app/Http/Controllers/Staff/DonationController.php @@ -20,7 +20,6 @@ use App\Enums\ModerationStatus; use App\Helpers\StringHelper; use App\Models\Conversation; use App\Services\Unit3dAnnounce; -use Carbon\Carbon; use App\Models\Donation; use Illuminate\Http\Request; use App\Models\PrivateMessage; @@ -68,7 +67,7 @@ class DonationController extends Controller { abort_unless($request->user()->group->is_owner, 403); - $now = Carbon::now(); + $now = now(); $donation = Donation::with(['user', 'package'])->findOrFail($id); $donation->status = ModerationStatus::APPROVED; diff --git a/app/Http/Controllers/Staff/DonationGatewayController.php b/app/Http/Controllers/Staff/DonationGatewayController.php index b5a6f9548..0caaac17b 100644 --- a/app/Http/Controllers/Staff/DonationGatewayController.php +++ b/app/Http/Controllers/Staff/DonationGatewayController.php @@ -47,7 +47,7 @@ class DonationGatewayController extends Controller /** * Store A Donation Gateway. */ - public function store(StoreDonationGatewayRequest $request) + public function store(StoreDonationGatewayRequest $request): \Illuminate\Http\RedirectResponse { abort_unless($request->user()->group->is_owner, 403); @@ -83,7 +83,7 @@ class DonationGatewayController extends Controller /** * Destroy A Donation Gateway. */ - public function destroy(Request $request, DonationGateway $gateway) + public function destroy(Request $request, DonationGateway $gateway): \Illuminate\Http\RedirectResponse { abort_unless($request->user()->group->is_owner, 403); diff --git a/app/Http/Controllers/ReseedController.php b/app/Http/Controllers/TorrentReseedController.php similarity index 51% rename from app/Http/Controllers/ReseedController.php rename to app/Http/Controllers/TorrentReseedController.php index a7e19b033..37f5fc4a8 100644 --- a/app/Http/Controllers/ReseedController.php +++ b/app/Http/Controllers/TorrentReseedController.php @@ -18,32 +18,67 @@ namespace App\Http\Controllers; use App\Models\History; use App\Models\Torrent; +use App\Models\TorrentReseed; use App\Models\User; use App\Notifications\NewReseedRequest; use App\Repositories\ChatRepository; use Illuminate\Http\Request; -class ReseedController extends Controller +class TorrentReseedController extends Controller { /** - * ReseedController Constructor. + * TorrentReseedController Constructor. */ public function __construct(private readonly ChatRepository $chatRepository) { } + /** + * Display a listing of torrent reseed requests. + */ + public function index(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application + { + return view('torrent-reseed.index'); + } + /** * Reseed Request A Torrent. */ public function store(Request $request, int $id): \Illuminate\Http\RedirectResponse { - // TODO: Store reseed requests so can be viewed in a table view. - $torrent = Torrent::findOrFail($id); - $potentialReseeds = History::where('torrent_id', '=', $torrent->id)->where('active', '=', 0)->get(); + $userId = $request->user()->id; + + // Check if this user has already made a reseed request for this torrent + $existingUserReseed = TorrentReseed::where('torrent_id', '=', $torrent->id) + ->where('user_id', '=', $userId) + ->first(); + + if ($existingUserReseed) { + return to_route('torrents.show', ['id' => $torrent->id]) + ->withErrors('You have already made a reseed request for this torrent.'); + } + + // Check seeders condition and if a request already exists for this torrent + $existingReseed = TorrentReseed::where('torrent_id', '=', $torrent->id)->first(); if ($torrent->seeders <= 2) { - // Send Notification + if ($existingReseed) { + $existingReseed->increment('requests_count'); + $existingReseed->save(); + + return to_route('torrents.show', ['id' => $torrent->id]) + ->with('success', 'A reseed request already exists. Your request has been counted.'); + } + TorrentReseed::create([ + 'torrent_id' => $torrent->id, + 'user_id' => $userId, + 'requests_count' => 1, + ]); + + // Send notifications + $potentialReseeds = History::where('torrent_id', '=', $torrent->id)->where('active', '=', 0)->get(); + foreach ($potentialReseeds as $potentialReseed) { User::find($potentialReseed->user_id)->notify(new NewReseedRequest($torrent)); } diff --git a/app/Http/Controllers/User/FollowController.php b/app/Http/Controllers/User/FollowController.php index 0d8ae28ba..510711bf9 100644 --- a/app/Http/Controllers/User/FollowController.php +++ b/app/Http/Controllers/User/FollowController.php @@ -77,7 +77,6 @@ class FollowController extends Controller $user->notify(new NewUnfollow('user', $request->user())); - return to_route('users.show', ['user' => $user]) - ->with('success', \sprintf(trans('user.follow-revoked'), $user->username)); + return back()->with('success', \sprintf(trans('user.follow-revoked'), $user->username)); } } diff --git a/app/Http/Controllers/User/UnregisteredInfoHashController.php b/app/Http/Controllers/User/UnregisteredInfoHashController.php new file mode 100644 index 000000000..540e02bc4 --- /dev/null +++ b/app/Http/Controllers/User/UnregisteredInfoHashController.php @@ -0,0 +1,36 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Controllers\User; + +use App\Http\Controllers\Controller; +use App\Models\User; +use Illuminate\Http\Request; + +class UnregisteredInfoHashController extends Controller +{ + /** + * Show user unregistered info hashes. + */ + public function index(Request $request, User $user): \Illuminate\Contracts\View\Factory|\Illuminate\View\View + { + abort_unless($request->user()->group->is_modo || $request->user()->is($user), 403); + + return view('user.unregistered-info-hash.index', [ + 'user' => $user, + ]); + } +} diff --git a/app/Http/Controllers/User/UserController.php b/app/Http/Controllers/User/UserController.php index dd1b1e871..949d7b313 100644 --- a/app/Http/Controllers/User/UserController.php +++ b/app/Http/Controllers/User/UserController.php @@ -231,7 +231,7 @@ class UserController extends Controller // Define data $request->validate([ 'title' => 'nullable|max:255', - 'about' => 'nullable|max:1000', + 'about' => 'nullable|max:20000', 'signature' => 'nullable|max:1000' ]); $user->title = $request->input('title'); diff --git a/app/Http/Livewire/AnnounceSearch.php b/app/Http/Livewire/AnnounceSearch.php index 76ee0f114..5aae3c038 100644 --- a/app/Http/Livewire/AnnounceSearch.php +++ b/app/Http/Livewire/AnnounceSearch.php @@ -18,14 +18,10 @@ namespace App\Http\Livewire; use App\Models\Announce; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $announces - */ class AnnounceSearch extends Component { use LivewireSort; @@ -59,12 +55,10 @@ class AnnounceSearch extends Component } /** - * @return \Illuminate\Pagination\Paginator + * @var \Illuminate\Pagination\Paginator */ - #[Computed] - final public function announces(): \Illuminate\Pagination\Paginator - { - return Announce::query() + protected \Illuminate\Pagination\Paginator $announces { + get => Announce::query() ->when($this->torrentId !== '', fn ($query) => $query->where('torrent_id', '=', $this->torrentId)) ->when($this->userId !== '', fn ($query) => $query->where('user_id', '=', $this->userId)) ->when($this->sortField !== '', fn ($query) => $query->orderBy($this->sortField, $this->sortDirection)) diff --git a/app/Http/Livewire/ApikeySearch.php b/app/Http/Livewire/ApikeySearch.php index ef9738437..2615d8c6e 100644 --- a/app/Http/Livewire/ApikeySearch.php +++ b/app/Http/Livewire/ApikeySearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\Apikey; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $apikeys - */ class ApikeySearch extends Component { use LivewireSort; @@ -50,14 +46,13 @@ class ApikeySearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function apikeys(): \Illuminate\Pagination\LengthAwarePaginator - { - return Apikey::with([ - 'user' => fn ($query) => $query->withTrashed()->with('group'), - ]) + final protected \Illuminate\Pagination\LengthAwarePaginator $apikeys { + get => Apikey::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed()->with('group'), + ]) ->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%'))) ->when($this->apikey, fn ($query) => $query->where('content', 'LIKE', '%'.$this->apikey.'%')) ->orderBy($this->sortField, $this->sortDirection) diff --git a/app/Http/Livewire/ApplicationSearch.php b/app/Http/Livewire/ApplicationSearch.php index f164e9b3a..013841517 100644 --- a/app/Http/Livewire/ApplicationSearch.php +++ b/app/Http/Livewire/ApplicationSearch.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Enums\ModerationStatus; use App\Models\Application; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -47,17 +46,17 @@ class ApplicationSearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function applications(): \Illuminate\Pagination\LengthAwarePaginator - { - return Application::withoutGlobalScopes()->with([ - 'user.group', - 'moderated.group', - 'imageProofs', - 'urlProofs' - ]) + protected \Illuminate\Pagination\LengthAwarePaginator $applications { + get => Application::query() + ->withoutGlobalScopes() + ->with([ + 'user.group', + 'moderated.group', + 'imageProofs', + 'urlProofs' + ]) ->when($this->email, fn ($query) => $query->where('email', 'LIKE', '%'.$this->email.'%')) ->when($this->status === '1', fn ($query) => $query->where('status', '=', ModerationStatus::APPROVED)) ->when($this->status === '0', fn ($query) => $query->where('status', '=', ModerationStatus::PENDING)) diff --git a/app/Http/Livewire/AttachmentUpload.php b/app/Http/Livewire/AttachmentUpload.php index d064d89e0..7a8e7d494 100644 --- a/app/Http/Livewire/AttachmentUpload.php +++ b/app/Http/Livewire/AttachmentUpload.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Ticket; use App\Models\TicketAttachment; use App\Models\User; -use Livewire\Attributes\Computed; use Livewire\Attributes\Validate; use Livewire\Component; use Livewire\WithFileUploads; @@ -67,16 +66,16 @@ class AttachmentUpload extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function attachments(): \Illuminate\Database\Eloquent\Collection - { - $ticket = Ticket::find($this->ticket); + protected \Illuminate\Database\Eloquent\Collection $attachments { + get { + $ticket = Ticket::find($this->ticket); - abort_unless($ticket->user_id === $this->user->id || $this->user->group->is_modo, 403); + abort_unless($ticket->user_id === $this->user->id || $this->user->group->is_modo, 403); - return $ticket->attachments; + return $ticket->attachments; + } } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/AuditLogSearch.php b/app/Http/Livewire/AuditLogSearch.php index 95128a4b7..a018d3535 100644 --- a/app/Http/Livewire/AuditLogSearch.php +++ b/app/Http/Livewire/AuditLogSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\Audit; use App\Traits\Auditable; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -56,12 +55,10 @@ class AuditLogSearch extends Component public string $sortDirection = 'desc'; /** - * @return string[] + * @var string[] */ - #[Computed] - final public function modelNames(): array - { - return collect(scandir(app_path('Models')) ?: []) + final protected array $modelNames { + get => collect(scandir(app_path('Models')) ?: []) ->filter(fn ($path) => str_ends_with($path, '.php')) ->map(fn ($path) => 'App\\Models\\'.basename($path, '.php')) ->filter(fn ($class) => class_exists($class)) @@ -73,25 +70,23 @@ class AuditLogSearch extends Component /** * @throws JsonException - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function audits(): \Illuminate\Pagination\LengthAwarePaginator - { - $audits = Audit::with('user') + final protected \Illuminate\Pagination\LengthAwarePaginator $audits { + get => Audit::query() + ->with('user') ->when($this->username, fn ($query) => $query->whereRelation('user', 'username', '=', $this->username)) ->when($this->modelName, fn ($query) => $query->where('model_name', '=', $this->modelName)) ->when($this->modelId, fn ($query) => $query->where('model_entry_id', '=', $this->modelId)) ->when($this->action, fn ($query) => $query->where('action', '=', $this->action)) ->when($this->record, fn ($query) => $query->where('record', 'LIKE', '%'.$this->record.'%')) ->latest() - ->paginate($this->perPage); + ->paginate($this->perPage) + ->through(function ($audit) { + $audit->values = json_decode((string) $audit->record, true, 512, JSON_THROW_ON_ERROR); - foreach ($audits as $audit) { - $audit->values = json_decode((string) $audit->record, true, 512, JSON_THROW_ON_ERROR); - } - - return $audits; + return $audit; + }); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/BackupPanel.php b/app/Http/Livewire/BackupPanel.php index 9e482ceb9..308fa5517 100644 --- a/app/Http/Livewire/BackupPanel.php +++ b/app/Http/Livewire/BackupPanel.php @@ -22,10 +22,10 @@ use App\Rules\PathToZip; use Illuminate\Http\Response; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\ValidationException; -use Livewire\Attributes\Computed; use Livewire\Component; use Spatie\Backup\BackupDestination\Backup; use Spatie\Backup\BackupDestination\BackupDestination; +use Spatie\Backup\Config\MonitoredBackupsConfig; use Spatie\Backup\Helpers\Format; use Spatie\Backup\Tasks\Monitor\BackupDestinationStatus; use Spatie\Backup\Tasks\Monitor\BackupDestinationStatusFactory; @@ -40,14 +40,10 @@ class BackupPanel extends Component protected $listeners = ['refreshBackups' => '$refresh']; /** - * @return array + * @var array */ - #[Computed] - final public function backupStatuses(): array - { - $monitorConfig = \Spatie\Backup\Config\MonitoredBackupsConfig::fromArray(config('backup.monitor_backups')); - - return BackupDestinationStatusFactory::createForMonitorConfig($monitorConfig) + final protected array $backupStatuses { + get => BackupDestinationStatusFactory::createForMonitorConfig(MonitoredBackupsConfig::fromArray(config('backup.monitor_backups'))) ->map(fn (BackupDestinationStatus $backupDestinationStatus) => [ 'name' => $backupDestinationStatus->backupDestination()->backupName(), 'disk' => $backupDestinationStatus->backupDestination()->diskName(), @@ -63,46 +59,37 @@ class BackupPanel extends Component ->toArray(); } - #[Computed] - final public function activeDisk(): ?string - { - if (\count($this->backupStatuses)) { - return $this->backupStatuses[0]['disk']; - } - - return null; + final protected ?string $activeDisk { + get => $this->backupStatuses[0]['disk'] ?? null; } /** - * @return array + * @var array */ - #[Computed] - final public function disks(): array - { - return collect($this->backupStatuses) + final protected array $disks { + get => collect($this->backupStatuses) ->map(fn ($backupStatus): mixed => $backupStatus['disk']) ->values() ->all(); } /** + * @var array * @throws ValidationException */ - #[Computed] - final public function backups(): array - { - $this->validateActiveDisk(); + final protected array $backups { + get { + $this->validateActiveDisk(); - $backupDestination = BackupDestination::create($this->activeDisk, config('backup.backup.name')); - - return $backupDestination - ->backups() - ->map(fn (Backup $backup) => [ - 'path' => $backup->path(), - 'date' => $backup->date()->format('Y-m-d H:i:s'), - 'size' => Format::humanReadableSize($backup->sizeInBytes()), - ]) - ->toArray(); + return BackupDestination::create($this->activeDisk, config('backup.backup.name')) + ->backups() + ->map(fn (Backup $backup) => [ + 'path' => $backup->path(), + 'date' => $backup->date()->format('Y-m-d H:i:s'), + 'size' => Format::humanReadableSize($backup->sizeInBytes()), + ]) + ->toArray(); + } } final public function deleteBackup(int $fileIndex): void diff --git a/app/Http/Livewire/BlockIpAddress.php b/app/Http/Livewire/BlockIpAddress.php index 4461565c6..e1fae9c55 100644 --- a/app/Http/Livewire/BlockIpAddress.php +++ b/app/Http/Livewire/BlockIpAddress.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\BlockedIp; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Attributes\Validate; use Livewire\Component; @@ -75,12 +74,10 @@ class BlockIpAddress extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function ipAddresses(): \Illuminate\Pagination\LengthAwarePaginator - { - return BlockedIp::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $ipAddresses { + get => BlockedIp::query() ->when($this->ipSearch, fn ($query) => $query->where('ip_address', 'LIKE', '%'.$this->ipSearch.'%')) ->when($this->reasonSearch, fn ($query) => $query->where('reason', 'LIKE', '%'.$this->reasonSearch.'%')) ->latest() diff --git a/app/Http/Livewire/Comments.php b/app/Http/Livewire/Comments.php index a7fc85720..c1c47d409 100644 --- a/app/Http/Livewire/Comments.php +++ b/app/Http/Livewire/Comments.php @@ -41,7 +41,6 @@ use App\Notifications\NewCommentTag; use App\Repositories\ChatRepository; use App\Traits\CastLivewireProperties; use Illuminate\Support\Facades\Notification; -use Livewire\Attributes\Computed; use Livewire\Attributes\Validate; use Livewire\Component; use Livewire\WithPagination; @@ -199,12 +198,10 @@ class Comments extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function comments(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return $this->model + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $comments { + get => $this->model ->comments() ->with(['user:id,username,group_id,image,title', 'user.group', 'children.user:id,username,group_id,image,title', 'children.user.group']) ->parent() diff --git a/app/Http/Livewire/ConversationSearch.php b/app/Http/Livewire/ConversationSearch.php index 40e2161a8..9b2d5012d 100644 --- a/app/Http/Livewire/ConversationSearch.php +++ b/app/Http/Livewire/ConversationSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\Conversation; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Rule; use Livewire\Attributes\Url; use Livewire\Component; @@ -49,12 +48,10 @@ class ConversationSearch extends Component public string $sortDirection = 'desc'; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function conversations(): \Illuminate\Pagination\LengthAwarePaginator - { - return Conversation::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $conversations { + get => Conversation::query() ->with([ 'users' => fn ($query) => $query->with('group')->where('users.id', '!=', auth()->id()), 'participants' => fn ($query) => $query->where('user_id', auth()->id()), diff --git a/app/Http/Livewire/EmailUpdateSearch.php b/app/Http/Livewire/EmailUpdateSearch.php index f7efffeb2..a1697becf 100644 --- a/app/Http/Livewire/EmailUpdateSearch.php +++ b/app/Http/Livewire/EmailUpdateSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\EmailUpdate; use App\Models\User; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -44,14 +43,13 @@ class EmailUpdateSearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function emailUpdates(): \Illuminate\Pagination\LengthAwarePaginator - { - return EmailUpdate::with([ - 'user' => fn ($query) => $query->withTrashed()->with('group'), - ]) + final protected \Illuminate\Pagination\LengthAwarePaginator $emailUpdates { + get => EmailUpdate::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed()->with('group'), + ]) ->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%'))) ->orderBy($this->sortField, $this->sortDirection) ->paginate($this->perPage); diff --git a/app/Http/Livewire/FailedLoginSearch.php b/app/Http/Livewire/FailedLoginSearch.php index 706f8b975..50d9fff01 100644 --- a/app/Http/Livewire/FailedLoginSearch.php +++ b/app/Http/Livewire/FailedLoginSearch.php @@ -20,7 +20,6 @@ use App\Models\FailedLoginAttempt; use App\Traits\LivewireSort; use Carbon\Carbon; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -51,12 +50,10 @@ class FailedLoginSearch extends Component public string $sortDirection = 'desc'; /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function failedLoginsTop10Ip(): \Illuminate\Database\Eloquent\Collection - { - return FailedLoginAttempt::query() + final protected \Illuminate\Database\Eloquent\Collection $failedLoginsTop10Ip { + get => FailedLoginAttempt::query() ->select(['ip_address', DB::raw('COUNT(*) as login_attempts'), DB::raw('MAX(created_at) as latest_created_at')]) ->groupBy('ip_address') ->having('login_attempts', '>', 3) @@ -67,12 +64,10 @@ class FailedLoginSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function failedLogins(): \Illuminate\Pagination\LengthAwarePaginator - { - return FailedLoginAttempt::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $failedLogins { + get => FailedLoginAttempt::query() ->with('user.group') ->when($this->username, fn ($query) => $query->where('username', 'LIKE', $this->username.'%')) ->when($this->userId, fn ($query) => $query->where('user_id', '=', $this->userId)) diff --git a/app/Http/Livewire/ForumCategoryTopicSearch.php b/app/Http/Livewire/ForumCategoryTopicSearch.php index b7d625de8..19bb92a9e 100644 --- a/app/Http/Livewire/ForumCategoryTopicSearch.php +++ b/app/Http/Livewire/ForumCategoryTopicSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\ForumCategory; use App\Models\Topic; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -63,12 +62,10 @@ class ForumCategoryTopicSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function topics(): \Illuminate\Pagination\LengthAwarePaginator - { - return Topic::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $topics { + get => Topic::query() ->select('topics.*') ->with([ 'user.group', diff --git a/app/Http/Livewire/ForumTopicSearch.php b/app/Http/Livewire/ForumTopicSearch.php index 46d077208..8b84d2638 100644 --- a/app/Http/Livewire/ForumTopicSearch.php +++ b/app/Http/Livewire/ForumTopicSearch.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Forum; use App\Models\Subscription; use App\Models\Topic; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -68,12 +67,10 @@ class ForumTopicSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function topics(): \Illuminate\Pagination\LengthAwarePaginator - { - return Topic::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $topics { + get => Topic::query() ->select('topics.*') ->with([ 'user.group', diff --git a/app/Http/Livewire/GiftLogSearch.php b/app/Http/Livewire/GiftLogSearch.php index 97cd1c17e..67feaf613 100644 --- a/app/Http/Livewire/GiftLogSearch.php +++ b/app/Http/Livewire/GiftLogSearch.php @@ -18,14 +18,10 @@ namespace App\Http\Livewire; use App\Models\Gift; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $gifts - */ class GiftLogSearch extends Component { use LivewireSort; @@ -52,15 +48,14 @@ class GiftLogSearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function gifts(): \Illuminate\Pagination\LengthAwarePaginator - { - return Gift::with([ - 'sender' => fn ($query) => $query->withTrashed()->with('group'), - 'recipient' => fn ($query) => $query->withTrashed()->with('group'), - ]) + final protected \Illuminate\Pagination\LengthAwarePaginator $gifts { + get => Gift::query() + ->with([ + 'sender' => fn ($query) => $query->withTrashed()->with('group'), + 'recipient' => fn ($query) => $query->withTrashed()->with('group'), + ]) ->when($this->sender, fn ($query) => $query->whereRelation('sender', 'username', '=', $this->sender)) ->when($this->receiver, fn ($query) => $query->whereRelation('recipient', 'username', '=', $this->receiver)) ->when($this->comment, fn ($query) => $query->where('comment', 'LIKE', '%'.$this->comment.'%')) diff --git a/app/Http/Livewire/HistorySearch.php b/app/Http/Livewire/HistorySearch.php index ac701589c..343fa0e0a 100644 --- a/app/Http/Livewire/HistorySearch.php +++ b/app/Http/Livewire/HistorySearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\History; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $histories - */ class HistorySearch extends Component { use LivewireSort; @@ -92,12 +88,10 @@ class HistorySearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function histories(): \Illuminate\Pagination\LengthAwarePaginator - { - return History::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $histories { + get => History::query() ->with('user', 'torrent:id,name') ->when( $this->groupBy === 'user_id', diff --git a/app/Http/Livewire/InviteLogSearch.php b/app/Http/Livewire/InviteLogSearch.php index ce141d0b9..b8dbec719 100644 --- a/app/Http/Livewire/InviteLogSearch.php +++ b/app/Http/Livewire/InviteLogSearch.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Invite; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -87,12 +86,10 @@ class InviteLogSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function invites(): \Illuminate\Pagination\LengthAwarePaginator - { - return Invite::withTrashed() + final protected \Illuminate\Pagination\LengthAwarePaginator $invites { + get => Invite::withTrashed() ->with([ 'sender' => fn ($query) => $query->withTrashed()->with('group'), 'receiver' => fn ($query) => $query->withTrashed()->with('group'), diff --git a/app/Http/Livewire/LaravelLogViewer.php b/app/Http/Livewire/LaravelLogViewer.php index cd8dab03c..adce05b54 100644 --- a/app/Http/Livewire/LaravelLogViewer.php +++ b/app/Http/Livewire/LaravelLogViewer.php @@ -19,16 +19,11 @@ namespace App\Http\Livewire; use App\Traits\CastLivewireProperties; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Facades\File; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; use SplFileInfo; -/** - * @property \Illuminate\Support\Collection $logFiles - * @property LengthAwarePaginator $entries - */ class LaravelLogViewer extends Component { use CastLivewireProperties; @@ -54,64 +49,64 @@ class LaravelLogViewer extends Component $this->perPage += 5; } - #[Computed] - final public function logFiles() - { - $directory = storage_path('logs'); - - return collect(File::allFiles($directory)) - ->sortByDesc(fn (SplFileInfo $file) => $file->getMTime())->values(); + /** + * @var \Illuminate\Support\Collection + */ + final protected \Illuminate\Support\Collection $logFiles { + get => collect(File::allFiles(storage_path('logs'))) + ->sortByDesc(fn (SplFileInfo $file) => $file->getMTime()) + ->values(); } /** - * @return LengthAwarePaginator<\Illuminate\Support\Collection> + * @var LengthAwarePaginator> */ - #[Computed] - final public function entries(): LengthAwarePaginator - { - $files = $this->logFiles; - $logString = ''; + final protected LengthAwarePaginator $entries { + get { + $files = $this->logFiles; + $logString = ''; - foreach ($this->logs as $log) { - if ($files[$log] ?? []) { - $logString .= file_get_contents($files[$log]->getPathname()); + foreach ($this->logs as $log) { + if ($files[$log] ?? []) { + $logString .= file_get_contents($files[$log]->getPathname()); + } } - } - $entryPattern = '/^\[(?.*)\]\s(?\w+)\.(?\w+)\:\s/m'; - $contextPattern = '/^(?[^\{]*)?(?:\{"exception"\:"\[object\]\s\((?[^\s\(]+))?.*\s(?:in|at)\s(?.*)\:(?\d+)\)?/ms'; + $entryPattern = '/^\[(?.*)\]\s(?\w+)\.(?\w+)\:\s/m'; + $contextPattern = '/^(?[^\{]*)?(?:\{"exception"\:"\[object\]\s\((?[^\s\(]+))?.*\s(?:in|at)\s(?.*)\:(?\d+)\)?/ms'; - $entries = collect(); + $entries = collect(); - if (preg_match_all($entryPattern, $logString, $entryMatches, PREG_SET_ORDER) !== false) { - $stacktraces = preg_split($entryPattern, $logString); - // Delete the empty first entry - array_shift($stacktraces); - $numEntries = \count($entryMatches); + if (preg_match_all($entryPattern, $logString, $entryMatches, PREG_SET_ORDER) !== false) { + $stacktraces = preg_split($entryPattern, $logString); + // Delete the empty first entry + array_shift($stacktraces); + $numEntries = \count($entryMatches); - for ($i = 0; $i < $numEntries; $i++) { - // The context is the portion before the first stack trace - $context = preg_split('/^\[stacktrace\]|Stack trace\:/ms', (string) $stacktraces[$i])[0]; - // The `context` consists of a message, an exception, a filename, and a line count - preg_match($contextPattern, $context, $contextMatches); + for ($i = 0; $i < $numEntries; $i++) { + // The context is the portion before the first stack trace + $context = preg_split('/^\[stacktrace\]|Stack trace\:/ms', (string) $stacktraces[$i])[0]; + // The `context` consists of a message, an exception, a filename, and a line count + preg_match($contextPattern, $context, $contextMatches); - $entries->push([ - 'date' => $entryMatches[$i]['date'], - 'env' => $entryMatches[$i]['env'], - 'level' => $entryMatches[$i]['level'], - 'message' => $contextMatches['message'] ?? '', - 'exception' => $contextMatches['exception'] ?? '', - 'in' => $contextMatches['in'] ?? '', - 'line' => $contextMatches['line'] ?? '', - 'stacktrace' => $stacktraces[$i], - ]); + $entries->push([ + 'date' => $entryMatches[$i]['date'], + 'env' => $entryMatches[$i]['env'], + 'level' => $entryMatches[$i]['level'], + 'message' => $contextMatches['message'] ?? '', + 'exception' => $contextMatches['exception'] ?? '', + 'in' => $contextMatches['in'] ?? '', + 'line' => $contextMatches['line'] ?? '', + 'stacktrace' => $stacktraces[$i], + ]); + } } + + $groupedEntries = $entries->groupBy(fn ($entry) => $entry['message'].'-'.$entry['exception'].'-'.$entry['in'].'-'.$entry['line']); + $currentEntries = $groupedEntries->forPage($this->page, $this->perPage); + + return new LengthAwarePaginator($currentEntries, $groupedEntries->count(), $this->perPage, $this->page); } - - $groupedEntries = $entries->groupBy(fn ($entry) => $entry['message'].'-'.$entry['exception'].'-'.$entry['in'].'-'.$entry['line']); - $currentEntries = $groupedEntries->forPage($this->page, $this->perPage); - - return new LengthAwarePaginator($currentEntries, $groupedEntries->count(), $this->perPage, $this->page); } final public function clearLatestLog(): void diff --git a/app/Http/Livewire/LeakerSearch.php b/app/Http/Livewire/LeakerSearch.php index 62ce5ba73..bf8401a8d 100644 --- a/app/Http/Livewire/LeakerSearch.php +++ b/app/Http/Livewire/LeakerSearch.php @@ -20,7 +20,6 @@ use App\Models\History; use App\Traits\CastLivewireProperties; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -52,12 +51,10 @@ class LeakerSearch extends Component public string $sortDirection = 'desc'; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function leakers(): \Illuminate\Pagination\LengthAwarePaginator - { - return History::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $leakers { + get => History::query() ->select([ 'history.user_id', DB::raw('count(*) as leak_count'), @@ -81,10 +78,8 @@ class LeakerSearch extends Component ->paginate($this->perPage); } - #[Computed] - final public function torrentIdCount(): int - { - return \count(array_filter(array_map('trim', explode(',', $this->torrentIds)))); + final protected int $torrentIdCount { + get => \count(array_filter(array_map('trim', explode(',', $this->torrentIds)))); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/MissingMediaSearch.php b/app/Http/Livewire/MissingMediaSearch.php index 806fa5acc..b46cebed0 100644 --- a/app/Http/Livewire/MissingMediaSearch.php +++ b/app/Http/Livewire/MissingMediaSearch.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\TmdbMovie; use App\Models\Type; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -50,12 +49,11 @@ class MissingMediaSearch extends Component public int $perPage = 50; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function medias(): \Illuminate\Pagination\LengthAwarePaginator - { - return TmdbMovie::with(['torrents:tmdb_movie_id,tmdb_tv_id,resolution_id,type_id' => ['resolution:id,position,name']]) + final protected \Illuminate\Pagination\LengthAwarePaginator $medias { + get => TmdbMovie::query() + ->with(['torrents:tmdb_movie_id,tmdb_tv_id,resolution_id,type_id' => ['resolution:id,position,name']]) ->when($this->name, fn ($query) => $query->where('title', 'LIKE', '%'.$this->name.'%')) ->when($this->year, fn ($query) => $query->where('release_date', 'LIKE', '%'.$this->year.'%')) ->withCount(['requests' => fn ($query) => $query->whereNull('torrent_id')->whereDoesntHave('claim')]) @@ -65,12 +63,13 @@ class MissingMediaSearch extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function types(): \Illuminate\Database\Eloquent\Collection - { - return Type::select(['id', 'position', 'name'])->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $types { + get => Type::query() + ->select(['id', 'position', 'name']) + ->orderBy('position') + ->get(); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/NoteSearch.php b/app/Http/Livewire/NoteSearch.php index f0b2dff26..7c13b75b0 100644 --- a/app/Http/Livewire/NoteSearch.php +++ b/app/Http/Livewire/NoteSearch.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\Note; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -40,12 +39,10 @@ class NoteSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function notes(): \Illuminate\Pagination\LengthAwarePaginator - { - return Note::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $notes { + get => Note::query() ->with([ 'noteduser' => fn ($query) => $query->withTrashed()->with(['group']), 'staffuser' => fn ($query) => $query->withTrashed()->with(['group']), diff --git a/app/Http/Livewire/NotificationSearch.php b/app/Http/Livewire/NotificationSearch.php index 379ad1b87..e5a1d60bc 100644 --- a/app/Http/Livewire/NotificationSearch.php +++ b/app/Http/Livewire/NotificationSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -103,12 +102,10 @@ class NotificationSearch extends Component public string $sortDirection = 'desc'; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function notifications(): \Illuminate\Pagination\LengthAwarePaginator - { - return auth()->user()->notifications() + final protected \Illuminate\Pagination\LengthAwarePaginator $notifications { + get => auth()->user()->notifications() ->select('*') ->selectRaw("CASE WHEN read_at IS NULL THEN 'FALSE' ELSE 'TRUE' END as is_read") ->where(function ($query): void { diff --git a/app/Http/Livewire/PasskeySearch.php b/app/Http/Livewire/PasskeySearch.php index c91e57fea..3e66af3cc 100644 --- a/app/Http/Livewire/PasskeySearch.php +++ b/app/Http/Livewire/PasskeySearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\Passkey; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $passkeys - */ class PasskeySearch extends Component { use LivewireSort; @@ -50,14 +46,13 @@ class PasskeySearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function passkeys(): \Illuminate\Pagination\LengthAwarePaginator - { - return Passkey::with([ - 'user' => fn ($query) => $query->withTrashed()->with('group'), - ]) + final protected \Illuminate\Pagination\LengthAwarePaginator $passkeys { + get => Passkey::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed()->with('group'), + ]) ->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', '=', $this->username))) ->when($this->passkey, fn ($query) => $query->where('content', 'LIKE', '%'.$this->passkey.'%')) ->orderBy($this->sortField, $this->sortDirection) diff --git a/app/Http/Livewire/PasswordResetHistorySearch.php b/app/Http/Livewire/PasswordResetHistorySearch.php index e263cd731..b414c716e 100644 --- a/app/Http/Livewire/PasswordResetHistorySearch.php +++ b/app/Http/Livewire/PasswordResetHistorySearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\PasswordResetHistory; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Contracts\Pagination\LengthAwarePaginator $passwordResetHistories - */ class PasswordResetHistorySearch extends Component { use LivewireSort; @@ -47,14 +43,13 @@ class PasswordResetHistorySearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function passwordResetHistories(): \Illuminate\Pagination\LengthAwarePaginator - { - return PasswordResetHistory::with([ - 'user' => fn ($query) => $query->withTrashed()->with('group'), - ]) + final protected \Illuminate\Pagination\LengthAwarePaginator $passwordResetHistories { + get => PasswordResetHistory::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed()->with('group'), + ]) ->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%'))) ->orderBy($this->sortField, $this->sortDirection) ->paginate($this->perPage); diff --git a/app/Http/Livewire/PeerSearch.php b/app/Http/Livewire/PeerSearch.php index c9aef4892..2a820f723 100644 --- a/app/Http/Livewire/PeerSearch.php +++ b/app/Http/Livewire/PeerSearch.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Peer; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -98,12 +97,10 @@ class PeerSearch extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function peers(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return Peer::query() + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $peers { + get => Peer::query() ->when( $this->groupBy === 'none', fn ($query) => $query diff --git a/app/Http/Livewire/PlaylistSearch.php b/app/Http/Livewire/PlaylistSearch.php index 13c359819..f7c5e7dee 100644 --- a/app/Http/Livewire/PlaylistSearch.php +++ b/app/Http/Livewire/PlaylistSearch.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Playlist; use App\Models\PlaylistCategory; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -55,14 +54,13 @@ class PlaylistSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function playlists() - { - return Playlist::with([ - 'user:id,username,group_id,image' => ['group'], - ]) + final protected $playlists { + get => Playlist::query() + ->with([ + 'user:id,username,group_id,image' => ['group'], + ]) ->withCount('torrents') ->when( ! auth()->user()->group->is_modo, @@ -81,12 +79,14 @@ class PlaylistSearch extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function playlistCategories(): \Illuminate\Database\Eloquent\Collection - { - return PlaylistCategory::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $playlistCategories { + get => cache()->remember( + 'playlist-categories', + 3600, + fn () => PlaylistCategory::query()->orderBy('position')->get() + ); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/PostSearch.php b/app/Http/Livewire/PostSearch.php index e9fc3233d..d5df18dda 100644 --- a/app/Http/Livewire/PostSearch.php +++ b/app/Http/Livewire/PostSearch.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\Post; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -37,12 +36,10 @@ class PostSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function posts(): \Illuminate\Pagination\LengthAwarePaginator - { - return Post::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $posts { + get => Post::query() ->with('user', 'user.group', 'topic:id,name,state') ->withCount('likes', 'dislikes', 'authorPosts', 'authorTopics') ->withSum('tips', 'bon') diff --git a/app/Http/Livewire/RandomMedia.php b/app/Http/Livewire/RandomMedia.php index 60da6abd9..165f39f1e 100644 --- a/app/Http/Livewire/RandomMedia.php +++ b/app/Http/Livewire/RandomMedia.php @@ -19,67 +19,49 @@ namespace App\Http\Livewire; use App\Models\TmdbTv; use App\Models\TmdbMovie; use Illuminate\Support\Facades\Redis; -use Livewire\Attributes\Computed; use Livewire\Component; class RandomMedia extends Component { /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed] - final public function movies(): \Illuminate\Support\Collection - { - $cacheKey = config('cache.prefix').':random-media-movie-ids'; + final protected \Illuminate\Support\Collection $movies { + get { + $cacheKey = config('cache.prefix').':random-media-movie-ids'; - $movieIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]); + $movieIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]); - return TmdbMovie::query() - ->select(['id', 'backdrop', 'title', 'release_date']) - ->withMin('torrents', 'category_id') - ->whereIn('id', $movieIds) - ->get(); + return TmdbMovie::query() + ->select(['id', 'backdrop', 'title', 'release_date']) + ->withMin('torrents', 'category_id') + ->whereIn('id', $movieIds) + ->get(); + } } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed] - final public function movies2(): \Illuminate\Support\Collection - { - $cacheKey = config('cache.prefix').':random-media-movie-ids'; + final protected \Illuminate\Support\Collection $tvs { + get { + $cacheKey = config('cache.prefix').':random-media-tv-ids'; - $movieIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]); + $tvIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]); - return TmdbMovie::query() - ->select(['id', 'backdrop', 'title', 'release_date']) - ->withMin('torrents', 'category_id') - ->whereIn('id', $movieIds) - ->get(); - } - - /** - * @return \Illuminate\Support\Collection - */ - #[Computed] - final public function tvs(): \Illuminate\Support\Collection - { - $cacheKey = config('cache.prefix').':random-media-tv-ids'; - - $tvIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]); - - return TmdbTv::query() - ->select(['id', 'backdrop', 'name', 'first_air_date']) - ->withMin('torrents', 'category_id') - ->whereIn('id', $tvIds) - ->get(); + return TmdbTv::query() + ->select(['id', 'backdrop', 'name', 'first_air_date']) + ->withMin('torrents', 'category_id') + ->whereIn('id', $tvIds) + ->get(); + } } final public function render(): \Illuminate\Contracts\View\Factory | \Illuminate\Contracts\View\View | \Illuminate\Contracts\Foundation\Application { return view('livewire.random-media', [ 'movies' => $this->movies, - 'movies2' => $this->movies2, + 'movies2' => $this->movies, 'tvs' => $this->tvs ]); } diff --git a/app/Http/Livewire/ReportSearch.php b/app/Http/Livewire/ReportSearch.php index b41da056f..42b3df90a 100644 --- a/app/Http/Livewire/ReportSearch.php +++ b/app/Http/Livewire/ReportSearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\Report; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $reports - */ class ReportSearch extends Component { use LivewireSort; @@ -68,12 +64,10 @@ class ReportSearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function reports(): \Illuminate\Pagination\LengthAwarePaginator - { - return Report::orderBy('solved') + final protected \Illuminate\Pagination\LengthAwarePaginator $reports { + get => Report::query() ->with('reported.group', 'reporter.group', 'staff.group') ->when($this->type !== null, fn ($query) => $query->where('type', '=', $this->type)) ->when($this->reporter !== null, fn ($query) => $query->whereIn('reporter_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->reporter.'%'))) @@ -86,6 +80,7 @@ class ReportSearch extends Component ->when($this->status === 'snoozed', fn ($query) => $query->where('solved', '=', false)->where('snoozed_until', '>', now())) ->when($this->status === 'closed', fn ($query) => $query->where('solved', '=', true)) ->when($this->status === 'all_open', fn ($query) => $query->where('solved', '=', false)) + ->orderBy('solved') ->orderBy($this->sortField, $this->sortDirection) ->paginate($this->perPage); } diff --git a/app/Http/Livewire/RsskeySearch.php b/app/Http/Livewire/RsskeySearch.php index 4317489d7..3a33777c3 100644 --- a/app/Http/Livewire/RsskeySearch.php +++ b/app/Http/Livewire/RsskeySearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\Rsskey; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $rsskeys - */ class RsskeySearch extends Component { use LivewireSort; @@ -50,14 +46,13 @@ class RsskeySearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function rsskeys(): \Illuminate\Pagination\LengthAwarePaginator - { - return Rsskey::with([ - 'user' => fn ($query) => $query->withTrashed()->with('group'), - ]) + final protected \Illuminate\Pagination\LengthAwarePaginator $rsskeys { + get => Rsskey::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed()->with('group'), + ]) ->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%'))) ->when($this->rsskey, fn ($query) => $query->where('content', 'LIKE', '%'.$this->rsskey.'%')) ->orderBy($this->sortField, $this->sortDirection) diff --git a/app/Http/Livewire/SimilarTorrent.php b/app/Http/Livewire/SimilarTorrent.php index 0bd5fd07f..1fe990ee7 100644 --- a/app/Http/Livewire/SimilarTorrent.php +++ b/app/Http/Livewire/SimilarTorrent.php @@ -35,7 +35,6 @@ use App\Services\Unit3dAnnounce; use App\Traits\CastLivewireProperties; use App\Traits\LivewireSort; use Illuminate\Support\Facades\Notification; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; @@ -228,138 +227,138 @@ class SimilarTorrent extends Component /** * @phpstan-ignore missingType.generics (The return type is too complex for phpstan, something to do with lack of support of Collection array shapes) */ - #[Computed] - final public function torrents(): \Illuminate\Support\Collection - { - $user = auth()->user(); + final protected \Illuminate\Support\Collection $torrents { + get { + $user = auth()->user(); - return Torrent::query() - ->with('type:id,name,position', 'resolution:id,name,position') - ->withCount([ - 'comments', - ]) - ->when( - !config('announce.external_tracker.is_enabled'), - fn ($query) => $query->withCount([ - 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - ]), - ) - ->when( - config('other.thanks-system.is-enabled'), - fn ($query) => $query->withCount('thanks') - ) - ->withExists([ - 'featured as featured', - 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()), - 'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id), - 'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 1), - 'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 0), - 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 0) - ->where('seeder', '=', 0) - ->whereNull('completed_at'), - 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 0) - ->where( - fn ($query) => $query - ->where('seeder', '=', 1) - ->orWhereNotNull('completed_at') - ), - 'trump', - ]) - ->when( - $this->category->movie_meta, - fn ($query) => $query->whereRelation('category', 'movie_meta', '=', true), - ) - ->when( - $this->category->tv_meta, - fn ($query) => $query->whereRelation('category', 'tv_meta', '=', true), - ) - ->when($this->category->tv_meta, fn ($query) => $query->where('tmdb_tv_id', '=', $this->tmdbId)) - ->when($this->category->movie_meta, fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)) - ->when($this->category->game_meta, fn ($query) => $query->where('igdb', '=', $this->igdbId)) - ->where((new TorrentSearchFiltersDTO( - name: $this->name, - description: $this->description, - mediainfo: $this->mediainfo, - keywords: $this->keywords ? array_map('trim', explode(',', $this->keywords)) : [], - uploader: $this->uploader, - episodeNumber: $this->episodeNumber, - seasonNumber: $this->seasonNumber, - minSize: $this->minSize === null ? null : $this->minSize * $this->minSizeMultiplier, - maxSize: $this->maxSize === null ? null : $this->maxSize * $this->maxSizeMultiplier, - playlistId: $this->playlistId, - typeIds: $this->typeIds, - resolutionIds: $this->resolutionIds, - free: $this->free, - doubleup: $this->doubleup, - featured: $this->featured, - refundable: $this->refundable, - internal: $this->internal, - personalRelease: $this->personalRelease, - trumpable: $this->trumpable, - highspeed: $this->highspeed, - userBookmarked: $this->bookmarked, - userWished: $this->wished, - alive: $this->alive, - dying: $this->dying, - dead: $this->dead, - graveyard: $this->graveyard, - userDownloaded: match (true) { - $this->downloaded => true, - $this->notDownloaded => false, - default => null, - }, - userSeeder: match (true) { - $this->seeding => true, - $this->leeching => false, - default => null, - }, - userActive: match (true) { - $this->seeding => true, - $this->leeching => true, - default => null, - }, - ))->toSqlQueryBuilder()) - ->orderBy($this->sortField, $this->sortDirection) - ->get() - ->when( - $this->category->movie_meta, - fn ($torrents) => $this->groupByTypeAndSort($torrents), - fn ($torrents) => $torrents - ->when($this->category->tv_meta, function ($torrents) { - return $torrents - ->groupBy(fn ($torrent) => $torrent->season_number === 0 ? ($torrent->episode_number === 0 ? 'Complete Pack' : 'Specials') : 'Seasons') - ->map(fn ($packOrSpecialOrSeasons, $key) => match ($key) { - 'Complete Pack' => $this->groupByTypeAndSort($packOrSpecialOrSeasons), - 'Specials' => $packOrSpecialOrSeasons - ->groupBy(fn ($torrent) => 'Special '.$torrent->episode_number) - ->sortKeysDesc(SORT_NATURAL) - ->map(fn ($episode) => $this->groupByTypeAndSort($episode)), - 'Seasons' => $packOrSpecialOrSeasons - ->groupBy(fn ($torrent) => 'Season '.$torrent->season_number) - ->sortKeysDesc(SORT_NATURAL) - ->map( - fn ($season) => $season - ->groupBy(fn ($torrent) => $torrent->episode_number === 0 ? 'Season Pack' : 'Episodes') - ->map(fn ($packOrEpisodes, $key) => match ($key) { - 'Season Pack' => $this->groupByTypeAndSort($packOrEpisodes), - 'Episodes' => $packOrEpisodes - ->groupBy(fn ($torrent) => 'Episode '.$torrent->episode_number) - ->sortKeysDesc(SORT_NATURAL) - ->map(fn ($episode) => $this->groupByTypeAndSort($episode)), - default => abort(500, 'Group found that isn\'t one of: Season Pack, Episodes.'), - }) - ), - default => abort(500, 'Group found that isn\'t one of: Complete Pack, Specials, Seasons'), - }); - }) - ); + return Torrent::query() + ->with('type:id,name,position', 'resolution:id,name,position') + ->withCount([ + 'comments', + ]) + ->when( + !config('announce.external_tracker.is_enabled'), + fn ($query) => $query->withCount([ + 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + ]), + ) + ->when( + config('other.thanks-system.is-enabled'), + fn ($query) => $query->withCount('thanks') + ) + ->withExists([ + 'featured as featured', + 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()), + 'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id), + 'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 1), + 'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 0), + 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 0) + ->where('seeder', '=', 0) + ->whereNull('completed_at'), + 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 0) + ->where( + fn ($query) => $query + ->where('seeder', '=', 1) + ->orWhereNotNull('completed_at') + ), + 'trump', + ]) + ->when( + $this->category->movie_meta, + fn ($query) => $query->whereRelation('category', 'movie_meta', '=', true), + ) + ->when( + $this->category->tv_meta, + fn ($query) => $query->whereRelation('category', 'tv_meta', '=', true), + ) + ->when($this->category->tv_meta, fn ($query) => $query->where('tmdb_tv_id', '=', $this->tmdbId)) + ->when($this->category->movie_meta, fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)) + ->when($this->category->game_meta, fn ($query) => $query->where('igdb', '=', $this->igdbId)) + ->where((new TorrentSearchFiltersDTO( + name: $this->name, + description: $this->description, + mediainfo: $this->mediainfo, + keywords: $this->keywords ? array_map('trim', explode(',', $this->keywords)) : [], + uploader: $this->uploader, + episodeNumber: $this->episodeNumber, + seasonNumber: $this->seasonNumber, + minSize: $this->minSize === null ? null : $this->minSize * $this->minSizeMultiplier, + maxSize: $this->maxSize === null ? null : $this->maxSize * $this->maxSizeMultiplier, + playlistId: $this->playlistId, + typeIds: $this->typeIds, + resolutionIds: $this->resolutionIds, + free: $this->free, + doubleup: $this->doubleup, + featured: $this->featured, + refundable: $this->refundable, + internal: $this->internal, + personalRelease: $this->personalRelease, + trumpable: $this->trumpable, + highspeed: $this->highspeed, + userBookmarked: $this->bookmarked, + userWished: $this->wished, + alive: $this->alive, + dying: $this->dying, + dead: $this->dead, + graveyard: $this->graveyard, + userDownloaded: match (true) { + $this->downloaded => true, + $this->notDownloaded => false, + default => null, + }, + userSeeder: match (true) { + $this->seeding => true, + $this->leeching => false, + default => null, + }, + userActive: match (true) { + $this->seeding => true, + $this->leeching => true, + default => null, + }, + ))->toSqlQueryBuilder()) + ->orderBy($this->sortField, $this->sortDirection) + ->get() + ->when( + $this->category->movie_meta, + fn ($torrents) => $this->groupByTypeAndSort($torrents), + fn ($torrents) => $torrents + ->when($this->category->tv_meta, function ($torrents) { + return $torrents + ->groupBy(fn ($torrent) => $torrent->season_number === 0 ? ($torrent->episode_number === 0 ? 'Complete Pack' : 'Specials') : 'Seasons') + ->map(fn ($packOrSpecialOrSeasons, $key) => match ($key) { + 'Complete Pack' => $this->groupByTypeAndSort($packOrSpecialOrSeasons), + 'Specials' => $packOrSpecialOrSeasons + ->groupBy(fn ($torrent) => 'Special '.$torrent->episode_number) + ->sortKeysDesc(SORT_NATURAL) + ->map(fn ($episode) => $this->groupByTypeAndSort($episode)), + 'Seasons' => $packOrSpecialOrSeasons + ->groupBy(fn ($torrent) => 'Season '.$torrent->season_number) + ->sortKeysDesc(SORT_NATURAL) + ->map( + fn ($season) => $season + ->groupBy(fn ($torrent) => $torrent->episode_number === 0 ? 'Season Pack' : 'Episodes') + ->map(fn ($packOrEpisodes, $key) => match ($key) { + 'Season Pack' => $this->groupByTypeAndSort($packOrEpisodes), + 'Episodes' => $packOrEpisodes + ->groupBy(fn ($torrent) => 'Episode '.$torrent->episode_number) + ->sortKeysDesc(SORT_NATURAL) + ->map(fn ($episode) => $this->groupByTypeAndSort($episode)), + default => abort(500, 'Group found that isn\'t one of: Season Pack, Episodes.'), + }) + ), + default => abort(500, 'Group found that isn\'t one of: Complete Pack, Specials, Seasons'), + }); + }) + ); + } } /** @@ -383,12 +382,10 @@ class SimilarTorrent extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function torrentRequests(): \Illuminate\Database\Eloquent\Collection - { - return TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution']) + final protected \Illuminate\Database\Eloquent\Collection $torrentRequests { + get => TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution']) ->withCount(['comments']) ->withExists('claim') ->when($this->category->movie_meta, fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)) @@ -404,12 +401,10 @@ class SimilarTorrent extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function playlistCategories(): \Illuminate\Database\Eloquent\Collection - { - return PlaylistCategory::query() + final protected \Illuminate\Database\Eloquent\Collection $playlistCategories { + get => PlaylistCategory::query() ->with([ 'playlists' => fn ($query) => $query ->withCount('torrents') @@ -433,16 +428,10 @@ class SimilarTorrent extends Component } /** - * @return ?\Illuminate\Database\Eloquent\Collection + * @var ?\Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function collectionMovies(): ?\Illuminate\Database\Eloquent\Collection - { - if (!$this->work instanceof TmdbMovie) { - return null; - } - - return $this->work->collections()->first()?->movies()->get(); + final protected ?\Illuminate\Database\Eloquent\Collection $collectionMovies { + get => $this->work instanceof TmdbMovie ? $this->work->collections()->first()?->movies()->get() : null; } final public function alertConfirm(): void @@ -475,9 +464,9 @@ class SimilarTorrent extends Component $torrents = Torrent::whereKey($this->checked)->get(); $users = []; $title = match (true) { - $this->category->movie_meta => ($movie = TmdbMovie::find($this->tmdbId))->title.' ('.$movie->release_date->format('Y').')', - $this->category->tv_meta => ($tv = TmdbTv::find($this->tmdbId))->name.' ('.$tv->first_air_date->format('Y').')', - $this->category->game_meta => ($game = IgdbGame::find($this->igdbId))->name.' ('.$game->first_release_date->format('Y').')', + $this->category->movie_meta => ($movie = TmdbMovie::find($this->tmdbId))->title.($movie->release_date === null ? '' : ' ('.$movie->release_date->format('Y').')'), + $this->category->tv_meta => ($tv = TmdbTv::find($this->tmdbId))->name.($tv->first_air_date === null ? '' : ' ('.$tv->first_air_date->format('Y').')'), + $this->category->game_meta => ($game = IgdbGame::find($this->igdbId))->name.($game->first_release_date === null ? '' : ' ('.$game->first_release_date->format('Y').')'), default => $torrents->pluck('name')->join(', '), }; @@ -537,46 +526,52 @@ class SimilarTorrent extends Component ); } - #[Computed] - final public function personalFreeleech(): bool - { - return cache()->get('personal_freeleech:'.auth()->id()) ?? false; + final protected bool $personalFreeleech { + get => cache()->get('personal_freeleech:'.auth()->id()) ?? false; } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function types(): \Illuminate\Database\Eloquent\Collection - { - return Type::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $types { + get => cache()->remember( + 'types', + 3600, + fn () => Type::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function resolutions(): \Illuminate\Database\Eloquent\Collection - { - return Resolution::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $resolutions { + get => cache()->remember( + 'resolutions', + 3600, + fn () => Resolution::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function regions(): \Illuminate\Database\Eloquent\Collection - { - return Region::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $regions { + get => cache()->remember( + 'regions', + 3600, + fn () => Region::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function distributors(): \Illuminate\Database\Eloquent\Collection - { - return Distributor::query()->orderBy('name')->get(); + final protected \Illuminate\Database\Eloquent\Collection $distributors { + get => cache()->remember( + 'distributors', + 3600, + fn () => Distributor::query()->orderBy('name')->get(), + ); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/Stats/PeerStats.php b/app/Http/Livewire/Stats/PeerStats.php index 8ccb9bbb9..9c463e5fd 100644 --- a/app/Http/Livewire/Stats/PeerStats.php +++ b/app/Http/Livewire/Stats/PeerStats.php @@ -18,34 +18,39 @@ namespace App\Http\Livewire\Stats; use App\Models\History; use App\Models\Peer; -use Livewire\Attributes\Computed; use Livewire\Attributes\Lazy; use Livewire\Component; #[Lazy(isolate: true)] class PeerStats extends Component { - #[Computed(cache: true, seconds: 10 * 60)] - final public function leecherCount(): int - { - // Generally sites have more seeders than leechers, so it ends up being faster (by approximately 50%) to compute leechers and total instead of seeders and leechers. - return Peer::query()->where('seeder', '=', false)->where('active', '=', true)->count(); + final protected int $leecherCount { + get => (int) cache()->remember( + 'peer-stats:leecher-count', + 10 * 60, + // Generally sites have more seeders than leechers, so it ends up being faster (by approximately 50%) to compute leechers and total instead of seeders and leechers. + fn () => Peer::query()->where('seeder', '=', false)->where('active', '=', true)->count() + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function peerCount(): int - { - return Peer::query()->where('active', '=', true)->count(); + final protected int $peerCount { + get => (int) cache()->remember( + 'peer-stats:peer-count', + 10 * 60, + fn () => Peer::query()->where('active', '=', true)->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function totalSeeded(): int - { - return (int) History::query() - ->join('torrents', 'history.torrent_id', '=', 'torrents.id') - ->where('history.active', '=', true) - ->where('history.seeder', '=', true) - ->sum('size'); + final protected int $totalSeeded { + get => (int) cache()->remember( + 'peer-stats:total-seeded', + 10 * 60, + fn () => History::query() + ->join('torrents', 'history.torrent_id', '=', 'torrents.id') + ->where('history.active', '=', true) + ->where('history.seeder', '=', true) + ->sum('size'), + ); } final public function placeholder(): string diff --git a/app/Http/Livewire/Stats/TorrentStats.php b/app/Http/Livewire/Stats/TorrentStats.php index d6e9d90f6..822597b1a 100644 --- a/app/Http/Livewire/Stats/TorrentStats.php +++ b/app/Http/Livewire/Stats/TorrentStats.php @@ -19,41 +19,48 @@ namespace App\Http\Livewire\Stats; use App\Models\Category; use App\Models\Resolution; use App\Models\Torrent; -use Livewire\Attributes\Computed; use Livewire\Attributes\Lazy; use Livewire\Component; #[Lazy(isolate: true)] class TorrentStats extends Component { - #[Computed(cache: true, seconds: 10 * 60)] - final public function totalCount(): int - { - return Torrent::query()->count(); + final protected int $totalCount { + get => (int) cache()->remember( + 'torrent-stats:total-count', + 10 * 60, + fn () => Torrent::query()->count(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(cache: true, seconds: 10 * 60)] - final public function resolutions(): \Illuminate\Database\Eloquent\Collection - { - return Resolution::query()->withCount('torrents')->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $resolutions { + get => cache()->remember( + 'torrent-stats:resolutions', + 10 * 60, + fn () => Resolution::query()->withCount('torrents')->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(cache: true, seconds: 10 * 60)] - final public function categories(): \Illuminate\Database\Eloquent\Collection - { - return Category::query()->withCount('torrents')->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $categories { + get => cache()->remember( + 'torrent-stats:categories', + 10 * 60, + fn () => Category::query()->withCount('torrents')->orderBy('position')->get(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function sizeSum(): int - { - return (int) Torrent::query()->sum('size'); + final protected int $sizeSum { + get => (int) cache()->remember( + 'torrent-stats:size-sum', + 10 * 60, + fn () => Torrent::query()->sum('size'), + ); } final public function placeholder(): string diff --git a/app/Http/Livewire/Stats/TrafficStats.php b/app/Http/Livewire/Stats/TrafficStats.php index 943de8f9c..6be324ea1 100644 --- a/app/Http/Livewire/Stats/TrafficStats.php +++ b/app/Http/Livewire/Stats/TrafficStats.php @@ -17,35 +17,42 @@ declare(strict_types=1); namespace App\Http\Livewire\Stats; use App\Models\History; -use Livewire\Attributes\Computed; use Livewire\Attributes\Lazy; use Livewire\Component; #[Lazy(isolate: true)] class TrafficStats extends Component { - #[Computed(cache: true, seconds: 10 * 60)] - final public function actualUpload(): int - { - return (int) History::query()->sum('actual_uploaded'); + final protected int $actualUpload { + get => (int) cache()->remember( + 'traffic-stats:actual-upload', + 10 * 60, + fn () => History::query()->sum('actual_uploaded'), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function creditedUpload(): int - { - return (int) History::query()->sum('uploaded'); + final protected int $creditedUpload { + get => (int) cache()->remember( + 'traffic-stats:credited-upload', + 10 * 60, + fn () => History::query()->sum('uploaded'), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function actualDownload(): int - { - return (int) History::query()->sum('actual_downloaded'); + final protected int $actualDownload { + get => (int) cache()->remember( + 'traffic-stats:actual-download', + 10 * 60, + fn () => History::query()->sum('actual_downloaded'), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function creditedDownload(): int - { - return (int) History::query()->sum('downloaded'); + final protected int $creditedDownload { + get => (int) cache()->remember( + 'traffic-stats:credited-download', + 10 * 60, + fn () => History::query()->sum('downloaded'), + ); } final public function placeholder(): string diff --git a/app/Http/Livewire/Stats/UserStats.php b/app/Http/Livewire/Stats/UserStats.php index 424ec951d..d13e4ca8a 100644 --- a/app/Http/Livewire/Stats/UserStats.php +++ b/app/Http/Livewire/Stats/UserStats.php @@ -17,59 +17,74 @@ declare(strict_types=1); namespace App\Http\Livewire\Stats; use App\Models\User; -use Livewire\Attributes\Computed; use Livewire\Attributes\Lazy; use Livewire\Component; #[Lazy(isolate: true)] class UserStats extends Component { - #[Computed(cache: true, seconds: 10 * 60)] - final public function allUsers(): int - { - return User::query()->withTrashed()->count(); + final protected int $allUsers { + get => (int) cache()->remember( + 'user-stats:all-users', + 10 * 60, + fn () => User::query()->withTrashed()->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function activeUsers(): int - { - return User::query()->whereHas('group', fn ($query) => $query->whereNotIn('slug', ['banned', 'validating', 'disabled', 'pruned']))->count(); + final protected int $activeUsers { + get => (int) cache()->remember( + 'user-stats:active-users', + 10 * 60, + fn () => User::query()->whereHas('group', fn ($query) => $query->whereNotIn('slug', ['banned', 'validating', 'disabled', 'pruned']))->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function disableUsers(): int - { - return User::query()->whereRelation('group', 'slug', '=', 'disabled')->count(); + final protected int $disableUsers { + get => (int) cache()->remember( + 'user-stats:disable-users', + 10 * 60, + fn () => User::query()->whereRelation('group', 'slug', '=', 'disabled')->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function prunedUsers(): int - { - return User::query()->onlyTrashed()->whereRelation('group', 'slug', '=', 'pruned')->count(); + final protected int $prunedUsers { + get => (int) cache()->remember( + 'user-stats:pruned-users', + 10 * 60, + fn () => User::query()->onlyTrashed()->whereRelation('group', 'slug', '=', 'pruned')->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function bannedUsers(): int - { - return User::query()->whereRelation('group', 'slug', '=', 'banned')->count(); + final protected int $bannedUsers { + get => (int) cache()->remember( + 'user-stats:banned-users', + 10 * 60, + fn () => User::query()->whereRelation('group', 'slug', '=', 'banned')->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function usersActiveToday(): int - { - return User::query()->where('last_action', '>', now()->subDay())->count(); + final protected int $usersActiveToday { + get => (int) cache()->remember( + 'user-stats:users-active-today', + 10 * 60, + fn () => User::query()->where('last_action', '>', now()->subDay())->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function usersActiveThisWeek(): int - { - return User::query()->where('last_action', '>', now()->subWeek())->count(); + final protected int $usersActiveThisWeek { + get => (int) cache()->remember( + 'user-stats:users-active-this-week', + 10 * 60, + fn () => User::query()->where('last_action', '>', now()->subWeek())->count(), + ); } - #[Computed(cache: true, seconds: 10 * 60)] - final public function usersActiveThisMonth(): int - { - return User::query()->where('last_action', '>', now()->subMonth())->count(); + final protected int $usersActiveThisMonth { + get => (int) cache()->remember( + 'user-stats:users-active-this-month', + 10 * 60, + fn () => User::query()->where('last_action', '>', now()->subMonth())->count(), + ); } final public function placeholder(): string diff --git a/app/Http/Livewire/SubscribedForum.php b/app/Http/Livewire/SubscribedForum.php index 3da90e667..dbbbeabb0 100644 --- a/app/Http/Livewire/SubscribedForum.php +++ b/app/Http/Livewire/SubscribedForum.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\Forum; -use Livewire\Attributes\Computed; use Livewire\Component; use Livewire\WithPagination; @@ -26,12 +25,10 @@ class SubscribedForum extends Component use WithPagination; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function forums() - { - return Forum::query() + final protected $forums { + get => Forum::query() ->with('latestPoster', 'lastRepliedTopic') ->whereRelation('subscribedUsers', 'users.id', '=', auth()->id()) ->authorized(canReadTopic: true) diff --git a/app/Http/Livewire/SubscribedTopic.php b/app/Http/Livewire/SubscribedTopic.php index 39b85b34b..63045f97b 100644 --- a/app/Http/Livewire/SubscribedTopic.php +++ b/app/Http/Livewire/SubscribedTopic.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\Topic; -use Livewire\Attributes\Computed; use Livewire\Component; use Livewire\WithPagination; @@ -26,12 +25,10 @@ class SubscribedTopic extends Component use WithPagination; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function topics(): \Illuminate\Pagination\LengthAwarePaginator - { - return Topic::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $topics { + get => Topic::query() ->select('topics.*') ->with([ 'user.group', diff --git a/app/Http/Livewire/SubtitleSearch.php b/app/Http/Livewire/SubtitleSearch.php index d0f93f0ee..d7a23084a 100644 --- a/app/Http/Livewire/SubtitleSearch.php +++ b/app/Http/Livewire/SubtitleSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\Subtitle; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -60,12 +59,11 @@ class SubtitleSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function subtitles(): \Illuminate\Pagination\LengthAwarePaginator - { - return Subtitle::with(['user.group', 'torrent.category', 'language']) + final protected \Illuminate\Pagination\LengthAwarePaginator $subtitles { + get => Subtitle::query() + ->with(['user.group', 'torrent.category', 'language']) ->whereHas('torrent') ->when($this->search, fn ($query) => $query->where('title', 'like', '%'.$this->search.'%')) ->when($this->categories, fn ($query) => $query->whereHas('torrent', fn ($query) => $query->whereIn('category_id', $this->categories))) diff --git a/app/Http/Livewire/TicketSearch.php b/app/Http/Livewire/TicketSearch.php index 6723f8d8e..b24c56d6d 100644 --- a/app/Http/Livewire/TicketSearch.php +++ b/app/Http/Livewire/TicketSearch.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\Ticket; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $tickets - */ class TicketSearch extends Component { use LivewireSort; @@ -71,12 +67,10 @@ class TicketSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function tickets(): \Illuminate\Pagination\LengthAwarePaginator - { - return Ticket::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $tickets { + get => Ticket::query() ->with(['user.group', 'staff.group', 'category', 'priority']) ->when(!$this->user->group->is_modo, fn ($query) => $query->where('user_id', '=', $this->user->id)) ->when( diff --git a/app/Http/Livewire/TmdbCollectionSearch.php b/app/Http/Livewire/TmdbCollectionSearch.php index 94bba829a..0ecd575a0 100644 --- a/app/Http/Livewire/TmdbCollectionSearch.php +++ b/app/Http/Livewire/TmdbCollectionSearch.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\TmdbCollection; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -37,12 +36,10 @@ class TmdbCollectionSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function collections(): \Illuminate\Pagination\LengthAwarePaginator - { - return TmdbCollection::withCount('movies') + final protected \Illuminate\Pagination\LengthAwarePaginator $collections { + get => TmdbCollection::withCount('movies') ->with('movies') ->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%')) ->oldest('name') diff --git a/app/Http/Livewire/TmdbCompanySearch.php b/app/Http/Livewire/TmdbCompanySearch.php index 624312f29..c988b8ddc 100644 --- a/app/Http/Livewire/TmdbCompanySearch.php +++ b/app/Http/Livewire/TmdbCompanySearch.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\TmdbCompany; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -37,12 +36,10 @@ class TmdbCompanySearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function companies(): \Illuminate\Pagination\LengthAwarePaginator - { - return TmdbCompany::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $companies { + get => TmdbCompany::query() ->withCount([ 'movie' => fn ($query) => $query->has('torrents'), 'tv' => fn ($query) => $query->has('torrents'), diff --git a/app/Http/Livewire/TmdbNetworkSearch.php b/app/Http/Livewire/TmdbNetworkSearch.php index 8d22acf58..64d464369 100644 --- a/app/Http/Livewire/TmdbNetworkSearch.php +++ b/app/Http/Livewire/TmdbNetworkSearch.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\TmdbNetwork; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -37,12 +36,10 @@ class TmdbNetworkSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function networks(): \Illuminate\Pagination\LengthAwarePaginator - { - return TmdbNetwork::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $networks { + get => TmdbNetwork::query() ->withCount([ 'tv' => fn ($query) => $query->has('torrents'), ]) diff --git a/app/Http/Livewire/TmdbPersonCredit.php b/app/Http/Livewire/TmdbPersonCredit.php index 424f964fd..93d37b4c0 100644 --- a/app/Http/Livewire/TmdbPersonCredit.php +++ b/app/Http/Livewire/TmdbPersonCredit.php @@ -20,7 +20,6 @@ use App\Enums\Occupation; use App\Models\TmdbPerson; use App\Models\Torrent; use App\Models\User; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; @@ -50,10 +49,8 @@ class TmdbPersonCredit extends Component }; } - #[Computed] - final public function personalFreeleech(): bool - { - return cache()->get('personal_freeleech:'.auth()->user()->id) ?? false; + final protected bool $personalFreeleech { + get => cache()->get('personal_freeleech:'.auth()->user()->id) ?? false; } /* @@ -64,291 +61,271 @@ class TmdbPersonCredit extends Component $value = Occupation::from($value); } - #[Computed] - public function directedCount(): int - { - return $this->person->directedMovies()->count() + $this->person->directedTv()->count(); + final protected int $directedCount { + get => $this->person->directedMovies()->count() + $this->person->directedTv()->count(); } - #[Computed] - public function createdCount(): int - { - return $this->person->createdTv()->count(); + final protected int $createdCount { + get => $this->person->createdTv()->count(); } - #[Computed] - public function writtenCount(): int - { - return $this->person->writtenMovies()->count() + $this->person->writtenTv()->count(); + final protected int $writtenCount { + get => $this->person->writtenMovies()->count() + $this->person->writtenTv()->count(); } - #[Computed] - public function producedCount(): int - { - return $this->person->producedMovies()->count() + $this->person->producedTv()->count(); + final protected int $producedCount { + get => $this->person->producedMovies()->count() + $this->person->producedTv()->count(); } - #[Computed] - public function composedCount(): int - { - return $this->person->composedMovies()->count() + $this->person->composedTv()->count(); + final protected int $composedCount { + get => $this->person->composedMovies()->count() + $this->person->composedTv()->count(); } - #[Computed] - public function cinematographedCount(): int - { - return $this->person->cinematographedMovies()->count() + $this->person->cinematographedTv()->count(); + final protected int $cinematographedCount { + get => $this->person->cinematographedMovies()->count() + $this->person->cinematographedTv()->count(); } - #[Computed] - public function editedCount(): int - { - return $this->person->editedMovies()->count() + $this->person->editedTv()->count(); + final protected int $editedCount { + get => $this->person->editedMovies()->count() + $this->person->editedTv()->count(); } - #[Computed] - public function productionDesignedCount(): int - { - return $this->person->productionDesignedMovies()->count() + $this->person->productionDesignedTv()->count(); + final protected int $productionDesignedCount { + get => $this->person->productionDesignedMovies()->count() + $this->person->productionDesignedTv()->count(); } - #[Computed] - public function artDirectedCount(): int - { - return $this->person->artDirectedMovies()->count() + $this->person->artDirectedTv()->count(); + final protected int $artDirectedCount { + get => $this->person->artDirectedMovies()->count() + $this->person->artDirectedTv()->count(); } - #[Computed] - public function actedCount(): int - { - return $this->person->actedMovies()->count() + $this->person->actedTv()->count(); + final protected int $actedCount { + get => $this->person->actedMovies()->count() + $this->person->actedTv()->count(); } /** * @return \Illuminate\Support\Collection */ - #[Computed] - final public function medias(): \Illuminate\Support\Collection - { - if ($this->occupationId === null) { - return collect(); - } + final protected \Illuminate\Support\Collection $medias { + get { + if ($this->occupationId === null) { + return collect(); + } - $movies = $this->person - ->movie() - ->with('genres', 'directors') - ->wherePivot('occupation_id', '=', $this->occupationId) - ->orderBy('release_date') - ->get() - // Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate movies - ->unique(); - $tv = $this->person - ->tv() - ->with('genres', 'creators') - ->wherePivot('occupation_id', '=', $this->occupationId) - ->orderBy('first_air_date') - ->get() - // Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate tv - ->unique(); + $movies = $this->person + ->movie() + ->with('genres', 'directors') + ->wherePivot('occupation_id', '=', $this->occupationId) + ->orderBy('release_date') + ->get() + // Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate movies + ->unique(); + $tv = $this->person + ->tv() + ->with('genres', 'creators') + ->wherePivot('occupation_id', '=', $this->occupationId) + ->orderBy('first_air_date') + ->get() + // Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate tv + ->unique(); - $movieIds = $movies->pluck('id'); - $tvIds = $tv->pluck('id'); + $movieIds = $movies->pluck('id'); + $tvIds = $tv->pluck('id'); - $torrents = Torrent::query() - ->with('type:id,name,position', 'resolution:id,name,position') - ->select([ - 'id', - 'name', - 'info_hash', - 'size', - 'leechers', - 'seeders', - 'times_completed', - 'category_id', - 'user_id', - 'season_number', - 'episode_number', - 'tmdb_movie_id', - 'tmdb_tv_id', - 'free', - 'doubleup', - 'highspeed', - 'sticky', - 'internal', - 'created_at', - 'bumped_at', - 'type_id', - 'resolution_id', - 'personal_release', - ]) - ->selectRaw(<<<'SQL' + $torrents = Torrent::query() + ->with('type:id,name,position', 'resolution:id,name,position') + ->select([ + 'id', + 'name', + 'info_hash', + 'size', + 'leechers', + 'seeders', + 'times_completed', + 'category_id', + 'user_id', + 'season_number', + 'episode_number', + 'tmdb_movie_id', + 'tmdb_tv_id', + 'free', + 'doubleup', + 'highspeed', + 'sticky', + 'internal', + 'created_at', + 'bumped_at', + 'type_id', + 'resolution_id', + 'personal_release', + ]) + ->selectRaw(<<<'SQL' CASE WHEN category_id IN (SELECT `id` from `categories` where `movie_meta` = 1) THEN 'movie' WHEN category_id IN (SELECT `id` from `categories` where `tv_meta` = 1) THEN 'tv' END as meta SQL) - ->withCount([ - 'comments', - ]) - ->when( - !config('announce.external_tracker.is_enabled'), - fn ($query) => $query->withCount([ - 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - ]), - ) - ->when( - config('other.thanks-system.is-enabled'), - fn ($query) => $query->withCount('thanks') - ) - ->withExists([ - 'featured as featured', - 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()), - 'bookmarks' => fn ($query) => $query->where('user_id', '=', auth()->id()), - 'history as seeding' => fn ($query) => $query->where('user_id', '=', auth()->id()) - ->where('active', '=', 1) - ->where('seeder', '=', 1), - 'history as leeching' => fn ($query) => $query->where('user_id', '=', auth()->id()) - ->where('active', '=', 1) - ->where('seeder', '=', 0), - 'history as not_completed' => fn ($query) => $query->where('user_id', '=', auth()->id()) - ->where('active', '=', 0) - ->where('seeder', '=', 0) - ->whereNull('completed_at'), - 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', auth()->id()) - ->where('active', '=', 0) - ->where( - fn ($query) => $query - ->where('seeder', '=', 1) - ->orWhereNotNull('completed_at') - ), - 'trump', - ]) - ->where( - fn ($query) => $query - ->where( - fn ($query) => $query - ->whereRelation('category', 'movie_meta', '=', true) - ->whereIntegerInRaw('tmdb_movie_id', $movieIds) - ) - ->orWhere( - fn ($query) => $query - ->whereRelation('category', 'tv_meta', '=', true) - ->whereIntegerInRaw('tmdb_tv_id', $tvIds) - ) - ) - ->get(); + ->withCount([ + 'comments', + ]) + ->when( + !config('announce.external_tracker.is_enabled'), + fn ($query) => $query->withCount([ + 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + ]), + ) + ->when( + config('other.thanks-system.is-enabled'), + fn ($query) => $query->withCount('thanks') + ) + ->withExists([ + 'featured as featured', + 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()), + 'bookmarks' => fn ($query) => $query->where('user_id', '=', auth()->id()), + 'history as seeding' => fn ($query) => $query->where('user_id', '=', auth()->id()) + ->where('active', '=', 1) + ->where('seeder', '=', 1), + 'history as leeching' => fn ($query) => $query->where('user_id', '=', auth()->id()) + ->where('active', '=', 1) + ->where('seeder', '=', 0), + 'history as not_completed' => fn ($query) => $query->where('user_id', '=', auth()->id()) + ->where('active', '=', 0) + ->where('seeder', '=', 0) + ->whereNull('completed_at'), + 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', auth()->id()) + ->where('active', '=', 0) + ->where( + fn ($query) => $query + ->where('seeder', '=', 1) + ->orWhereNotNull('completed_at') + ), + 'trump', + ]) + ->where( + fn ($query) => $query + ->where( + fn ($query) => $query + ->whereRelation('category', 'movie_meta', '=', true) + ->whereIntegerInRaw('tmdb_movie_id', $movieIds) + ) + ->orWhere( + fn ($query) => $query + ->whereRelation('category', 'tv_meta', '=', true) + ->whereIntegerInRaw('tmdb_tv_id', $tvIds) + ) + ) + ->get(); - $groupedTorrents = []; + $groupedTorrents = []; - foreach ($torrents as &$torrent) { - // Memoizing and avoiding casts reduces runtime duration from 70ms to 40ms. - // If accessing laravel's attributes array directly, it's reduced to 11ms, - // but the attributes array is marked as protected so we can't access it. - $tmdb = $torrent->getAttributeValue('tmdb_movie_id') ?: $torrent->getAttributeValue('tmdb_tv_id'); - $type = $torrent->getRelationValue('type')->getAttributeValue('name'); + foreach ($torrents as &$torrent) { + // Memoizing and avoiding casts reduces runtime duration from 70ms to 40ms. + // If accessing laravel's attributes array directly, it's reduced to 11ms, + // but the attributes array is marked as protected so we can't access it. + $tmdb = $torrent->getAttributeValue('tmdb_movie_id') ?: $torrent->getAttributeValue('tmdb_tv_id'); + $type = $torrent->getRelationValue('type')->getAttributeValue('name'); - switch ($torrent->getAttributeValue('meta')) { - case 'movie': - $groupedTorrents['movie'][$tmdb]['Movie'][$type][] = $torrent; - $groupedTorrents['movie'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); + switch ($torrent->getAttributeValue('meta')) { + case 'movie': + $groupedTorrents['movie'][$tmdb]['Movie'][$type][] = $torrent; + $groupedTorrents['movie'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); - break; - case 'tv': - $episode = $torrent->getAttributeValue('episode_number'); - $season = $torrent->getAttributeValue('season_number'); + break; + case 'tv': + $episode = $torrent->getAttributeValue('episode_number'); + $season = $torrent->getAttributeValue('season_number'); - if ($season == 0) { - if ($episode == 0) { - $groupedTorrents['tv'][$tmdb]['Complete Pack'][$type][] = $torrent; + if ($season == 0) { + if ($episode == 0) { + $groupedTorrents['tv'][$tmdb]['Complete Pack'][$type][] = $torrent; + } else { + $groupedTorrents['tv'][$tmdb]['Specials']["Special {$episode}"][$type][] = $torrent; + } } else { - $groupedTorrents['tv'][$tmdb]['Specials']["Special {$episode}"][$type][] = $torrent; - } - } else { - if ($episode == 0) { - $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Season Pack'][$type][] = $torrent; - } else { - $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Episodes']["Episode {$episode}"][$type][] = $torrent; - } - } - $groupedTorrents['tv'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); - } - } - - foreach ($groupedTorrents as $mediaType => &$workTorrents) { - switch ($mediaType) { - case 'movie': - foreach ($workTorrents as &$movieTorrents) { - $this->sortTorrentTypes($movieTorrents['Movie']); - } - - break; - case 'tv': - foreach ($workTorrents as &$tvTorrents) { - foreach ($tvTorrents as $packOrSpecialOrSeasonsType => &$packOrSpecialOrSeasons) { - switch ($packOrSpecialOrSeasonsType) { - case 'Complete Pack': - $this->sortTorrentTypes($packOrSpecialOrSeasons); - - break; - case 'Specials': - krsort($packOrSpecialOrSeasons, SORT_NATURAL); - - foreach ($packOrSpecialOrSeasons as &$specialTorrents) { - $this->sortTorrentTypes($specialTorrents); - } - - break; - case 'Seasons': - krsort($packOrSpecialOrSeasons, SORT_NATURAL); - - foreach ($packOrSpecialOrSeasons as &$season) { - foreach ($season as $packOrEpisodesType => &$packOrEpisodes) { - switch ($packOrEpisodesType) { - case 'Season Pack': - $this->sortTorrentTypes($packOrEpisodes); - - break; - case 'Episodes': - krsort($packOrEpisodes, SORT_NATURAL); - - foreach ($packOrEpisodes as &$episodeTorrents) { - $this->sortTorrentTypes($episodeTorrents); - } - - break; - } - } - } + if ($episode == 0) { + $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Season Pack'][$type][] = $torrent; + } else { + $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Episodes']["Episode {$episode}"][$type][] = $torrent; } } - } + $groupedTorrents['tv'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); + } } - } - $medias = collect(); + foreach ($groupedTorrents as $mediaType => &$workTorrents) { + switch ($mediaType) { + case 'movie': + foreach ($workTorrents as &$movieTorrents) { + $this->sortTorrentTypes($movieTorrents['Movie']); + } - foreach ($movies as $movie) { - if (\array_key_exists('movie', $groupedTorrents) && \array_key_exists($movie->id, $groupedTorrents['movie'])) { - $media = $movie; - $media->setAttribute('meta', 'movie'); - $media->setRelation('torrents', $groupedTorrents['movie'][$movie->id]); - $media->setAttribute('category_id', $media->torrents['category_id']); - $medias->add($media); + break; + case 'tv': + foreach ($workTorrents as &$tvTorrents) { + foreach ($tvTorrents as $packOrSpecialOrSeasonsType => &$packOrSpecialOrSeasons) { + switch ($packOrSpecialOrSeasonsType) { + case 'Complete Pack': + $this->sortTorrentTypes($packOrSpecialOrSeasons); + + break; + case 'Specials': + krsort($packOrSpecialOrSeasons, SORT_NATURAL); + + foreach ($packOrSpecialOrSeasons as &$specialTorrents) { + $this->sortTorrentTypes($specialTorrents); + } + + break; + case 'Seasons': + krsort($packOrSpecialOrSeasons, SORT_NATURAL); + + foreach ($packOrSpecialOrSeasons as &$season) { + foreach ($season as $packOrEpisodesType => &$packOrEpisodes) { + switch ($packOrEpisodesType) { + case 'Season Pack': + $this->sortTorrentTypes($packOrEpisodes); + + break; + case 'Episodes': + krsort($packOrEpisodes, SORT_NATURAL); + + foreach ($packOrEpisodes as &$episodeTorrents) { + $this->sortTorrentTypes($episodeTorrents); + } + + break; + } + } + } + } + } + } + } } - } - foreach ($tv as $show) { - if (\array_key_exists('tv', $groupedTorrents) && \array_key_exists($show->id, $groupedTorrents['tv'])) { - $media = $show; - $media->setAttribute('meta', 'tv'); - $media->setRelation('torrents', $groupedTorrents['tv'][$show->id]); - $media->setAttribute('category_id', $media->torrents['category_id']); - $medias->add($media); + $medias = collect(); + + foreach ($movies as $movie) { + if (\array_key_exists('movie', $groupedTorrents) && \array_key_exists($movie->id, $groupedTorrents['movie'])) { + $media = $movie; + $media->setAttribute('meta', 'movie'); + $media->setRelation('torrents', $groupedTorrents['movie'][$movie->id]); + $media->setAttribute('category_id', $media->torrents['category_id']); + $medias->add($media); + } } - } - return $medias; + foreach ($tv as $show) { + if (\array_key_exists('tv', $groupedTorrents) && \array_key_exists($show->id, $groupedTorrents['tv'])) { + $media = $show; + $media->setAttribute('meta', 'tv'); + $media->setRelation('torrents', $groupedTorrents['tv'][$show->id]); + $media->setAttribute('category_id', $media->torrents['category_id']); + $medias->add($media); + } + } + + return $medias; + } } /** diff --git a/app/Http/Livewire/TmdbPersonSearch.php b/app/Http/Livewire/TmdbPersonSearch.php index c44aff7e4..19afe208f 100644 --- a/app/Http/Livewire/TmdbPersonSearch.php +++ b/app/Http/Livewire/TmdbPersonSearch.php @@ -17,7 +17,6 @@ declare(strict_types=1); namespace App\Http\Livewire; use App\Models\TmdbPerson; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -46,12 +45,11 @@ class TmdbPersonSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function persons(): \Illuminate\Pagination\LengthAwarePaginator - { - return TmdbPerson::select(['id', 'still', 'name']) + final protected \Illuminate\Pagination\LengthAwarePaginator $persons { + get => TmdbPerson::query() + ->select(['id', 'still', 'name']) ->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%')) ->when($this->occupationIds !== [], fn ($query) => $query->whereHas('credits', fn ($query) => $query->whereIn('occupation_id', $this->occupationIds))) ->when($this->firstCharacter !== '', fn ($query) => $query->where('name', 'LIKE', $this->firstCharacter.'%')) @@ -60,12 +58,11 @@ class TmdbPersonSearch extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function firstCharacters(): \Illuminate\Database\Eloquent\Collection - { - return TmdbPerson::selectRaw('substr(name, 1, 1) as alpha, count(*) as count') + final protected \Illuminate\Database\Eloquent\Collection $firstCharacters { + get => TmdbPerson::query() + ->selectRaw('substr(name, 1, 1) as alpha, count(*) as count') ->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%')) ->when($this->occupationIds !== [], fn ($query) => $query->whereHas('credits', fn ($query) => $query->whereIn('occupation_id', $this->occupationIds))) ->groupBy('alpha') diff --git a/app/Http/Livewire/TopTorrents.php b/app/Http/Livewire/TopTorrents.php index b8f7036bf..83cf830ad 100644 --- a/app/Http/Livewire/TopTorrents.php +++ b/app/Http/Livewire/TopTorrents.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Torrent; use App\Models\User; use App\Traits\TorrentMeta; -use Livewire\Attributes\Computed; use Livewire\Component; class TopTorrents extends Component @@ -36,74 +35,72 @@ class TopTorrents extends Component } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed] - final public function torrents(): \Illuminate\Support\Collection - { - $torrents = Torrent::query() - ->with(['user.group', 'category', 'type', 'resolution']) - ->withExists([ - 'featured as featured', - 'bookmarks' => fn ($query) => $query->where('user_id', '=', $this->user->id), - 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $this->user->id), - 'history as seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 1), - 'history as leeching' => fn ($query) => $query->where('user_id', '=', $this->user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 0), - 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $this->user->id) - ->where('active', '=', 0) - ->where('seeder', '=', 0) - ->whereNull('completed_at'), - 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id) - ->where('active', '=', 0) - ->where( - fn ($query) => $query - ->where('seeder', '=', 1) - ->orWhereNotNull('completed_at') - ), - ]) - ->selectRaw(<<withCount(['thanks', 'comments']) - ->when($this->tab === 'newest', fn ($query) => $query->orderByDesc('id')) - ->when($this->tab === 'seeded', fn ($query) => $query->orderByDesc('seeders')) - ->when( - $this->tab === 'dying', - fn ($query) => $query - ->where('seeders', '=', 1) - ->where('times_completed', '>=', 1) - ->orderByDesc('leechers') - ) - ->when($this->tab === 'leeched', fn ($query) => $query->orderByDesc('leechers')) - ->when( - $this->tab === 'dead', - fn ($query) => $query - ->where('seeders', '=', 0) - ->orderByDesc('leechers') - ) - ->take(5) - ->get(); + final protected \Illuminate\Support\Collection $torrents { + get { + $torrents = Torrent::query() + ->with(['user.group', 'category', 'type', 'resolution']) + ->withExists([ + 'featured as featured', + 'bookmarks' => fn ($query) => $query->where('user_id', '=', $this->user->id), + 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $this->user->id), + 'history as seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 1), + 'history as leeching' => fn ($query) => $query->where('user_id', '=', $this->user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 0), + 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $this->user->id) + ->where('active', '=', 0) + ->where('seeder', '=', 0) + ->whereNull('completed_at'), + 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id) + ->where('active', '=', 0) + ->where( + fn ($query) => $query + ->where('seeder', '=', 1) + ->orWhereNotNull('completed_at') + ), + ]) + ->selectRaw(<<withCount(['thanks', 'comments']) + ->when($this->tab === 'newest', fn ($query) => $query->orderByDesc('id')) + ->when($this->tab === 'seeded', fn ($query) => $query->orderByDesc('seeders')) + ->when( + $this->tab === 'dying', + fn ($query) => $query + ->where('seeders', '=', 1) + ->where('times_completed', '>=', 1) + ->orderByDesc('leechers') + ) + ->when($this->tab === 'leeched', fn ($query) => $query->orderByDesc('leechers')) + ->when( + $this->tab === 'dead', + fn ($query) => $query + ->where('seeders', '=', 0) + ->orderByDesc('leechers') + ) + ->take(5) + ->get(); - // See app/Traits/TorrentMeta.php - $this->scopeMeta($torrents); + // See app/Traits/TorrentMeta.php + $this->scopeMeta($torrents); - return $torrents; + return $torrents; + } } - #[Computed] - final public function personalFreeleech(): bool - { - return cache()->get('personal_freeleech:'.$this->user->id) ?? false; + final protected bool $personalFreeleech { + get => cache()->get('personal_freeleech:'.$this->user->id) ?? false; } final public function render(): \Illuminate\Contracts\View\Factory | \Illuminate\Contracts\View\View | \Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/TopUsers.php b/app/Http/Livewire/TopUsers.php index ae7feb8ae..05b2a8503 100644 --- a/app/Http/Livewire/TopUsers.php +++ b/app/Http/Livewire/TopUsers.php @@ -12,7 +12,6 @@ use App\Models\Thank; use App\Models\Torrent; use App\Models\User; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Component; class TopUsers extends Component @@ -20,175 +19,208 @@ class TopUsers extends Component public string $tab = 'uploaders'; /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function uploaders(): \Illuminate\Support\Collection - { - return Torrent::with(['user.group']) - ->select(DB::raw('user_id, COUNT(user_id) as value')) - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->where('anon', '=', false) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $uploaders { + get => cache()->remember( + 'top-users:uploaders', + 3600, + fn () => Torrent::query() + ->with(['user.group']) + ->select(DB::raw('user_id, COUNT(user_id) as value')) + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->where('anon', '=', false) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function downloaders(): \Illuminate\Support\Collection - { - return History::with(['user.group']) - ->select(DB::raw('user_id, count(distinct torrent_id) as value')) - ->whereNotNull('completed_at') - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $downloaders { + get => cache()->remember( + 'top-users:downloaders', + 3600, + fn () => History::query() + ->with(['user.group']) + ->select(DB::raw('user_id, count(distinct torrent_id) as value')) + ->whereNotNull('completed_at') + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function uploaded(): \Illuminate\Support\Collection - { - return User::select(['id', 'group_id', 'username', 'uploaded', 'image']) - ->with('group') - ->where('id', '!=', User::SYSTEM_USER_ID) - ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) - ->orderByDesc('uploaded') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $uploaded { + get => cache()->remember( + 'top-users:uploaded', + 3600, + fn () => User::query() + ->select(['id', 'group_id', 'username', 'uploaded', 'image']) + ->with('group') + ->where('id', '!=', User::SYSTEM_USER_ID) + ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) + ->orderByDesc('uploaded') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function downloaded(): \Illuminate\Support\Collection - { - return User::select(['id', 'group_id', 'username', 'downloaded', 'image']) - ->with('group') - ->where('id', '!=', User::SYSTEM_USER_ID) - ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) - ->orderByDesc('downloaded') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $downloaded { + get => cache()->remember( + 'top-users:downloaded', + 3600, + fn () => User::query() + ->select(['id', 'group_id', 'username', 'downloaded', 'image']) + ->with('group') + ->where('id', '!=', User::SYSTEM_USER_ID) + ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) + ->orderByDesc('downloaded') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function seeders(): \Illuminate\Support\Collection - { - return Peer::with(['user.group']) - ->select(DB::raw('user_id, count(distinct torrent_id) as value')) - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->where('seeder', '=', 1) - ->where('active', '=', 1) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $seeders { + get => cache()->remember( + 'top-users:seeders', + 3600, + fn () => Peer::query() + ->with(['user.group']) + ->select(DB::raw('user_id, count(distinct torrent_id) as value')) + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->where('seeder', '=', 1) + ->where('active', '=', 1) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function seedtimes(): \Illuminate\Support\Collection - { - return User::withSum('history as seedtime', 'seedtime') - ->with('group') - ->where('id', '!=', User::SYSTEM_USER_ID) - ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) - ->orderByDesc('seedtime') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $seedtimes { + get => cache()->remember( + 'top-users:seedtimes', + 3600, + fn () => User::query() + ->withSum('history as seedtime', 'seedtime') + ->with('group') + ->where('id', '!=', User::SYSTEM_USER_ID) + ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) + ->orderByDesc('seedtime') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function served(): \Illuminate\Support\Collection - { - return User::withCount('uploadSnatches') - ->with('group') - ->where('id', '!=', User::SYSTEM_USER_ID) - ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) - ->orderByDesc('upload_snatches_count') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $served { + get => cache()->remember( + 'top-users:served', + 3600, + fn () => User::query() + ->withCount('uploadSnatches') + ->with('group') + ->where('id', '!=', User::SYSTEM_USER_ID) + ->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned'])) + ->orderByDesc('upload_snatches_count') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function commenters(): \Illuminate\Support\Collection - { - return Comment::with(['user.group']) - ->select(DB::raw('user_id, COUNT(user_id) as value')) - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->where('anon', '=', false) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $commenters { + get => cache()->remember( + 'top-users:commenters', + 3600, + fn () => Comment::query() + ->with(['user.group']) + ->select(DB::raw('user_id, COUNT(user_id) as value')) + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->where('anon', '=', false) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function posters(): \Illuminate\Support\Collection - { - return Post::with(['user.group']) - ->select(DB::raw('user_id, COUNT(user_id) as value')) - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $posters { + get => cache()->remember( + 'top-users:posters', + 3600, + fn () => Post::query() + ->with(['user.group']) + ->select(DB::raw('user_id, COUNT(user_id) as value')) + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function thankers(): \Illuminate\Support\Collection - { - return Thank::with(['user.group']) - ->select(DB::raw('user_id, COUNT(user_id) as value')) - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $thankers { + get => cache()->remember( + 'top-users:thankers', + 3600, + fn () => Thank::query() + ->with(['user.group']) + ->select(DB::raw('user_id, COUNT(user_id) as value')) + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(cache: true)] - final public function personals(): \Illuminate\Support\Collection - { - return Torrent::with(['user.group']) - ->select(DB::raw('user_id, COUNT(user_id) as value')) - ->where('user_id', '!=', User::SYSTEM_USER_ID) - ->where('anon', '=', false) - ->where('personal_release', '=', true) - ->groupBy('user_id') - ->orderByDesc('value') - ->take(8) - ->get(); + final protected \Illuminate\Support\Collection $personals { + get => cache()->remember( + 'top-users:personals', + 3600, + fn () => Torrent::query() + ->with(['user.group']) + ->select(DB::raw('user_id, COUNT(user_id) as value')) + ->where('user_id', '!=', User::SYSTEM_USER_ID) + ->where('anon', '=', false) + ->where('personal_release', '=', true) + ->groupBy('user_id') + ->orderByDesc('value') + ->take(8) + ->get(), + ); } public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/TopicPostSearch.php b/app/Http/Livewire/TopicPostSearch.php index 783aec30d..4aefc1acd 100644 --- a/app/Http/Livewire/TopicPostSearch.php +++ b/app/Http/Livewire/TopicPostSearch.php @@ -20,7 +20,6 @@ use App\Models\Post; use App\Models\Topic; use App\Models\TopicRead; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -47,35 +46,35 @@ class TopicPostSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function posts(): \Illuminate\Pagination\LengthAwarePaginator - { - $posts = Post::query() - ->with('user', 'user.group') - ->withCount('likes', 'dislikes', 'authorPosts', 'authorTopics') - ->withSum('tips', 'bon') - ->where('topic_id', '=', $this->topic->id) - ->authorized(canReadTopic: true) - ->when($this->search !== '', fn ($query) => $query->where('content', 'LIKE', '%'.$this->search.'%')) - ->orderBy('created_at') - ->paginate(25); + final protected \Illuminate\Pagination\LengthAwarePaginator $posts { + get { + $posts = Post::query() + ->with('user', 'user.group') + ->withCount('likes', 'dislikes', 'authorPosts', 'authorTopics') + ->withSum('tips', 'bon') + ->where('topic_id', '=', $this->topic->id) + ->authorized(canReadTopic: true) + ->when($this->search !== '', fn ($query) => $query->where('content', 'LIKE', '%'.$this->search.'%')) + ->orderBy('created_at') + ->paginate(25); - if ($lastPost = $posts->getCollection()->last()) { - TopicRead::upsert([[ - 'topic_id' => $this->topic->id, - 'user_id' => auth()->id(), - 'last_read_post_id' => $lastPost->id, - ]], [ - 'topic_id', - 'user_id' - ], [ - 'last_read_post_id' => DB::raw('GREATEST(last_read_post_id, VALUES(last_read_post_id))') - ]); + if ($lastPost = $posts->getCollection()->last()) { + TopicRead::upsert([[ + 'topic_id' => $this->topic->id, + 'user_id' => auth()->id(), + 'last_read_post_id' => $lastPost->id, + ]], [ + 'topic_id', + 'user_id' + ], [ + 'last_read_post_id' => DB::raw('GREATEST(last_read_post_id, VALUES(last_read_post_id))') + ]); + } + + return $posts; } - - return $posts; } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/TopicSearch.php b/app/Http/Livewire/TopicSearch.php index ebf9c089c..222776fbc 100644 --- a/app/Http/Livewire/TopicSearch.php +++ b/app/Http/Livewire/TopicSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\ForumCategory; use App\Models\Topic; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -59,12 +58,10 @@ class TopicSearch extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function forumCategories(): \Illuminate\Database\Eloquent\Collection - { - return ForumCategory::query() + final protected \Illuminate\Database\Eloquent\Collection $forumCategories { + get => ForumCategory::query() ->with([ 'forums' => fn ($query) => $query->authorized(canReadTopic: true) ]) @@ -74,12 +71,10 @@ class TopicSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function topics(): \Illuminate\Pagination\LengthAwarePaginator - { - return Topic::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $topics { + get => Topic::query() ->select('topics.*') ->with([ 'user.group', diff --git a/app/Http/Livewire/TorrentDownloadSearch.php b/app/Http/Livewire/TorrentDownloadSearch.php index bac7d0efc..d673f5c69 100644 --- a/app/Http/Livewire/TorrentDownloadSearch.php +++ b/app/Http/Livewire/TorrentDownloadSearch.php @@ -16,19 +16,14 @@ declare(strict_types=1); namespace App\Http\Livewire; -use App\Models\Announce; use App\Models\TorrentDownload; use App\Traits\LivewireSort; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $announces - */ class TorrentDownloadSearch extends Component { use LivewireSort; @@ -92,12 +87,10 @@ class TorrentDownloadSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function torrentDownloads(): \Illuminate\Pagination\LengthAwarePaginator - { - return TorrentDownload::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $torrentDownloads { + get => TorrentDownload::query() ->with([ 'user' => fn ($query) => $query->with('group')->withTrashed(), 'torrent:id,name' diff --git a/app/Http/Livewire/TorrentRequestSearch.php b/app/Http/Livewire/TorrentRequestSearch.php index e9e505594..a8bd34de2 100644 --- a/app/Http/Livewire/TorrentRequestSearch.php +++ b/app/Http/Livewire/TorrentRequestSearch.php @@ -25,7 +25,6 @@ use App\Models\Type; use App\Traits\CastLivewireProperties; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -125,68 +124,74 @@ class TorrentRequestSearch extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function categories(): \Illuminate\Database\Eloquent\Collection - { - return Category::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $categories { + get => cache()->remember( + 'categories', + 3600, + fn () => Category::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function types(): \Illuminate\Database\Eloquent\Collection - { - return Type::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $types { + get => cache()->remember( + 'types', + 3600, + fn () => Type::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function resolutions(): \Illuminate\Database\Eloquent\Collection - { - return Resolution::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $resolutions { + get => cache()->remember( + 'resolutions', + 3600, + fn () => Resolution::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function genres(): \Illuminate\Database\Eloquent\Collection - { - return TmdbGenre::query()->orderBy('name')->get(); + final protected \Illuminate\Database\Eloquent\Collection $genres { + get => cache()->remember( + 'genres', + 3600, + fn () => TmdbGenre::query()->orderBy('name')->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function primaryLanguages(): \Illuminate\Support\Collection - { - return TmdbMovie::query() - ->select('original_language') - ->distinct() - ->orderBy('original_language') - ->pluck('original_language'); + final protected \Illuminate\Support\Collection $primaryLanguages { + get => cache()->remember( + 'original-languages', + 3600, + fn () => TmdbMovie::query() + ->select('original_language') + ->distinct() + ->orderBy('original_language') + ->pluck('original_language'), + ); } - #[Computed] - final public function torrentRequestStat(): ?object - { - return DB::table('requests') + final protected ?object $torrentRequestStat { + get => DB::table('requests') ->selectRaw('count(*) as total') ->selectRaw('count(case when filled_by is not null then 1 end) as filled') ->selectRaw('count(case when filled_by is null then 1 end) as unfilled') ->first(); } - #[Computed] - final public function torrentRequestBountyStat(): ?object - { - return DB::table('requests') + final protected ?object $torrentRequestBountyStat { + get => DB::table('requests') ->selectRaw('coalesce(sum(bounty), 0) as total') ->selectRaw('coalesce(sum(case when filled_by is not null then bounty end), 0) as claimed') ->selectRaw('coalesce(sum(case when filled_by is null then bounty end), 0) as unclaimed') @@ -194,129 +199,129 @@ class TorrentRequestSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function torrentRequests(): \Illuminate\Pagination\LengthAwarePaginator - { - $user = auth()->user(); - $isRegexAllowed = $user->group->is_modo; - $isRegex = fn ($field) => $isRegexAllowed - && \strlen((string) $field) > 2 - && $field[0] === '/' - && $field[-1] === '/' - && @preg_match($field, 'Validate regex') !== false; + final protected \Illuminate\Pagination\LengthAwarePaginator $torrentRequests { + get { + $user = auth()->user(); + $isRegexAllowed = $user->group->is_modo; + $isRegex = fn ($field) => $isRegexAllowed + && \strlen((string) $field) > 2 + && $field[0] === '/' + && $field[-1] === '/' + && @preg_match($field, 'Validate regex') !== false; - return TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution']) - ->withCount(['comments', 'bounties']) - ->withExists('claim') - ->when( - $this->name !== '', - fn ($query) => $query - ->when( - $isRegex($this->name), - fn ($query) => $query->where('name', 'REGEXP', substr($this->name, 1, -1)), - fn ($query) => $query->where('name', 'LIKE', '%'.str_replace(' ', '%', $this->name).'%') - ) - ) - ->when( - $this->requestor !== '', - fn ($query) => $query - ->whereRelation('user', 'username', '=', $this->requestor) - ->when( - $user === null, - fn ($query) => $query->where('anon', '=', false), - fn ($query) => $query - ->when( - !$user->group->is_modo, - fn ($query) => $query - ->where( - fn ($query) => $query - ->where('anon', '=', false) - ->orWhere('user_id', '=', $user->id) - ) - ) - ) - ) - ->when($this->categoryIds !== [], fn ($query) => $query->whereIntegerInRaw('category_id', $this->categoryIds)) - ->when($this->typeIds !== [], fn ($query) => $query->whereIntegerInRaw('type_id', $this->typeIds)) - ->when($this->resolutionIds !== [], fn ($query) => $query->whereIntegerInRaw('resolution_id', $this->resolutionIds)) - ->when($this->tmdbId !== null, fn ($query) => $query->where(fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)->orWhere('tmdb_tv_id', '=', $this->tmdbId))) - ->when($this->imdbId !== '', fn ($query) => $query->where('imdb', '=', (preg_match('/tt0*(\d{7,})/', $this->imdbId, $matches) ? $matches[1] : $this->imdbId))) - ->when($this->tvdbId !== null, fn ($query) => $query->where('tvdb', '=', $this->tvdbId)) - ->when($this->malId !== null, fn ($query) => $query->where('mal', '=', $this->malId)) - ->when( - $this->genreIds !== [], - fn ($query) => $query - ->where( - fn ($query) => $query - ->where( - fn ($query) => $query - ->whereRelation('category', 'movie_meta', '=', true) - ->whereIn('tmdb_movie_id', DB::table('tmdb_genre_tmdb_movie')->select('tmdb_movie_id')->whereIn('tmdb_genre_id', $this->genreIds)) - ) - ->orWhere( - fn ($query) => $query - ->whereRelation('category', 'tv_meta', '=', true) - ->whereIn('tmdb_tv_id', DB::table('tmdb_genre_tmdb_tv')->select('tmdb_tv_id')->whereIn('tmdb_genre_id', $this->genreIds)) - ) - ) - ) - ->when( - $this->primaryLanguageNames !== [], - fn ($query) => $query - ->where( - fn ($query) => $query - ->where( - fn ($query) => $query - ->whereRelation('category', 'movie_meta', '=', true) - ->whereHas('movie', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames)) - ) - ->orWhere( - fn ($query) => $query - ->whereRelation('category', 'tv_meta', '=', true) - ->whereHas('tv', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames)) - ) - ) - ) - ->when($this->unfilled || $this->claimed || $this->pending || $this->filled, function ($query): void { - $query->where(function ($query): void { + return TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution']) + ->withCount(['comments', 'bounties']) + ->withExists('claim') + ->when( + $this->name !== '', + fn ($query) => $query + ->when( + $isRegex($this->name), + fn ($query) => $query->where('name', 'REGEXP', substr($this->name, 1, -1)), + fn ($query) => $query->where('name', 'LIKE', '%'.str_replace(' ', '%', $this->name).'%') + ) + ) + ->when( + $this->requestor !== '', + fn ($query) => $query + ->whereRelation('user', 'username', '=', $this->requestor) + ->when( + $user === null, + fn ($query) => $query->where('anon', '=', false), + fn ($query) => $query + ->when( + !$user->group->is_modo, + fn ($query) => $query + ->where( + fn ($query) => $query + ->where('anon', '=', false) + ->orWhere('user_id', '=', $user->id) + ) + ) + ) + ) + ->when($this->categoryIds !== [], fn ($query) => $query->whereIntegerInRaw('category_id', $this->categoryIds)) + ->when($this->typeIds !== [], fn ($query) => $query->whereIntegerInRaw('type_id', $this->typeIds)) + ->when($this->resolutionIds !== [], fn ($query) => $query->whereIntegerInRaw('resolution_id', $this->resolutionIds)) + ->when($this->tmdbId !== null, fn ($query) => $query->where(fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)->orWhere('tmdb_tv_id', '=', $this->tmdbId))) + ->when($this->imdbId !== '', fn ($query) => $query->where('imdb', '=', (preg_match('/tt0*(\d{7,})/', $this->imdbId, $matches) ? $matches[1] : $this->imdbId))) + ->when($this->tvdbId !== null, fn ($query) => $query->where('tvdb', '=', $this->tvdbId)) + ->when($this->malId !== null, fn ($query) => $query->where('mal', '=', $this->malId)) + ->when( + $this->genreIds !== [], + fn ($query) => $query + ->where( + fn ($query) => $query + ->where( + fn ($query) => $query + ->whereRelation('category', 'movie_meta', '=', true) + ->whereIn('tmdb_movie_id', DB::table('tmdb_genre_tmdb_movie')->select('tmdb_movie_id')->whereIn('tmdb_genre_id', $this->genreIds)) + ) + ->orWhere( + fn ($query) => $query + ->whereRelation('category', 'tv_meta', '=', true) + ->whereIn('tmdb_tv_id', DB::table('tmdb_genre_tmdb_tv')->select('tmdb_tv_id')->whereIn('tmdb_genre_id', $this->genreIds)) + ) + ) + ) + ->when( + $this->primaryLanguageNames !== [], + fn ($query) => $query + ->where( + fn ($query) => $query + ->where( + fn ($query) => $query + ->whereRelation('category', 'movie_meta', '=', true) + ->whereHas('movie', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames)) + ) + ->orWhere( + fn ($query) => $query + ->whereRelation('category', 'tv_meta', '=', true) + ->whereHas('tv', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames)) + ) + ) + ) + ->when($this->unfilled || $this->claimed || $this->pending || $this->filled, function ($query): void { $query->where(function ($query): void { - if ($this->unfilled) { - $query->whereNull('torrent_id')->whereDoesntHave('claim'); - } - }) - ->orWhere(function ($query): void { - if ($this->claimed) { - $query->whereHas('claim')->whereNull('torrent_id')->whereNull('approved_when'); + $query->where(function ($query): void { + if ($this->unfilled) { + $query->whereNull('torrent_id')->whereDoesntHave('claim'); } }) - ->orWhere(function ($query): void { - if ($this->pending) { - $query->whereNotNull('torrent_id')->whereNull('approved_when'); - } - }) - ->orWhere(function ($query): void { - if ($this->filled) { - $query->whereNotNull('torrent_id')->whereNotNull('approved_when'); - } - }); - }); - }) - ->when($this->myRequests, function ($query) use ($user): void { - $query->where('user_id', '=', $user->id); - }) - ->when($this->myClaims, function ($query) use ($user): void { - $query->whereRelation('claim', 'user_id', '=', $user->id)->whereNull('torrent_id')->whereNull('approved_by'); - }) - ->when($this->myVoted, function ($query) use ($user): void { - $query->whereRelation('bounties', 'user_id', '=', $user->id); - }) - ->when($this->myFilled, function ($query) use ($user): void { - $query->where('filled_by', '=', $user->id); - }) - ->orderBy($this->sortField, $this->sortDirection) - ->paginate($this->perPage); + ->orWhere(function ($query): void { + if ($this->claimed) { + $query->whereHas('claim')->whereNull('torrent_id')->whereNull('approved_when'); + } + }) + ->orWhere(function ($query): void { + if ($this->pending) { + $query->whereNotNull('torrent_id')->whereNull('approved_when'); + } + }) + ->orWhere(function ($query): void { + if ($this->filled) { + $query->whereNotNull('torrent_id')->whereNotNull('approved_when'); + } + }); + }); + }) + ->when($this->myRequests, function ($query) use ($user): void { + $query->where('user_id', '=', $user->id); + }) + ->when($this->myClaims, function ($query) use ($user): void { + $query->whereRelation('claim', 'user_id', '=', $user->id)->whereNull('torrent_id')->whereNull('approved_by'); + }) + ->when($this->myVoted, function ($query) use ($user): void { + $query->whereRelation('bounties', 'user_id', '=', $user->id); + }) + ->when($this->myFilled, function ($query) use ($user): void { + $query->where('filled_by', '=', $user->id); + }) + ->orderBy($this->sortField, $this->sortDirection) + ->paginate($this->perPage); + } } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/TorrentReseedSearch.php b/app/Http/Livewire/TorrentReseedSearch.php new file mode 100644 index 000000000..04cafaaf6 --- /dev/null +++ b/app/Http/Livewire/TorrentReseedSearch.php @@ -0,0 +1,80 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Livewire; + +use App\Models\TorrentReseed; +use App\Traits\CastLivewireProperties; +use App\Traits\LivewireSort; +use Livewire\Attributes\Url; +use Livewire\Component; +use Livewire\WithPagination; + +class TorrentReseedSearch extends Component +{ + use CastLivewireProperties; + use LivewireSort; + use WithPagination; + + #TODO: Update URL attributes once Livewire 3 fixes upstream bug. See: https://github.com/livewire/livewire/discussions/7746 + + #[Url(history: true)] + public int $perPage = 25; + + #[Url(history: true)] + public string $torrentName = ''; + + #[Url(history: true)] + public bool $myRequests = false; + + #[Url(history: true)] + public string $sortField = 'created_at'; + + #[Url(history: true)] + public string $sortDirection = 'desc'; + + final public function updatingTorrentName(): void + { + $this->resetPage(); + } + + final public function updatingMyRequests(): void + { + $this->resetPage(); + } + + /** + * @var \Illuminate\Pagination\LengthAwarePaginator + */ + final protected \Illuminate\Pagination\LengthAwarePaginator $torrentReseeds { + get => TorrentReseed::query() + ->with([ + 'user:id,username,group_id,deleted_at', + 'torrent:id,name,seeders,leechers,deleted_at', + ]) + ->when($this->torrentName !== '', fn ($query) => $query->whereRelation('torrent', 'name', 'LIKE', '%'.$this->torrentName.'%')) + ->when($this->myRequests, fn ($query) => $query->where('user_id', '=', auth()->id())) + ->orderBy($this->sortField, $this->sortDirection) + ->paginate($this->perPage); + } + + final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application + { + return view('livewire.torrent-reseed-search', [ + 'torrentReseeds' => $this->torrentReseeds, + ]); + } +} diff --git a/app/Http/Livewire/TorrentSearch.php b/app/Http/Livewire/TorrentSearch.php index e390317ed..5a0e08163 100644 --- a/app/Http/Livewire/TorrentSearch.php +++ b/app/Http/Livewire/TorrentSearch.php @@ -31,7 +31,6 @@ use App\Traits\LivewireSort; use App\Traits\TorrentMeta; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -234,15 +233,17 @@ class TorrentSearch extends Component /** * Get torrent health statistics. */ - #[Computed(seconds: 3600, cache: true)] - final public function torrentHealth(): object - { - return DB::table('torrents') - ->whereNull('deleted_at') - ->selectRaw('COUNT(*) AS total') - ->selectRaw('SUM(seeders > 0) AS alive') - ->selectRaw('SUM(seeders = 0) AS dead') - ->first(); + final protected object $torrentHealth { + get => cache()->remember( + 'torrent-search:health', + 3600, + fn () => DB::table('torrents') + ->whereNull('deleted_at') + ->selectRaw('COUNT(*) AS total') + ->selectRaw('SUM(seeders > 0) AS alive') + ->selectRaw('SUM(seeders = 0) AS dead') + ->first(), + ); } final public function mount(Request $request): void @@ -276,77 +277,89 @@ class TorrentSearch extends Component $this->perPage = \in_array($this->view, ['card', 'poster']) ? 24 : 25; } - #[Computed] - final public function personalFreeleech(): bool - { - return cache()->get('personal_freeleech:'.auth()->id()) ?? false; + final protected bool $personalFreeleech { + get => cache()->get('personal_freeleech:'.auth()->id()) ?? false; } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function categories(): \Illuminate\Database\Eloquent\Collection - { - return Category::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $categories { + get => cache()->remember( + 'categories', + 3600, + fn () => Category::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function types(): \Illuminate\Database\Eloquent\Collection - { - return Type::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $types { + get => cache()->remember( + 'types', + 3600, + fn () => Type::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function resolutions(): \Illuminate\Database\Eloquent\Collection - { - return Resolution::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $resolutions { + get => cache()->remember( + 'resolutions', + 3600, + fn () => Resolution::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function genres(): \Illuminate\Database\Eloquent\Collection - { - return TmdbGenre::query()->orderBy('name')->get(); + final protected \Illuminate\Database\Eloquent\Collection $genres { + get => cache()->remember( + 'genres', + 3600, + fn () => TmdbGenre::query()->orderBy('name')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function regions(): \Illuminate\Database\Eloquent\Collection - { - return Region::query()->orderBy('position')->get(); + final protected \Illuminate\Database\Eloquent\Collection $regions { + get => cache()->remember( + 'regions', + 3600, + fn () => Region::query()->orderBy('position')->get(), + ); } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function distributors(): \Illuminate\Database\Eloquent\Collection - { - return Distributor::query()->orderBy('name')->get(); + final protected \Illuminate\Database\Eloquent\Collection $distributors { + get => cache()->remember( + 'distributors', + 3600, + fn () => Distributor::query()->orderBy('name')->get(), + ); } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed(seconds: 3600, cache: true)] - final public function primaryLanguages(): \Illuminate\Support\Collection - { - return TmdbMovie::query() - ->select('original_language') - ->distinct() - ->orderBy('original_language') - ->pluck('original_language'); + final protected \Illuminate\Support\Collection $primaryLanguages { + get => cache()->remember( + 'original-languages', + 3600, + fn () => TmdbMovie::query() + ->select('original_language') + ->distinct() + ->orderBy('original_language') + ->pluck('original_language'), + ); } final public function filters(): TorrentSearchFiltersDTO @@ -417,61 +430,60 @@ class TorrentSearch extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function torrents(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - $user = auth()->user()->load('group'); + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $torrents { + get { + $user = auth()->user()->load('group'); - // Whitelist which columns are allowed to be ordered by - if (!\in_array($this->sortField, [ - 'name', - 'rating', - 'size', - 'seeders', - 'leechers', - 'times_completed', - 'created_at', - 'bumped_at' - ])) { - $this->reset('sortField'); - } + // Whitelist which columns are allowed to be ordered by + if (!\in_array($this->sortField, [ + 'name', + 'rating', + 'size', + 'seeders', + 'leechers', + 'times_completed', + 'created_at', + 'bumped_at' + ])) { + $this->reset('sortField'); + } - $isSqlAllowed = (($user->group->is_modo || $user->group->is_torrent_modo || $user->group->is_editor) && $this->driver === 'sql') || $this->description || $this->mediainfo; + $isSqlAllowed = (($user->group->is_modo || $user->group->is_torrent_modo || $user->group->is_editor) && $this->driver === 'sql') || $this->description || $this->mediainfo; - $eagerLoads = fn (Builder $query) => $query - ->with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution']) - ->withCount([ - 'thanks', - 'comments', - 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - ]) - ->withExists([ - 'featured as featured', - 'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id), - 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $user->id), - 'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 1), - 'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 0), - 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 0) - ->where('seeder', '=', 0) - ->whereNull('completed_at'), - 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 0) - ->where( - fn ($query) => $query - ->where('seeder', '=', 1) - ->orWhereNotNull('completed_at') - ), - 'trump', - ]) - ->selectRaw(<<<'SQL' + $eagerLoads = fn (Builder $query) => $query + ->with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution']) + ->withCount([ + 'thanks', + 'comments', + 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + ]) + ->withExists([ + 'featured as featured', + 'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id), + 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $user->id), + 'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 1), + 'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 0), + 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 0) + ->where('seeder', '=', 0) + ->whereNull('completed_at'), + 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 0) + ->where( + fn ($query) => $query + ->where('seeder', '=', 1) + ->orWhereNotNull('completed_at') + ), + 'trump', + ]) + ->selectRaw(<<<'SQL' CASE WHEN category_id IN (SELECT id FROM categories WHERE movie_meta = 1) THEN 'movie' WHEN category_id IN (SELECT id FROM categories WHERE tv_meta = 1) THEN 'tv' @@ -481,337 +493,369 @@ class TorrentSearch extends Component END AS meta SQL); - if ($isSqlAllowed) { - $torrents = Torrent::query() - ->where($this->filters()->toSqlQueryBuilder()) - ->latest('sticky') - ->orderBy($this->sortField, $this->sortDirection); + if ($isSqlAllowed) { + $torrents = Torrent::query() + ->where($this->filters()->toSqlQueryBuilder()) + ->latest('sticky') + ->orderBy($this->sortField, $this->sortDirection); - $eagerLoads($torrents); - $torrents = $torrents->paginate(min($this->perPage, 100)); - } else { - $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); - $index = $client->getIndex(config('scout.prefix').'torrents'); + $eagerLoads($torrents); + $torrents = $torrents->paginate(min($this->perPage, 100)); + } else { + $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); + $index = $client->getIndex(config('scout.prefix').'torrents'); - $results = $index->search($this->name, [ - 'sort' => [ - 'sticky:desc', - $this->sortField.':'.$this->sortDirection, - ], - 'filter' => $this->filters()->toMeilisearchFilter(), - 'matchingStrategy' => 'all', - 'page' => (int) $this->getPage(), - 'hitsPerPage' => min($this->perPage, 100), - 'attributesToRetrieve' => ['id'], - ]); + $results = $index->search($this->name, [ + 'sort' => [ + 'sticky:desc', + $this->sortField.':'.$this->sortDirection, + ], + 'filter' => $this->filters()->toMeilisearchFilter(), + 'matchingStrategy' => 'all', + 'page' => (int) $this->getPage(), + 'hitsPerPage' => min($this->perPage, 100), + 'attributesToRetrieve' => ['id'], + ]); - $ids = array_column($results->getHits(), 'id'); + $ids = array_column($results->getHits(), 'id'); - $torrents = Torrent::query()->whereIntegerInRaw('id', $ids); + $torrents = Torrent::query()->whereIntegerInRaw('id', $ids); - $eagerLoads($torrents); + $eagerLoads($torrents); - $torrents = $torrents->get()->sortBy(fn ($torrent) => array_search($torrent->id, $ids)); + $torrents = $torrents->get()->sortBy(fn ($torrent) => array_search($torrent->id, $ids)); - $torrents = new LengthAwarePaginator($torrents, $results->getTotalHits(), $this->perPage, $this->getPage()); + $torrents = new LengthAwarePaginator($torrents, $results->getTotalHits(), $this->perPage, $this->getPage()); + } + + // See app/Traits/TorrentMeta.php + $this->scopeMeta($torrents); + + return $torrents; } - - // See app/Traits/TorrentMeta.php - $this->scopeMeta($torrents); - - return $torrents; } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function groupedTorrents() - { - $user = auth()->user(); + final protected $groupedTorrents { + get { + $user = auth()->user(); - // Whitelist which columns are allowed to be ordered by - if (!\in_array($this->sortField, [ - 'bumped_at', - 'created_at', - 'times_completed', - ])) { - $this->reset('sortField'); - } + // Whitelist which columns are allowed to be ordered by + if (!\in_array($this->sortField, [ + 'bumped_at', + 'created_at', + 'times_completed', + ])) { + $this->reset('sortField'); + } - $isSqlAllowed = (($user->group->is_modo || $user->group->is_torrent_modo || $user->group->is_editor) && $this->driver === 'sql') || $this->description || $this->mediainfo; + $isSqlAllowed = (($user->group->is_modo || $user->group->is_torrent_modo || $user->group->is_editor) && $this->driver === 'sql') || $this->description || $this->mediainfo; - $groupQuery = Torrent::query() - ->select('tmdb_movie_id', 'tmdb_tv_id') - ->selectRaw('MAX(sticky) as sticky') - ->selectRaw('MAX(bumped_at) as bumped_at') - ->selectRaw('MAX(created_at) as created_at') - ->selectRaw('SUM(times_completed) as times_completed') - ->selectRaw(<<<'SQL' + $groupQuery = Torrent::query() + ->select('tmdb_movie_id', 'tmdb_tv_id') + ->selectRaw('MAX(sticky) as sticky') + ->selectRaw('MAX(bumped_at) as bumped_at') + ->selectRaw('MAX(created_at) as created_at') + ->selectRaw('SUM(times_completed) as times_completed') + ->selectRaw(<<<'SQL' MIN(CASE WHEN category_id IN (SELECT id FROM categories WHERE movie_meta = 1) THEN 'movie' WHEN category_id IN (SELECT id FROM categories WHERE tv_meta = 1) THEN 'tv' END) AS meta SQL) - ->havingNotNull('meta') - ->where(fn ($query) => $query->whereNotNull('tmdb_movie_id')->orWhereNotNull('tmdb_tv_id')) - ->whereNotNull('imdb') - ->groupBy('tmdb_movie_id', 'tmdb_tv_id') - ->latest('sticky') - ->orderBy($this->sortField, $this->sortDirection); + ->havingNotNull('meta') + ->where(fn ($query) => $query->whereNotNull('tmdb_movie_id')->orWhereNotNull('tmdb_tv_id')) + ->whereNotNull('imdb') + ->groupBy('tmdb_movie_id', 'tmdb_tv_id') + ->latest('sticky') + ->orderBy($this->sortField, $this->sortDirection); - if ($isSqlAllowed) { - $groups = $groupQuery - ->where($this->filters()->toSqlQueryBuilder()) - ->paginate(min($this->perPage, 100)); - } else { - $results = (new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key'))) - ->index(config('scout.prefix').'torrents') - ->search($this->name, [ - 'sort' => ['sticky:desc', $this->sortField.':'.$this->sortDirection,], - 'filter' => [...$this->filters()->toMeilisearchFilter(), 'imdb IS NOT NULL', ['tmdb_movie_id IS NOT NULL', 'tmdb_tv_id IS NOT NULL']], - 'matchingStrategy' => 'all', - 'page' => (int) $this->getPage(), - 'hitsPerPage' => min($this->perPage, 100), - 'attributesToRetrieve' => ['tmdb_movie_id', 'tmdb_tv_id'], - 'distinct' => 'imdb', - ]); - - $ids = []; - - foreach ($results->getHits() as $result) { - if ($result['tmdb_movie_id']) { - $ids[] = "tmdb-movie:{$result['tmdb_movie_id']}"; - } elseif ($result['tmdb_tv_id']) { - $ids[] = "tmdb-tv:{$result['tmdb_tv_id']}"; - } - } - - $groups = $groupQuery - ->where( - fn ($query) => $query - ->whereIntegerInRaw('tmdb_movie_id', array_filter(array_column($results->getHits(), 'tmdb_movie_id'))) - ->orWhereIntegerInRaw('tmdb_tv_id', array_filter(array_column($results->getHits(), 'tmdb_tv_id'))) - ) - ->get() - ->sortBy(fn ($group) => array_search($group->tmdb_movie_id ? "tmdb-movie:{$group->tmdb_movie_id}" : "tmdb-tv:{$group->tmdb_tv_id}", $ids)); - - $groups = new LengthAwarePaginator($groups, $results->getTotalHits(), $this->perPage, $this->getPage()); - } - - $movieIds = $groups->getCollection()->where('meta', '=', 'movie')->pluck('tmdb_movie_id'); - $tvIds = $groups->getCollection()->where('meta', '=', 'tv')->pluck('tmdb_tv_id'); - - $movies = TmdbMovie::with('genres', 'directors')->whereIntegerInRaw('id', $movieIds)->get()->keyBy('id'); - $tv = TmdbTv::with('genres', 'creators')->whereIntegerInRaw('id', $tvIds)->get()->keyBy('id'); - - $torrents = Torrent::query() - ->with(['type:id,name,position', 'resolution:id,name,position']) - ->select([ - 'id', - 'name', - 'info_hash', - 'size', - 'leechers', - 'seeders', - 'times_completed', - 'category_id', - 'user_id', - 'season_number', - 'episode_number', - 'tmdb_movie_id', - 'tmdb_tv_id', - 'free', - 'doubleup', - 'highspeed', - 'sticky', - 'internal', - 'created_at', - 'bumped_at', - 'type_id', - 'resolution_id', - 'personal_release', - ]) - ->selectRaw(<<<'SQL' + $eagerLoads = fn (Builder $query) => $query + ->with(['type:id,name,position', 'resolution:id,name,position']) + ->select([ + 'id', + 'name', + 'info_hash', + 'size', + 'leechers', + 'seeders', + 'times_completed', + 'category_id', + 'user_id', + 'season_number', + 'episode_number', + 'tmdb_movie_id', + 'tmdb_tv_id', + 'free', + 'doubleup', + 'highspeed', + 'sticky', + 'internal', + 'created_at', + 'bumped_at', + 'type_id', + 'resolution_id', + 'personal_release', + ]) + ->selectRaw(<<<'SQL' CASE WHEN category_id IN (SELECT id FROM categories WHERE movie_meta = 1) THEN 'movie' WHEN category_id IN (SELECT id FROM categories WHERE tv_meta = 1) THEN 'tv' END AS meta SQL) - ->with('user:id,username,group_id', 'category', 'type', 'resolution') - ->withCount([ - 'comments', - ]) - ->when( - !config('announce.external_tracker.is_enabled'), - fn ($query) => $query->withCount([ - 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), - ]), - ) - ->when( - config('other.thanks-system.is-enabled'), - fn ($query) => $query->withCount('thanks') - ) - ->withExists([ - 'featured as featured', - 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $user->id), - 'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id), - 'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 1), - 'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 1) - ->where('seeder', '=', 0), - 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 0) - ->where('seeder', '=', 0) - ->whereNull('completed_at'), - 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id) - ->where('active', '=', 0) - ->where( - fn ($query) => $query - ->where('seeder', '=', 1) - ->orWhereNotNull('completed_at') - ), - 'trump', - ]) - ->where( - fn ($query) => $query - ->where( - fn ($query) => $query - ->whereRelation('category', 'movie_meta', '=', true) - ->whereIntegerInRaw('tmdb_movie_id', $movieIds) - ) - ->orWhere( - fn ($query) => $query - ->whereRelation('category', 'tv_meta', '=', true) - ->whereIntegerInRaw('tmdb_tv_id', $tvIds) - ) - ) - ->when($isSqlAllowed, fn ($query) => $query->where($this->filters()->toSqlQueryBuilder())) - ->get(); + ->with('user:id,username,group_id', 'category', 'type', 'resolution') + ->withCount([ + 'comments', + ]) + ->when( + !config('announce.external_tracker.is_enabled'), + fn ($query) => $query->withCount([ + 'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + 'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true), + ]), + ) + ->when( + config('other.thanks-system.is-enabled'), + fn ($query) => $query->withCount('thanks') + ) + ->withExists([ + 'featured as featured', + 'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $user->id), + 'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id), + 'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 1), + 'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 1) + ->where('seeder', '=', 0), + 'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 0) + ->where('seeder', '=', 0) + ->whereNull('completed_at'), + 'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id) + ->where('active', '=', 0) + ->where( + fn ($query) => $query + ->where('seeder', '=', 1) + ->orWhereNotNull('completed_at') + ), + 'trump', + ]); - $groupedTorrents = []; + if ($isSqlAllowed) { + $groups = $groupQuery + ->where($this->filters()->toSqlQueryBuilder()) + ->paginate(min($this->perPage, 100)); + } else { + $results = (new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key'))) + ->index(config('scout.prefix').'torrents') + ->search($this->name, [ + 'sort' => ['sticky:desc', $this->sortField.':'.$this->sortDirection,], + 'filter' => [...$this->filters()->toMeilisearchFilter(), 'imdb IS NOT NULL', ['tmdb_movie_id IS NOT NULL', 'tmdb_tv_id IS NOT NULL']], + 'matchingStrategy' => 'all', + 'page' => (int) $this->getPage(), + 'hitsPerPage' => min($this->perPage, 100), + 'attributesToRetrieve' => ['tmdb_movie_id', 'tmdb_tv_id'], + 'distinct' => 'imdb', + ]); - foreach ($torrents as &$torrent) { - // Memoizing and avoiding casts reduces runtime duration from 70ms to 40ms. - // If accessing laravel's attributes array directly, it's reduced to 11ms, - // but the attributes array is marked as protected so we can't access it. - $tmdb = $torrent->getAttributeValue('tmdb_movie_id') ?: $torrent->getAttributeValue('tmdb_tv_id'); - $type = $torrent->getRelationValue('type')->getAttributeValue('name'); + $ids = []; - switch ($torrent->getAttributeValue('meta')) { - case 'movie': - $groupedTorrents['movie'][$tmdb]['Movie'][$type][] = $torrent; - $groupedTorrents['movie'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); - - break; - case 'tv': - $episode = $torrent->getAttributeValue('episode_number'); - $season = $torrent->getAttributeValue('season_number'); - - if ($season == 0) { - if ($episode == 0) { - $groupedTorrents['tv'][$tmdb]['Complete Pack'][$type][] = $torrent; - } else { - $groupedTorrents['tv'][$tmdb]['Specials']["Special {$episode}"][$type][] = $torrent; - } - } else { - if ($episode == 0) { - $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Season Pack'][$type][] = $torrent; - } else { - $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Episodes']["Episode {$episode}"][$type][] = $torrent; - } + foreach ($results->getHits() as $result) { + if ($result['tmdb_movie_id']) { + $ids[] = "tmdb-movie:{$result['tmdb_movie_id']}"; + } elseif ($result['tmdb_tv_id']) { + $ids[] = "tmdb-tv:{$result['tmdb_tv_id']}"; } + } - $groupedTorrents['tv'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); + $groups = $groupQuery + ->where( + fn ($query) => $query + ->whereIntegerInRaw('tmdb_movie_id', array_filter(array_column($results->getHits(), 'tmdb_movie_id'))) + ->orWhereIntegerInRaw('tmdb_tv_id', array_filter(array_column($results->getHits(), 'tmdb_tv_id'))) + ) + ->get() + ->sortBy(fn ($group) => array_search($group->tmdb_movie_id ? "tmdb-movie:{$group->tmdb_movie_id}" : "tmdb-tv:{$group->tmdb_tv_id}", $ids)); + + $groups = new LengthAwarePaginator($groups, $results->getTotalHits(), $this->perPage, $this->getPage()); } - } - foreach ($groupedTorrents as $mediaType => &$workTorrents) { - switch ($mediaType) { - case 'movie': - foreach ($workTorrents as &$movieTorrents) { - $this->sortTorrentTypes($movieTorrents['Movie']); - } + $movieIds = $groups->getCollection()->where('meta', '=', 'movie')->pluck('tmdb_movie_id'); + $tvIds = $groups->getCollection()->where('meta', '=', 'tv')->pluck('tmdb_tv_id'); - break; - case 'tv': - foreach ($workTorrents as &$tvTorrents) { - foreach ($tvTorrents as $packOrSpecialOrSeasonsType => &$packOrSpecialOrSeasons) { - switch ($packOrSpecialOrSeasonsType) { - case 'Complete Pack': - $this->sortTorrentTypes($packOrSpecialOrSeasons); + $movies = TmdbMovie::with('genres', 'directors')->whereIntegerInRaw('id', $movieIds)->get()->keyBy('id'); + $tv = TmdbTv::with('genres', 'creators')->whereIntegerInRaw('id', $tvIds)->get()->keyBy('id'); - break; - case 'Specials': - krsort($packOrSpecialOrSeasons, SORT_NATURAL); + if ($isSqlAllowed) { + $torrents = Torrent::query() + ->where( + fn ($query) => $query + ->where( + fn ($query) => $query + ->whereRelation('category', 'movie_meta', '=', true) + ->whereIntegerInRaw('tmdb_movie_id', $movieIds) + ) + ->orWhere( + fn ($query) => $query + ->whereRelation('category', 'tv_meta', '=', true) + ->whereIntegerInRaw('tmdb_tv_id', $tvIds) + ) + ) + ->where($this->filters()->toSqlQueryBuilder()); - foreach ($packOrSpecialOrSeasons as &$specialTorrents) { - $this->sortTorrentTypes($specialTorrents); - } + $eagerLoads($torrents); - break; - case 'Seasons': - krsort($packOrSpecialOrSeasons, SORT_NATURAL); + $torrents = $torrents->get(); + } else { + $results = (new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key'))) + ->index(config('scout.prefix').'torrents') + ->search($this->name, [ + 'sort' => ['sticky:desc', $this->sortField.':'.$this->sortDirection,], + 'filter' => [ + ...$this->filters()->toMeilisearchFilter(), + [ + 'tmdb_movie_id IN '.json_encode($movieIds->values()), + 'tmdb_tv_id IN '.json_encode($tvIds->values()) + ] + ], + 'matchingStrategy' => 'all', + 'hitsPerPage' => 10_000, + 'attributesToRetrieve' => ['id'], + ]); - foreach ($packOrSpecialOrSeasons as &$season) { - foreach ($season as $packOrEpisodesType => &$packOrEpisodes) { - switch ($packOrEpisodesType) { - case 'Season Pack': - $this->sortTorrentTypes($packOrEpisodes); + $torrentIds = array_column($results->getHits(), 'id'); - break; - case 'Episodes': - krsort($packOrEpisodes, SORT_NATURAL); + $torrents = Torrent::query()->whereIntegerInRaw('id', $torrentIds); - foreach ($packOrEpisodes as &$episodeTorrents) { - $this->sortTorrentTypes($episodeTorrents); - } + $eagerLoads($torrents); - break; - } - } - } + $torrents = $torrents->get(); + } + + $groupedTorrents = []; + + foreach ($torrents as &$torrent) { + // Memoizing and avoiding casts reduces runtime duration from 70ms to 40ms. + // If accessing laravel's attributes array directly, it's reduced to 11ms, + // but the attributes array is marked as protected so we can't access it. + $tmdb = $torrent->getAttributeValue('tmdb_movie_id') ?: $torrent->getAttributeValue('tmdb_tv_id'); + $type = $torrent->getRelationValue('type')->getAttributeValue('name'); + + switch ($torrent->getAttributeValue('meta')) { + case 'movie': + $groupedTorrents['movie'][$tmdb]['Movie'][$type][] = $torrent; + $groupedTorrents['movie'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); + + break; + case 'tv': + $episode = $torrent->getAttributeValue('episode_number'); + $season = $torrent->getAttributeValue('season_number'); + + if ($season == 0) { + if ($episode == 0) { + $groupedTorrents['tv'][$tmdb]['Complete Pack'][$type][] = $torrent; + } else { + $groupedTorrents['tv'][$tmdb]['Specials']["Special {$episode}"][$type][] = $torrent; + } + } else { + if ($episode == 0) { + $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Season Pack'][$type][] = $torrent; + } else { + $groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Episodes']["Episode {$episode}"][$type][] = $torrent; } } - } + + $groupedTorrents['tv'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id'); + } } + + foreach ($groupedTorrents as $mediaType => &$workTorrents) { + switch ($mediaType) { + case 'movie': + foreach ($workTorrents as &$movieTorrents) { + $this->sortTorrentTypes($movieTorrents['Movie']); + } + + break; + case 'tv': + foreach ($workTorrents as &$tvTorrents) { + foreach ($tvTorrents as $packOrSpecialOrSeasonsType => &$packOrSpecialOrSeasons) { + switch ($packOrSpecialOrSeasonsType) { + case 'Complete Pack': + $this->sortTorrentTypes($packOrSpecialOrSeasons); + + break; + case 'Specials': + krsort($packOrSpecialOrSeasons, SORT_NATURAL); + + foreach ($packOrSpecialOrSeasons as &$specialTorrents) { + $this->sortTorrentTypes($specialTorrents); + } + + break; + case 'Seasons': + krsort($packOrSpecialOrSeasons, SORT_NATURAL); + + foreach ($packOrSpecialOrSeasons as &$season) { + foreach ($season as $packOrEpisodesType => &$packOrEpisodes) { + switch ($packOrEpisodesType) { + case 'Season Pack': + $this->sortTorrentTypes($packOrEpisodes); + + break; + case 'Episodes': + krsort($packOrEpisodes, SORT_NATURAL); + + foreach ($packOrEpisodes as &$episodeTorrents) { + $this->sortTorrentTypes($episodeTorrents); + } + + break; + } + } + } + } + } + } + } + } + + $medias = $groups->through(function ($group) use ($groupedTorrents, $movies, $tv) { + switch ($group->meta) { + case 'movie': + if ($movies->has($group->tmdb_movie_id)) { + $media = $movies[$group->tmdb_movie_id]; + $media->setAttribute('meta', 'movie'); + $media->setRelation('torrents', $groupedTorrents['movie'][$group->tmdb_movie_id] ?? []); + $media->setAttribute('category_id', $media->torrents['category_id']); + } else { + $media = null; + } + + break; + case 'tv': + if ($tv->has($group->tmdb_tv_id)) { + $media = $tv[$group->tmdb_tv_id]; + $media->setAttribute('meta', 'tv'); + $media->setRelation('torrents', $groupedTorrents['tv'][$group->tmdb_tv_id] ?? []); + $media->setAttribute('category_id', $media->torrents['category_id']); + } else { + $media = null; + } + + break; + default: + $media = null; + } + + return $media; + }); + + return $medias; } - - $medias = $groups->through(function ($group) use ($groupedTorrents, $movies, $tv) { - switch ($group->meta) { - case 'movie': - if ($movies->has($group->tmdb_movie_id)) { - $media = $movies[$group->tmdb_movie_id]; - $media->setAttribute('meta', 'movie'); - $media->setRelation('torrents', $groupedTorrents['movie'][$group->tmdb_movie_id] ?? []); - $media->setAttribute('category_id', $media->torrents['category_id']); - } else { - $media = null; - } - - break; - case 'tv': - if ($tv->has($group->tmdb_tv_id)) { - $media = $tv[$group->tmdb_tv_id]; - $media->setAttribute('meta', 'tv'); - $media->setRelation('torrents', $groupedTorrents['tv'][$group->tmdb_tv_id] ?? []); - $media->setAttribute('category_id', $media->torrents['category_id']); - } else { - $media = null; - } - - break; - default: - $media = null; - } - - return $media; - }); - - return $medias; } /** @@ -840,61 +884,61 @@ class TorrentSearch extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function groupedPosters() - { - // Whitelist which columns are allowed to be ordered by - if (!\in_array($this->sortField, [ - 'bumped_at', - 'times_completed', - ])) { - $this->reset('sortField'); - } + final protected $groupedPosters { + get { + // Whitelist which columns are allowed to be ordered by + if (!\in_array($this->sortField, [ + 'bumped_at', + 'times_completed', + ])) { + $this->reset('sortField'); + } - $groups = Torrent::query() - ->select('tmdb_movie_id', 'tmdb_tv_id') - ->selectRaw('MAX(sticky) as sticky') - ->selectRaw('MAX(bumped_at) as bumped_at') - ->selectRaw('SUM(times_completed) as times_completed') - ->selectRaw('MIN(category_id) as category_id') - ->selectRaw(<<<'SQL' + $groups = Torrent::query() + ->select('tmdb_movie_id', 'tmdb_tv_id') + ->selectRaw('MAX(sticky) as sticky') + ->selectRaw('MAX(bumped_at) as bumped_at') + ->selectRaw('SUM(times_completed) as times_completed') + ->selectRaw('MIN(category_id) as category_id') + ->selectRaw(<<<'SQL' MIN(CASE WHEN category_id IN (SELECT id FROM categories WHERE movie_meta = 1) THEN 'movie' WHEN category_id IN (SELECT id FROM categories WHERE tv_meta = 1) THEN 'tv' END) AS meta SQL) - ->havingNotNull('meta') - ->where(fn ($query) => $query->whereNotNull('tmdb_movie_id')->orWhereNotNull('tmdb_tv_id')) - ->where($this->filters()->toSqlQueryBuilder()) - ->groupBy('tmdb_movie_id', 'tmdb_tv_id') - ->latest('sticky') - ->orderBy($this->sortField, $this->sortDirection) - ->paginate(min($this->perPage, 100)); + ->havingNotNull('meta') + ->where(fn ($query) => $query->whereNotNull('tmdb_movie_id')->orWhereNotNull('tmdb_tv_id')) + ->where($this->filters()->toSqlQueryBuilder()) + ->groupBy('tmdb_movie_id', 'tmdb_tv_id') + ->latest('sticky') + ->orderBy($this->sortField, $this->sortDirection) + ->paginate(min($this->perPage, 100)); - $movieIds = $groups->getCollection()->where('meta', '=', 'movie')->pluck('tmdb_movie_id'); - $tvIds = $groups->getCollection()->where('meta', '=', 'tv')->pluck('tmdb_tv_id'); + $movieIds = $groups->getCollection()->where('meta', '=', 'movie')->pluck('tmdb_movie_id'); + $tvIds = $groups->getCollection()->where('meta', '=', 'tv')->pluck('tmdb_tv_id'); - $movies = TmdbMovie::with('genres', 'directors')->whereIntegerInRaw('id', $movieIds)->get()->keyBy('id'); - $tv = TmdbTv::with('genres', 'creators')->whereIntegerInRaw('id', $tvIds)->get()->keyBy('id'); + $movies = TmdbMovie::with('genres', 'directors')->whereIntegerInRaw('id', $movieIds)->get()->keyBy('id'); + $tv = TmdbTv::with('genres', 'creators')->whereIntegerInRaw('id', $tvIds)->get()->keyBy('id'); - $groups = $groups->through(function ($group) use ($movies, $tv) { - switch ($group->meta) { - case 'movie': - $group->movie = $movies[$group->tmdb_movie_id] ?? null; + $groups = $groups->through(function ($group) use ($movies, $tv) { + switch ($group->meta) { + case 'movie': + $group->movie = $movies[$group->tmdb_movie_id] ?? null; - break; - case 'tv': - $group->tv = $tv[$group->tmdb_tv_id] ?? null; + break; + case 'tv': + $group->tv = $tv[$group->tmdb_tv_id] ?? null; - break; - } + break; + } - return $group; - }); + return $group; + }); - return $groups; + return $groups; + } } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/TorrentTrumpSearch.php b/app/Http/Livewire/TorrentTrumpSearch.php index 04d4b2beb..88a895359 100644 --- a/app/Http/Livewire/TorrentTrumpSearch.php +++ b/app/Http/Livewire/TorrentTrumpSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\TorrentTrump; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -46,12 +45,10 @@ class TorrentTrumpSearch extends Component public int $perPage = 25; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function torrentTrumps(): \Illuminate\Pagination\LengthAwarePaginator - { - return TorrentTrump::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $torrentTrumps { + get => TorrentTrump::query() ->with([ 'user:id,username,group_id,deleted_at', 'torrent:id,name,deleted_at', diff --git a/app/Http/Livewire/Trending.php b/app/Http/Livewire/Trending.php index 896a9da2b..e67e5f1b5 100644 --- a/app/Http/Livewire/Trending.php +++ b/app/Http/Livewire/Trending.php @@ -25,16 +25,11 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Attributes\Validate; use Livewire\Component; use Throwable; -/** - * @property Collection $works - * @property array $metaTypes - */ class Trending extends Component { #TODO: Update URL attributes once Livewire 3 fixes upstream bug. See: https://github.com/livewire/livewire/discussions/7746 @@ -74,214 +69,214 @@ class Trending extends Component } /** - * @return Collection + * @var Collection */ - #[Computed] - final public function works(): Collection - { - $this->validate(); + final protected Collection $works { + get { + $this->validate(); - $metaIdColumn = match ($this->metaType) { - 'tv_meta' => 'tmdb_tv_id', - default => 'tmdb_movie_id', - }; + $metaIdColumn = match ($this->metaType) { + 'tv_meta' => 'tmdb_tv_id', + default => 'tmdb_movie_id', + }; - return cache()->remember( - 'trending-'.$this->interval.'-'.($this->from ?? '').'-'.($this->until ?? '').'-'.$this->metaType, - 0, //3600, - fn () => Torrent::query() - ->with('movie', 'tv') - ->addSelect([ - $metaIdColumn, - DB::raw('MIN(category_id) as category_id'), - DB::raw('COUNT(*) as download_count'), - ]) - ->join('history', 'history.torrent_id', '=', 'torrents.id') - ->where($metaIdColumn, '!=', 0) - ->when($this->interval === 'day', fn ($query) => $query->whereBetween('history.completed_at', [now()->subDay(), now()])) - ->when($this->interval === 'week', fn ($query) => $query->whereBetween('history.completed_at', [now()->subWeek(), now()])) - ->when($this->interval === 'month', fn ($query) => $query->whereBetween('history.completed_at', [now()->subMonth(), now()])) - ->when($this->interval === 'year', fn ($query) => $query->whereBetween('history.completed_at', [now()->subYear(), now()])) - ->when($this->interval === 'all', fn ($query) => $query->whereNotNull('history.completed_at')) - ->when($this->interval === 'custom', fn ($query) => $query->whereBetween('history.completed_at', [$this->from ?: now(), $this->until ?: now()])) - ->whereRelation('category', $this->metaType, '=', true) - // Small torrents screw the stats since users download them only to farm bon. - ->where('torrents.size', '>', 1024 * 1024 * 1024) - ->groupBy($metaIdColumn) - ->orderByRaw('COUNT(*) DESC') - ->limit(250) - ->get($metaIdColumn) - ); - } - - /** - * @return Collection> - * @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error) - */ - #[Computed] - final public function weekly(): Collection - { - $this->validate(); - - $metaIdColumn = match ($this->metaType) { - 'tv_meta' => 'tmdb_tv_id', - default => 'tmdb_movie_id', - }; - - return cache()->remember( - 'weekly-charts:'.$this->metaType, - 24 * 3600, - fn () => Torrent::query() - ->withoutGlobalScopes() - ->with('movie', 'tv') - ->fromSub( - History::query() - ->withoutGlobalScopes() - ->join('torrents', 'torrents.id', '=', 'history.torrent_id') - ->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true)) - ->select([ - DB::raw('FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) AS week_start'), - $metaIdColumn, - DB::raw('MIN(categories.id) as category_id'), - DB::raw('COUNT(*) AS download_count'), - DB::raw('ROW_NUMBER() OVER (PARTITION BY FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) ORDER BY COUNT(*) DESC) AS place'), - ]) - ->where($metaIdColumn, '!=', 0) - // Small torrents screw the stats since users download them only to farm bon. - ->where('torrents.size', '>', 1024 * 1024 * 1024) - ->groupBy('week_start', $metaIdColumn), - 'ranked_groups', - ) - ->where('place', '<=', 10) - ->orderByDesc('week_start') - ->orderBy('place') - ->withCasts([ - 'week_start' => 'datetime', - ]) - ->get() - ->groupBy('week_start') - ); - } - - /** - * @return Collection> - * @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error) - */ - #[Computed] - final public function monthly(): Collection - { - $this->validate(); - - $metaIdColumn = match ($this->metaType) { - 'tv_meta' => 'tmdb_tv_id', - default => 'tmdb_movie_id', - }; - - return cache()->remember( - 'monthly-charts:'.$this->metaType, - 24 * 3600, - fn () => Torrent::query() - ->withoutGlobalScopes() - ->with($this->metaType === 'movie_meta' ? 'movie' : 'tv') - ->fromSub( - History::query() - ->withoutGlobalScopes() - ->join('torrents', 'torrents.id', '=', 'history.torrent_id') - ->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true)) - ->select([ - DB::raw('EXTRACT(YEAR_MONTH FROM history.created_at) AS the_year_month'), - $metaIdColumn, - DB::raw('MIN(categories.id) as category_id'), - DB::raw('COUNT(*) AS download_count'), - DB::raw('ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR_MONTH FROM history.created_at) ORDER BY COUNT(*) DESC) AS place'), - ]) - ->where($metaIdColumn, '!=', 0) - // Small torrents screw the stats since users download them only to farm bon. - ->where('torrents.size', '>', 1024 * 1024 * 1024) - ->groupBy('the_year_month', $metaIdColumn), - 'ranked_groups', - ) - ->where('place', '<=', 10) - ->orderByDesc('the_year_month') - ->orderBy('place') - ->get() - ->groupBy('the_year_month') - ); - } - - /** - * @return Collection> - * @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error) - */ - #[Computed] - final public function releaseYear(): Collection - { - $this->validate(); - - $metaIdColumn = match ($this->metaType) { - 'tv_meta' => 'tmdb_tv_id', - default => 'tmdb_movie_id', - }; - - return cache()->remember( - 'trending-by-release-year:'.$this->metaType, - 24 * 3600, - fn () => Torrent::query() - ->withoutGlobalScopes() - ->with($this->metaType === 'movie_meta' ? 'movie' : 'tv') - ->fromSub( - Torrent::query() - ->withoutGlobalScopes() - ->whereRelation('category', $this->metaType, '=', true) - ->leftJoin('tmdb_movies', 'torrents.tmdb_movie_id', '=', 'tmdb_movies.id') - ->leftJoin('tmdb_tv', 'torrents.tmdb_tv_id', '=', 'tmdb_tv.id') - ->select([ - $metaIdColumn, - DB::raw('MIN(category_id) as category_id'), - DB::raw('SUM(times_completed) AS download_count'), - 'the_year' => $this->metaType === 'movie_meta' - ? TmdbMovie::query() - ->selectRaw('EXTRACT(YEAR FROM tmdb_movies.release_date)') - ->whereColumn('tmdb_movies.id', '=', 'torrents.tmdb_movie_id') - : TmdbTv::query() - ->selectRaw('EXTRACT(YEAR FROM tmdb_tv.first_air_date)') - ->whereColumn('tmdb_tv.id', '=', 'torrents.tmdb_tv_id'), - DB::raw('ROW_NUMBER() OVER (PARTITION BY COALESCE(EXTRACT(YEAR FROM MAX(tmdb_movies.release_date)), EXTRACT(YEAR FROM MAX(tmdb_tv.first_air_date))) ORDER BY SUM(times_completed) DESC) AS place'), - ]) - ->where($metaIdColumn, '!=', 0) - // Small torrents screw the stats since users download them only to farm bon. - ->where('torrents.size', '>', 2 * 1024 * 1024 * 1024) - ->when($this->metaType === 'tv_meta', fn ($query) => $query->where('episode_number', '=', 0)) - ->havingNotNull('the_year') - ->where(fn ($query) => $query->whereNotNull('tmdb_movies.id')->orWhereNotNull('tmdb_tv.id')) - ->groupBy('the_year', $metaIdColumn), - 'ranked_groups', - ) - ->where('place', '<=', 10) - ->orderByDesc('the_year') - ->orderBy('place') - ->get() - ->groupBy('the_year') - ); - } - - /** - * @return array - */ - #[Computed] - final public function metaTypes(): array - { - $metaTypes = []; - - if (Category::where('movie_meta', '=', true)->exists()) { - $metaTypes[(string) __('mediahub.movie')] = 'movie_meta'; + return cache()->remember( + 'trending-'.$this->interval.'-'.($this->from ?? '').'-'.($this->until ?? '').'-'.$this->metaType, + 0, //3600, + fn () => Torrent::query() + ->with('movie', 'tv') + ->addSelect([ + $metaIdColumn, + DB::raw('MIN(category_id) as category_id'), + DB::raw('COUNT(*) as download_count'), + ]) + ->join('history', 'history.torrent_id', '=', 'torrents.id') + ->where($metaIdColumn, '!=', 0) + ->when($this->interval === 'day', fn ($query) => $query->whereBetween('history.completed_at', [now()->subDay(), now()])) + ->when($this->interval === 'week', fn ($query) => $query->whereBetween('history.completed_at', [now()->subWeek(), now()])) + ->when($this->interval === 'month', fn ($query) => $query->whereBetween('history.completed_at', [now()->subMonth(), now()])) + ->when($this->interval === 'year', fn ($query) => $query->whereBetween('history.completed_at', [now()->subYear(), now()])) + ->when($this->interval === 'all', fn ($query) => $query->whereNotNull('history.completed_at')) + ->when($this->interval === 'custom', fn ($query) => $query->whereBetween('history.completed_at', [$this->from ?: now(), $this->until ?: now()])) + ->whereRelation('category', $this->metaType, '=', true) + // Small torrents screw the stats since users download them only to farm bon. + ->where('torrents.size', '>', 1024 * 1024 * 1024) + ->groupBy($metaIdColumn) + ->orderByRaw('COUNT(*) DESC') + ->limit(250) + ->get($metaIdColumn) + ); } + } - if (Category::where('tv_meta', '=', true)->exists()) { - $metaTypes[(string) __('mediahub.show')] = 'tv_meta'; + /** + * @var Collection> + * @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error) + */ + final protected Collection $weekly { + get { + $this->validate(); + + $metaIdColumn = match ($this->metaType) { + 'tv_meta' => 'tmdb_tv_id', + default => 'tmdb_movie_id', + }; + + return cache()->remember( + 'weekly-charts:'.$this->metaType, + 24 * 3600, + fn () => Torrent::query() + ->withoutGlobalScopes() + ->with('movie', 'tv') + ->fromSub( + History::query() + ->withoutGlobalScopes() + ->join('torrents', 'torrents.id', '=', 'history.torrent_id') + ->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true)) + ->select([ + DB::raw('FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) AS week_start'), + $metaIdColumn, + DB::raw('MIN(categories.id) as category_id'), + DB::raw('COUNT(*) AS download_count'), + DB::raw('ROW_NUMBER() OVER (PARTITION BY FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) ORDER BY COUNT(*) DESC) AS place'), + ]) + ->where($metaIdColumn, '!=', 0) + // Small torrents screw the stats since users download them only to farm bon. + ->where('torrents.size', '>', 1024 * 1024 * 1024) + ->groupBy('week_start', $metaIdColumn), + 'ranked_groups', + ) + ->where('place', '<=', 10) + ->orderByDesc('week_start') + ->orderBy('place') + ->withCasts([ + 'week_start' => 'datetime', + ]) + ->get() + ->groupBy('week_start') + ); } + } - return $metaTypes; + /** + * @var Collection> + * @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error) + */ + final protected Collection $monthly { + get { + $this->validate(); + + $metaIdColumn = match ($this->metaType) { + 'tv_meta' => 'tmdb_tv_id', + default => 'tmdb_movie_id', + }; + + return cache()->remember( + 'monthly-charts:'.$this->metaType, + 24 * 3600, + fn () => Torrent::query() + ->withoutGlobalScopes() + ->with($this->metaType === 'movie_meta' ? 'movie' : 'tv') + ->fromSub( + History::query() + ->withoutGlobalScopes() + ->join('torrents', 'torrents.id', '=', 'history.torrent_id') + ->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true)) + ->select([ + DB::raw('EXTRACT(YEAR_MONTH FROM history.created_at) AS the_year_month'), + $metaIdColumn, + DB::raw('MIN(categories.id) as category_id'), + DB::raw('COUNT(*) AS download_count'), + DB::raw('ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR_MONTH FROM history.created_at) ORDER BY COUNT(*) DESC) AS place'), + ]) + ->where($metaIdColumn, '!=', 0) + // Small torrents screw the stats since users download them only to farm bon. + ->where('torrents.size', '>', 1024 * 1024 * 1024) + ->groupBy('the_year_month', $metaIdColumn), + 'ranked_groups', + ) + ->where('place', '<=', 10) + ->orderByDesc('the_year_month') + ->orderBy('place') + ->get() + ->groupBy('the_year_month') + ); + } + } + + /** + * @var Collection> + * @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error) + */ + final protected Collection $releaseYear { + get { + $this->validate(); + + $metaIdColumn = match ($this->metaType) { + 'tv_meta' => 'tmdb_tv_id', + default => 'tmdb_movie_id', + }; + + return cache()->remember( + 'trending-by-release-year:'.$this->metaType, + 24 * 3600, + fn () => Torrent::query() + ->withoutGlobalScopes() + ->with($this->metaType === 'movie_meta' ? 'movie' : 'tv') + ->fromSub( + Torrent::query() + ->withoutGlobalScopes() + ->whereRelation('category', $this->metaType, '=', true) + ->leftJoin('tmdb_movies', 'torrents.tmdb_movie_id', '=', 'tmdb_movies.id') + ->leftJoin('tmdb_tv', 'torrents.tmdb_tv_id', '=', 'tmdb_tv.id') + ->select([ + $metaIdColumn, + DB::raw('MIN(category_id) as category_id'), + DB::raw('SUM(times_completed) AS download_count'), + 'the_year' => $this->metaType === 'movie_meta' + ? TmdbMovie::query() + ->selectRaw('EXTRACT(YEAR FROM tmdb_movies.release_date)') + ->whereColumn('tmdb_movies.id', '=', 'torrents.tmdb_movie_id') + : TmdbTv::query() + ->selectRaw('EXTRACT(YEAR FROM tmdb_tv.first_air_date)') + ->whereColumn('tmdb_tv.id', '=', 'torrents.tmdb_tv_id'), + DB::raw('ROW_NUMBER() OVER (PARTITION BY COALESCE(EXTRACT(YEAR FROM MAX(tmdb_movies.release_date)), EXTRACT(YEAR FROM MAX(tmdb_tv.first_air_date))) ORDER BY SUM(times_completed) DESC) AS place'), + ]) + ->where($metaIdColumn, '!=', 0) + // Small torrents screw the stats since users download them only to farm bon. + ->where('torrents.size', '>', 2 * 1024 * 1024 * 1024) + ->when($this->metaType === 'tv_meta', fn ($query) => $query->where('episode_number', '=', 0)) + ->havingNotNull('the_year') + ->where(fn ($query) => $query->whereNotNull('tmdb_movies.id')->orWhereNotNull('tmdb_tv.id')) + ->groupBy('the_year', $metaIdColumn), + 'ranked_groups', + ) + ->where('place', '<=', 10) + ->orderByDesc('the_year') + ->orderBy('place') + ->get() + ->groupBy('the_year') + ); + } + } + + /** + * @var array + */ + final protected array $metaTypes { + get { + $metaTypes = []; + + if (Category::where('movie_meta', '=', true)->exists()) { + $metaTypes[(string) __('mediahub.movie')] = 'movie_meta'; + } + + if (Category::where('tv_meta', '=', true)->exists()) { + $metaTypes[(string) __('mediahub.show')] = 'tv_meta'; + } + + return $metaTypes; + } } final public function placeholder(): string diff --git a/app/Http/Livewire/TwoFactorAuthForm.php b/app/Http/Livewire/TwoFactorAuthForm.php index 4c3cf55dc..3ca9ea32f 100644 --- a/app/Http/Livewire/TwoFactorAuthForm.php +++ b/app/Http/Livewire/TwoFactorAuthForm.php @@ -21,7 +21,6 @@ use Laravel\Fortify\Actions\DisableTwoFactorAuthentication; use Laravel\Fortify\Actions\EnableTwoFactorAuthentication; use Laravel\Fortify\Actions\GenerateNewRecoveryCodes; use Laravel\Fortify\Features; -use Livewire\Attributes\Computed; use Livewire\Component; class TwoFactorAuthForm extends Component @@ -126,19 +125,15 @@ class TwoFactorAuthForm extends Component /** * Get the current user of the application. */ - #[Computed] - final public function user(): ?\Illuminate\Contracts\Auth\Authenticatable - { - return auth()->user(); + final protected ?\Illuminate\Contracts\Auth\Authenticatable $user { + get => auth()->user(); } /** * Determine if two-factor authentication is enabled. */ - #[Computed] - final public function enabled(): bool - { - return !empty($this->user->two_factor_secret); + final protected bool $enabled { + get => !empty($this->user->two_factor_secret); } /** diff --git a/app/Http/Livewire/UnregisteredInfoHashSearch.php b/app/Http/Livewire/UnregisteredInfoHashSearch.php index 73971bee1..e03edc513 100644 --- a/app/Http/Livewire/UnregisteredInfoHashSearch.php +++ b/app/Http/Livewire/UnregisteredInfoHashSearch.php @@ -21,7 +21,6 @@ use App\Models\UnregisteredInfoHash; use App\Traits\CastLivewireProperties; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -58,12 +57,10 @@ class UnregisteredInfoHashSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function unregisteredInfoHashes(): \Illuminate\Pagination\LengthAwarePaginator - { - return UnregisteredInfoHash::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $unregisteredInfoHashes { + get => UnregisteredInfoHash::query() ->with('user') ->when($this->username !== '', fn ($query) => $query->whereRelation('user', 'username', 'LIKE', '%'.$this->username.'%')) ->when( diff --git a/app/Http/Livewire/UserActive.php b/app/Http/Livewire/UserActive.php index 2c3edac27..eb60309db 100644 --- a/app/Http/Livewire/UserActive.php +++ b/app/Http/Livewire/UserActive.php @@ -19,14 +19,10 @@ namespace App\Http\Livewire; use App\Models\Peer; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $actives - */ class UserActive extends Component { use LivewireSort; @@ -80,12 +76,10 @@ class UserActive extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function actives(): \Illuminate\Pagination\LengthAwarePaginator - { - return Peer::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $actives { + get => Peer::query() ->join('torrents', 'peers.torrent_id', '=', 'torrents.id') ->select( 'peers.port', diff --git a/app/Http/Livewire/UserBookmarks.php b/app/Http/Livewire/UserBookmarks.php index 4d67c7d34..a7bd2f491 100644 --- a/app/Http/Livewire/UserBookmarks.php +++ b/app/Http/Livewire/UserBookmarks.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Bookmark; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -45,12 +44,10 @@ class UserBookmarks extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function bookmarks(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return Bookmark::query() + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $bookmarks { + get => Bookmark::query() ->select([ 'bookmarks.torrent_id', 'bookmarks.created_at as bookmark_created_at', diff --git a/app/Http/Livewire/UserEarnings.php b/app/Http/Livewire/UserEarnings.php index b5d98fb53..dbdb7db17 100644 --- a/app/Http/Livewire/UserEarnings.php +++ b/app/Http/Livewire/UserEarnings.php @@ -21,14 +21,10 @@ use App\Models\User; use App\Models\Peer; use App\Traits\LivewireSort; use Illuminate\Support\Facades\DB; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $bonEarnings - */ class UserEarnings extends Component { use LivewireSort; @@ -64,75 +60,89 @@ class UserEarnings extends Component } /** - * @return \Illuminate\Database\Eloquent\Collection + * @var \Illuminate\Database\Eloquent\Collection */ - #[Computed] - final public function bonEarnings(): \Illuminate\Support\Collection - { - $outerQuery = DB::query()->select(DB::raw(1)); - $innerQuery = Peer::query() - ->select(DB::raw(1)) - ->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id')) - ->join('torrents', 'peers.torrent_id', '=', 'torrents.id') - ->where('peers.seeder', '=', true) - ->where('peers.active', '=', true) - ->where('peers.user_id', '=', $this->user->id) - ->where('peers.created_at', '<', now()->subMinutes(30)) - ->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%') - ->groupBy('peers.torrent_id'); + final protected \Illuminate\Support\Collection $bonEarnings { + get { + $outerQuery = DB::query()->select(DB::raw(1)); + $innerQuery = Peer::query() + ->select(DB::raw(1)) + ->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id')) + ->join('torrents', 'peers.torrent_id', '=', 'torrents.id') + ->where('peers.seeder', '=', true) + ->where('peers.active', '=', true) + ->where('peers.user_id', '=', $this->user->id) + ->where('peers.created_at', '<', now()->subMinutes(30)) + ->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%') + ->groupBy('peers.torrent_id'); - foreach (BonEarning::with('conditions')->orderBy('position')->get() as $bonEarning) { - // Raw bindings are fine since all database values are either enums or numeric - $conditionQuery = '1=1'; + foreach (BonEarning::with('conditions')->orderBy('position')->get() as $bonEarning) { + // Raw bindings are fine since all database values are either enums or numeric + $conditionQuery = '1=1'; - foreach ($bonEarning->conditions as $condition) { - $conditionQuery .= ' AND '.match ($condition->operand1) { - '1' => '1', - 'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())', - 'size' => 'torrents.size', - 'seeders' => 'torrents.seeders', - 'leechers' => 'torrents.leechers', - 'times_completed' => 'torrents.times_completed', - 'internal' => 'torrents.internal', - 'personal_release' => 'torrents.personal_release', - 'type_id' => 'torrents.type_id', - 'seedtime' => 'history.seedtime', - 'connectable' => 'peers.connectable', - }.' '.$condition->operator.' '.$condition->operand2; + foreach ($bonEarning->conditions as $condition) { + $conditionQuery .= ' AND '.match ($condition->operand1) { + '1' => '1', + 'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())', + 'size' => 'torrents.size', + 'seeders' => 'torrents.seeders', + 'leechers' => 'torrents.leechers', + 'times_completed' => 'torrents.times_completed', + 'internal' => 'torrents.internal', + 'personal_release' => 'torrents.personal_release', + 'type_id' => 'torrents.type_id', + 'seedtime' => 'history.seedtime', + 'connectable' => 'peers.connectable', + }.' '.$condition->operator.' '.$condition->operand2; + } + + $innerQuery->selectRaw("MAX({$conditionQuery}) AS bon_earning_{$bonEarning->id}"); + $outerQuery->selectRaw("SUM(bon_earning_{$bonEarning->id}) AS bon_earning_{$bonEarning->id}"); } - $innerQuery->selectRaw("MAX({$conditionQuery}) AS bon_earning_{$bonEarning->id}"); - $outerQuery->selectRaw("SUM(bon_earning_{$bonEarning->id}) AS bon_earning_{$bonEarning->id}"); + $torrentCounts = $outerQuery->fromSub($innerQuery, 'peers_per_torrent')->first(); + + return BonEarning::query() + ->orderBy('position') + ->get() + ->map(function ($bonEarning) use ($torrentCounts) { + $bonEarning->setAttribute('torrents_count', $torrentCounts->{"bon_earning_{$bonEarning->id}"}); + + return $bonEarning; + }); } - - $torrentCounts = $outerQuery->fromSub($innerQuery, 'peers_per_torrent')->first(); - - return BonEarning::query() - ->orderBy('position') - ->get() - ->map(function ($bonEarning) use ($torrentCounts) { - $bonEarning->setAttribute('torrents_count', $torrentCounts->{"bon_earning_{$bonEarning->id}"}); - - return $bonEarning; - }); } /** - * @return \Illuminate\Database\Query\Builder + * @var \Illuminate\Database\Query\Builder */ - #[Computed] - final public function query(): \Illuminate\Database\Query\Builder - { - $bonEarnings = BonEarning::with('conditions')->orderBy('position')->get(); + final protected \Illuminate\Database\Query\Builder $query { + get { + $bonEarnings = BonEarning::with('conditions')->orderBy('position')->get(); - $earningsQuery = str_repeat('(', $bonEarnings->count()).'0'; + $earningsQuery = str_repeat('(', $bonEarnings->count()).'0'; - foreach ($bonEarnings as $bonEarning) { - // Raw bindings are fine since all database values are either enums or numeric - $conditionQuery = '1=1'; + foreach ($bonEarnings as $bonEarning) { + // Raw bindings are fine since all database values are either enums or numeric + $conditionQuery = '1=1'; - foreach ($bonEarning->conditions as $condition) { - $conditionQuery .= ' AND '.match ($condition->operand1) { + foreach ($bonEarning->conditions as $condition) { + $conditionQuery .= ' AND '.match ($condition->operand1) { + '1' => '1', + 'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())', + 'size' => 'torrents.size', + 'seeders' => 'torrents.seeders', + 'leechers' => 'torrents.leechers', + 'times_completed' => 'torrents.times_completed', + 'internal' => 'torrents.internal', + 'personal_release' => 'torrents.personal_release', + 'type_id' => 'torrents.type_id', + 'seedtime' => 'history.seedtime', + 'connectable' => 'MAX(peers.connectable)', + }.' '.$condition->operator.' '.$condition->operand2; + } + + $variable = match ($bonEarning->variable) { '1' => '1', 'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())', 'size' => 'torrents.size', @@ -141,68 +151,52 @@ class UserEarnings extends Component 'times_completed' => 'torrents.times_completed', 'internal' => 'torrents.internal', 'personal_release' => 'torrents.personal_release', - 'type_id' => 'torrents.type_id', 'seedtime' => 'history.seedtime', 'connectable' => 'MAX(peers.connectable)', - }.' '.$condition->operator.' '.$condition->operand2; + }; + + $earningsQuery .= match ($bonEarning->operation) { + 'append' => " + CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 0 END)", + 'multiply' => " * CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 1 END)", + }; } - $variable = match ($bonEarning->variable) { - '1' => '1', - 'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())', - 'size' => 'torrents.size', - 'seeders' => 'torrents.seeders', - 'leechers' => 'torrents.leechers', - 'times_completed' => 'torrents.times_completed', - 'internal' => 'torrents.internal', - 'personal_release' => 'torrents.personal_release', - 'seedtime' => 'history.seedtime', - 'connectable' => 'MAX(peers.connectable)', - }; + $query = DB::table('peers') + ->select([ + DB::raw('1 as "1"'), + 'torrents.name', + DB::raw('TIMESTAMPDIFF(SECOND, torrents.created_at, NOW()) as age'), + 'torrents.type_id', + 'torrents.size', + 'torrents.seeders', + 'torrents.leechers', + 'torrents.times_completed', + 'history.seedtime', + 'torrents.personal_release', + 'torrents.internal', + DB::raw('MAX(peers.connectable) as connectable'), + 'peers.torrent_id', + 'peers.user_id', + DB::raw("({$earningsQuery}) AS hourly_earnings"), + ]) + ->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id')) + ->join('torrents', 'peers.torrent_id', '=', 'torrents.id') + ->where('peers.seeder', '=', true) + ->where('peers.active', '=', true) + ->where('peers.user_id', '=', $this->user->id) + ->where('peers.created_at', '<', now()->subMinutes(30)) + ->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%') + ->groupBy(['peers.torrent_id', 'peers.user_id']); - $earningsQuery .= match ($bonEarning->operation) { - 'append' => " + CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 0 END)", - 'multiply' => " * CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 1 END)", - }; + return $query; } - - $query = DB::table('peers') - ->select([ - DB::raw('1 as "1"'), - 'torrents.name', - DB::raw('TIMESTAMPDIFF(SECOND, torrents.created_at, NOW()) as age'), - 'torrents.type_id', - 'torrents.size', - 'torrents.seeders', - 'torrents.leechers', - 'torrents.times_completed', - 'history.seedtime', - 'torrents.personal_release', - 'torrents.internal', - DB::raw('MAX(peers.connectable) as connectable'), - 'peers.torrent_id', - 'peers.user_id', - DB::raw("({$earningsQuery}) AS hourly_earnings"), - ]) - ->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id')) - ->join('torrents', 'peers.torrent_id', '=', 'torrents.id') - ->where('peers.seeder', '=', true) - ->where('peers.active', '=', true) - ->where('peers.user_id', '=', $this->user->id) - ->where('peers.created_at', '<', now()->subMinutes(30)) - ->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%') - ->groupBy(['peers.torrent_id', 'peers.user_id']); - - return $query; } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function torrents(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return $this + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $torrents { + get => $this ->query ->orderBy($this->sortField, $this->sortDirection) ->paginate(25); @@ -211,10 +205,8 @@ class UserEarnings extends Component /** * @return float|numeric-string */ - #[Computed] - final public function total(): float|string - { - return DB::query()->fromSub($this->query, 'earnings_per_torrent')->sum('hourly_earnings'); + final protected float|string $total { + get => DB::query()->fromSub($this->query, 'earnings_per_torrent')->sum('hourly_earnings'); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/UserNotes.php b/app/Http/Livewire/UserNotes.php index 95ed22e94..e71b2d824 100644 --- a/app/Http/Livewire/UserNotes.php +++ b/app/Http/Livewire/UserNotes.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\Note; use App\Models\User; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -70,12 +69,10 @@ class UserNotes extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function notes(): \Illuminate\Pagination\LengthAwarePaginator - { - return Note::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $notes { + get => Note::query() ->with('staffuser', 'staffuser.group') ->where('user_id', '=', $this->user->id) ->paginate($this->perPage); diff --git a/app/Http/Livewire/UserResurrections.php b/app/Http/Livewire/UserResurrections.php index c8ad197d8..2b4137ff2 100644 --- a/app/Http/Livewire/UserResurrections.php +++ b/app/Http/Livewire/UserResurrections.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\Resurrection; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -59,12 +58,10 @@ class UserResurrections extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function resurrections(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return Resurrection::query() + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $resurrections { + get => Resurrection::query() ->select([ 'resurrections.id', 'resurrections.created_at', diff --git a/app/Http/Livewire/UserSearch.php b/app/Http/Livewire/UserSearch.php index a2e71dea0..30deb64fd 100644 --- a/app/Http/Livewire/UserSearch.php +++ b/app/Http/Livewire/UserSearch.php @@ -20,7 +20,6 @@ use App\Models\Group; use App\Models\User; use App\Traits\CastLivewireProperties; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -75,12 +74,10 @@ class UserSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function users(): \Illuminate\Pagination\LengthAwarePaginator - { - return User::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $users { + get => User::query() ->with('group') ->when($this->username !== '', fn ($query) => $query->where('username', 'LIKE', '%'.$this->username.'%')) ->when( @@ -106,12 +103,10 @@ class UserSearch extends Component } /** - * @return \Illuminate\Support\Collection + * @var \Illuminate\Support\Collection */ - #[Computed] - final public function groups() - { - return Group::orderBy('position')->get(); + final protected $groups { + get => Group::orderBy('position')->get(); } final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application diff --git a/app/Http/Livewire/UserTorrents.php b/app/Http/Livewire/UserTorrents.php index f6708b42c..f9fd6d696 100644 --- a/app/Http/Livewire/UserTorrents.php +++ b/app/Http/Livewire/UserTorrents.php @@ -19,7 +19,6 @@ namespace App\Http\Livewire; use App\Models\History; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -89,12 +88,10 @@ class UserTorrents extends Component } /** - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ - #[Computed] - final public function history(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return History::query() + final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $history { + get => History::query() ->join( 'torrents', fn ($join) => $join diff --git a/app/Http/Livewire/UserUnregisteredInfoHashSearch.php b/app/Http/Livewire/UserUnregisteredInfoHashSearch.php new file mode 100644 index 000000000..5e79f6fc1 --- /dev/null +++ b/app/Http/Livewire/UserUnregisteredInfoHashSearch.php @@ -0,0 +1,86 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Livewire; + +use App\Models\UnregisteredInfoHash; +use App\Models\User; +use App\Traits\CastLivewireProperties; +use App\Traits\LivewireSort; +use Livewire\Attributes\Url; +use Livewire\Component; +use Livewire\WithPagination; + +class UserUnregisteredInfoHashSearch extends Component +{ + use CastLivewireProperties; + use LivewireSort; + use WithPagination; + + public ?User $user = null; + + #TODO: Update URL attributes once Livewire 3 fixes upstream bug. See: https://github.com/livewire/livewire/discussions/7746 + + #[Url(history: true)] + public int $perPage = 25; + + #[Url(history: true)] + public string $sortField = 'deleted_at'; + + #[Url(history: true)] + public string $sortDirection = 'desc'; + + final public function mount(int $userId): void + { + $this->user = User::find($userId); + } + + final public function updatingSearch(): void + { + $this->resetPage(); + } + + /** + * @var \Illuminate\Pagination\LengthAwarePaginator + */ + final protected \Illuminate\Pagination\LengthAwarePaginator $unregisteredInfoHashes { + get => UnregisteredInfoHash::query() + ->select([ + 'unregistered_info_hashes.info_hash', + 'unregistered_info_hashes.updated_at', + 'torrents.id', + 'torrents.name', + 'torrents.size', + 'torrents.deleted_at', + ]) + ->withCasts([ + 'deleted_at' => 'datetime', + ]) + ->join('torrents', 'unregistered_info_hashes.info_hash', '=', 'torrents.info_hash') + ->whereBelongsTo($this->user) + ->whereNotNull('torrents.deleted_at') + ->where('unregistered_info_hashes.updated_at', '>', now()->subHours(2)) + ->orderBy($this->sortField, $this->sortDirection) + ->paginate($this->perPage); + } + + final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application + { + return view('livewire.user-unregistered-info-hash-search', [ + 'unregisteredInfoHashes' => $this->unregisteredInfoHashes, + ]); + } +} diff --git a/app/Http/Livewire/UserUploads.php b/app/Http/Livewire/UserUploads.php index 57f35d3fd..3e8805ddb 100644 --- a/app/Http/Livewire/UserUploads.php +++ b/app/Http/Livewire/UserUploads.php @@ -20,7 +20,6 @@ use App\Models\Scopes\ApprovedScope; use App\Models\Torrent; use App\Models\User; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -69,12 +68,10 @@ class UserUploads extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function uploads(): \Illuminate\Pagination\LengthAwarePaginator - { - return Torrent::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $uploads { + get => Torrent::query() ->withCount('thanks', 'comments') ->withSum('tips', 'bon') ->withoutGlobalScope(ApprovedScope::class) diff --git a/app/Http/Livewire/UserWarnings.php b/app/Http/Livewire/UserWarnings.php index 03a3dd0fb..50b4f44e0 100644 --- a/app/Http/Livewire/UserWarnings.php +++ b/app/Http/Livewire/UserWarnings.php @@ -25,18 +25,11 @@ use App\Notifications\WarningsDeleted; use App\Notifications\WarningTorrentDeleted; use App\Traits\LivewireSort; use Illuminate\Support\Carbon; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Attributes\Validate; use Livewire\Component; use Livewire\WithPagination; -/** - * @property \Illuminate\Pagination\LengthAwarePaginator $warnings - * @property int $automatedWarningsCount - * @property int $manualWarningsCount - * @property int $deletedWarningsCount - */ class UserWarnings extends Component { use LivewireSort; @@ -64,12 +57,10 @@ class UserWarnings extends Component public string $sortDirection = 'desc'; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function warnings(): \Illuminate\Pagination\LengthAwarePaginator - { - return $this->user + final protected \Illuminate\Pagination\LengthAwarePaginator $warnings { + get => $this->user ->userwarning() ->when( auth()->user()->group->is_modo, @@ -87,22 +78,16 @@ class UserWarnings extends Component ->paginate($this->perPage); } - #[Computed] - final public function automatedWarningsCount(): int - { - return $this->user->userwarning()->whereNotNull('torrent')->count(); + final protected int $automatedWarningsCount { + get => $this->user->userwarning()->whereNotNull('torrent')->count(); } - #[Computed] - final public function manualWarningsCount(): int - { - return $this->user->userwarning()->whereNull('torrent')->count(); + final protected int $manualWarningsCount { + get => $this->user->userwarning()->whereNull('torrent')->count(); } - #[Computed] - final public function deletedWarningsCount(): int - { - return $this->user->userwarning()->onlyTrashed()->count(); + final protected int $deletedWarningsCount { + get => $this->user->userwarning()->onlyTrashed()->count(); } /** diff --git a/app/Http/Livewire/WarningLogSearch.php b/app/Http/Livewire/WarningLogSearch.php index 0d1dd84da..f92981340 100644 --- a/app/Http/Livewire/WarningLogSearch.php +++ b/app/Http/Livewire/WarningLogSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\Warning; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -55,12 +54,10 @@ class WarningLogSearch extends Component public string $sortDirection = 'desc'; /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function warnings(): \Illuminate\Pagination\LengthAwarePaginator - { - return Warning::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $warnings { + get => Warning::query() ->with(['warneduser.group', 'staffuser.group', 'torrenttitle']) ->when($this->sender, fn ($query) => $query->whereRelation('staffuser', 'username', '=', $this->sender)) ->when($this->receiver, fn ($query) => $query->whereRelation('warneduser', 'username', '=', $this->receiver)) diff --git a/app/Http/Livewire/WatchlistSearch.php b/app/Http/Livewire/WatchlistSearch.php index aee76d514..f9d8ce4d9 100644 --- a/app/Http/Livewire/WatchlistSearch.php +++ b/app/Http/Livewire/WatchlistSearch.php @@ -18,7 +18,6 @@ namespace App\Http\Livewire; use App\Models\Watchlist; use App\Traits\LivewireSort; -use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; @@ -55,12 +54,10 @@ class WatchlistSearch extends Component } /** - * @return \Illuminate\Pagination\LengthAwarePaginator + * @var \Illuminate\Pagination\LengthAwarePaginator */ - #[Computed] - final public function users(): \Illuminate\Pagination\LengthAwarePaginator - { - return Watchlist::query() + final protected \Illuminate\Pagination\LengthAwarePaginator $users { + get => Watchlist::query() ->with(['user.group', 'author.group']) ->when($this->search, fn ($query) => $query->where('message', 'LIKE', '%'.$this->search.'%')) ->orderBy($this->sortField, $this->sortDirection) diff --git a/app/Http/Middleware/CheckIfBanned.php b/app/Http/Middleware/CheckIfBanned.php index 3fbc6a0f7..aa40c120b 100644 --- a/app/Http/Middleware/CheckIfBanned.php +++ b/app/Http/Middleware/CheckIfBanned.php @@ -39,6 +39,28 @@ class CheckIfBanned 'message' => __('auth.banned'), ]); } + + if ($request->is('rss/*')) { + $message = __('auth.banned'); + $now = now()->toRssString(); + $url = config('app.url'); + + return response( + << + + + {$message} + {$url} + {$message} + {$now} + + + XML, + 403 + )->header('Content-Type', 'text/xml'); + } + auth()->logout(); $request->session()->flush(); diff --git a/app/Http/Requests/StoreTorrentRequestRequest.php b/app/Http/Requests/StoreTorrentRequestRequest.php index 3b42db779..9ef585a0b 100644 --- a/app/Http/Requests/StoreTorrentRequestRequest.php +++ b/app/Http/Requests/StoreTorrentRequestRequest.php @@ -88,6 +88,26 @@ class StoreTorrentRequestRequest extends FormRequest $mustBeNull, ]), ], + 'season_number' => [ + Rule::when($category->tv_meta, [ + 'required', + 'integer', + 'min:0', + ]), + Rule::when(!$category->tv_meta, [ + $mustBeNull, + ]), + ], + 'episode_number' => [ + Rule::when($category->tv_meta, [ + 'required', + 'integer', + 'min:0', + ]), + Rule::when(!$category->tv_meta, [ + $mustBeNull, + ]), + ], 'tmdb_movie_id' => [ Rule::when($category->movie_meta, [ 'required_with:movie_exists_on_tmdb', diff --git a/app/Http/Requests/UpdateTorrentRequestRequest.php b/app/Http/Requests/UpdateTorrentRequestRequest.php index dc8521ce8..19bce4f53 100644 --- a/app/Http/Requests/UpdateTorrentRequestRequest.php +++ b/app/Http/Requests/UpdateTorrentRequestRequest.php @@ -88,6 +88,26 @@ class UpdateTorrentRequestRequest extends FormRequest $mustBeNull, ]), ], + 'season_number' => [ + Rule::when($category->tv_meta, [ + 'required', + 'integer', + 'min:0', + ]), + Rule::when(!$category->tv_meta, [ + $mustBeNull, + ]), + ], + 'episode_number' => [ + Rule::when($category->tv_meta, [ + 'required', + 'integer', + 'min:0', + ]), + Rule::when(!$category->tv_meta, [ + $mustBeNull, + ]), + ], 'tmdb_movie_id' => [ Rule::when($category->movie_meta, [ 'required_with:movie_exists_on_tmdb', diff --git a/app/Http/Resources/BotResource.php b/app/Http/Resources/BotResource.php index bd2d91348..7d7e6c88c 100644 --- a/app/Http/Resources/BotResource.php +++ b/app/Http/Resources/BotResource.php @@ -16,8 +16,8 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; -use JsonSerializable; /** * @mixin \App\Models\Bot @@ -26,9 +26,41 @@ class BotResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * id: int, + * position: int, + * name: string, + * command: string, + * color: string|null, + * icon: string|null, + * emoji: string|null, + * help: string|null, + * active: bool, + * is_protected: bool, + * is_nerdbot: bool, + * is_systembot: bool, + * created_at: \Illuminate\Support\Carbon|null, + * updated_at: \Illuminate\Support\Carbon|null, + * } */ - public function toArray($request): array|\Illuminate\Contracts\Support\Arrayable|JsonSerializable + public function toArray(Request $request): array { - return parent::toArray($request); + return [ + 'id' => $this->id, + 'position' => $this->position, + 'name' => $this->name, + 'command' => $this->command, + 'color' => $this->color, + 'icon' => $this->icon, + 'emoji' => $this->emoji, + 'help' => $this->help, + 'active' => $this->active, + 'is_protected' => $this->is_protected, + 'is_nerdbot' => $this->is_nerdbot, + 'is_systembot' => $this->is_systembot, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; } } diff --git a/app/Http/Resources/ChatMessageResource.php b/app/Http/Resources/ChatMessageResource.php index fb6048383..12398e4bd 100644 --- a/app/Http/Resources/ChatMessageResource.php +++ b/app/Http/Resources/ChatMessageResource.php @@ -18,6 +18,7 @@ namespace App\Http\Resources; use App\Helpers\Bbcode; use hdvinnie\LaravelJoyPixels\LaravelJoyPixels; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** @@ -29,8 +30,19 @@ class ChatMessageResource extends JsonResource * Transform the resource into an array. * * @throws \Illuminate\Contracts\Container\BindingResolutionException + * + * @return array{ + * id: int, + * bot: BotResource, + * user: ChatUserResource, + * receiver: ChatUserResource, + * chatroom: ChatRoomResource, + * message: string, + * created_at: string, + * updated_at: string, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { $emojiOne = new LaravelJoyPixels(); diff --git a/app/Http/Resources/ChatRoomResource.php b/app/Http/Resources/ChatRoomResource.php index 93030e9d3..905eec274 100644 --- a/app/Http/Resources/ChatRoomResource.php +++ b/app/Http/Resources/ChatRoomResource.php @@ -16,6 +16,7 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** @@ -25,8 +26,17 @@ class ChatRoomResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * id: int, + * name: string, + * users: \Illuminate\Http\Resources\Json\AnonymousResourceCollection, + * messages: \Illuminate\Http\Resources\Json\AnonymousResourceCollection, + * created_at: string, + * updated_at: string, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'id' => $this->id, diff --git a/app/Http/Resources/ChatUserResource.php b/app/Http/Resources/ChatUserResource.php index ced441d67..b6a684127 100644 --- a/app/Http/Resources/ChatUserResource.php +++ b/app/Http/Resources/ChatUserResource.php @@ -16,6 +16,7 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** @@ -25,8 +26,24 @@ class ChatUserResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * id: int, + * username: string, + * chat_status: mixed, + * chat_status_id: int, + * chatroom_id: int, + * group: mixed, + * echoes: mixed, + * group_id: int, + * title: string, + * image: string, + * is_lifetime: bool, + * is_donor: bool, + * icon: string, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'id' => $this->id, diff --git a/app/Http/Resources/TorrentRequestResource.php b/app/Http/Resources/TorrentRequestResource.php new file mode 100644 index 000000000..e81f1c454 --- /dev/null +++ b/app/Http/Resources/TorrentRequestResource.php @@ -0,0 +1,59 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Resources; + +use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Http\Request; + +/** + * @mixin \App\Models\TorrentRequest + */ +class TorrentRequestResource extends JsonResource +{ + /** + * Transform the resource into an array. + * + * @param Request $request + * @return array + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'category_id' => $this->category_id, + 'type_id' => $this->type_id, + 'resolution_id' => $this->whenNotNull($this->resolution_id), + 'user' => $this->anon ? 'anonymous' : $this->user->username, + 'tmdb' => $this->tmdb_movie_id ?: $this->tmdb_tv_id, + 'imdb' => $this->imdb, + 'tvdb' => $this->tvdb, + 'mal' => $this->mal, + 'igdb' => $this->igdb, + 'season_number' => $this->whenNotNull($this->season_number), + 'episode_number' => $this->whenNotNull($this->episode_number), + 'bounty' => $this->whenAggregated('bounties', 'seedbonus', 'sum'), + 'status' => $this->filled_by !== null ? ($this->approved_by !== null ? 'filled' : 'pending') : ($this->claim ? 'claimed' : 'unfilled'), + 'claimed' => $this->claim !== null, + 'claimed_by' => $this->when($this->claim !== null, $this->claim?->anon ? 'anonymous' : ($this->claim?->user?->username ?? null)), + 'filled_by' => $this->when($this->filled_by !== null, $this->filled_anon ? 'anonymous' : ($this->filler?->username ?? null)), + 'created' => $this->created_at->toIso8601String(), + 'updated_at' => $this->updated_at->toIso8601String(), + ]; + } +} diff --git a/app/Http/Resources/TorrentResource.php b/app/Http/Resources/TorrentResource.php index 0c5e6d9b3..297193916 100644 --- a/app/Http/Resources/TorrentResource.php +++ b/app/Http/Resources/TorrentResource.php @@ -17,17 +17,76 @@ declare(strict_types=1); namespace App\Http\Resources; use App\Enums\AuthGuard; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** * @mixin \App\Models\Torrent + * @property \App\Models\TmdbMovie|\App\Models\TmdbTv|\App\Models\IgdbGame $meta */ class TorrentResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * type: 'torrent', + * id: string, + * attributes: array{ + * meta: array{ + * poster: string, + * genres: string, + * }, + * name: string, + * release_year: string|null, + * category: string, + * type: string, + * resolution: string, + * distributor: string, + * region: string, + * media_info: string, + * bd_info: string, + * description: string, + * size: float, + * folder: string|null, + * num_file: int, + * files: \Illuminate\Support\Collection< + * int, + * array{ + * index: int, + * name: string, + * size: int, + * }, + * >, + * freeleech: string, + * double_upload: bool, + * refundable: bool, + * internal: int, + * featured: \Illuminate\Http\Resources\MissingValue|mixed, + * personal_release: bool, + * uploader: string, + * seeders: int, + * leechers: int, + * times_completed: int, + * tmdb_id: int|null, + * imdb_id: int, + * tvdb_id: int, + * mal_id: int, + * igdb_id: int, + * category_id: int|null, + * type_id: int, + * resolution_id: \Illuminate\Http\Resources\MissingValue|mixed, + * distributor_id: \Illuminate\Http\Resources\MissingValue|mixed, + * region_id: \Illuminate\Http\Resources\MissingValue|mixed, + * created_at: \Illuminate\Support\Carbon|null, + * download_link: string, + * magnet_link: \Illuminate\Http\Resources\MissingValue|mixed, + * details_link: string, + * } + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'type' => 'torrent', @@ -47,7 +106,6 @@ class TorrentResource extends JsonResource 'media_info' => $this->mediainfo, 'bd_info' => $this->bdinfo, 'description' => $this->description, - 'info_hash' => bin2hex($this->info_hash), 'size' => $this->size, 'folder' => $this->folder, 'num_file' => $this->num_file, @@ -87,7 +145,7 @@ class TorrentResource extends JsonResource /** * Customize the outgoing response for the resource. */ - public function withResponse($request, $response): void + public function withResponse(Request $request, JsonResponse $response): void { $response->setEncodingOptions(JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); } diff --git a/app/Http/Resources/TorrentsResource.php b/app/Http/Resources/TorrentsResource.php index 009ea60dc..40bb4ded2 100644 --- a/app/Http/Resources/TorrentsResource.php +++ b/app/Http/Resources/TorrentsResource.php @@ -16,14 +16,20 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\ResourceCollection; class TorrentsResource extends ResourceCollection { /** * Transform the resource collection into an array. + * + * @return array{ + * data: \Illuminate\Http\Resources\Json\AnonymousResourceCollection, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'data' => TorrentResource::collection($this->collection), @@ -32,8 +38,14 @@ class TorrentsResource extends ResourceCollection /** * Get additional data that should be returned with the resource array. + * + * @return array{ + * links: array{ + * self: string, + * } + * } */ - public function with($request): array + public function with(Request $request): array { return [ 'links' => [ @@ -45,7 +57,7 @@ class TorrentsResource extends ResourceCollection /** * Customize the outgoing response for the resource. */ - public function withResponse($request, $response): void + public function withResponse(Request $request, JsonResponse $response): void { $response->setEncodingOptions(JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); } diff --git a/app/Http/Resources/UserAudibleResource.php b/app/Http/Resources/UserAudibleResource.php index 469e4c15f..8ed0fa794 100644 --- a/app/Http/Resources/UserAudibleResource.php +++ b/app/Http/Resources/UserAudibleResource.php @@ -16,6 +16,7 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** @@ -25,8 +26,18 @@ class UserAudibleResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * id: int, + * user_id: int, + * user: ChatUserResource, + * target: ChatUserResource, + * room: \App\Models\Chatroom|null, + * bot: \App\Models\Bot|null, + * status: int, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'id' => $this->id, diff --git a/app/Http/Resources/UserEchoResource.php b/app/Http/Resources/UserEchoResource.php index bf73e480d..11f130b87 100644 --- a/app/Http/Resources/UserEchoResource.php +++ b/app/Http/Resources/UserEchoResource.php @@ -16,6 +16,7 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** @@ -25,8 +26,17 @@ class UserEchoResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * id: int, + * user_id: int, + * user: ChatUserResource, + * target: ChatUserResource, + * room: \App\Models\Chatroom, + * bot: \App\Models\Bot, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'id' => $this->id, diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index 4b0dd07d0..413504f61 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -16,6 +16,7 @@ declare(strict_types=1); namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; /** @@ -25,8 +26,21 @@ class UserResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array{ + * username: string, + * group: string, + * uploaded: string, + * downloaded: string, + * ratio: string, + * buffer: string, + * seeding: int, + * leeching: int, + * seedbonus: string, + * hit_and_runs: int, + * } */ - public function toArray($request): array + public function toArray(Request $request): array { return [ 'username' => $this->username, diff --git a/app/Models/Donation.php b/app/Models/Donation.php index b1cba66c9..bb2161bb4 100644 --- a/app/Models/Donation.php +++ b/app/Models/Donation.php @@ -23,17 +23,17 @@ use Illuminate\Database\Eloquent\Model; /** * App\Models\Donation. * - * @property int $id - * @property int $user_id - * @property int $gifted_user_id - * @property ModerationStatus $status - * @property int $package_id - * @property string $transaction - * @property bool $is_gifted - * @property \Illuminate\Support\Carbon $starts_at - * @property \Illuminate\Support\Carbon $ends_at - * @property \Illuminate\Support\Carbon $created_at - * @property \Illuminate\Support\Carbon $updated_at + * @property int $id + * @property int $user_id + * @property int $gifted_user_id + * @property ModerationStatus $status + * @property int $package_id + * @property string $transaction + * @property bool $is_gifted + * @property \Illuminate\Support\Carbon|null $starts_at + * @property \Illuminate\Support\Carbon|null $ends_at + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at */ class Donation extends Model { diff --git a/app/Models/TorrentRequest.php b/app/Models/TorrentRequest.php index 1807521b5..b133c355c 100644 --- a/app/Models/TorrentRequest.php +++ b/app/Models/TorrentRequest.php @@ -46,6 +46,8 @@ use Illuminate\Database\Eloquent\Model; * @property \Illuminate\Support\Carbon|null $approved_when * @property int|null $type_id * @property int|null $resolution_id + * @property int|null $season_number + * @property int|null $episode_number */ class TorrentRequest extends Model { diff --git a/app/Models/TorrentReseed.php b/app/Models/TorrentReseed.php new file mode 100644 index 000000000..a120ec5ef --- /dev/null +++ b/app/Models/TorrentReseed.php @@ -0,0 +1,63 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Models; + +use App\Traits\Auditable; +use Illuminate\Database\Eloquent\Model; + +/** + * App\Models\TorrentReseed. + * + * @property int $id + * @property int $torrent_id + * @property int $user_id + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read Torrent $torrent + * @property-read User $user + */ +class TorrentReseed extends Model +{ + use Auditable; + + /** + * The attributes that aren't mass assignable. + * + * @var string[] + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Belongs To A Torrent. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function torrent(): \Illuminate\Database\Eloquent\Relations\BelongsTo + { + return $this->belongsTo(Torrent::class); + } + + /** + * Belongs To A User. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Services/Unit3dAnnounce.php b/app/Services/Unit3dAnnounce.php index 23728a787..e95db88d3 100644 --- a/app/Services/Unit3dAnnounce.php +++ b/app/Services/Unit3dAnnounce.php @@ -111,7 +111,7 @@ class Unit3dAnnounce * array{ * ip_address: string, * user_id: int, - * torrent_id: int, + * peer_id: string, * port: int, * is_seeder: bool, * is_active: bool, @@ -150,11 +150,9 @@ class Unit3dAnnounce return []; } - foreach ($torrent['peers'] as $peer) { + foreach ($torrent['peers'] as $userIdAndPeerId => &$peer) { if ( !\array_key_exists('ip_address', $peer) || !\is_string($peer['ip_address']) - || !\array_key_exists('user_id', $peer) || !\is_int($peer['user_id']) - || !\array_key_exists('torrent_id', $peer) || !\is_int($peer['torrent_id']) || !\array_key_exists('port', $peer) || !\is_int($peer['port']) || !\array_key_exists('is_seeder', $peer) || !\is_bool($peer['is_seeder']) || !\array_key_exists('is_active', $peer) || !\is_bool($peer['is_active']) @@ -165,6 +163,13 @@ class Unit3dAnnounce ) { return []; } + + if (preg_match('/^(\d+)\-([0-9a-fA-F]{40})$/', $userIdAndPeerId, $matches)) { + $peer['user_id'] = $matches[1]; + $peer['peer_id'] = hex2bin($matches[2]); + } else { + return []; + } } return $torrent; diff --git a/book/src/local_development_arch_linux.md b/book/src/local_development_arch_linux.md index 6aaf47041..9262b46ca 100644 --- a/book/src/local_development_arch_linux.md +++ b/book/src/local_development_arch_linux.md @@ -1,4 +1,4 @@ -# UNIT3D v8.x.x on Arch Linux with Laravel Sail +# UNIT3D development on Arch Linux with Laravel Sail @@ -72,12 +72,12 @@ Clone the UNIT3D repository to your local environment: ## Step 3: Docker environment initialization -1. **Switch to branch 8.x.x:** +1. **Switch to branch `development`:** - Before starting Docker, switch to the `8.x.x` branch: + Before starting Docker, switch to the `development` branch: ```sh - git checkout 8.x.x + git checkout development ``` 2. **Start the Docker environment using Laravel Sail:** diff --git a/book/src/torrent_request_api.md b/book/src/torrent_request_api.md new file mode 100644 index 000000000..01f745699 --- /dev/null +++ b/book/src/torrent_request_api.md @@ -0,0 +1,169 @@ +# Torrent Requests API Documentation + +## Endpoints + +### Filter Requests + +`GET /api/requests/filter` + +Filter, sort, and paginate torrent requests. + +#### Query Parameters + +| Parameter | Type | Description | Default | +|-----------------|---------|---------------------------------------------------------|-------------| +| `name` | string | Search by name | - | +| `category_id` | int[] | Filter by category ID(s) | - | +| `type_id` | int[] | Filter by type ID(s) | - | +| `resolution_id` | int[] | Filter by resolution ID(s) | - | +| `tmdb` | integer | Filter by TMDB ID | - | +| `imdb` | integer | Filter by IMDB ID | - | +| `tvdb` | integer | Filter by TVDB ID | - | +| `mal` | integer | Filter by MAL ID | - | +| `filled` | boolean | Filter by filled status | - | +| `claimed` | boolean | Filter by claimed status | - | +| `perPage` | integer | Items per page (max: 100) | 25 | + +#### Example Request + +```bash +curl -X GET "https://unit3d.site/api/requests/filter?tmdb=2508" \ +-H "Authorization: Bearer YOUR_API_KEY_HERE" \ +-H "Accept: application/json" +``` + +#### Example Response + +```json +{ + "data": [ + { + "id": 1, + "name": "Mind Your Language S04", + "description": "Example description.", + "category_id": 2, + "type_id": 2, + "resolution_id": 6, + "user": "anonymous", + "tmdb": 2508, + "imdb": 75537, + "tvdb": 78286, + "mal": null, + "igdb": null, + "season_number": 4, + "episode_number": 0, + "bounty": 125000, + "status": "unfilled", + "claimed": false, + "created": "2025-08-01T11:02:22+00:00", + "updated_at": "2025-08-21T12:40:27+00:00" + } + ], + "links": { + "first": "https://unit3d.site/api/requests/filter?page=1", + "last": "https://unit3d.site/api/requests/filter?page=1", + "prev": null, + "next": null + }, + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [ + { + "url": null, + "label": "« Previous", + "active": false + }, + { + "url": "https://unit3d.site/api/requests/filter?page=1", + "label": "1", + "active": true + }, + { + "url": null, + "label": "Next »", + "active": false + } + ], + "path": "https://unit3d.site/api/requests/filter", + "per_page": 25, + "to": 1, + "total": 1 + } +} +``` + +### Get Single Request + +`GET /api/requests/{id}` + +Filter information on a single request ID. + +#### Parameters + +| Parameter | Type | Description | +|-----------|---------|---------------------| +| `id` | integer | Torrent request ID | + +#### Example Request + +```bash +curl -X GET "https://unit3d.site/api/requests/1" \ +-H "Authorization: Bearer YOUR_API_KEY_HERE" \ +-H "Accept: application/json" +``` + +#### Example Response + +```json +{ + "data": { + "id": 1, + "name": "Mind Your Language S04", + "description": "Example description.", + "category_id": 2, + "type_id": 2, + "resolution_id": 6, + "user": "anonymous", + "tmdb": 2508, + "imdb": 75537, + "tvdb": 78286, + "mal": null, + "igdb": null, + "season_number": 4, + "episode_number": 0, + "bounty": 125000, + "status": "unfilled", + "claimed": false, + "created": "2025-08-01T11:02:22+00:00", + "updated_at": "2025-08-21T12:40:27+00:00" + } +} +``` + +## Response Fields + +| Field | Type | Description | +|-----------------|---------|-----------------------------------------------------------| +| `id` | integer | Request ID | +| `name` | string | Request title | +| `description` | string | Request description | +| `category_id` | integer | Category ID | +| `type_id` | integer | Release type ID, null if set to "any" | +| `resolution_id` | integer | Resolution ID, null if set to "any" | +| `user` | string | Username of requester or "anonymous" | +| `tmdb` | integer | TMDB ID | +| `imdb` | integer | IMDB ID | +| `tvdb` | integer | TVDB ID | +| `mal` | integer | MyAnimeList ID | +| `igdb` | integer | IGDB ID | +| `season_number` | integer | Season number | +| `episode_number`| integer | Episode number | +| `bounty` | integer | Total bounty amount | +| `status` | string | Request status, unfilled, claimed, pending, or filled | +| `claimed` | boolean | Whether or not the request is claimed | +| `claimed_by` | string | Username of claimer, "anonymous", null if unclaimed | +| `filled_by` | string | Username of filler, "anonymous", null if unfilled | +| `created` | string | Creation date | +| `updated_at` | string | Last update date | diff --git a/composer.json b/composer.json index 91f8748ed..7a7013e3f 100644 --- a/composer.json +++ b/composer.json @@ -16,48 +16,48 @@ "ext-zip": "*", "assada/laravel-achievements": "^2.8", "bjeavons/zxcvbn-php": "^1.4.2", - "doctrine/dbal": "^3.10.0", + "doctrine/dbal": "^3.10.1", "gabrielelana/byte-units": "^0.5.0", "graham-campbell/markdown": "^v16.0.0", - "guzzlehttp/guzzle": "^7.9.3", + "guzzlehttp/guzzle": "^7.10.0", "hdvinnie/laravel-joypixel-emojis": "^3.0.1", "hdvinnie/laravel-security-headers": "^3.0.3", "intervention/image": "^2.7.2", "joypixels/assets": "^v7.0.1", - "laravel/fortify": "^1.27.0", - "laravel/framework": "^12.20.0", - "laravel/octane": "^2.11.0", - "laravel/scout": "^10.16.0", + "laravel/fortify": "^1.30.0", + "laravel/framework": "^12.26.4", + "laravel/octane": "^2.12.1", + "laravel/scout": "^10.19.0", "laravel/tinker": "^2.10.1", "livewire/livewire": "^3.6.4", "maennchen/zipstream-php": "^3.2", "marcreichel/igdb-laravel": "^5.3.1", "meilisearch/meilisearch-php": "^1.15.0", "paragonie/constant_time_encoding": "^2.7.0", - "spatie/laravel-backup": "^9.3.3", + "spatie/laravel-backup": "^9.3.4", "spatie/laravel-cookie-consent": "^3.3.3", "spatie/laravel-image-optimizer": "^1.8.2", "spatie/ssl-certificate": "^2.6.10", - "symfony/dom-crawler": "^6.4.23", + "symfony/dom-crawler": "^6.4.25", "theodorejb/polycast": "dev-master", "vstelmakh/url-highlight": "^3.1.2" }, "require-dev": { - "barryvdh/laravel-debugbar": "^3.15.4", - "brianium/paratest": "^7.8.3", + "barryvdh/laravel-debugbar": "^3.16.0", + "brianium/paratest": "^7.12.0", "calebdw/larastan": "3.4.2", - "calebdw/larastan-livewire": "^2.2.0", + "calebdw/larastan-livewire": "^2.3.0", "fakerphp/faker": "^1.24.1", "jasonmccreary/laravel-test-assertions": "^2.8.0", - "laravel/pint": "v1.20.0", - "laravel/sail": "^1.43.1", + "laravel/pint": "v1.24.0", + "laravel/sail": "^1.45.0", "mockery/mockery": "^1.6.12", "nunomaduro/collision": "^8.8.2", - "pestphp/pest": "^3.8.2", - "pestphp/pest-plugin-laravel": "^3.2", - "pestphp/pest-plugin-livewire": "^3.0", - "phpstan/phpstan": "^2.1.18", - "phpunit/phpunit": "^11.5.15", + "pestphp/pest": "^4.0.4", + "pestphp/pest-plugin-laravel": "^4.0.0", + "pestphp/pest-plugin-livewire": "^4.0.1", + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^12.3.7", "ryoluo/sail-ssl": "^1.4.0", "spatie/laravel-ignition": "^2.9.1", "tomasvotruba/bladestan": "^0.11.3" diff --git a/composer.lock b/composer.lock index 650261c3f..6f24b3012 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f7f0c7df5833e4e06ebab22b49ad097b", + "content-hash": "8deacba02d6f674a6d641c2f4f8a3bdb", "packages": [ { "name": "assada/laravel-achievements", @@ -431,16 +431,16 @@ }, { "name": "doctrine/dbal", - "version": "3.10.0", + "version": "3.10.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214" + "reference": "3626601014388095d3af9de7e9e958623b7ef005" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/1cf840d696373ea0d58ad0a8875c0fadcfc67214", - "reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/3626601014388095d3af9de7e9e958623b7ef005", + "reference": "3626601014388095d3af9de7e9e958623b7ef005", "shasum": "" }, "require": { @@ -525,7 +525,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.10.0" + "source": "https://github.com/doctrine/dbal/tree/3.10.1" }, "funding": [ { @@ -541,7 +541,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T21:11:04+00:00" + "time": "2025-08-05T12:18:06+00:00" }, { "name": "doctrine/deprecations", @@ -684,33 +684,32 @@ }, { "name": "doctrine/inflector", - "version": "2.0.10", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25 || ^5.4" + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + "Doctrine\\Inflector\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -755,7 +754,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.10" + "source": "https://github.com/doctrine/inflector/tree/2.1.0" }, "funding": [ { @@ -771,7 +770,7 @@ "type": "tidelift" } ], - "time": "2024-02-18T20:23:39+00:00" + "time": "2025-08-10T19:31:58+00:00" }, { "name": "doctrine/lexer", @@ -1253,22 +1252,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.9.3", + "version": "7.10.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -1359,7 +1358,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" }, "funding": [ { @@ -1375,20 +1374,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:37:11+00:00" + "time": "2025-08-23T22:36:01+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { @@ -1396,7 +1395,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { @@ -1442,7 +1441,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.2.0" + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { @@ -1458,20 +1457,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:27:01+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + "reference": "21dc724a0583619cd1652f673303492272778051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -1487,7 +1486,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1558,7 +1557,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.1" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -1574,20 +1573,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T12:30:47+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.4", + "version": "v1.0.5", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1", "shasum": "" }, "require": { @@ -1596,7 +1595,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.44 || ^9.6.25", "uri-template/tests": "1.0.0" }, "type": "library", @@ -1644,7 +1643,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.5" }, "funding": [ { @@ -1660,7 +1659,7 @@ "type": "tidelift" } ], - "time": "2025-02-03T10:55:03+00:00" + "time": "2025-08-22T14:27:06+00:00" }, { "name": "hdvinnie/laravel-joypixel-emojis", @@ -2067,16 +2066,16 @@ }, { "name": "laravel/fortify", - "version": "v1.27.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/laravel/fortify.git", - "reference": "0fb2ec99dfee77ed66884668fc06683acca91ebd" + "reference": "005f4d535ae671312d267d942b964807fc0ef6f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/fortify/zipball/0fb2ec99dfee77ed66884668fc06683acca91ebd", - "reference": "0fb2ec99dfee77ed66884668fc06683acca91ebd", + "url": "https://api.github.com/repos/laravel/fortify/zipball/005f4d535ae671312d267d942b964807fc0ef6f8", + "reference": "005f4d535ae671312d267d942b964807fc0ef6f8", "shasum": "" }, "require": { @@ -2128,20 +2127,20 @@ "issues": "https://github.com/laravel/fortify/issues", "source": "https://github.com/laravel/fortify" }, - "time": "2025-06-11T14:30:52+00:00" + "time": "2025-08-29T20:15:47+00:00" }, { "name": "laravel/framework", - "version": "v12.20.0", + "version": "v12.26.4", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "1b9a00f8caf5503c92aa436279172beae1a484ff" + "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/1b9a00f8caf5503c92aa436279172beae1a484ff", - "reference": "1b9a00f8caf5503c92aa436279172beae1a484ff", + "url": "https://api.github.com/repos/laravel/framework/zipball/085a367a32ba86fcfa647bfc796098ae6f795b09", + "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09", "shasum": "" }, "require": { @@ -2181,7 +2180,9 @@ "symfony/http-kernel": "^7.2.0", "symfony/mailer": "^7.2.0", "symfony/mime": "^7.2.0", - "symfony/polyfill-php83": "^1.31", + "symfony/polyfill-php83": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php85": "^1.33", "symfony/process": "^7.2.0", "symfony/routing": "^7.2.0", "symfony/uid": "^7.2.0", @@ -2249,7 +2250,7 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^10.0.0", + "orchestra/testbench-core": "^10.6.3", "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", @@ -2343,20 +2344,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-07-08T15:02:21+00:00" + "time": "2025-08-29T14:15:53+00:00" }, { "name": "laravel/octane", - "version": "v2.11.0", + "version": "v2.12.1", "source": { "type": "git", "url": "https://github.com/laravel/octane.git", - "reference": "00e4d40047a24c267c9d3d0abfb47a6e27a7dc7f" + "reference": "4ca38b90d76f31b8c1e27873316c2db34450151c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/octane/zipball/00e4d40047a24c267c9d3d0abfb47a6e27a7dc7f", - "reference": "00e4d40047a24c267c9d3d0abfb47a6e27a7dc7f", + "url": "https://api.github.com/repos/laravel/octane/zipball/4ca38b90d76f31b8c1e27873316c2db34450151c", + "reference": "4ca38b90d76f31b8c1e27873316c2db34450151c", "shasum": "" }, "require": { @@ -2433,7 +2434,7 @@ "issues": "https://github.com/laravel/octane/issues", "source": "https://github.com/laravel/octane" }, - "time": "2025-06-28T17:28:13+00:00" + "time": "2025-07-25T15:03:05+00:00" }, { "name": "laravel/prompts", @@ -2496,16 +2497,16 @@ }, { "name": "laravel/scout", - "version": "v10.16.0", + "version": "v10.19.0", "source": { "type": "git", "url": "https://github.com/laravel/scout.git", - "reference": "5d56b6116a05d004e6a5d16a8ed95c2dc089b587" + "reference": "996b2a8b5ccc583e7df667c8aac924a46bc8bdd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/scout/zipball/5d56b6116a05d004e6a5d16a8ed95c2dc089b587", - "reference": "5d56b6116a05d004e6a5d16a8ed95c2dc089b587", + "url": "https://api.github.com/repos/laravel/scout/zipball/996b2a8b5ccc583e7df667c8aac924a46bc8bdd3", + "reference": "996b2a8b5ccc583e7df667c8aac924a46bc8bdd3", "shasum": "" }, "require": { @@ -2573,7 +2574,7 @@ "issues": "https://github.com/laravel/scout/issues", "source": "https://github.com/laravel/scout" }, - "time": "2025-07-08T15:09:47+00:00" + "time": "2025-08-26T14:24:24+00:00" }, { "name": "laravel/serializable-closure", @@ -2704,16 +2705,16 @@ }, { "name": "league/commonmark", - "version": "2.7.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405" + "reference": "10732241927d3971d28e7ea7b5712721fa2296ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", - "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca", + "reference": "10732241927d3971d28e7ea7b5712721fa2296ca", "shasum": "" }, "require": { @@ -2742,7 +2743,7 @@ "symfony/process": "^5.4 | ^6.0 | ^7.0", "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", "unleashedtech/php-coding-standard": "^3.1.1", - "vimeo/psalm": "^4.24.0 || ^5.0.0" + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, "suggest": { "symfony/yaml": "v2.3+ required if using the Front Matter extension" @@ -2807,7 +2808,7 @@ "type": "tidelift" } ], - "time": "2025-05-05T12:20:28+00:00" + "time": "2025-07-20T12:47:49+00:00" }, { "name": "league/config", @@ -3478,16 +3479,16 @@ }, { "name": "masterminds/html5", - "version": "2.9.0", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + "reference": "fcf91eb64359852f00d921887b219479b4f21251" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", "shasum": "" }, "require": { @@ -3539,9 +3540,9 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" }, - "time": "2024-03-31T07:05:07+00:00" + "time": "2025-07-25T09:04:22+00:00" }, { "name": "meilisearch/meilisearch-php", @@ -3714,16 +3715,16 @@ }, { "name": "nesbot/carbon", - "version": "3.10.1", + "version": "3.10.2", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00" + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/1fd1935b2d90aef2f093c5e35f7ae1257c448d00", - "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "shasum": "" }, "require": { @@ -3815,7 +3816,7 @@ "type": "tidelift" } ], - "time": "2025-06-21T15:19:35+00:00" + "time": "2025-08-02T09:36:06+00:00" }, { "name": "nette/schema", @@ -3881,29 +3882,29 @@ }, { "name": "nette/utils", - "version": "v4.0.7", + "version": "v4.0.8", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", "shasum": "" }, "require": { - "php": "8.0 - 8.4" + "php": "8.0 - 8.5" }, "conflict": { "nette/finder": "<3", "nette/schema": "<1.2.2" }, "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", + "jetbrains/phpstorm-attributes": "^1.2", "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -3921,6 +3922,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -3961,22 +3965,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.7" + "source": "https://github.com/nette/utils/tree/v4.0.8" }, - "time": "2025-06-03T04:55:08+00:00" + "time": "2025-08-06T21:43:34+00:00" }, { "name": "nikic/php-parser", - "version": "v5.5.0", + "version": "v5.6.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", "shasum": "" }, "require": { @@ -3995,7 +3999,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -4019,9 +4023,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" }, - "time": "2025-05-31T08:24:38+00:00" + "time": "2025-08-13T20:13:15+00:00" }, { "name": "nunomaduro/termwind", @@ -4258,16 +4262,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", "shasum": "" }, "require": { @@ -4275,7 +4279,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -4317,7 +4321,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" }, "funding": [ { @@ -4329,7 +4333,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-08-21T11:53:16+00:00" }, { "name": "pragmarx/google2fa", @@ -4846,16 +4850,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.9", + "version": "v0.12.10", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "1b801844becfe648985372cb4b12ad6840245ace" + "reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1b801844becfe648985372cb4b12ad6840245ace", - "reference": "1b801844becfe648985372cb4b12ad6840245ace", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/6e80abe6f2257121f1eb9a4c55bf29d921025b22", + "reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22", "shasum": "" }, "require": { @@ -4905,12 +4909,11 @@ "authors": [ { "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "email": "justin@justinhileman.info" } ], "description": "An interactive shell for modern PHP.", - "homepage": "http://psysh.org", + "homepage": "https://psysh.org", "keywords": [ "REPL", "console", @@ -4919,9 +4922,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.9" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.10" }, - "time": "2025-06-23T02:35:06+00:00" + "time": "2025-08-04T12:39:37+00:00" }, { "name": "ralouphie/getallheaders", @@ -5241,16 +5244,16 @@ }, { "name": "spatie/laravel-backup", - "version": "9.3.3", + "version": "9.3.4", "source": { "type": "git", "url": "https://github.com/spatie/laravel-backup.git", - "reference": "5820c1b50a8991c0c824c322c1c81f5724f4d41c" + "reference": "707e27eb1746296ac7e111179ec5da842f64e235" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/5820c1b50a8991c0c824c322c1c81f5724f4d41c", - "reference": "5820c1b50a8991c0c824c322c1c81f5724f4d41c", + "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/707e27eb1746296ac7e111179ec5da842f64e235", + "reference": "707e27eb1746296ac7e111179ec5da842f64e235", "shasum": "" }, "require": { @@ -5325,7 +5328,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-backup/issues", - "source": "https://github.com/spatie/laravel-backup/tree/9.3.3" + "source": "https://github.com/spatie/laravel-backup/tree/9.3.4" }, "funding": [ { @@ -5337,7 +5340,7 @@ "type": "other" } ], - "time": "2025-05-20T15:01:22+00:00" + "time": "2025-07-25T07:51:20+00:00" }, { "name": "spatie/laravel-cookie-consent", @@ -5877,16 +5880,16 @@ }, { "name": "symfony/console", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101" + "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101", - "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101", + "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", + "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", "shasum": "" }, "require": { @@ -5951,7 +5954,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.1" + "source": "https://github.com/symfony/console/tree/v7.3.3" }, "funding": [ { @@ -5962,12 +5965,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "symfony/css-selector", @@ -6103,16 +6110,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v6.4.23", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "22210aacb35dbadd772325d759d17bce2374a84d" + "reference": "976302990f9f2a6d4c07206836dd4ca77cae9524" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/22210aacb35dbadd772325d759d17bce2374a84d", - "reference": "22210aacb35dbadd772325d759d17bce2374a84d", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/976302990f9f2a6d4c07206836dd4ca77cae9524", + "reference": "976302990f9f2a6d4c07206836dd4ca77cae9524", "shasum": "" }, "require": { @@ -6150,7 +6157,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.23" + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.25" }, "funding": [ { @@ -6161,25 +6168,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-13T12:10:00+00:00" + "time": "2025-08-05T18:56:08+00:00" }, { "name": "symfony/error-handler", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "35b55b166f6752d6aaf21aa042fc5ed280fce235" + "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/35b55b166f6752d6aaf21aa042fc5ed280fce235", - "reference": "35b55b166f6752d6aaf21aa042fc5ed280fce235", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/0b31a944fcd8759ae294da4d2808cbc53aebd0c3", + "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3", "shasum": "" }, "require": { @@ -6227,7 +6238,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.1" + "source": "https://github.com/symfony/error-handler/tree/v7.3.2" }, "funding": [ { @@ -6238,25 +6249,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-13T07:48:40+00:00" + "time": "2025-07-07T08:17:57+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", "shasum": "" }, "require": { @@ -6307,7 +6322,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" }, "funding": [ { @@ -6318,12 +6333,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-22T09:11:45+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6403,16 +6422,16 @@ }, { "name": "symfony/finder", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { @@ -6447,7 +6466,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.0" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { @@ -6458,25 +6477,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-30T19:00:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "23dd60256610c86a3414575b70c596e5deff6ed9" + "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/23dd60256610c86a3414575b70c596e5deff6ed9", - "reference": "23dd60256610c86a3414575b70c596e5deff6ed9", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00", + "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00", "shasum": "" }, "require": { @@ -6526,7 +6549,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.1" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.3" }, "funding": [ { @@ -6537,25 +6560,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-23T15:07:14+00:00" + "time": "2025-08-20T08:04:18+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "1644879a66e4aa29c36fe33dfa6c54b450ce1831" + "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1644879a66e4aa29c36fe33dfa6c54b450ce1831", - "reference": "1644879a66e4aa29c36fe33dfa6c54b450ce1831", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b", + "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b", "shasum": "" }, "require": { @@ -6640,7 +6667,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.1" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.3" }, "funding": [ { @@ -6651,25 +6678,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-28T08:24:55+00:00" + "time": "2025-08-29T08:23:45+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368" + "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/b5db5105b290bdbea5ab27b89c69effcf1cb3368", - "reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368", + "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575", + "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575", "shasum": "" }, "require": { @@ -6720,7 +6751,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.1" + "source": "https://github.com/symfony/mailer/tree/v7.3.3" }, "funding": [ { @@ -6731,25 +6762,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/mime", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9" + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", + "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", "shasum": "" }, "require": { @@ -6804,7 +6839,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.0" + "source": "https://github.com/symfony/mime/tree/v7.3.2" }, "funding": [ { @@ -6815,16 +6850,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-19T08:51:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -6883,7 +6922,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -6894,6 +6933,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6903,16 +6946,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -6961,7 +7004,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -6972,16 +7015,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -7044,7 +7091,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -7055,6 +7102,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7064,7 +7115,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -7125,7 +7176,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -7136,6 +7187,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7145,7 +7200,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -7206,7 +7261,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -7217,6 +7272,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7291,7 +7350,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -7351,7 +7410,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -7362,6 +7421,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7371,16 +7434,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -7427,7 +7490,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -7438,16 +7501,180 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" + }, + { + "name": "symfony/polyfill-php84", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-24T13:30:11+00:00" + }, + { + "name": "symfony/polyfill-php85", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-23T16:12:55+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -7506,7 +7733,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -7517,6 +7744,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7526,16 +7757,16 @@ }, { "name": "symfony/process", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "reference": "32241012d521e2e8a9d713adb0812bb773b907f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1", + "reference": "32241012d521e2e8a9d713adb0812bb773b907f1", "shasum": "" }, "require": { @@ -7567,7 +7798,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/process/tree/v7.3.3" }, "funding": [ { @@ -7578,12 +7809,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2025-08-18T09:42:54+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -7670,16 +7905,16 @@ }, { "name": "symfony/routing", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "8e213820c5fea844ecea29203d2a308019007c15" + "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15", - "reference": "8e213820c5fea844ecea29203d2a308019007c15", + "url": "https://api.github.com/repos/symfony/routing/zipball/7614b8ca5fa89b9cd233e21b627bfc5774f586e4", + "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4", "shasum": "" }, "require": { @@ -7731,7 +7966,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.0" + "source": "https://github.com/symfony/routing/tree/v7.3.2" }, "funding": [ { @@ -7742,12 +7977,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T20:43:28+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/service-contracts", @@ -7834,16 +8073,16 @@ }, { "name": "symfony/string", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", "shasum": "" }, "require": { @@ -7901,7 +8140,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.0" + "source": "https://github.com/symfony/string/tree/v7.3.3" }, "funding": [ { @@ -7912,25 +8151,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-20T20:19:01+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "symfony/translation", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "241d5ac4910d256660238a7ecf250deba4c73063" + "reference": "e0837b4cbcef63c754d89a4806575cada743a38d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/241d5ac4910d256660238a7ecf250deba4c73063", - "reference": "241d5ac4910d256660238a7ecf250deba4c73063", + "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d", + "reference": "e0837b4cbcef63c754d89a4806575cada743a38d", "shasum": "" }, "require": { @@ -7997,7 +8240,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.1" + "source": "https://github.com/symfony/translation/tree/v7.3.3" }, "funding": [ { @@ -8008,12 +8251,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-01T21:02:37+00:00" }, { "name": "symfony/translation-contracts", @@ -8169,16 +8416,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42" + "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", - "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", + "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", "shasum": "" }, "require": { @@ -8190,7 +8437,6 @@ "symfony/console": "<6.4" }, "require-dev": { - "ext-iconv": "*", "symfony/console": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", @@ -8233,7 +8479,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.1" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.3" }, "funding": [ { @@ -8244,12 +8490,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "theodorejb/polycast", @@ -8634,16 +8884,16 @@ "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.15.4", + "version": "v3.16.0", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "c0667ea91f7185f1e074402c5788195e96bf8106" + "reference": "f265cf5e38577d42311f1a90d619bcd3740bea23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/c0667ea91f7185f1e074402c5788195e96bf8106", - "reference": "c0667ea91f7185f1e074402c5788195e96bf8106", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f265cf5e38577d42311f1a90d619bcd3740bea23", + "reference": "f265cf5e38577d42311f1a90d619bcd3740bea23", "shasum": "" }, "require": { @@ -8651,7 +8901,7 @@ "illuminate/session": "^9|^10|^11|^12", "illuminate/support": "^9|^10|^11|^12", "php": "^8.1", - "php-debugbar/php-debugbar": "~2.1.1", + "php-debugbar/php-debugbar": "~2.2.0", "symfony/finder": "^6|^7" }, "require-dev": { @@ -8671,7 +8921,7 @@ ] }, "branch-alias": { - "dev-master": "3.15-dev" + "dev-master": "3.16-dev" } }, "autoload": { @@ -8703,7 +8953,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.15.4" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.16.0" }, "funding": [ { @@ -8715,20 +8965,20 @@ "type": "github" } ], - "time": "2025-04-16T06:32:06+00:00" + "time": "2025-07-14T11:56:43+00:00" }, { "name": "brianium/paratest", - "version": "v7.8.3", + "version": "v7.12.0", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "a585c346ddf1bec22e51e20b5387607905604a71" + "reference": "6a34ddb12a3bd5bd07d831ce95f111087f3bcbd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/a585c346ddf1bec22e51e20b5387607905604a71", - "reference": "a585c346ddf1bec22e51e20b5387607905604a71", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/6a34ddb12a3bd5bd07d831ce95f111087f3bcbd8", + "reference": "6a34ddb12a3bd5bd07d831ce95f111087f3bcbd8", "shasum": "" }, "require": { @@ -8736,27 +8986,28 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-simplexml": "*", - "fidry/cpu-core-counter": "^1.2.0", - "jean85/pretty-package-versions": "^2.1.0", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "phpunit/php-code-coverage": "^11.0.9 || ^12.0.4", - "phpunit/php-file-iterator": "^5.1.0 || ^6", - "phpunit/php-timer": "^7.0.1 || ^8", - "phpunit/phpunit": "^11.5.11 || ^12.0.6", - "sebastian/environment": "^7.2.0 || ^8", - "symfony/console": "^6.4.17 || ^7.2.1", - "symfony/process": "^6.4.19 || ^7.2.4" + "fidry/cpu-core-counter": "^1.3.0", + "jean85/pretty-package-versions": "^2.1.1", + "php": "~8.3.0 || ~8.4.0 || ~8.5.0", + "phpunit/php-code-coverage": "^12.3.2", + "phpunit/php-file-iterator": "^6", + "phpunit/php-timer": "^8", + "phpunit/phpunit": "^12.3.6", + "sebastian/environment": "^8.0.3", + "symfony/console": "^6.4.20 || ^7.3.2", + "symfony/process": "^6.4.20 || ^7.3.0" }, "require-dev": { - "doctrine/coding-standard": "^12.0.0", + "doctrine/coding-standard": "^13.0.1", + "ext-pcntl": "*", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.6", - "phpstan/phpstan-deprecation-rules": "^2.0.1", - "phpstan/phpstan-phpunit": "^2.0.4", - "phpstan/phpstan-strict-rules": "^2.0.3", - "squizlabs/php_codesniffer": "^3.11.3", - "symfony/filesystem": "^6.4.13 || ^7.2.0" + "phpstan/phpstan": "^2.1.22", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.6", + "squizlabs/php_codesniffer": "^3.13.2", + "symfony/filesystem": "^6.4.13 || ^7.3.2" }, "bin": [ "bin/paratest", @@ -8796,7 +9047,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.8.3" + "source": "https://github.com/paratestphp/paratest/tree/v7.12.0" }, "funding": [ { @@ -8808,7 +9059,7 @@ "type": "paypal" } ], - "time": "2025-03-05T08:29:11+00:00" + "time": "2025-08-29T05:28:31+00:00" }, { "name": "calebdw/larastan", @@ -8913,16 +9164,16 @@ }, { "name": "calebdw/larastan-livewire", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/calebdw/larastan-livewire.git", - "reference": "ae9525f1023111f47e0029bfbd43d7f7e48dbb44" + "reference": "fb537cd27374af153c4489f059a235cf6bea11f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/calebdw/larastan-livewire/zipball/ae9525f1023111f47e0029bfbd43d7f7e48dbb44", - "reference": "ae9525f1023111f47e0029bfbd43d7f7e48dbb44", + "url": "https://api.github.com/repos/calebdw/larastan-livewire/zipball/fb537cd27374af153c4489f059a235cf6bea11f8", + "reference": "fb537cd27374af153c4489f059a235cf6bea11f8", "shasum": "" }, "require": { @@ -8967,7 +9218,7 @@ ], "support": { "issues": "https://github.com/calebdw/larastan-livewire/issues", - "source": "https://github.com/calebdw/larastan-livewire/tree/v2.2.0" + "source": "https://github.com/calebdw/larastan-livewire/tree/v2.3.0" }, "funding": [ { @@ -8975,7 +9226,7 @@ "type": "github" } ], - "time": "2025-04-30T14:43:33+00:00" + "time": "2025-08-20T14:52:29+00:00" }, { "name": "fakerphp/faker", @@ -9042,16 +9293,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "8520451a140d3f46ac33042715115e290cf5785f" + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", - "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { @@ -9061,10 +9312,10 @@ "fidry/makefile": "^0.2.0", "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, @@ -9091,7 +9342,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, "funding": [ { @@ -9099,20 +9350,20 @@ "type": "github" } ], - "time": "2024-08-06T10:04:20+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { "name": "filp/whoops", - "version": "2.18.3", + "version": "2.18.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "59a123a3d459c5a23055802237cb317f609867e5" + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", - "reference": "59a123a3d459c5a23055802237cb317f609867e5", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { @@ -9162,7 +9413,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.3" + "source": "https://github.com/filp/whoops/tree/2.18.4" }, "funding": [ { @@ -9170,7 +9421,7 @@ "type": "github" } ], - "time": "2025-06-16T00:02:10+00:00" + "time": "2025-08-08T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -9335,16 +9586,16 @@ }, { "name": "laravel/pint", - "version": "v1.20.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "53072e8ea22213a7ed168a8a15b96fbb8b82d44b" + "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/53072e8ea22213a7ed168a8a15b96fbb8b82d44b", - "reference": "53072e8ea22213a7ed168a8a15b96fbb8b82d44b", + "url": "https://api.github.com/repos/laravel/pint/zipball/0345f3b05f136801af8c339f9d16ef29e6b4df8a", + "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a", "shasum": "" }, "require": { @@ -9352,15 +9603,15 @@ "ext-mbstring": "*", "ext-tokenizer": "*", "ext-xml": "*", - "php": "^8.1.0" + "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.66.0", - "illuminate/view": "^10.48.25", - "larastan/larastan": "^2.9.12", - "laravel-zero/framework": "^10.48.25", + "friendsofphp/php-cs-fixer": "^3.82.2", + "illuminate/view": "^11.45.1", + "larastan/larastan": "^3.5.0", + "laravel-zero/framework": "^11.45.0", "mockery/mockery": "^1.6.12", - "nunomaduro/termwind": "^1.17.0", + "nunomaduro/termwind": "^2.3.1", "pestphp/pest": "^2.36.0" }, "bin": [ @@ -9368,6 +9619,9 @@ ], "type": "project", "autoload": { + "files": [ + "overrides/Runner/Parallel/ProcessFactory.php" + ], "psr-4": { "App\\": "app/", "Database\\Seeders\\": "database/seeders/", @@ -9397,20 +9651,20 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2025-01-14T16:20:53+00:00" + "time": "2025-07-10T18:09:32+00:00" }, { "name": "laravel/sail", - "version": "v1.43.1", + "version": "v1.45.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72" + "reference": "019a2933ff4a9199f098d4259713f9bc266a874e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/3e7d899232a8c5e3ea4fc6dee7525ad583887e72", - "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72", + "url": "https://api.github.com/repos/laravel/sail/zipball/019a2933ff4a9199f098d4259713f9bc266a874e", + "reference": "019a2933ff4a9199f098d4259713f9bc266a874e", "shasum": "" }, "require": { @@ -9460,7 +9714,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2025-05-19T13:19:21+00:00" + "time": "2025-08-25T19:28:31+00:00" }, { "name": "mockery/mockery", @@ -9547,16 +9801,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.13.3", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", - "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -9595,7 +9849,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -9603,7 +9857,7 @@ "type": "tidelift" } ], - "time": "2025-07-05T12:25:42+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "nunomaduro/collision", @@ -9706,38 +9960,41 @@ }, { "name": "pestphp/pest", - "version": "v3.8.2", + "version": "v4.0.4", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "c6244a8712968dbac88eb998e7ff3b5caa556b0d" + "reference": "47fb1d77631d608022cc7af96cac90ac741c8394" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/c6244a8712968dbac88eb998e7ff3b5caa556b0d", - "reference": "c6244a8712968dbac88eb998e7ff3b5caa556b0d", + "url": "https://api.github.com/repos/pestphp/pest/zipball/47fb1d77631d608022cc7af96cac90ac741c8394", + "reference": "47fb1d77631d608022cc7af96cac90ac741c8394", "shasum": "" }, "require": { - "brianium/paratest": "^7.8.3", - "nunomaduro/collision": "^8.8.0", - "nunomaduro/termwind": "^2.3.0", - "pestphp/pest-plugin": "^3.0.0", - "pestphp/pest-plugin-arch": "^3.1.0", - "pestphp/pest-plugin-mutate": "^3.0.5", - "php": "^8.2.0", - "phpunit/phpunit": "^11.5.15" + "brianium/paratest": "^7.11.2", + "nunomaduro/collision": "^8.8.2", + "nunomaduro/termwind": "^2.3.1", + "pestphp/pest-plugin": "^4.0.0", + "pestphp/pest-plugin-arch": "^4.0.0", + "pestphp/pest-plugin-mutate": "^4.0.1", + "pestphp/pest-plugin-profanity": "^4.0.1", + "php": "^8.3.0", + "phpunit/phpunit": "^12.3.7", + "symfony/process": "^7.3.0" }, "conflict": { - "filp/whoops": "<2.16.0", - "phpunit/phpunit": ">11.5.15", - "sebastian/exporter": "<6.0.0", + "filp/whoops": "<2.18.3", + "phpunit/phpunit": ">12.3.7", + "sebastian/exporter": "<7.0.0", "webmozart/assert": "<1.11.0" }, "require-dev": { - "pestphp/pest-dev-tools": "^3.4.0", - "pestphp/pest-plugin-type-coverage": "^3.5.0", - "symfony/process": "^7.2.5" + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-browser": "^4.0.2", + "pestphp/pest-plugin-type-coverage": "^4.0.2", + "psy/psysh": "^0.12.10" }, "bin": [ "bin/pest" @@ -9763,6 +10020,7 @@ "Pest\\Plugins\\Snapshot", "Pest\\Plugins\\Verbose", "Pest\\Plugins\\Version", + "Pest\\Plugins\\Shard", "Pest\\Plugins\\Parallel" ] }, @@ -9802,7 +10060,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v3.8.2" + "source": "https://github.com/pestphp/pest/tree/v4.0.4" }, "funding": [ { @@ -9814,34 +10072,34 @@ "type": "github" } ], - "time": "2025-04-17T10:53:02+00:00" + "time": "2025-08-28T18:19:42+00:00" }, { "name": "pestphp/pest-plugin", - "version": "v3.0.0", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin.git", - "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83" + "reference": "9d4b93d7f73d3f9c3189bb22c220fef271cdf568" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/e79b26c65bc11c41093b10150c1341cc5cdbea83", - "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83", + "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/9d4b93d7f73d3f9c3189bb22c220fef271cdf568", + "reference": "9d4b93d7f73d3f9c3189bb22c220fef271cdf568", "shasum": "" }, "require": { "composer-plugin-api": "^2.0.0", "composer-runtime-api": "^2.2.2", - "php": "^8.2" + "php": "^8.3" }, "conflict": { - "pestphp/pest": "<3.0.0" + "pestphp/pest": "<4.0.0" }, "require-dev": { - "composer/composer": "^2.7.9", - "pestphp/pest": "^3.0.0", - "pestphp/pest-dev-tools": "^3.0.0" + "composer/composer": "^2.8.10", + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0" }, "type": "composer-plugin", "extra": { @@ -9868,7 +10126,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin/tree/v3.0.0" + "source": "https://github.com/pestphp/pest-plugin/tree/v4.0.0" }, "funding": [ { @@ -9884,30 +10142,30 @@ "type": "patreon" } ], - "time": "2024-09-08T23:21:41+00:00" + "time": "2025-08-20T12:35:58+00:00" }, { "name": "pestphp/pest-plugin-arch", - "version": "v3.1.1", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin-arch.git", - "reference": "db7bd9cb1612b223e16618d85475c6f63b9c8daa" + "reference": "25bb17e37920ccc35cbbcda3b00d596aadf3e58d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/db7bd9cb1612b223e16618d85475c6f63b9c8daa", - "reference": "db7bd9cb1612b223e16618d85475c6f63b9c8daa", + "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/25bb17e37920ccc35cbbcda3b00d596aadf3e58d", + "reference": "25bb17e37920ccc35cbbcda3b00d596aadf3e58d", "shasum": "" }, "require": { - "pestphp/pest-plugin": "^3.0.0", - "php": "^8.2", - "ta-tikoma/phpunit-architecture-test": "^0.8.4" + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3", + "ta-tikoma/phpunit-architecture-test": "^0.8.5" }, "require-dev": { - "pestphp/pest": "^3.8.1", - "pestphp/pest-dev-tools": "^3.4.0" + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0" }, "type": "library", "extra": { @@ -9942,7 +10200,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-arch/tree/v3.1.1" + "source": "https://github.com/pestphp/pest-plugin-arch/tree/v4.0.0" }, "funding": [ { @@ -9954,31 +10212,31 @@ "type": "github" } ], - "time": "2025-04-16T22:59:48+00:00" + "time": "2025-08-20T13:10:51+00:00" }, { "name": "pestphp/pest-plugin-laravel", - "version": "v3.2.0", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin-laravel.git", - "reference": "6801be82fd92b96e82dd72e563e5674b1ce365fc" + "reference": "e12a07046b826a40b1c8632fd7b80d6b8d7b628e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/6801be82fd92b96e82dd72e563e5674b1ce365fc", - "reference": "6801be82fd92b96e82dd72e563e5674b1ce365fc", + "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/e12a07046b826a40b1c8632fd7b80d6b8d7b628e", + "reference": "e12a07046b826a40b1c8632fd7b80d6b8d7b628e", "shasum": "" }, "require": { - "laravel/framework": "^11.39.1|^12.9.2", - "pestphp/pest": "^3.8.2", - "php": "^8.2.0" + "laravel/framework": "^11.45.2|^12.25.0", + "pestphp/pest": "^4.0.0", + "php": "^8.3.0" }, "require-dev": { - "laravel/dusk": "^8.2.13|dev-develop", - "orchestra/testbench": "^9.9.0|^10.2.1", - "pestphp/pest-dev-tools": "^3.4.0" + "laravel/dusk": "^8.3.3", + "orchestra/testbench": "^9.13.0|^10.5.0", + "pestphp/pest-dev-tools": "^4.0.0" }, "type": "library", "extra": { @@ -10016,7 +10274,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v3.2.0" + "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v4.0.0" }, "funding": [ { @@ -10028,30 +10286,30 @@ "type": "github" } ], - "time": "2025-04-21T07:40:53+00:00" + "time": "2025-08-20T12:46:37+00:00" }, { "name": "pestphp/pest-plugin-livewire", - "version": "v3.0.0", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin-livewire.git", - "reference": "e2f2edb0a7d414d6837d87908a0e148256d3bf89" + "reference": "cc30502ef62487d9a0bec5e73b64d59eec3b5f42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-livewire/zipball/e2f2edb0a7d414d6837d87908a0e148256d3bf89", - "reference": "e2f2edb0a7d414d6837d87908a0e148256d3bf89", + "url": "https://api.github.com/repos/pestphp/pest-plugin-livewire/zipball/cc30502ef62487d9a0bec5e73b64d59eec3b5f42", + "reference": "cc30502ef62487d9a0bec5e73b64d59eec3b5f42", "shasum": "" }, "require": { - "livewire/livewire": "^3.5.6", - "pestphp/pest": "^3.0.0", - "php": "^8.1" + "livewire/livewire": "^3.6.4", + "pestphp/pest": "^4.0.0", + "php": "^8.3" }, "require-dev": { - "orchestra/testbench": "^9.4.0", - "pestphp/pest-dev-tools": "^3.0.0" + "orchestra/testbench": "^10.6.0", + "pestphp/pest-dev-tools": "^4.0.0" }, "type": "library", "autoload": { @@ -10078,7 +10336,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-livewire/tree/v3.0.0" + "source": "https://github.com/pestphp/pest-plugin-livewire/tree/v4.0.1" }, "funding": [ { @@ -10094,32 +10352,32 @@ "type": "patreon" } ], - "time": "2024-09-09T00:05:59+00:00" + "time": "2025-08-21T09:16:34+00:00" }, { "name": "pestphp/pest-plugin-mutate", - "version": "v3.0.5", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin-mutate.git", - "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08" + "reference": "d9b32b60b2385e1688a68cc227594738ec26d96c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/e10dbdc98c9e2f3890095b4fe2144f63a5717e08", - "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08", + "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/d9b32b60b2385e1688a68cc227594738ec26d96c", + "reference": "d9b32b60b2385e1688a68cc227594738ec26d96c", "shasum": "" }, "require": { - "nikic/php-parser": "^5.2.0", - "pestphp/pest-plugin": "^3.0.0", - "php": "^8.2", + "nikic/php-parser": "^5.6.1", + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3", "psr/simple-cache": "^3.0.0" }, "require-dev": { - "pestphp/pest": "^3.0.8", - "pestphp/pest-dev-tools": "^3.0.0", - "pestphp/pest-plugin-type-coverage": "^3.0.0" + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-type-coverage": "^4.0.0" }, "type": "library", "autoload": { @@ -10132,6 +10390,10 @@ "MIT" ], "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + }, { "name": "Sandro Gehri", "email": "sandrogehri@gmail.com" @@ -10150,7 +10412,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v3.0.5" + "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v4.0.1" }, "funding": [ { @@ -10166,7 +10428,63 @@ "type": "github" } ], - "time": "2024-09-22T07:54:40+00:00" + "time": "2025-08-21T20:19:25+00:00" + }, + { + "name": "pestphp/pest-plugin-profanity", + "version": "v4.0.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-profanity.git", + "reference": "823d5d8ae07a265c70f5e1a9ce50639543b0bf11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/823d5d8ae07a265c70f5e1a9ce50639543b0bf11", + "reference": "823d5d8ae07a265c70f5e1a9ce50639543b0bf11", + "shasum": "" + }, + "require": { + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3" + }, + "require-dev": { + "faissaloux/pest-plugin-inside": "^1.9", + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Profanity\\Plugin" + ] + } + }, + "autoload": { + "psr-4": { + "Pest\\Profanity\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest Profanity Plugin", + "keywords": [ + "framework", + "pest", + "php", + "plugin", + "profanity", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.0.1" + }, + "time": "2025-08-20T12:58:03+00:00" }, { "name": "phar-io/manifest", @@ -10288,16 +10606,16 @@ }, { "name": "php-debugbar/php-debugbar", - "version": "v2.1.6", + "version": "v2.2.4", "source": { "type": "git", "url": "https://github.com/php-debugbar/php-debugbar.git", - "reference": "16fa68da5617220594aa5e33fa9de415f94784a0" + "reference": "3146d04671f51f69ffec2a4207ac3bdcf13a9f35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/16fa68da5617220594aa5e33fa9de415f94784a0", - "reference": "16fa68da5617220594aa5e33fa9de415f94784a0", + "url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/3146d04671f51f69ffec2a4207ac3bdcf13a9f35", + "reference": "3146d04671f51f69ffec2a4207ac3bdcf13a9f35", "shasum": "" }, "require": { @@ -10305,6 +10623,9 @@ "psr/log": "^1|^2|^3", "symfony/var-dumper": "^4|^5|^6|^7" }, + "replace": { + "maximebf/debugbar": "self.version" + }, "require-dev": { "dbrekelmans/bdi": "^1", "phpunit/phpunit": "^8|^9", @@ -10319,7 +10640,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -10352,9 +10673,9 @@ ], "support": { "issues": "https://github.com/php-debugbar/php-debugbar/issues", - "source": "https://github.com/php-debugbar/php-debugbar/tree/v2.1.6" + "source": "https://github.com/php-debugbar/php-debugbar/tree/v2.2.4" }, - "time": "2025-02-21T17:47:03+00:00" + "time": "2025-07-22T14:01:30+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -10411,16 +10732,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.2", + "version": "5.6.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", - "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", "shasum": "" }, "require": { @@ -10469,9 +10790,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" }, - "time": "2025-04-13T19:20:35+00:00" + "time": "2025-08-01T19:43:32+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -10533,16 +10854,16 @@ }, { "name": "phpmyadmin/sql-parser", - "version": "5.11.0", + "version": "5.11.1", "source": { "type": "git", "url": "https://github.com/phpmyadmin/sql-parser.git", - "reference": "07044bc8c13abd542756c3fd34dc66a5d6dee8e4" + "reference": "1b70d03526df92bd1e170e2670b7d3510e1b722b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/07044bc8c13abd542756c3fd34dc66a5d6dee8e4", - "reference": "07044bc8c13abd542756c3fd34dc66a5d6dee8e4", + "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/1b70d03526df92bd1e170e2670b7d3510e1b722b", + "reference": "1b70d03526df92bd1e170e2670b7d3510e1b722b", "shasum": "" }, "require": { @@ -10618,7 +10939,7 @@ "type": "other" } ], - "time": "2025-02-22T20:00:59+00:00" + "time": "2025-07-20T15:49:56+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -10669,16 +10990,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.18", + "version": "2.1.22", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "ee1f390b7a70cdf74a2b737e554f68afea885db7" + "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee1f390b7a70cdf74a2b737e554f68afea885db7", - "reference": "ee1f390b7a70cdf74a2b737e554f68afea885db7", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4", + "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4", "shasum": "" }, "require": { @@ -10723,20 +11044,20 @@ "type": "github" } ], - "time": "2025-07-17T17:22:31+00:00" + "time": "2025-08-04T19:17:37+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "11.0.10", + "version": "12.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1a800a7446add2d79cc6b3c01c45381810367d76" + "reference": "7ad0e9bdc72b147600badccd694a2e57ffc9297a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76", - "reference": "1a800a7446add2d79cc6b3c01c45381810367d76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7ad0e9bdc72b147600badccd694a2e57ffc9297a", + "reference": "7ad0e9bdc72b147600badccd694a2e57ffc9297a", "shasum": "" }, "require": { @@ -10744,18 +11065,17 @@ "ext-libxml": "*", "ext-xmlwriter": "*", "nikic/php-parser": "^5.4.0", - "php": ">=8.2", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-text-template": "^4.0.1", - "sebastian/code-unit-reverse-lookup": "^4.0.1", - "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.0", - "sebastian/lines-of-code": "^3.0.1", - "sebastian/version": "^5.0.2", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^12.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -10764,7 +11084,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0.x-dev" + "dev-main": "12.3.x-dev" } }, "autoload": { @@ -10793,7 +11113,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.4" }, "funding": [ { @@ -10813,32 +11133,32 @@ "type": "tidelift" } ], - "time": "2025-06-18T08:56:18+00:00" + "time": "2025-08-29T11:32:44+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -10866,7 +11186,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" }, "funding": [ { @@ -10874,28 +11194,28 @@ "type": "github" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2025-02-07T04:58:37+00:00" }, { "name": "phpunit/php-invoker", - "version": "5.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-pcntl": "*" @@ -10903,7 +11223,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -10930,7 +11250,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" }, "funding": [ { @@ -10938,32 +11258,32 @@ "type": "github" } ], - "time": "2024-07-03T05:07:44+00:00" + "time": "2025-02-07T04:58:58+00:00" }, { "name": "phpunit/php-text-template", - "version": "4.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -10990,7 +11310,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" }, "funding": [ { @@ -10998,32 +11318,32 @@ "type": "github" } ], - "time": "2024-07-03T05:08:43+00:00" + "time": "2025-02-07T04:59:16+00:00" }, { "name": "phpunit/php-timer", - "version": "7.0.1", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -11050,7 +11370,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", "security": "https://github.com/sebastianbergmann/php-timer/security/policy", - "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" }, "funding": [ { @@ -11058,20 +11378,20 @@ "type": "github" } ], - "time": "2024-07-03T05:09:35+00:00" + "time": "2025-02-07T04:59:38+00:00" }, { "name": "phpunit/phpunit", - "version": "11.5.15", + "version": "12.3.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c" + "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", - "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b8fa997c49682979ad6bfaa0d7fb25f54954965e", + "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e", "shasum": "" }, "require": { @@ -11081,37 +11401,33 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.0", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.9", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-invoker": "^5.0.1", - "phpunit/php-text-template": "^4.0.1", - "phpunit/php-timer": "^7.0.1", - "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.1", - "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.0", - "sebastian/exporter": "^6.3.0", - "sebastian/global-state": "^7.0.2", - "sebastian/object-enumerator": "^6.0.1", - "sebastian/type": "^5.1.2", - "sebastian/version": "^5.0.2", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.3.3", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.0.0", + "sebastian/comparator": "^7.1.3", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.3", + "sebastian/exporter": "^7.0.0", + "sebastian/global-state": "^8.0.0", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.3", + "sebastian/version": "^6.0.0", "staabm/side-effects-detector": "^1.0.5" }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" - }, "bin": [ "phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-main": "11.5-dev" + "dev-main": "12.3-dev" } }, "autoload": { @@ -11143,7 +11459,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.7" }, "funding": [ { @@ -11154,12 +11470,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-03-23T16:02:11+00:00" + "time": "2025-08-28T05:15:46+00:00" }, { "name": "ryoluo/sail-ssl", @@ -11225,28 +11549,28 @@ }, { "name": "sebastian/cli-parser", - "version": "3.0.2", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/6d584c727d9114bcdc14c86711cd1cad51778e7c", + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -11270,7 +11594,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.0.0" }, "funding": [ { @@ -11278,144 +11602,31 @@ "type": "github" } ], - "time": "2024-07-03T04:41:36+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "security": "https://github.com/sebastianbergmann/code-unit/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2025-03-19T07:56:08+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-07-03T04:45:54+00:00" + "time": "2025-02-07T04:53:50+00:00" }, { "name": "sebastian/comparator", - "version": "6.3.1", + "version": "7.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/diff": "^6.0", - "sebastian/exporter": "^6.0" + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^11.4" + "phpunit/phpunit": "^12.2" }, "suggest": { "ext-bcmath": "For comparing BcMath\\Number objects" @@ -11423,7 +11634,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "7.1-dev" } }, "autoload": { @@ -11463,41 +11674,53 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2025-03-07T06:57:01+00:00" + "time": "2025-08-20T11:27:00+00:00" }, { "name": "sebastian/complexity", - "version": "4.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -11521,7 +11744,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" }, "funding": [ { @@ -11529,33 +11752,33 @@ "type": "github" } ], - "time": "2024-07-03T04:49:50+00:00" + "time": "2025-02-07T04:55:25+00:00" }, { "name": "sebastian/diff", - "version": "6.0.2", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -11588,7 +11811,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" }, "funding": [ { @@ -11596,27 +11819,27 @@ "type": "github" } ], - "time": "2024-07-03T04:53:05+00:00" + "time": "2025-02-07T04:55:46+00:00" }, { "name": "sebastian/environment", - "version": "7.2.1", + "version": "8.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-posix": "*" @@ -11624,7 +11847,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "7.2-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -11652,7 +11875,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3" }, "funding": [ { @@ -11672,34 +11895,34 @@ "type": "tidelift" } ], - "time": "2025-05-21T11:55:47+00:00" + "time": "2025-08-12T14:11:56+00:00" }, { "name": "sebastian/exporter", - "version": "6.3.0", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + "reference": "76432aafc58d50691a00d86d0632f1217a47b688" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/76432aafc58d50691a00d86d0632f1217a47b688", + "reference": "76432aafc58d50691a00d86d0632f1217a47b688", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/recursion-context": "^6.0" + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -11742,7 +11965,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.0" }, "funding": [ { @@ -11750,35 +11973,35 @@ "type": "github" } ], - "time": "2024-12-05T09:17:50+00:00" + "time": "2025-02-07T04:56:42+00:00" }, { "name": "sebastian/global-state", - "version": "7.0.2", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + "reference": "ef1377171613d09edd25b7816f05be8313f9115d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -11804,41 +12027,53 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2024-07-03T04:57:36+00:00" + "time": "2025-08-29T11:29:25+00:00" }, { "name": "sebastian/lines-of-code", - "version": "3.0.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -11862,7 +12097,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" }, "funding": [ { @@ -11870,34 +12105,34 @@ "type": "github" } ], - "time": "2024-07-03T04:58:38+00:00" + "time": "2025-02-07T04:57:28+00:00" }, { "name": "sebastian/object-enumerator", - "version": "6.0.1", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -11920,7 +12155,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" }, "funding": [ { @@ -11928,32 +12163,32 @@ "type": "github" } ], - "time": "2024-07-03T05:00:13+00:00" + "time": "2025-02-07T04:57:48+00:00" }, { "name": "sebastian/object-reflector", - "version": "4.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -11976,7 +12211,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" }, "funding": [ { @@ -11984,32 +12219,32 @@ "type": "github" } ], - "time": "2024-07-03T05:01:32+00:00" + "time": "2025-02-07T04:58:17+00:00" }, { "name": "sebastian/recursion-context", - "version": "6.0.2", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -12040,40 +12275,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2024-07-03T05:10:34+00:00" + "time": "2025-08-13T04:44:59+00:00" }, { "name": "sebastian/type", - "version": "5.1.2", + "version": "6.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -12097,37 +12344,49 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + "source": "https://github.com/sebastianbergmann/type/tree/6.0.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "time": "2025-03-18T13:35:50+00:00" + "time": "2025-08-09T06:57:12+00:00" }, { "name": "sebastian/version", - "version": "5.0.2", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -12151,7 +12410,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/version/issues", "security": "https://github.com/sebastianbergmann/version/security/policy", - "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" }, "funding": [ { @@ -12159,20 +12418,20 @@ "type": "github" } ], - "time": "2024-10-09T05:16:32+00:00" + "time": "2025-02-07T05:00:38+00:00" }, { "name": "spatie/backtrace", - "version": "1.7.4", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/spatie/backtrace.git", - "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe" + "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/cd37a49fce7137359ac30ecc44ef3e16404cccbe", - "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/8c0f16a59ae35ec8c62d85c3c17585158f430110", + "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110", "shasum": "" }, "require": { @@ -12210,7 +12469,8 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/backtrace/tree/1.7.4" + "issues": "https://github.com/spatie/backtrace/issues", + "source": "https://github.com/spatie/backtrace/tree/1.8.1" }, "funding": [ { @@ -12222,7 +12482,7 @@ "type": "other" } ], - "time": "2025-05-08T15:41:09+00:00" + "time": "2025-08-26T08:22:30+00:00" }, { "name": "spatie/error-solutions", @@ -12595,16 +12855,16 @@ }, { "name": "symfony/yaml", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0c3555045a46ab3cd4cc5a69d161225195230edb" + "reference": "d4f4a66866fe2451f61296924767280ab5732d9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0c3555045a46ab3cd4cc5a69d161225195230edb", - "reference": "0c3555045a46ab3cd4cc5a69d161225195230edb", + "url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d", + "reference": "d4f4a66866fe2451f61296924767280ab5732d9d", "shasum": "" }, "require": { @@ -12647,7 +12907,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.1" + "source": "https://github.com/symfony/yaml/tree/v7.3.3" }, "funding": [ { @@ -12658,12 +12918,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-03T06:57:57+00:00" + "time": "2025-08-27T11:34:33+00:00" }, { "name": "ta-tikoma/phpunit-architecture-test", diff --git a/config/unit3d.php b/config/unit3d.php index 1ad069374..991066360 100755 --- a/config/unit3d.php +++ b/config/unit3d.php @@ -24,7 +24,7 @@ return [ | */ - 'powered-by' => 'Powered By UNIT3D v9.1.5', + 'powered-by' => 'Powered By UNIT3D v9.1.6', /* |-------------------------------------------------------------------------- @@ -46,7 +46,7 @@ return [ | */ - 'version' => 'v9.1.5', + 'version' => 'v9.1.6', /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2025_02_17_074140_update_columns_to_boolean.php b/database/migrations/2025_02_17_074140_update_columns_to_boolean.php index 552c67136..da32acf8c 100644 --- a/database/migrations/2025_02_17_074140_update_columns_to_boolean.php +++ b/database/migrations/2025_02_17_074140_update_columns_to_boolean.php @@ -16,6 +16,7 @@ declare(strict_types=1); use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; return new class () extends Migration { @@ -24,6 +25,14 @@ return new class () extends Migration { */ public function up(): void { + DB::table('tickets')->whereNull('user_read')->update([ + 'user_read' => false, + ]); + + DB::table('tickets')->whereNull('staff_read')->update([ + 'staff_read' => false, + ]); + Schema::table('tickets', function (Blueprint $table): void { $table->boolean('user_read')->default(false)->change(); $table->boolean('staff_read')->default(false)->change(); diff --git a/database/migrations/2025_02_23_221840_move_public_files_to_private.php b/database/migrations/2025_02_23_221840_move_public_files_to_private.php index 63d47332e..80d291ddd 100644 --- a/database/migrations/2025_02_23_221840_move_public_files_to_private.php +++ b/database/migrations/2025_02_23_221840_move_public_files_to_private.php @@ -28,38 +28,38 @@ return new class () extends Migration { $locations = [ [ - 'baseNames' => DB::table('articles')->whereNotNull('image')->pluck('image')->toArray(), + 'baseNames' => DB::table('articles')->whereNotNull('image')->where('image', '!=', '')->pluck('image')->toArray(), 'oldDirectory' => public_path('files/img'), 'newDirectory' => storage_path('app/images/articles/images'), ], [ - 'baseNames' => DB::table('ticket_attachments')->pluck('file_name')->toArray(), + 'baseNames' => DB::table('ticket_attachments')->where('file_name', '!=', '')->pluck('file_name')->toArray(), 'oldDirectory' => public_path('files/attachments'), 'newDirectory' => storage_path('app/files/attachments/files'), ], [ // cspell:ignore profil - 'baseNames' => DB::table('users')->whereNotNull('image')->whereNotIn('image', ['profil.png', 'profile.png'])->pluck('image')->toArray(), + 'baseNames' => DB::table('users')->whereNotNull('image')->where('image', '!=', '')->whereNotIn('image', ['profil.png', 'profile.png'])->pluck('image')->toArray(), 'oldDirectory' => public_path('files/img'), 'newDirectory' => storage_path('app/images/users/avatars'), ], [ - 'baseNames' => DB::table('users')->whereNotNull('icon')->pluck('icon')->toArray(), + 'baseNames' => DB::table('users')->whereNotNull('icon')->where('icon', '!=', '')->pluck('icon')->toArray(), 'oldDirectory' => public_path('files/img'), 'newDirectory' => storage_path('app/images/users/icons'), ], [ - 'baseNames' => DB::table('categories')->whereNotNull('image')->pluck('image')->toArray(), + 'baseNames' => DB::table('categories')->whereNotNull('image')->where('image', '!=', '')->pluck('image')->toArray(), 'oldDirectory' => public_path('files/img'), 'newDirectory' => storage_path('app/images/categories/images'), ], [ - 'baseNames' => DB::table('playlists')->whereNotNull('cover_image')->pluck('cover_image')->toArray(), + 'baseNames' => DB::table('playlists')->whereNotNull('cover_image')->where('cover_image', '!=', '')->pluck('cover_image')->toArray(), 'oldDirectory' => public_path('files/img'), 'newDirectory' => storage_path('app/images/playlists/images'), ], [ - 'baseNames' => DB::table('subtitles')->pluck('file_name')->toArray(), + 'baseNames' => DB::table('subtitles')->where('file_name', '!=', '')->pluck('file_name')->toArray(), 'oldDirectory' => public_path('files/subtitles'), 'newDirectory' => storage_path('app/files/subtitles/files'), ], @@ -74,7 +74,7 @@ return new class () extends Migration { 'newDirectory' => storage_path('app/images/torrents/covers'), ], [ - 'baseNames' => DB::table('torrents')->pluck('file_name')->toArray(), + 'baseNames' => DB::table('torrents')->where('file_name', '!=', '')->pluck('file_name')->toArray(), 'oldDirectory' => public_path('files/torrents'), 'newDirectory' => storage_path('app/files/torrents/files'), ], diff --git a/database/migrations/2025_08_22_064916_add_season_episode_to_requests_table.php b/database/migrations/2025_08_22_064916_add_season_episode_to_requests_table.php new file mode 100644 index 000000000..fa2a8da42 --- /dev/null +++ b/database/migrations/2025_08_22_064916_add_season_episode_to_requests_table.php @@ -0,0 +1,23 @@ +unsignedInteger('season_number')->after('igdb')->nullable(); + $table->unsignedInteger('episode_number')->after('season_number')->nullable(); + + $table->index(['season_number', 'episode_number']); + $table->index('episode_number'); + }); + } +}; diff --git a/database/migrations/2025_08_30_015125_create_torrent_reseeds_table.php b/database/migrations/2025_08_30_015125_create_torrent_reseeds_table.php new file mode 100644 index 000000000..b0c51c014 --- /dev/null +++ b/database/migrations/2025_08_30_015125_create_torrent_reseeds_table.php @@ -0,0 +1,38 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +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::create('torrent_reseeds', function (Blueprint $table): void { + $table->increments('id'); + $table->unsignedInteger('torrent_id'); + $table->unsignedInteger('user_id'); + $table->integer('requests_count')->default(0); + $table->timestamps(); + + $table->foreign('torrent_id')->references('id')->on('torrents')->cascadeOnUpdate()->cascadeOnDelete(); + $table->foreign('user_id')->references('id')->on('users')->cascadeOnUpdate()->cascadeOnDelete(); + }); + } +}; diff --git a/database/schema/mysql-schema.sql b/database/schema/mysql-schema.sql index ba1b405fb..97136e463 100644 --- a/database/schema/mysql-schema.sql +++ b/database/schema/mysql-schema.sql @@ -1427,6 +1427,8 @@ CREATE TABLE `requests` ( `tvdb` int unsigned DEFAULT NULL, `mal` int unsigned DEFAULT NULL, `igdb` int unsigned DEFAULT NULL, + `season_number` int unsigned DEFAULT NULL, + `episode_number` int unsigned DEFAULT NULL, `description` text COLLATE utf8mb4_unicode_ci NOT NULL, `user_id` int unsigned NOT NULL, `tmdb_movie_id` int unsigned DEFAULT NULL, @@ -1457,6 +1459,8 @@ CREATE TABLE `requests` ( KEY `requests_torrent_id_foreign` (`torrent_id`), KEY `requests_movie_id_index` (`tmdb_movie_id`), KEY `requests_tv_id_index` (`tmdb_tv_id`), + KEY `requests_season_number_episode_number_index` (`season_number`,`episode_number`), + KEY `requests_episode_number_index` (`episode_number`), CONSTRAINT `requests_approved_by_foreign` FOREIGN KEY (`approved_by`) REFERENCES `users` (`id`) ON UPDATE CASCADE, CONSTRAINT `requests_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE RESTRICT, CONSTRAINT `requests_filled_by_foreign` FOREIGN KEY (`filled_by`) REFERENCES `users` (`id`) ON UPDATE CASCADE, @@ -2053,6 +2057,23 @@ CREATE TABLE `torrent_downloads` ( CONSTRAINT `torrent_downloads_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `torrent_reseeds`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `torrent_reseeds` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `torrent_id` int unsigned NOT NULL, + `user_id` int unsigned NOT NULL, + `requests_count` int NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `torrent_reseeds_torrent_id_foreign` (`torrent_id`), + KEY `torrent_reseeds_user_id_foreign` (`user_id`), + CONSTRAINT `torrent_reseeds_torrent_id_foreign` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `torrent_reseeds_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `torrent_tips`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; @@ -3005,3 +3026,5 @@ INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (354,'2025_06_18_00 INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (355,'2025_06_18_040627_alter_requests_drop_claimed',1); INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (356,'2025_06_21_234021_alter_requests_drop_votes',1); INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (357,'2025_07_15_061844_add_block_order_to_user_settings',1); +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (358,'2025_08_22_064916_add_season_episode_to_requests_table',1); +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (359,'2025_08_30_015125_create_torrent_reseeds_table',1); diff --git a/lang/da/bon.php b/lang/da/bon.php index 93d09d293..6cb5c3150 100644 --- a/lang/da/bon.php +++ b/lang/da/bon.php @@ -20,7 +20,7 @@ return [ 'earning' => 'Optjening', 'earning-rate' => 'Med denne indtjeningsrate vil du tjene følgende pr. tidsramme..', 'earnings' => 'Indtjening', - 'exchange' => 'Udveksle', + 'exchange' => 'Udveksling', 'exchange-warning' => 'Udvekslinger er endelige. Tjek venligst dine valg, inden du foretager en udveksling.', 'extended-stats' => 'Udvidet statestik', 'gift' => 'Send BON', diff --git a/lang/da/bot.php b/lang/da/bot.php index d496092ad..4b24bb53f 100644 --- a/lang/da/bot.php +++ b/lang/da/bot.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'about' => 'Om', - 'bot' => 'Bot', - 'bots' => 'Bots', - 'color' => 'Farve', - 'command' => 'Kommando', - 'edit-bot' => 'Rediger Bot', - 'emoji-code' => 'Emoji Code', - 'help' => 'Hjælp', - 'icon' => 'Ikon', - 'info' => 'Info', - 'name' => 'Navn', + 'about' => 'Om', + 'bot' => 'Bot', + 'bots' => 'Bots', + 'color' => 'Farve', + 'command' => 'Kommando', + 'edit-bot' => 'Rediger Bot', + 'emoji-code' => 'Emoji Kode', + 'help' => 'Hjælp', + 'icon' => 'Ikon', + 'info' => 'Info', + 'name' => 'Navn', ]; diff --git a/lang/da/common.php b/lang/da/common.php index 638c169d7..53dddcac6 100644 --- a/lang/da/common.php +++ b/lang/da/common.php @@ -237,7 +237,12 @@ return [ 'system-message' => 'DETTE ER EN AUTOMATISK SYSTEMBESKED, SVAR VENLIGST IKKE!', 'top-10' => 'Top 10', 'wished' => 'Ønskede', - 'article' => 'Articolo', + 'article' => 'Artikel', 'and' => 'og', 'test' => 'test', + 'alive' => 'I live', + 'dead' => 'Døde', + 'total' => 'Total', + 'trending' => 'Trender', + 'deleted_at' => 'Slettet', ]; diff --git a/lang/da/notification.php b/lang/da/notification.php index d33ff43f5..9fba115b8 100644 --- a/lang/da/notification.php +++ b/lang/da/notification.php @@ -17,7 +17,7 @@ return [ 'delete' => 'Slet', 'delete-all' => 'Slet alle notifikationer', 'filter-by-type' => 'Filtrer via Notifikationstype', - 'mark-all-read' => 'Markér alt som læst', + 'mark-all-read' => 'Markér alt som Læst', 'mark-read' => 'Markér som læst', 'message' => 'Besked', 'no-notifications' => 'Der er ingen notifikationer fundet', diff --git a/lang/da/pm.php b/lang/da/pm.php index 0d518f9d5..02bfa7705 100644 --- a/lang/da/pm.php +++ b/lang/da/pm.php @@ -16,7 +16,7 @@ return [ 'enter-subject' => 'Indtast emne', 'from' => 'Fra', 'inbox' => 'Indbakke', - 'mark-all-read' => 'Markér alle meddelelser som læst', + 'mark-all-read' => 'Markér alle meddelelser som Læst', 'message' => 'Besked', 'messages' => 'Beskeder', 'new' => 'Ny meddelelse', diff --git a/lang/da/staff.php b/lang/da/staff.php index 81ef55de4..6e2c773bc 100644 --- a/lang/da/staff.php +++ b/lang/da/staff.php @@ -27,7 +27,7 @@ return [ 'config-manager' => 'Konfigurations Manager', 'commands' => 'Kommandoer', 'dashboard' => 'Dahsboard', - 'failed-login-log' => 'Mislykkede login Log', + 'failed-login-log' => 'Mislykkede logins', 'flush-ghost-peers' => 'Tøm Ghost peers', 'forums' => 'Fora', 'frontend' => 'Frontend', @@ -48,11 +48,11 @@ return [ 'please-moderate' => 'Moderer venligst denne Torrent!', 'polls' => 'Afstemninger', 'rooms' => 'Rum', - 'reports-log' => 'Anmeldelses Log', + 'reports-log' => 'Anmeldelseslog', 'rss' => 'RSS', 'staff-dashboard' => 'Staff Dashboard', 'status' => 'Status', - 'statuses' => 'Status', + 'statuses' => 'Statusser', 'torrent-categories' => 'Torrent Kategorier', 'torrent-moderation' => 'Torrent Moderering', 'torrent-tools' => 'Torrent Værktøjer', @@ -60,10 +60,10 @@ return [ 'torrent-resolutions' => 'Torrent Opløsninger', 'torrents' => 'Torrents', 'user-gifting' => 'Brugerbelønning', - 'user-notes' => 'Brugernoter Log', + 'user-notes' => 'Brugernoter', 'user-search' => 'Brugersøgning', 'user-tools' => 'Brugerværktøjer', - 'warnings-log' => 'Advarsels Log', + 'warnings-log' => 'Advarselslog', 'you-have' => 'Du har', 'possible-leech-cheaters' => 'Mulige snydere', 'chat-tools' => 'Chatværktøjer', @@ -75,5 +75,5 @@ return [ 'gifts-log' => 'Gavelog', 'mass-email' => 'Masse-email', 'notes' => 'Noter', - 'passkeys' => 'Passkeys', + 'passkeys' => 'Adgangsnøgler', ]; diff --git a/lang/da/subtitle.php b/lang/da/subtitle.php index 70441c8d4..06a009632 100644 --- a/lang/da/subtitle.php +++ b/lang/da/subtitle.php @@ -29,6 +29,6 @@ return [ 'subtitle-file' => 'Undertekst fil', 'subtitle-file-types' => 'Accepterede filer er ICO, SRT and ZIP', 'search' => 'Søg efter torrent', - 'uploaded' => 'Uploaded', + 'uploaded' => 'Uploadet', 'uploader' => 'Uploader', ]; diff --git a/lang/da/torrent.php b/lang/da/torrent.php index ba2f8e509..cbe4d21fb 100644 --- a/lang/da/torrent.php +++ b/lang/da/torrent.php @@ -38,7 +38,7 @@ return [ 'completed' => 'Fuldført', 'completed_at' => 'Fuldført den', 'completed-not-seeding' => 'Du har fuldført dette download, men seeder ikke længere', - 'completed-times' => 'Gange Fulført', + 'completed-times' => 'Gange Fuldført', 'comments-left' => 'Kommentarer givet', 'created_at' => 'Oprettet den', 'credited' => 'Krediteret', @@ -88,7 +88,7 @@ return [ 'have-downloaded' => 'Downloadet', 'have-not-completed' => 'Ikke fuldført', 'have-not-downloaded' => 'Ikke downloadet', - 'health' => 'Sundhed', + 'health' => 'Tilstand', 'history' => 'Historik', 'hitrun' => 'H & R?', 'hit-and-runs' => 'Hitn Run antal', @@ -182,7 +182,7 @@ return [ 'staff-tools' => 'Staff værktøjer', 'start-year' => 'År fra', 'started' => 'Startet', - 'status' => 'status', + 'status' => 'Status', 'statistics' => 'Statistik', 'stats' => 'Stats', 'sticky' => 'Gør Sticky', @@ -216,7 +216,7 @@ return [ 'unsticky' => 'Fjern Sticky', 'updated' => 'Opdateret', 'updated_at' => 'Opdateret kl', - 'uploaded' => 'Uploaded', + 'uploaded' => 'Uploadet', 'uploaded-by' => 'Uploadet af', 'uploader' => 'Uploader', 'use-fl-token' => 'Brug en Freeleech Token', diff --git a/lang/da/user.php b/lang/da/user.php index 21fcbfc08..19d9be35c 100644 --- a/lang/da/user.php +++ b/lang/da/user.php @@ -37,7 +37,7 @@ return [ 'badges' => 'Udmærkelser', 'ban' => 'Udeluk Bruger', 'bans' => 'Udelukkelser', - 'ban-log' => 'Udelukkelses Log', + 'ban-log' => 'Udelukkelseslog', 'become-hidden' => 'Bliv skjult', 'become-visible' => 'Bliv synlig', 'bon' => 'BON', @@ -351,7 +351,7 @@ return [ 'warning-log' => 'Advarselslog', 'wishlist' => 'Ønskeliste', 'apikey' => 'API nøgle', - 'apikeys' => 'API nøgler', + 'apikeys' => 'API-nøgler', 'client-connectable-state' => '{0}Nej|{1}Ja', 'client-list' => 'Klienter og IP-adresser', 'email-updates' => 'E-mailopdateringer', @@ -372,7 +372,7 @@ return [ 'password-resets' => 'Nulstilling af adgangskoder', 'reactivate' => 'Genaktiver', 'rsskey' => 'RSS nøgle', - 'rsskeys' => 'RSS nøgler', + 'rsskeys' => 'RSS-nøgler', 'seedbox-deleted-success' => 'Seedbox er blevet slettet', 'top-leeched' => 'Top Leeched', 'top-bountied' => 'Top Belønnet', @@ -405,4 +405,17 @@ return [ 'follow-yourself' => 'Godt forsøg, men desværre kan du ikke følge dig selv.', 'invite-already-sent' => 'Den e-mailadresse, du forsøger at sende en invitation til, har allerede modtaget en.', 'invite-already-used' => 'Den invitation, du forsøger at gensende, er allerede blevet brugt.', + 'homepage-blocks' => 'Hjemmesideblokke', + 'homepage-block-chat-visible' => 'Vis Chatboks', + 'homepage-block-featured-visible' => 'Vis Udvalgte Torrents', + 'homepage-block-latest-comments-visible' => 'Vis Seneste Kommentarer', + 'homepage-block-latest-posts-visible' => 'Vis Seneste Indlæg', + 'homepage-block-latest-topics-visible' => 'Vis Seneste Emner', + 'homepage-block-news-visible' => 'Vis Nyheder', + 'homepage-block-online-visible' => 'Vis Online Brugere', + 'homepage-block-poll-visible' => 'Vis Afstemninger', + 'homepage-block-random-media-visible' => 'Vis Tilfældig Medier', + 'homepage-block-top-torrents-visible' => 'Vis Top Torrents', + 'homepage-block-top-users-visible' => 'Vis Top Brugere', + 'unregistered-info-hashes' => 'Uregistrerede Info Hashes', ]; diff --git a/lang/da/validation.php b/lang/da/validation.php index f865bce24..38195de4f 100644 --- a/lang/da/validation.php +++ b/lang/da/validation.php @@ -121,7 +121,7 @@ return [ 'timezone' => ':attribute skal være en gyldig tidszone.', 'unique' => ':attribute er allerede taget.', 'uploaded' => ':attribute fejlene i uploaden.', - 'url' => ':attribute formatet er ugyldigt.', + 'url' => ':attribute skal være en gyldig URL.', 'uuid' => ':attribute skal være en gyldig UUID.', 'custom' => [ 'attribute-name' => [ diff --git a/lang/de/auth.php b/lang/de/auth.php index 7afe14a89..d58cdab3c 100644 --- a/lang/de/auth.php +++ b/lang/de/auth.php @@ -77,4 +77,6 @@ return [ 'verify' => 'Verifizieren', 'verify-email' => 'Email Verifizieren', 'verifying' => 'Verifizierung läuft...', + 'code' => '2FA Code', + 'totp-code' => 'TOTP code', ]; diff --git a/lang/de/bon.php b/lang/de/bon.php index 3bb23f526..36f323f3c 100644 --- a/lang/de/bon.php +++ b/lang/de/bon.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'activated' => 'Aktiviert', - 'active' => 'Aktiv!', - 'amount' => 'Menge', - 'bon' => 'Bonus', - 'bonus' => 'Bonus', - 'date' => 'Datum', - 'earning' => 'Verdienst', - 'earning-rate' => 'Bei dieser Rate erhältst du folgende Punktzahl in folgenden Zeiträumen:', - 'earnings' => 'Verdienste', - 'exchange' => 'Einwechseln', - 'exchange-warning' => 'Der Umtausch ist endgültig. Bitte überprüfe deine Auswahl, bevor der Umstausch durchgeführt wird.', - 'extended-stats' => 'Erweiterte Statistiken', - 'failed' => 'Umtausch fehlgeschlagen!', - 'failed-amount-message' => 'Du musst einen Betrag und eine Nachricht eingeben!', - 'failed-funds-poster' => 'Du hast zu wenig Punkte, um dem Poster Trinkgeld zu geben!', - 'failed-funds-uploader' => 'Du hast zu wenig Punkte, um dem Uploader Trinkgeld zu geben!', - 'failed-negative' => 'Du kannst kein negatives Trinkgeld geben!', - 'failed-user-not-found' => 'Der angegebene Nutzer kann nicht gefunden werden', - 'failed-yourself' => 'Du kannst dir selbst kein Trinkgeld geben!', - 'gift' => 'Geschenk', - 'gift-bonus' => 'Geschenk-Bonuspunkte', - 'gift-sent' => 'Geschenk gesendet', - 'gift-to' => 'Geschenk an', - 'gifts' => 'Geschenke', - 'item' => 'Artikel', - 'no-refund' => 'KEINE RÜCKERSTATTUNG!', - 'per-day' => 'Punkte pro Tag', - 'per-hour' => 'Punkte pro Stunde', - 'per-minute' => 'Punkte pro Minute', - 'per-month' => 'Punkte pro Monat', - 'per-second' => 'Punkte pro Sekunde', - 'per-week' => 'Punkte pro Woche', - 'per-year' => 'Punkte pro Jahr', - 'pm-subject' => 'Persönlicher 24-Stunden-Freeleech Aktiviert', - 'pm-message' => 'Dein [b]Persönlicher 24-Stunden-Freeleech[/b] hat begonnen! Er läuft ab am %s [b]', - 'points' => 'Punkte', - 'receiver' => 'Empfänger', - 'review-seeds' => 'Übersicht aller geseedeten Torrents', - 'send-gift' => 'Geschenk senden', - 'sender' => 'Absender', - 'store' => 'Bonus Store', - 'success' => 'Bonus-Austausch erfolgreich', - 'success-tip' => 'Dein Trinkgeld wurde erfolgreich übertragen!', - 'tips' => 'Trinkgeld', - 'total' => 'Gesamteinnahmen', - 'total-gifts' => 'Verschenkte Bonuspunkte', - 'total-tips' => 'Verschenktes Trinkgeld', + 'activated' => 'Aktiviert', + 'active' => 'Aktiv!', + 'amount' => 'Menge', + 'bon' => 'Bonus', + 'bonus' => 'Bonus', + 'date' => 'Datum', + 'earning' => 'Verdienst', + 'earning-rate' => 'Bei dieser Rate erhältst du folgende Punktzahl in folgenden Zeiträumen:', + 'earnings' => 'Verdienste', + 'exchange' => 'Einwechseln', + 'exchange-warning' => 'Der Umtausch ist endgültig. Bitte überprüfe deine Auswahl, bevor der Umstausch durchgeführt wird.', + 'extended-stats' => 'Erweiterte Statistiken', + 'failed' => 'Umtausch fehlgeschlagen!', + 'failed-amount-message' => 'Du musst einen Betrag und eine Nachricht eingeben!', + 'failed-funds-poster' => 'Du hast zu wenig Punkte, um dem Poster Trinkgeld zu geben!', + 'failed-funds-uploader' => 'Du hast zu wenig Punkte, um dem Uploader Trinkgeld zu geben!', + 'failed-negative' => 'Du kannst kein negatives Trinkgeld geben!', + 'failed-user-not-found' => 'Der angegebene Nutzer kann nicht gefunden werden', + 'failed-yourself' => 'Du kannst dir selbst kein Trinkgeld geben!', + 'gift' => 'Geschenk', + 'gift-bonus' => 'Bonuspunkte schenken', + 'gift-sent' => 'Geschenk gesendet', + 'gift-to' => 'Geschenk an', + 'gifts' => 'Geschenke', + 'item' => 'Artikel', + 'no-refund' => 'KEINE RÜCKERSTATTUNG!', + 'per-day' => 'Punkte pro Tag', + 'per-hour' => 'Punkte pro Stunde', + 'per-minute' => 'Punkte pro Minute', + 'per-month' => 'Punkte pro Monat', + 'per-second' => 'Punkte pro Sekunde', + 'per-week' => 'Punkte pro Woche', + 'per-year' => 'Punkte pro Jahr', + 'pm-subject' => 'Persönlicher 24-Stunden-Freeleech Aktiviert', + 'pm-message' => 'Dein [b]Persönlicher 24-Stunden-Freeleech[/b] hat begonnen! Er läuft ab am %s [b]', + 'points' => 'Punkte', + 'receiver' => 'Empfänger', + 'review-seeds' => 'Übersicht aller geseedeten Torrents', + 'send-gift' => 'Geschenk senden', + 'sender' => 'Absender', + 'store' => 'Bonus Store', + 'success' => 'Bonus-Austausch erfolgreich', + 'success-tip' => 'Dein Trinkgeld wurde erfolgreich übertragen!', + 'tips' => 'Trinkgeld', + 'total' => 'Gesamteinnahmen', + 'total-gifts' => 'Verschenkte Bonuspunkte', + 'total-tips' => 'Verschenktes Trinkgeld', 'you-have-received-gifts' => 'Erhalten', - 'you-have-sent-gifts' => 'Gesendet', - 'you-have-received-tips' => 'Erhalten', - 'you-have-sent-tips' => 'Gesendet', - 'your-points' => 'Deine Punkte', + 'you-have-sent-gifts' => 'Gesendet', + 'you-have-received-tips' => 'Erhalten', + 'you-have-sent-tips' => 'Gesendet', + 'your-points' => 'Deine Punkte', ]; diff --git a/lang/de/common.php b/lang/de/common.php index fb44618dd..896de5788 100644 --- a/lang/de/common.php +++ b/lang/de/common.php @@ -194,14 +194,14 @@ return [ 'yes' => 'Ja', 'your' => 'Ihre', 'your-comment' => 'Dein Kommentar', - 'abbrev-days' => 'Tage ', - 'abbrev-hours' => 'Stunden ', - 'abbrev-minutes' => 'Minuten ', - 'abbrev-months' => 'Monate ', - 'abbrev-seconds' => 'Sekunden', + 'abbrev-days' => 'D ', + 'abbrev-hours' => 'h ', + 'abbrev-minutes' => 'm ', + 'abbrev-months' => 'M ', + 'abbrev-seconds' => 's', 'and' => 'und', - 'abbrev-weeks' => 'Wochen ', - 'abbrev-years' => 'Jahre ', + 'abbrev-weeks' => 'W ', + 'abbrev-years' => 'Y ', 'chat' => 'Chat', 'chat-room' => 'Chatraum', 'chat-rooms' => 'Chaträume', @@ -228,4 +228,6 @@ return [ 'dead' => 'Tod', 'image' => 'Bild', 'total' => 'Gesamt', + 'deleted_at' => 'Gelöscht am', + 'trending' => 'Trending', ]; diff --git a/lang/de/mediahub.php b/lang/de/mediahub.php index ef1694d80..9d5990b24 100644 --- a/lang/de/mediahub.php +++ b/lang/de/mediahub.php @@ -36,4 +36,5 @@ return [ 'show' => 'Serie', 'shows' => 'Serien', 'title' => 'MediaHub', + 'tv-credits' => 'Serien Credits:', ]; diff --git a/lang/de/playlist.php b/lang/de/playlist.php index f47975dc6..ce495278e 100644 --- a/lang/de/playlist.php +++ b/lang/de/playlist.php @@ -39,4 +39,5 @@ return [ 'suggestion-review' => 'Dein Vorschlag wurde zur Prüfung an den Playlistersteller geschickt', 'suggestion-approved' => 'Playlist Vorschlag angenommen', 'suggestion-rejected' => 'Playlist Vorschlag abgelehnt', + 'last-addition-at' => 'Zuletzt hinzugefügt am', ]; diff --git a/lang/de/staff.php b/lang/de/staff.php index 213f5317e..cf561d009 100644 --- a/lang/de/staff.php +++ b/lang/de/staff.php @@ -69,4 +69,10 @@ return [ 'blocked-ips' => 'Gesperrte IP Adressen', 'bon-exchange' => 'BON Tauschbörse', 'bon-earnings' => 'BON Verdienst', + 'gifts-log' => 'Geschenk-Log', + 'mass-email' => 'Massen-Mail', + 'notes' => 'Anmerkungen', + 'status' => 'Status', + 'statuses' => 'Status', + 'passkeys' => 'Passkeys', ]; diff --git a/lang/de/torrent.php b/lang/de/torrent.php index f8914c2d6..31e1d9534 100644 --- a/lang/de/torrent.php +++ b/lang/de/torrent.php @@ -232,4 +232,12 @@ return [ 'votes' => 'Abstimmung', 'year-range' => 'Jahresbereich', 'comments-left' => 'Verbleibende Kommentare', + 'distributor' => 'Vertrieb', + 'not-personal-release' => 'Kein Personal Release', + 'personal-release' => 'Personal Release', + 'postponed' => 'Verschoben', + 'refundable' => 'Erstattungsfähig', + 'refunded' => 'Erstattet', + 'region' => 'Region', + 'season' => 'Staffel', ]; diff --git a/lang/de/user.php b/lang/de/user.php index 11412daad..0f84ae923 100644 --- a/lang/de/user.php +++ b/lang/de/user.php @@ -353,4 +353,36 @@ return [ 'apikey' => 'API Schlüssel', 'apikeys' => 'API Schlüssel', 'bans' => 'Sperren', + 'deactivate' => 'Deaktivieren', + 'deactivate-all' => 'Alle deaktivieren', + 'email-updates' => 'Email Ankündigungen', + 'following' => 'Folgend', + 'homepage-blocks' => 'Startseiten Blöcke', + 'homepage-block-chat-visible' => 'Zeige Chatbox', + 'homepage-block-featured-visible' => 'Zeige vorgestellte Torrents', + 'homepage-block-latest-comments-visible' => 'Zeige letzte Kommentare', + 'homepage-block-latest-posts-visible' => 'Zeige letzte Posts', + 'homepage-block-latest-topics-visible' => 'Zeige letzte Themen', + 'homepage-block-news-visible' => 'Zeige letzte Neuigkeiten', + 'homepage-block-online-visible' => 'Zeige Online User', + 'homepage-block-poll-visible' => 'Zeige letzte Abstimmungen', + 'homepage-block-random-media-visible' => 'Zeige zufällige Medien', + 'homepage-block-top-torrents-visible' => 'Zeige Top Torrents', + 'homepage-block-top-users-visible' => 'Zeige Top User', + 'internal-releases' => 'Internal Releases', + 'invite-expired' => 'Die Einladung ist abgelaufen.', + 'last-action' => 'Letzte Aktion', + 'my-achievements' => 'Meine Erfolge', + 'my-downloads' => 'Meine Downloads', + 'my-playlists' => 'Meine Playlists', + 'no-ban' => 'Es existieren keine Bans für diesen Nutzer!', + 'no-soft-warning' => 'Es existieren keine "soft deleted" Warnungen für diesen Nutzer!', + 'no-warning' => 'Es existieren keine Warnungen für diesen Nutzer!', + 'open-registration' => 'Offene Registrierung', + 'password-resets' => 'Password Resets', + 'reactivate' => 'Reaktivieren', + 'reason-ban' => 'Grund für den Ban', + 'reason-unban' => 'Grund für den Unban', + 'removed' => 'Entfernt', + 'reset-api-token' => 'API Token zurücksetzen', ]; diff --git a/lang/de/validation.php b/lang/de/validation.php index e2e437043..859bc2705 100644 --- a/lang/de/validation.php +++ b/lang/de/validation.php @@ -182,4 +182,5 @@ return [ 'size' => 'Größe', ], 'current_password' => 'Das Passwort ist nicht korrekt.', + 'declined' => ':attribute muss abgelehnt werden.', ]; diff --git a/lang/en/common.php b/lang/en/common.php index bb800e632..1a70adcd6 100644 --- a/lang/en/common.php +++ b/lang/en/common.php @@ -65,6 +65,7 @@ return [ 'dead' => 'Dead', 'delete' => 'Delete', 'delete-your-comment' => 'Delete your Comment', + 'deleted_at' => 'Deleted at', 'description' => 'Description', 'descending' => 'Descending', 'direction' => 'Direction', diff --git a/lang/en/torrent.php b/lang/en/torrent.php index 2981fdec3..c7d2f4b78 100644 --- a/lang/en/torrent.php +++ b/lang/en/torrent.php @@ -169,6 +169,7 @@ return [ 'required-anime' => 'Required For Anime', 'required-games' => 'Required For Games', 'requires-reseed' => 'Requires Reseed', + 'reseed-requests' => 'Reseed Requests', 'resolution' => 'Resolution', 'resolutions' => 'Resolutions', 'resurrections' => 'Resurrections', diff --git a/lang/en/user.php b/lang/en/user.php index d5cbc4e86..a3e989d03 100644 --- a/lang/en/user.php +++ b/lang/en/user.php @@ -419,6 +419,7 @@ return [ 'upload-true' => 'True Upload', 'uploads' => 'Uploads', 'uploads-table' => 'Uploads Table', + 'unregistered-info-hashes' => 'Unregistered Info Hashes', 'personal-releases' => 'Personal Releases', 'user' => 'User', 'user-id' => 'User ID', diff --git a/lang/es/common.php b/lang/es/common.php index b166a9a60..0aae01670 100644 --- a/lang/es/common.php +++ b/lang/es/common.php @@ -34,7 +34,7 @@ return [ 'ascending' => 'Ascendente', 'author' => 'Autor', 'balance' => 'Saldo', - 'blacklist' => 'Lista negra', + 'blacklist' => 'Lista negra de clientes', 'bookmarked' => 'Marcado', 'buffer' => 'Buffer', 'bug' => 'Reportar un error', @@ -236,4 +236,9 @@ return [ 'your' => 'Tu', 'your-comment' => 'Tu comentario', 'test' => 'prueba', + 'alive' => 'Vivo', + 'dead' => 'Muerto', + 'total' => 'Total', + 'trending' => 'Tendencia', + 'deleted_at' => 'Eliminado el', ]; diff --git a/lang/es/user.php b/lang/es/user.php index 1ce94efb0..c63fd5381 100644 --- a/lang/es/user.php +++ b/lang/es/user.php @@ -435,4 +435,17 @@ Estos ajustes se anulan si activas el modo privado o si 'Lista de deseos', 'my-playlists' => 'Mis playlists', 'total-internal-releases' => 'Total de publicaciones internas', + 'homepage-blocks' => 'Bloques de página de inicio', + 'homepage-block-chat-visible' => 'Mostrar Chatbox', + 'homepage-block-featured-visible' => 'Mostrar torrents destacados', + 'homepage-block-latest-comments-visible' => 'Mostrar últimos comentarios', + 'homepage-block-latest-posts-visible' => 'Mostrar últimos posts', + 'homepage-block-latest-topics-visible' => 'Mostrar últimos topics', + 'homepage-block-news-visible' => 'Mostrar últimas noticias', + 'homepage-block-online-visible' => 'Mostrar usuarios en línea', + 'homepage-block-poll-visible' => 'Mostrar últimas encuentas', + 'homepage-block-random-media-visible' => 'Mostrar contenido aleatorio', + 'homepage-block-top-torrents-visible' => 'Mostrar los mejores torrents', + 'homepage-block-top-users-visible' => 'Mostrar los mejores usuarios', + 'unregistered-info-hashes' => 'Hashes de información no registrados', ]; diff --git a/lang/it/auth.php b/lang/it/auth.php index 16e20f6bf..ed425cf06 100644 --- a/lang/it/auth.php +++ b/lang/it/auth.php @@ -59,4 +59,29 @@ return [ 'welcome-restore' => 'Bentornato! Il tuo account non è più disabilitato!', 'password' => 'Password', 'username' => 'Nome utente', + 'application' => 'Richiesta', + 'apply' => 'Fare richiesta', + 'code' => 'Codice TOTP', + 'confirm-password' => 'Conferma password', + 'confirm-new-password' => 'Conferma nuova password', + 'email-verification-link' => 'Ti è stato inviato un link di verifica via email!', + 'enter-recovery' => 'Inserisci uno dei codici di ripristino forniti quando hai attivato la prima volta la autenticazione a due fattori.', + 'enter-totp' => 'Inserisci il codice di autenticazione a 6 cifre generato dalla tua app.', + 'new-password' => 'Nuova password', + 'newbie' => 'Nuovo nel gioco', + 'password-confirm-desc' => 'Si prega di confermare la password prima di procedere.', + 'password-confirmation' => 'Conferma della password', + 'password-reset' => 'Reimposta la password', + 'proof-image' => 'Collegamento allo screenshot della pagina del profilo', + 'proof-image-title' => 'Link agli screenshot del profilo', + 'proof-profile' => 'Collegamento alla pagina del profilo', + 'proof-profile-title' => 'Link ai tuoi profili', + 'recovery-code' => 'Codice di recupero', + 'remember-me' => 'Ricordati di me', + 'send-verification-email' => 'Invia email di verifica', + 'totp-code' => 'Codice TOTP', + 'user-icon' => 'Icona utente', + 'verify' => 'Verificare', + 'verify-email' => 'Verifica email', + 'verifying' => 'Verifica in corso...', ]; diff --git a/lang/it/backup.php b/lang/it/backup.php index 6a811db86..6b73541ce 100644 --- a/lang/it/backup.php +++ b/lang/it/backup.php @@ -39,4 +39,5 @@ return [ 'manager' => 'Manager', 'no_disks_configured' => 'Nessun disco di backup configurato in config / backup.php', 'only_local_downloads_supported' => 'Sono supportati solo i download dal filesystem locale.', + 'backup_process_started' => 'Nuovo processo di backup avviato', ]; diff --git a/lang/it/blocks.php b/lang/it/blocks.php index f5778d3a9..5af0d50b6 100644 --- a/lang/it/blocks.php +++ b/lang/it/blocks.php @@ -26,4 +26,5 @@ return [ 'check-news' => 'Leggi cliccando qui le notizie', 'new-news' => 'Nuove notizie ', 'new-torrents' => 'Nuovi torrents', + 'latest-comments' => 'Ultimi commenti', ]; diff --git a/lang/it/bon.php b/lang/it/bon.php index 0bca6da57..a57ce9956 100644 --- a/lang/it/bon.php +++ b/lang/it/bon.php @@ -51,4 +51,16 @@ return [ 'you-have-received-tips' => 'Hai ricevuto', 'you-have-sent-tips' => 'Hai inviato', 'your-points' => 'I tuoi punti', + 'failed' => 'Scambio bonus fallito!', + 'failed-amount-message' => 'Devi inserire un importo e un messaggio!', + 'failed-funds-poster' => 'Sei troppo povero per dare la mancia al poster!', + 'failed-funds-uploader' => 'Sei troppo al verde per dare la mancia a chi ha caricato il file!', + 'failed-negative' => 'Non puoi dare una mancia negativa!', + 'failed-user-not-found' => 'Impossibile trovare l\'utente specificato', + 'failed-yourself' => 'Non puoi darti la mancia da solo!', + 'gift-sent' => 'Regalo inviato', + 'pm-subject' => 'Freeleech personale attivato 24 ore', + 'pm-message' => 'La tua [b]sessione personale Freeleech di 24 ore è iniziata! Scadrà il %s [/b]', + 'success' => 'Scambio bonus riuscito', + 'success-tip' => 'La tua mancia è stata applicata con successo!', ]; diff --git a/lang/it/common.php b/lang/it/common.php index 138678827..baf0de4cf 100644 --- a/lang/it/common.php +++ b/lang/it/common.php @@ -34,7 +34,7 @@ return [ 'description' => 'Descrizione', 'direction' => 'Direzione', 'disable' => 'disattivare', - 'doubleup_activated' => 'Doppio Upload globale attivato', + 'doubleup_activated' => 'Doppio Upload Globale attivato', 'download' => 'Download', 'edit' => 'Modifica', 'edit-your-comment' => 'Modifica il tuo commento', @@ -56,7 +56,7 @@ return [ 'for' => 'per', 'forum' => 'Forum', 'free' => 'Gratuito', - 'freeleech_activated' => 'Freeleech globale attivato', + 'freeleech_activated' => 'Freeleech Globale Attivato', 'global' => 'Globale', 'group' => 'Gruppo', 'groups' => 'gruppi', @@ -108,12 +108,12 @@ return [ 'pages' => 'Pagine', 'password' => 'Password', 'patron' => 'Diventa un sostenitore', - 'pending-torrents' => 'Torrent in attesa', + 'pending-torrents' => 'Torrent in sospeso', 'personal' => 'Personale', 'port' => 'Porta', 'position' => 'Posizione', 'posts' => 'Messaggi', - 'powered-by' => 'Sostenuto da UNIT3D', + 'powered-by' => 'Supportato da UNIT3D', 'preview' => 'Anteprima', 'previous' => 'Precedente', 'progress' => 'Progresso', @@ -149,7 +149,7 @@ return [ 'terms' => 'Condizioni d uso', 'times' => 'Volte', 'title' => 'Titolo', - 'top-bountied' => 'Top Ricompense', + 'top-bountied' => 'Top Ricompensato', 'topics' => 'Temi', 'tracker-codes' => 'Codici del Tracker', 'type' => 'Sorgente', @@ -174,7 +174,7 @@ return [ 'your' => 'Il tuo', 'your-comment' => 'Il tuo commento', 'abbrev-days' => 'gg. ', - 'abbrev-months' => 'mesi ', + 'abbrev-months' => 'M ', 'abbrev-years' => 'aa. ', 'abbrev-weeks' => 'sett. ', 'and' => 'e', @@ -205,14 +205,14 @@ return [ 'subtitle' => 'Sottotitolo', 'subtitles' => 'Sottotitoli', 'support' => 'Supporto', - 'system-message' => 'QUESTO È UN MESSAGGIO AUTOMATICO DI SISTEMA, PER FAVORE NON RISPONDERE!', + 'system-message' => 'QUESTO È UN MESSAGGIO AUTOMATICO DI SISTEMA, INUTILE RISPONDERE!', 'the' => 'il/la', 'this' => 'questo', 'top-10' => 'Top 10', 'wished' => 'Desiderato', 'chat-room' => 'Chatroom', 'abbrev-minutes' => 'm ', - 'bookmarked' => 'Contrassegnato', + 'bookmarked' => 'Aggiunto ai preferiti', 'abbrev-seconds' => 's', 'abbrev-hours' => 'h ', 'media-language' => 'Linguaggio dei Media', @@ -227,4 +227,6 @@ return [ 'overview' => 'Panoramica', 'search-advanced' => 'Ricerca avanzata', 'total' => 'Totale', + 'deleted_at' => 'Eliminato al/alle', + 'trending' => 'Di tendenza', ]; diff --git a/lang/it/forum.php b/lang/it/forum.php index 71b4aa610..61619ae58 100644 --- a/lang/it/forum.php +++ b/lang/it/forum.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'action' => 'Azione', - 'activity' => 'Attività', - 'approved' => 'Approvato', - 'author' => 'Autore', - 'bug' => 'insetto', - 'category-quick-search' => 'Ricerca rapida per nome argomento (all interno della categoria)', - 'close-topic' => 'Blocca argomento', - 'closed' => 'Chiuso', - 'create-new-topic' => 'Crea nuovo argomento', - 'created' => 'Creato', - 'current' => 'attuale', - 'delete-topic' => 'Elimina questo argomento', - 'denied' => 'negato', - 'dislike-post' => 'Non mi piace questo post', - 'display-forum' => 'Mostra argomenti in', - 'edit-post' => 'Modifica post', - 'edit-topic' => 'Modifica argomento', - 'forum' => 'Forum', - 'forums' => 'Forum', - 'implemented' => 'implementato', - 'in' => 'Nel', - 'invalid' => 'Non valido', - 'label' => 'Etichetta', - 'label-system' => 'Sistema di etichette', - 'last-message' => 'Ultimo messaggio', - 'last-post-info' => 'Informazioni ultimo post', - 'latest' => 'Più recente', - 'like-post' => 'Piace questo post', - 'meta-category' => 'Elenco dei forum nella categoria', - 'moderation' => 'Moderazione', - 'name' => 'Nome', - 'not-connected' => 'Devi essere connesso', - 'not-subscribed' => 'Non iscritto', - 'open' => 'Aperto', - 'open-topic' => 'Apri questo argomento', - 'permalink' => 'Permalink', - 'pin' => 'Fissa', - 'post' => 'Inviare', - 'post-quick-search' => 'Ricerca rapida corpo postale', - 'posts' => 'Messaggi', - 'quote' => 'Citazione', - 'read-topic' => 'Leggi l argomento', - 'replies' => 'risposte', - 'send-new-topic' => 'Salva questo argomento', - 'solved' => 'risolto', - 'state' => 'Stato', - 'stats' => 'Statistiche', - 'subscribed' => 'sottoscritto', + 'action' => 'Azione', + 'activity' => 'Attività', + 'approved' => 'Approvato', + 'author' => 'Autore', + 'bug' => 'insetto', + 'category-quick-search' => 'Ricerca rapida per nome argomento (all interno della categoria)', + 'close-topic' => 'Blocca argomento', + 'closed' => 'Chiuso', + 'create-new-topic' => 'Crea nuovo argomento', + 'created' => 'Creato', + 'current' => 'attuale', + 'delete-topic' => 'Elimina questo argomento', + 'denied' => 'negato', + 'dislike-post' => 'Non mi piace questo post', + 'display-forum' => 'Mostra argomenti in', + 'edit-post' => 'Modifica post', + 'edit-topic' => 'Modifica argomento', + 'forum' => 'Forum', + 'forums' => 'Forum', + 'implemented' => 'implementato', + 'in' => 'Nel', + 'invalid' => 'Non valido', + 'label' => 'Etichetta', + 'label-system' => 'Sistema di etichette', + 'last-message' => 'Ultimo messaggio', + 'last-post-info' => 'Informazioni ultimo post', + 'latest' => 'Più recente', + 'like-post' => 'Piace questo post', + 'meta-category' => 'Elenco dei forum nella categoria', + 'moderation' => 'Moderazione', + 'name' => 'Nome', + 'not-connected' => 'Devi essere connesso', + 'not-subscribed' => 'Non iscritto', + 'open' => 'Aperto', + 'open-topic' => 'Apri questo argomento', + 'permalink' => 'Permalink', + 'pin' => 'Fissa', + 'post' => 'Inviare', + 'post-quick-search' => 'Ricerca rapida corpo postale', + 'posts' => 'Messaggi', + 'quote' => 'Citazione', + 'read-topic' => 'Leggi l argomento', + 'replies' => 'risposte', + 'send-new-topic' => 'Salva questo argomento', + 'solved' => 'risolto', + 'state' => 'Stato', + 'stats' => 'Statistiche', + 'subscribed' => 'sottoscritto', 'subscription-quick-search' => 'Ricerca rapida per nome argomento (all interno degli abbonamenti)', - 'suggestion' => 'Suggerimento', - 'topic' => 'Argomento', - 'topic-closed' => 'Questo argomento è chiuso', - 'topic-name' => 'Nome dell argomento', - 'topic-quick-search' => 'Argomento Nome ricerca rapida', - 'topic-title' => 'Titolo di questo argomento', - 'topics' => 'Temi', - 'unpin' => 'Sblocca', - 'view-all' => 'Visualizza tutti gli argomenti', - 'views' => 'Visualizzazioni', + 'suggestion' => 'Suggerimento', + 'topic' => 'Argomento', + 'topic-closed' => 'Questo argomento è chiuso', + 'topic-name' => 'Nome dell argomento', + 'topic-quick-search' => 'Argomento Nome ricerca rapida', + 'topic-title' => 'Titolo di questo argomento', + 'topics' => 'Temi', + 'unpin' => 'Sblocca', + 'view-all' => 'Visualizza tutti gli argomenti', + 'views' => 'Visualizzazioni', + 'created-at' => 'Creato', + 'delete-post-success' => 'Questo post è stato eliminato!', + 'edit-post-success' => 'Post modificato con successo!', + 'forums-post-search' => 'Ricerca post', + 'forums-topic-search' => 'Ricerca argomento', + 'reply-topic-error' => 'Non puoi rispondere a questo argomento!', + 'reply-topic-success' => 'Post pubblicato con successo', + 'select-all-forum' => 'Tutte le categorie/forum', + 'subscribe' => 'Iscriviti', + 'tip-post-total' => 'Questo post ha ricevuto una mancia totale di', + 'tip-this-post' => 'Dai una mancia a questo poster', + 'updated-at' => 'Aggiornato al/alle', + 'unsubscribe' => 'Annulla iscrizione', ]; diff --git a/lang/it/graveyard.php b/lang/it/graveyard.php index b4ec22dc4..3eb307bc4 100644 --- a/lang/it/graveyard.php +++ b/lang/it/graveyard.php @@ -22,4 +22,13 @@ return [ 'pending' => 'in attesa di', 'resurrect' => 'riesumare', 'reward' => 'Token Freeleech', + 'current-seedtime' => 'Tempo di semina attuale', + 'not-rewarded' => 'Non ricompensato', + 'resurrect-canceled' => 'Resurrezione annullata con successo!', + 'resurrect-complete' => 'Resurrezione del Torrent completata! Sarai ricompensato automaticamente una volta soddisfatti i requisiti di seed time.', + 'resurrect-date' => 'Data di resurrezione', + 'resurrect-failed-own' => 'Resurrezione del torrent fallita! Non puoi resuscitare i tuoi uploads.', + 'resurrect-failed-pending' => 'Resurrezione del torrent fallita! Questo torrent è già in attesa di essere resuscitato.', + 'rewarded' => 'Premiato', + 'seedtime-goal' => 'Obiettivo di semina', ]; diff --git a/lang/it/notification.php b/lang/it/notification.php index 08fd4ac1f..b25c329cd 100644 --- a/lang/it/notification.php +++ b/lang/it/notification.php @@ -21,4 +21,23 @@ return [ 'notifications' => 'Notifiche', 'read' => 'Leggere', 'title' => 'Titolo', + 'already-marked-read' => 'Notifica già contrassegnata come letta!', + 'all-deleted' => 'Tutte le notifiche eliminate!', + 'all-marked-read' => 'Tutte le notifiche contrassegnate come lette!', + 'bon-gifts' => 'Buoni regalo', + 'comment-tags' => 'Tag di commento', + 'deleted' => 'Notifica eliminata!', + 'filter-by-type' => 'Filtra per tipo di notifica', + 'marked-read' => 'Notifica contrassegnata come letta!', + 'not-existent' => 'La notifica non esiste!', + 'post-tags' => 'Tag dei post', + 'post-tips' => 'Suggerimenti per i post', + 'request-approvals' => 'Approvazione richiesta', + 'request-bounties' => 'Premio Richiesta', + 'request-claims' => 'Reclama la richiesta', + 'request-fills' => 'Richiesta esaudita', + 'request-rejections' => 'Richiesta scartata', + 'request-unclaims' => 'Richiesta non reclamata', + 'reseed-requests' => 'Richiesta di condivisione', + 'unfollows' => 'Smetti di seguire', ]; diff --git a/lang/it/pm.php b/lang/it/pm.php index 361e1d6eb..ecab3aa9d 100644 --- a/lang/it/pm.php +++ b/lang/it/pm.php @@ -35,4 +35,9 @@ return [ 'subject' => 'Soggetto', 'to' => 'A', 'unread' => 'Non letto', + 'all-marked-read' => 'Tutti i tuoi messaggi sono stati contrassegnati come letti!', + 'delete-success' => 'PM eliminato con successo!', + 'error' => 'Cosa stai cercando di fare ?!', + 'sent-success' => 'Il tuo messaggio privato è stato inviato con successo!', + 'empty-inbox' => 'Svuota messaggi in arrivo', ]; diff --git a/lang/it/poll.php b/lang/it/poll.php index 667b5342d..c0ca78a66 100644 --- a/lang/it/poll.php +++ b/lang/it/poll.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'add-option' => 'Aggiungi opzione', - 'create-poll' => 'Crea sondaggio', - 'current' => 'Sondaggio (i) corrente', - 'delete-option' => 'Elimina l opzione', + 'add-option' => 'Aggiungi opzione', + 'create-poll' => 'Crea sondaggio', + 'current' => 'Sondaggio (i) corrente', + 'delete-option' => 'Elimina l opzione', 'multiple-choice' => 'Questo è un sondaggio a scelta multipla. Seleziona tutte le risposte che vuoi.', - 'option' => 'Opzione', - 'poll' => 'Sondaggio', - 'polls' => 'sondaggi', - 'results' => 'Risultati del sondaggio', - 'title' => 'Titolo', - 'total' => 'Voti totali di sempre', - 'vote' => 'Votazione', - 'vote-now' => 'Ottieni il tuo voto adesso!', - 'votes' => 'voti', + 'option' => 'Opzione', + 'poll' => 'Sondaggio', + 'polls' => 'sondaggi', + 'results' => 'Risultati del sondaggio', + 'title' => 'Titolo', + 'total' => 'Voti totali di sempre', + 'vote' => 'Votazione', + 'vote-now' => 'Ottieni il tuo voto adesso!', + 'votes' => 'voti', + 'already-voted-error' => 'Hai già votato per questo sondaggio. Il tuo voto non è stato conteggiato.', + 'already-voted-result' => 'Hai già votato per questo sondaggio. Ecco i risultati.', + 'expired-voted-result' => 'Questo sondaggio è terminato. Ecco i risultati.', + 'edit-poll' => 'Modifica sondaggio', + 'vote-counted' => 'Il tuo voto è stato conteggiato.', + 'close-date' => 'Chiudi sondaggio dopo', ]; diff --git a/lang/it/request.php b/lang/it/request.php index d4131ec42..1bae1d4ba 100644 --- a/lang/it/request.php +++ b/lang/it/request.php @@ -76,4 +76,23 @@ return [ 'yes' => 'sì', 'resolution' => 'Risoluzione', 'resolutions' => 'Risoluzioni', + 'access-error' => 'Non hai i diritti per approvare questa richiesta.', + 'access-delete-error' => 'Non hai i diritti necessari per eliminare questa richiesta.', + 'added-bonus' => 'Il tuo bonus è stato aggiunto con successo.', + 'added-request' => 'Richiesta aggiunta.', + 'already-approved' => 'Sembra che questa richiesta sia già stata approvata', + 'already-claimed' => 'Qualcun altro ha già reclamato questa richiesta.', + 'already-rejected' => 'Sembra che questa richiesta sia già stata respinta', + 'approved-anon' => 'Hai approvato %s e la ricompensa è stata assegnata a un utente anonimo', + 'approved-user' => 'Hai approvato %s e la taglia è stata assegnata a %s', + 'claimed-success' => 'Richiesta reclamata con successo', + 'deleted' => 'Hai eliminato %s', + 'edited-request' => 'Richiesta modificata con successo.', + 'my-filled' => 'Il mio contributo', + 'my-claims' => 'I miei reclami', + 'my-voted' => 'I miei voti', + 'pending-approval' => 'La richiesta è in attesa di approvazione da parte del richiedente.', + 'pending-moderation' => 'ID torrent che stai cercando di utilizzare è valido nel nostro database, ma è ancora in attesa di moderazione. Attendi che il tuo torrent venga approvato e riprova.', + 'request-reset' => 'Questa richiesta è stata reimpostata.', + 'unclaim-error' => 'Niente da reclamare.', ]; diff --git a/lang/it/rss.php b/lang/it/rss.php index 24ac4a040..faf93d8fe 100644 --- a/lang/it/rss.php +++ b/lang/it/rss.php @@ -26,4 +26,8 @@ return [ 'rss' => 'RSS', 'rss-feed' => 'RSS Feed', 'type' => 'Sorgente', + 'created' => 'Feed RSS privato creato', + 'deleted' => 'Feed RSS eliminato!', + 'error' => 'Impossibile elaborare la richiesta', + 'updated' => 'Feed RSS privato aggiornato', ]; diff --git a/lang/it/staff.php b/lang/it/staff.php index 5317d2bc9..fa59b9980 100644 --- a/lang/it/staff.php +++ b/lang/it/staff.php @@ -56,4 +56,22 @@ return [ 'flush-chat' => 'Cancella Chatbox', 'seedboxes' => 'Seedbox registrate', 'status' => 'stato', + 'application' => 'Richiesta', + 'application-type' => 'Genere', + 'application-referrer' => 'Referente', + 'article-content' => 'Contenuto', + 'blocked-ips' => 'IP bloccati', + 'bon-exchange' => 'Scambio BONUS', + 'bon-earnings' => 'BONUS guadagnato', + 'gifts-log' => 'Registro dei regali', + 'link' => 'Link', + 'mass-email' => 'E-mail di massa', + 'media-languages-desc' => '(Lingue utilizzate per popolare i menu a discesa delle lingue per sottotitoli /audio / ecc.)', + 'moderation-since' => 'Moderato a', + 'notes' => 'Note', + 'page' => 'Pagina', + 'passkeys' => 'Passkeys', + 'rooms' => 'Stanze', + 'statuses' => 'Status', + 'torrent-resolutions' => 'Risoluzione del torrent', ]; diff --git a/lang/it/stat.php b/lang/it/stat.php index 23bb3fe48..28bafc122 100644 --- a/lang/it/stat.php +++ b/lang/it/stat.php @@ -31,15 +31,15 @@ return [ 'stats' => 'Statistiche', 'stats-format' => 'Tutte le statistiche visualizzate nel formato Top 100', 'top-bankers' => 'Top banchieri', - 'top-bountied' => 'Top Ricompense', - 'top-completed' => 'In alto completato', - 'top-dead' => 'Top Dead', + 'top-bountied' => 'Top Ricompensato', + 'top-completed' => 'Top Completati', + 'top-dead' => 'Top morti', 'top-downloaded' => 'Top Torrent scaricati', 'top-downloaders' => 'Top downloader', - 'top-dying' => 'Top Dying', - 'top-leeched' => 'Top Leeched', + 'top-dying' => 'Top morenti', + 'top-leeched' => 'Top in download', 'top-leechers' => 'Leechers migliori', - 'top-seeded' => 'Top Seed', + 'top-seeded' => 'Top in condivisione', 'top-seeding' => 'Top Seeding', 'top-seeders' => 'Top Seeders', 'top-seedsize' => 'Top Seedsize', @@ -52,4 +52,12 @@ return [ 'users-in-group' => 'Utenti nel gruppo', 'users-per-group' => 'Utenti per gruppo', 'active' => 'Attivo', + 'all' => 'Tutto', + 'banned' => 'Bannato', + 'credited' => 'Accreditato', + 'disabled' => 'Disabilitato', + 'last60days' => 'Ultimi 60 giorni', + 'pruned' => 'Sfoltito', + 'real' => 'Effettivo', + 'updated' => '(Aggiornato ogni 10 minuti!)', ]; diff --git a/lang/it/torrent.php b/lang/it/torrent.php index eb065ae11..9b91afc6b 100644 --- a/lang/it/torrent.php +++ b/lang/it/torrent.php @@ -37,7 +37,7 @@ return [ 'completed_at' => 'Completato a', 'completed-not-seeding' => 'Hai completato questo download ma non lo seminano più', 'created_at' => 'Creato il', - 'credited' => 'accreditato', + 'credited' => 'Accreditato', 'current' => 'attuale', 'current-filters' => 'Filtri attuali', 'currently-leeching' => 'Attualmente Leeching', @@ -179,11 +179,11 @@ return [ 'tip-jar' => 'Barattolo delle mance, salvadanaio', 'title' => 'Titolo', 'titles' => 'Titoli', - 'top-completed' => 'Completato il top', - 'top-dead' => 'Top morto', - 'top-dying' => 'Top morendo', - 'top-leeched' => 'Top sanguisughe', - 'top-seeded' => 'Top seminato', + 'top-completed' => 'Top Completati', + 'top-dead' => 'Top morti', + 'top-dying' => 'Top morenti', + 'top-leeched' => 'Top in download', + 'top-seeded' => 'Top in condivisione', 'torrent' => 'Torrent', 'torrent-request' => 'Richiesta Torrent', 'torrent-tips' => 'In totale :total punti BONUS sono stati consegnati all autore del caricamento, di cui :user provengono da te', @@ -207,4 +207,35 @@ return [ 'votes' => 'voti', 'date' => 'Data', 'staff-tools' => 'Strumenti dello Staff', + 'add-to-playlist' => 'Aggiungi alla playlist', + 'comments-left' => 'Commenti lasciati', + 'completed-times' => 'Volte completato', + 'distributor' => 'Distributore', + 'download-rights-active' => 'Diritti di Download attivi', + 'end-year' => 'Fino al anno', + 'episode-number' => 'Numero episodio', + 'genre-tags' => 'Tag di Genere', + 'info-hash' => 'Info Hash', + 'keywords' => 'Parole chiave', + 'keywords-example' => 'Esempio: supereroe, DC Comics, Marvel', + 'not-personal-release' => 'Non è una Release personale', + 'not-seeding' => 'Non condiviso', + 'personal-release' => 'Personal Release', + 'postponed' => 'Rinviati', + 'recent-bumped' => 'Recentemente portato in alto', + 'recommendations' => 'Raccomandazioni', + 'refundable' => 'Rimborsabile', + 'refunded' => 'Rimborsato', + 'region' => 'Regione', + 'required-anime' => 'Richiesto per gli Anime', + 'required-games' => 'Richiesto per i giochi', + 'revokefeatured' => 'Revoca In Evidenza', + 'search-by-name' => 'Cerca per nome', + 'season-number' => 'Numero della stagione', + 'season' => 'Stagione', + 'special-double_upload' => 'Doppio Upload Speciale', + 'start-year' => 'Anno di inizio', + 'subtitle-included' => 'Questo torrent include già i seguenti sottotitoli mixati:', + 'torrents-matched' => 'Torrent abbinati', + 'year-range' => 'Intervallo di anni', ]; diff --git a/lang/it/user.php b/lang/it/user.php index 79627852f..6c12182cf 100644 --- a/lang/it/user.php +++ b/lang/it/user.php @@ -306,12 +306,15 @@ return [ 'user-id' => 'ID utente', 'username-seedbox' => 'Nome utente Seedbox', 'visible-to-achievement' => 'Risultati visibili a', - 'visible-to-achievement-help' => 'I tuoi risultati saranno visibili solo al personale e ai seguenti gruppi. Queste impostazioni sono sovrascritte se vai privato', - 'visible-to-follower' => 'Seguaci visibili', - 'visible-to-follower-help' => 'I tuoi follower saranno visibili solo allo staff e ai seguenti gruppi. Queste impostazioni sono sovrascritte se vai privato', + 'visible-to-achievement-help' => 'I tuoi risultati saranno visibili solo al personale e ai seguenti gruppi. +Queste impostazioni sono sovrascritte se vai privato', + 'visible-to-follower' => 'Seguaci visibili a', + 'visible-to-follower-help' => 'I tuoi follower saranno visibili solo allo staff e ai seguenti gruppi. +Queste impostazioni sono sovrascritte se vai privato', 'visible-to-forum' => 'Informazioni sul forum Visibile a', - 'visible-to-forum-help' => 'Le informazioni del tuo forum saranno visibili solo allo staff e ai seguenti gruppi. Queste impostazioni sono sovrascritte se vai privato', - 'visible-to-other' => 'Altro visibile', + 'visible-to-forum-help' => 'Le tue informazioni nel forum saranno visibili solo allo staff e ai seguenti gruppi. +Queste impostazioni sono sovrascritte se vai privato', + 'visible-to-other' => 'Altro visibile a', 'visible-to-other-help' => 'Altre informazioni relative al tuo account saranno visibili solo allo staff e ai seguenti gruppi. Queste impostazioni sono sovrascritte se vai privato o se vai nascosto', 'visible-to-profile' => 'Profilo visibile a', 'visible-to-profile-help' => 'Il tuo profilo sarà visibile solo al personale e ai seguenti gruppi. Queste impostazioni sono sovrascritte se vai privato', @@ -323,6 +326,94 @@ return [ 'warning' => 'avvertimento', 'warning-log' => 'Registro avvisi', 'wishlist' => 'Lista dei desideri', - 'top-bountied' => 'Top Ricompense', + 'top-bountied' => 'Top Ricompensato', 'warnings' => 'Avvertenze', + 'unregistered-info-hashes' => 'Informazioni HASH non registrate', + 'personal-releases' => 'Release Personali', + 'apikey' => 'Chiave API', + 'apikeys' => 'Chiavi API', + 'bans' => 'Bans', + 'client-list' => 'Clients e indirizzi IP', + 'created' => 'Creato', + 'deactivate' => 'Disattivare', + 'deactivate-all' => 'Disattiva tutto', + 'delete-all' => 'Elimina tutto', + 'deleted-by' => 'Eliminato da', + 'deleted-on' => 'Eliminato il/nel', + 'email-updates' => 'E-mail aggiornate', + 'follow-already' => 'Stai già seguendo questo utente', + 'follow-not-to-begin-with' => 'Non stai seguendo questo utente', + 'follow-revoked' => 'Non segui più %s', + 'follow-user' => 'Ora stai seguendo %s', + 'follow-yourself' => 'Bel tentativo, ma purtroppo non puoi seguire te stesso.', + 'following' => 'Stai seguendo', + 'homepage-blocks' => 'Blocchi in Homepage', + 'homepage-block-chat-visible' => 'Mostra Chatbox', + 'homepage-block-featured-visible' => 'Mostra i torrent In Evidenza', + 'homepage-block-latest-comments-visible' => 'Mostra gli ultimi commenti', + 'homepage-block-latest-posts-visible' => 'Mostra gli ultimi post', + 'homepage-block-latest-topics-visible' => 'Mostra gli argomenti più recenti', + 'homepage-block-news-visible' => 'Mostra le ultime notizie', + 'homepage-block-online-visible' => 'Mostra utenti online', + 'homepage-block-poll-visible' => 'Mostra ultimo sondaggio', + 'homepage-block-random-media-visible' => 'Mostra contenuti multimediali casuali', + 'homepage-block-top-torrents-visible' => 'Mostra i migliori Torrents', + 'homepage-block-top-users-visible' => 'Mostra gli utenti migliori', + 'invite-already-used' => 'L invito che stai tentando di inviare è già stato utilizzato.', + 'invite-expired' => 'L invito che stai tentando di inviare è scaduto.', + 'invite-resent-success' => 'invito inviato con successo!', + 'invite-sent-success' => 'invito inviato con successo!', + 'invites-disabled-group' => 'Al momento per il tuo gruppo gli inviti sono disabilitati.', + 'judge' => 'Giudice', + 'last-action' => 'Ultima azione', + 'my-achievements' => 'I miei risultati', + 'my-downloads' => 'I miei downloads', + 'my-playlists' => 'Le mie playlist', + 'my-uploads' => 'I miei Uploads', + 'no-ban' => 'Non ci sono BAN nel database per questo utente!', + 'no-soft-warning' => 'Non ci sono avvertimenti eliminati nel database per questo utente!', + 'no-warning' => 'Non ci sono avvertimenti nel database per questo utente!', + 'not-enough-invites' => 'Non hai abbastanza inviti!', + 'not-satisfied-not-immune' => 'Non soddisfatto / Non immune', + 'open-registration' => 'Registrazione aperta', + 'password-resets' => 'Reimpostazione della password', + 'reactivate' => 'Riattivare', + 'reason-ban' => 'Motivo del BAN', + 'reason-unban' => 'Motivo UnBAN', + 'removed' => 'RIMOSSO', + 'report-sent' => 'Il tuo report è stato inviato con successo', + 'reset-api-token' => 'Reimposta token API', + 'reset-api-help' => 'Dopo aver reimpostato il token API, dovrai aggiornare tutti gli script o le applicazioni che stai utilizzando con il tuo nuovo token.', + 'restore' => 'Ripristina', + 'rsskey' => 'Chiave RSS', + 'rsskeys' => 'Chiavi RSS', + 'satisfied-immune' => 'Soddisfatto / Immune', + 'seedbox-added-success' => 'La Seedbox è stata aggiunta con successo!', + 'seedbox-deleted-success' => 'La Seedbox è stata eliminata con successo', + 'seeding-size' => 'Condiviso', + 'soft-deleted-warnings' => 'Avvertimenti cancellati', + 'top-completed' => 'Top Completati', + 'top-dead' => 'Top morti', + 'top-dying' => 'Top morenti', + 'top-leeched' => 'Top in download', + 'top-seeded' => 'Top in condivisione', + 'total-internal-releases' => 'Totale Releases interne', + 'total-personal-releases' => 'Totale Releases personali', + 'two-step-auth' => [ + 'title' => 'Autenticazione a due fattori', + 'totp' => 'Autenticazione con password monouso basata sul tempo (TOTP)', + 'email' => 'Autenticazione e-mail', + 'totp-is-enabled' => 'Autenticazione TOTP attualmente abilitata. Per disabilitarla, clicca sul pulsante "Disabilita" qui sotto.', + 'totp-is-disabled' => 'Autenticazione TOTP attualmente disabilitata. Per abilitarla, clicca sul pulsante "Abilita" qui sotto.', + 'password-confirm' => 'Richiede la conferma della password', + 'upon-enabling' => 'Dopo averlo abilitato, ti verrà chiesto di inserire un codice di autenticazione a due fattori valido.', + 'complete-setup' => 'Per completare l abilitazione dell\'autenticazione TOTP, scansiona il codice a barre qui sotto con la tua app di autenticazione (Google Authenticator, Authy, BitWarden, ecc.) e inserisci il codice TOTP nel modulo sottostante.', + 'confirm-code' => 'Conferma il codice TOTP', + 'recovery-code' => 'Codici di recupero della password monouso basata sul tempo (TOTP)', + 'recovery-code-description' => 'Clicca sul pulsante "Rivela" per visualizzare i codici di recupero del tuo account. Salva questi codici offline in modo sicuro nel caso in cui perdessi accesso al tuo dispositivo TOTP. Se ritieni che questi codici possano essere stati compromessi, clicca su "Reimposta" per generare un nuovo set di codici.', + 'recovery-code-reveal' => 'Rivela', + 'recovery-code-reset' => 'Reset', + ], + 'upload-snatches' => 'Caricamento in corso', + 'warned-by' => 'Ammonito da', ]; diff --git a/lang/it/validation.php b/lang/it/validation.php index 01fbb3c93..972e4cc5e 100644 --- a/lang/it/validation.php +++ b/lang/it/validation.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ /* |-------------------------------------------------------------------------- | Validation Language Lines @@ -24,111 +21,111 @@ return [ | as the size rules. Feel free to tweak each of these messages here. | */ - - 'accepted' => ':attribute deve essere accettato.', - 'active_url' => ':attribute non è un URL valido.', - 'after' => ':attribute deve essere una data successiva al :date.', - 'after_or_equal' => ':attribute deve essere una data successiva o uguale al :date.', - 'alpha' => ':attribute può contenere solo lettere.', - 'alpha_dash' => ':attribute può contenere solo lettere, numeri e trattini.', - 'alpha_num' => ':attribute può contenere solo lettere e numeri.', - 'array' => ':attribute deve essere un array.', - 'before' => ':attribute deve essere una data precedente al :date.', + 'accepted' => ':attribute deve essere accettato.', + 'active_url' => ':attribute non è un URL valido.', + 'after' => ':attribute deve essere una data successiva al :date.', + 'after_or_equal' => ':attribute deve essere una data successiva o uguale al :date.', + 'alpha' => ':attribute può contenere solo lettere.', + 'alpha_dash' => ':attribute può contenere solo lettere, numeri e trattini.', + 'alpha_num' => ':attribute può contenere solo lettere e numeri.', + 'array' => ':attribute deve essere un array.', + 'before' => ':attribute deve essere una data precedente al :date.', 'before_or_equal' => ':attribute deve essere una data precedente o uguale al :date.', - 'between' => [ + 'between' => [ 'numeric' => ':attribute deve trovarsi tra :min - :max.', - 'file' => ':attribute deve trovarsi tra :min - :max kilobyte.', - 'string' => ':attribute di :min - :max caratteri', - 'array' => ':attribute deve avere tra :min - :max elementi.', + 'file' => ':attribute deve trovarsi tra :min - :max kilobyte.', + 'string' => ':attribute di :min - :max caratteri', + 'array' => ':attribute deve avere tra :min - :max elementi.', ], - 'boolean' => 'Il campo :attribute deve essere vero o falso.', - 'confirmed' => 'Il campo di conferma per :attribute non coincide.', - 'date' => ':attribute non è una data valida.', - 'date_equals' => ':attribute deve essere una data e uguale a :date.', - 'date_format' => ':attribute non coincide con il formato :format.', - 'different' => ':attribute e :other devono essere differenti.', - 'digits' => ':attribute deve essere di :digits cifre.', + 'boolean' => 'Il campo :attribute deve essere vero o falso.', + 'confirmed' => 'Il campo di conferma per :attribute non coincide.', + 'date' => ':attribute non è una data valida.', + 'date_equals' => ':attribute deve essere una data e uguale a :date.', + 'date_format' => ':attribute non coincide con il formato :format.', + 'different' => ':attribute e :other devono essere differenti.', + 'digits' => ':attribute deve essere di :digits cifre.', 'digits_between' => ':attribute deve essere tra :min e :max cifre.', - 'dimensions' => "Le dimensioni dell'immagine di :attribute non sono valide.", - 'distinct' => ':attribute contiene un valore duplicato.', - 'email' => ':attribute non è valido.', - 'exists' => ':attribute selezionato non è valido.', - 'file' => ':attribute deve essere un file.', - 'filled' => 'Il campo :attribute deve contenere un valore.', - 'gt' => [ + 'dimensions' => "Le dimensioni dell'immagine di :attribute non sono valide.", + 'distinct' => ':attribute contiene un valore duplicato.', + 'email' => ':attribute non è valido.', + 'exists' => ':attribute selezionato non è valido.', + 'file' => ':attribute deve essere un file.', + 'filled' => 'Il campo :attribute deve contenere un valore.', + 'gt' => [ 'numeric' => ':attribute deve essere maggiore di :value.', - 'file' => ':attribute deve essere maggiore di :value kilobyte.', - 'string' => ':attribute deve contenere più di :value caratteri.', - 'array' => ':attribute deve contenere più di :value elementi.', + 'file' => ':attribute deve essere maggiore di :value kilobyte.', + 'string' => ':attribute deve contenere più di :value caratteri.', + 'array' => ':attribute deve contenere più di :value elementi.', ], 'gte' => [ 'numeric' => ':attribute deve essere uguale o maggiore di :value.', - 'file' => ':attribute deve essere uguale o maggiore di :value kilobyte.', - 'string' => ':attribute deve contenere un numero di caratteri uguale o maggiore di :value.', - 'array' => ':attribute deve contenere un numero di elementi uguale o maggiore di :value.', + 'file' => ':attribute deve essere uguale o maggiore di :value kilobyte.', + 'string' => ':attribute deve contenere un numero di caratteri uguale o maggiore di :value.', + 'array' => ':attribute deve contenere un numero di elementi uguale o maggiore di :value.', ], - 'image' => ":attribute deve essere un'immagine.", - 'in' => ':attribute selezionato non è valido.', + 'image' => ":attribute deve essere un'immagine.", + 'in' => ':attribute selezionato non è valido.', 'in_array' => 'Il valore del campo :attribute non esiste in :other.', - 'integer' => ':attribute deve essere un numero intero.', - 'ip' => ':attribute deve essere un indirizzo IP valido.', - 'ipv4' => ':attribute deve essere un indirizzo IPv4 valido.', - 'ipv6' => ':attribute deve essere un indirizzo IPv6 valido.', - 'json' => ':attribute deve essere una stringa JSON valida.', - 'lt' => [ + 'integer' => ':attribute deve essere un numero intero.', + 'ip' => ':attribute deve essere un indirizzo IP valido.', + 'ipv4' => ':attribute deve essere un indirizzo IPv4 valido.', + 'ipv6' => ':attribute deve essere un indirizzo IPv6 valido.', + 'json' => ':attribute deve essere una stringa JSON valida.', + 'lt' => [ 'numeric' => ':attribute deve essere minore di :value.', - 'file' => ':attribute deve essere minore di :value kilobyte.', - 'string' => ':attribute deve contenere meno di :value caratteri.', - 'array' => ':attribute deve contenere meno di :value elementi.', + 'file' => ':attribute deve essere minore di :value kilobyte.', + 'string' => ':attribute deve contenere meno di :value caratteri.', + 'array' => ':attribute deve contenere meno di :value elementi.', ], 'lte' => [ 'numeric' => ':attribute deve essere minore o uguale a :value.', - 'file' => ':attribute deve essere minore o uguale a :value kilobyte.', - 'string' => ':attribute deve contenere un numero di caratteri minore o uguale a :value.', - 'array' => ':attribute deve contenere un numero di elementi minore o uguale a :value.', + 'file' => ':attribute deve essere minore o uguale a :value kilobyte.', + 'string' => ':attribute deve contenere un numero di caratteri minore o uguale a :value.', + 'array' => ':attribute deve contenere un numero di elementi minore o uguale a :value.', ], 'max' => [ 'numeric' => ':attribute non può essere superiore a :max.', - 'file' => ':attribute non può essere superiore a :max kilobyte.', - 'string' => ':attribute non può contenere più di :max caratteri.', - 'array' => ':attribute non può avere più di :max elementi.', + 'file' => ':attribute non può essere superiore a :max kilobyte.', + 'string' => ':attribute non può contenere più di :max caratteri.', + 'array' => ':attribute non può avere più di :max elementi.', ], - 'mimes' => ':attribute deve essere del tipo: :values.', + 'mimes' => ':attribute deve essere del tipo: :values.', 'mimetypes' => ':attribute deve essere del tipo: :values.', - 'min' => [ + 'min' => [ 'numeric' => ':attribute deve essere almeno :min.', - 'file' => ':attribute deve essere almeno di :min kilobyte.', - 'string' => ':attribute deve contenere almeno :min caratteri.', - 'array' => ':attribute deve avere almeno :min elementi.', + 'file' => ':attribute deve essere almeno di :min kilobyte.', + 'string' => ':attribute deve contenere almeno :min caratteri.', + 'array' => ':attribute deve avere almeno :min elementi.', ], - 'not_in' => 'Il valore selezionato per :attribute non è valido.', - 'not_regex' => 'Il formato di :attribute non è valido.', - 'numeric' => ':attribute deve essere un numero.', - 'present' => 'Il campo :attribute deve essere presente.', - 'regex' => 'Il formato del campo :attribute non è valido.', - 'required' => 'Il campo :attribute è richiesto.', - 'required_if' => 'Il campo :attribute è richiesto quando :other è :value.', - 'required_unless' => 'Il campo :attribute è richiesto a meno che :other sia in :values.', - 'required_with' => 'Il campo :attribute è richiesto quando :values è presente.', - 'required_with_all' => 'Il campo :attribute è richiesto quando :values sono presenti.', - 'required_without' => 'Il campo :attribute è richiesto quando :values non è presente.', + 'not_in' => 'Il valore selezionato per :attribute non è valido.', + 'not_regex' => 'Il formato di :attribute non è valido.', + 'numeric' => ':attribute deve essere un numero.', + 'present' => 'Il campo :attribute deve essere presente.', + 'regex' => 'Il formato del campo :attribute non è valido.', + 'required' => 'Il campo :attribute è richiesto.', + 'required_if' => 'Il campo :attribute è richiesto quando :other è :value.', + 'required_unless' => 'Il campo :attribute è richiesto a meno che :other sia in :values.', + 'required_with' => 'Il campo :attribute è richiesto quando :values è presente.', + 'required_with_all' => 'Il campo :attribute è richiesto quando :values sono presenti.', + 'required_without' => 'Il campo :attribute è richiesto quando :values non è presente.', 'required_without_all' => 'Il campo :attribute è richiesto quando nessuno di :values è presente.', - 'same' => ':attribute e :other devono coincidere.', - 'size' => [ + 'same' => ':attribute e :other devono coincidere.', + 'size' => [ 'numeric' => ':attribute deve essere :size.', - 'file' => ':attribute deve essere :size kilobyte.', - 'string' => ':attribute deve contenere :size caratteri.', - 'array' => ':attribute deve contenere :size elementi.', + 'file' => ':attribute deve essere :size kilobyte.', + 'string' => ':attribute deve contenere :size caratteri.', + 'array' => ':attribute deve contenere :size elementi.', ], 'starts_with' => ':attribute deve iniziare con uno dei seguenti: :values', - 'string' => ':attribute deve essere una stringa.', - 'timezone' => ':attribute deve essere una zona valida.', - 'unique' => ':attribute già utilizzato', - 'uploaded' => ':attribute non è stato caricato.', - 'url' => 'Il formato del campo :attribute non è valido.', - 'uuid' => ':attribute deve essere un UUID valido.', - - /* + 'string' => ':attribute deve essere una stringa.', + 'timezone' => ':attribute deve essere una zona valida.', + 'unique' => ':attribute già utilizzato', + 'uploaded' => ':attribute non è stato caricato.', + 'url' => 'Il formato del campo :attribute non è valido.', + 'uuid' => ':attribute deve essere un UUID valido.', + 'custom' => [ + 'attribute-name' => [ + /* |-------------------------------------------------------------------------- | Custom Validation Language Lines |-------------------------------------------------------------------------- @@ -138,14 +135,11 @@ return [ | specify a specific custom language line for a given attribute rule. | */ - - 'custom' => [ - 'attribute-name' => [ 'rule-name' => 'custom-message', ], ], - - /* + 'attributes' => [ + /* |-------------------------------------------------------------------------- | Custom Validation Attributes |-------------------------------------------------------------------------- @@ -155,34 +149,52 @@ return [ | of "email". This simply helps us make messages a little cleaner. | */ - - 'attributes' => [ - 'name' => 'nome', - 'username' => 'nome utente', - 'first_name' => 'nome', - 'last_name' => 'cognome', + 'name' => 'nome', + 'username' => 'nome utente', + 'first_name' => 'nome', + 'last_name' => 'cognome', 'password_confirmation' => 'conferma password', - 'city' => 'città', - 'country' => 'paese', - 'address' => 'indirizzo', - 'phone' => 'telefono', - 'mobile' => 'cellulare', - 'age' => 'età', - 'sex' => 'sesso', - 'gender' => 'genere', - 'day' => 'giorno', - 'month' => 'mese', - 'year' => 'anno', - 'hour' => 'ora', - 'minute' => 'minuto', - 'second' => 'secondo', - 'title' => 'titolo', - 'content' => 'contenuto', - 'description' => 'descrizione', - 'excerpt' => 'estratto', - 'date' => 'data', - 'time' => 'ora', - 'available' => 'disponibile', - 'size' => 'dimensione', + 'city' => 'città', + 'country' => 'paese', + 'address' => 'indirizzo', + 'phone' => 'telefono', + 'mobile' => 'cellulare', + 'age' => 'età', + 'sex' => 'sesso', + 'gender' => 'genere', + 'day' => 'giorno', + 'month' => 'mese', + 'year' => 'anno', + 'hour' => 'ora', + 'minute' => 'minuto', + 'second' => 'secondo', + 'title' => 'titolo', + 'content' => 'contenuto', + 'description' => 'descrizione', + 'excerpt' => 'estratto', + 'date' => 'data', + 'time' => 'ora', + 'available' => 'disponibile', + 'size' => 'dimensione', ], + 'accepted_if' => ':attribute deve essere accettato quando :other è :value.', + 'current_password' => 'La password non è corretta.', + 'declined' => ':attribute deve essere rifiutato.', + 'declined_if' => ':attribute deve essere rifiutato quando :other è :value.', + 'ends_with' => ':attribute deve terminare con uno dei seguenti: :values.', + 'enum' => ':attribute selezionato non è valido', + 'mac_address' => ':attribute deve essere un indirizzo MAC valido.', + 'multiple_of' => ':attribute deve essere un multiplo di :value.', + 'password' => [ + 'letters' => ':attribute deve contenere almeno una lettera.', + 'mixed' => ':attribute deve contenere almeno una lettera maiuscola e una minuscola.', + 'numbers' => ':attribute deve contenere almeno un numero.', + 'symbols' => ':attribute deve contenere almeno un simbolo.', + 'uncompromised' => ':attribute specificato è apparso in una fuga di dati. Scegli un :attribute diverso.', + ], + 'prohibited' => 'Il campo :attribute è proibito.', + 'prohibited_if' => 'Il campo :attribute è proibito quando :other è :value.', + 'prohibited_unless' => 'Il campo :attribute è proibito a meno che :other non sia in :values.', + 'prohibits' => 'Il campo :attribute impedisce la presenza di :other.', + 'recaptcha' => 'Si prega di compilare il ReCaptcha.', ]; diff --git a/lang/uk/articles.php b/lang/uk/articles.php index 542ee0320..4ba7fe2d2 100644 --- a/lang/uk/articles.php +++ b/lang/uk/articles.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'articles' => 'Новини', - 'meta-articles' => 'Новини на трекері', - 'published-at' => 'Опубліковано', - 'read-more' => 'Докладніше', + 'articles' => 'Новини', + 'meta-articles' => 'Статті та новини на трекері та в спільноті', + 'published-at' => 'Дата публікації ', + 'read-more' => 'Докладніше', ]; diff --git a/lang/uk/auth.php b/lang/uk/auth.php index 503e6bf77..40e9e2621 100644 --- a/lang/uk/auth.php +++ b/lang/uk/auth.php @@ -24,16 +24,16 @@ return [ */ 'activation-error' => 'Заблокований чи неправильний токен або обліковий запис вже підтверджено!', 'activation-success' => 'Обліковий запис підтверджено! Ви можете увійти!', - 'add-image' => 'Додати ще одне', + 'add-image' => 'Ще одне покликання', 'add-profile' => 'Додати ще одне', 'allow-invite-appl' => 'Відкрита реєстрація вимкнена! Ви повинні мати інвайт, щоб зареєструватись! Але Ви можете створити заявку на реєстрацію. Вас буде перенаправлено на сторінку створення заявки!', 'allow-invite' => 'Відкрита реєстрація вимкнена! Ви повинні мати інвайт, щоб зареєструватись! Вас буде перенаправлено на сторінку входу!', 'are-you' => 'Ви:', 'application' => 'Заявка на реєстрацію', - 'appl-closed' => 'Заявки закриті', - 'appl-intro' => 'це закрита спільнота. Тут Ви можете створити заявку на реєстрацію. Заповніть посилання на Ваш профіль на закритих трекерах. Чим більше Ви заповните інформації про себе, тим більша ймовірність, що Ваша заявка буде прийнята.', + 'appl-closed' => 'Подання заявок на реєстрацію завершено', + 'appl-intro' => 'це закрита спільнота. Для реєстрації необхідне запрошення. Якщо ви не можете отримати запрошення, ви можете заповнити наступну заявку на вступ до спільноти.', 'appl-reason' => 'Як ви дізналися про ":sitename" і чому хочете долучитися? ', - 'application-submitted' => 'Вашу заявку надіслано. Незабаром ви отримаєте електронний лист!', + 'application-submitted' => 'Заявку прийнято. Лист із рішенням буде надіслано найближчим часом!', 'banned' => 'Цей профіль заблоковано!', 'check-later' => 'Перевірте пізніше!', 'delete-image' => 'Видалити останнє', @@ -42,19 +42,19 @@ return [ 'failed' => 'Ці облікові дані не збігаються з нашими записами.', 'invalid-key' => 'Недійсний або протермінований ключ інвайту!', 'login' => 'Вхід', - 'login-now-on' => 'Ввійти зараз', + 'login-now-on' => 'Увійти зараз', 'logout' => 'Вийти', 'lost-password' => 'Забули Пароль?', 'lost-username' => 'Забули Логін?', 'need-invite' => 'Відкрита реєстрація вимкнена і вам потрібен інвайт, щоб отримати доступ!', 'newbie' => 'Новачок', 'not-a-member' => 'Ще не є учасником? Зареєструйтесь менше ніж за 30с.', - 'not-activated' => 'Цей обліковий запис ще не був активований і знаходиться на перевірці. Будь ласка перевірте свою пошту на наявність активаційного посилання. Якщо Ви його не отримали, натисність "Забув пароль" і пройдіть наступні кроки.', + 'not-activated' => 'Цей обліковий запис ще не був активований і знаходиться на перевірці. Будь ласка перевірте свою пошту на наявність активаційного посилання. Якщо Ви його не отримали, натисніть "Забув пароль" і пройдіть наступні кроки.', 'password' => 'Пароль', 'proof-image' => 'Посилання на скріншот профілю на трекері', 'proof-image-title' => 'Посилання на скріншоти Ваших профілів на інших торрент трекерах, пріоритет надається закритим трекерам', 'proof-profile' => 'Посилання на Ваш профіль на трекері', - 'proof-profile-title' => 'Посилання на Ваші профілі на інших торрент трекерах, пріоритет надається закритим трекерам', + 'proof-profile-title' => 'Посилання на Ваші профілі на інших торрент-трекерах, пріоритет надається закритим трекерам', 'proof-min' => '(Мінімум 2)', 'recover-my-password' => 'Відновити Мій Пароль', 'register-thanks' => 'Дякуємо за реєстрацію! Будь ласка, перевірте свою електронну пошту, щоб підтвердити свій обліковий запис', @@ -63,7 +63,7 @@ return [ 'signup' => 'Реєстрація', 'throttle' => 'Занадто багато спроб входу. Будь ласка, спробуйте ще раз, через :seconds секунд.', 'unlock' => 'Розблокувати', - 'user-icon' => 'Піктограма', + 'user-icon' => 'Піктограма користувача', 'username' => 'Логін', 'veteran' => 'Маєте досвід користування закритими торрент трекерами', 'welcome' => 'З Поверненням!', @@ -71,12 +71,18 @@ return [ 'password-reset' => 'Скинути пароль', 'enter-recovery' => 'Будь ласка, введіть один з кодів відновлення, наданих вам під час першого ввімкнення двофакторної автентифікації.', 'code' => 'Код TOTP', - 'confirm-password' => 'Підтвердити пароль', - 'confirm-new-password' => 'Підтвердити новий пароль', + 'confirm-password' => 'Підтвердьте пароль', + 'confirm-new-password' => 'Підтвердьте новий пароль', 'email-verification-link' => 'Посилання для підтвердження було надіслано вам на електронну пошту!', 'enter-totp' => 'Будь ласка, введіть 6-значний код автентифікації, згенерований вашим додатком.', 'new-password' => 'Новий пароль', - 'password-confirm-desc' => 'Будь ласка, підтвердіть свій пароль, перш ніж продовжити.', + 'password-confirm-desc' => 'Будь ласка, підтвердьте свій пароль, перш ніж продовжити.', 'password-confirmation' => 'Підтвердження пароля', 'recovery-code' => 'Код відновлення', + 'send-verification-email' => 'Надіслати е-лист для підтвердження', + 'verify' => 'Підтвердити', + 'verifying' => 'Перевіряється...', + 'verify-email' => 'Підтвердити електронну пошту', + 'totp-code' => 'Код TOTP', + 'apply' => 'Застосувати', ]; diff --git a/lang/uk/backup.php b/lang/uk/backup.php index efdb672ef..0f4ee0c45 100644 --- a/lang/uk/backup.php +++ b/lang/uk/backup.php @@ -14,10 +14,10 @@ return [ 'actions' => 'Дії', 'backup' => 'Резервне копіювання', 'backup_doesnt_exist' => 'Файл резервної копії не існує.', - 'create_a_new_backup' => 'Створити повне резервне копіювання', + 'create_a_new_backup' => 'Створити повноцінну резервну копію', 'create_a_new_files_backup' => 'Створити резервну копію файлів', 'create_a_new_db_backup' => 'Створити резервну копію бази даних', - 'create_confirmation_message' => 'Перезавантаження сторінки за 3 секунди.', + 'create_confirmation_message' => 'Зачекайте кілька хвилин, потім оновіть сторінку.', 'create_confirmation_title' => 'Резервне копіювання завершено', 'create_error_message' => 'Не вдалося створити файл резервної копії.', 'create_error_title' => 'Помилка резервного копіювання', diff --git a/lang/uk/blocks.php b/lang/uk/blocks.php index 31f2e10b4..f87c9322a 100644 --- a/lang/uk/blocks.php +++ b/lang/uk/blocks.php @@ -13,18 +13,18 @@ return [ */ 'chatbox' => 'Вікно чату', 'click' => 'Натисніть', - 'to-enable-editor' => ', щоб включити редактор', - 'featured-by' => 'Рекомендовано користувачем', + 'to-enable-editor' => ', для активації редактора', + 'featured-by' => 'Рекомендувач', 'featured-torrents' => 'Рекомендовані Торренти', 'featured-torrents-intro' => 'Завантажуйте їх, поки є можливість!', 'featured-until' => 'Рекомендовано до', 'top-torrents' => 'Найпопулярніші Торренти', - 'latest-posts' => 'Останні повідомлення', - 'latest-topics' => 'Останні теми', + 'latest-posts' => 'Останні дописи', + 'latest-topics' => 'Актуальні обговорення', 'active-in-last' => 'Активна в останній', 'users-online' => 'Користувачі онлайн', 'check-news' => 'Останні новини', - 'new-news' => 'Нові новини', + 'new-news' => 'Актуальне', 'new-torrents' => 'Нові торренти', 'latest-comments' => 'Останні коментарі', ]; diff --git a/lang/uk/bon.php b/lang/uk/bon.php index 6225cc921..70497eb7a 100644 --- a/lang/uk/bon.php +++ b/lang/uk/bon.php @@ -18,7 +18,7 @@ return [ 'bonus' => 'Бонус', 'date' => 'Дата', 'earning' => 'Прибуток', - 'earning-rate' => 'За цей показник ви зароблятимете за кожний період часу.', + 'earning-rate' => 'З поточною ставкою ваш погодинний заробіток становитиме...', 'earnings' => 'Прибутки', 'exchange' => 'Обмін', 'exchange-warning' => 'Обмін є остаточним, будь ласка, перевірте свій вибір, перш ніж здійснювати обмін.', @@ -50,4 +50,17 @@ return [ 'you-have-received-tips' => 'Ви отримали', 'you-have-sent-tips' => 'Ви надіслали', 'your-points' => 'Ваші бонуси', + 'failed-amount-message' => 'Ви повинні ввести суму та повідомлення!', + 'failed' => 'Обмін BON\'ів не відбувся!', + 'failed-user-not-found' => 'Не вдалося знайти вказаного користувача', + 'failed-yourself' => 'Не можна давати чайові самому собі!', + 'gift-sent' => 'Подарунок відправлено', + 'failed-funds-poster' => 'Ваш гаманець каже "ні" чайовим для автора!', + 'failed-funds-uploader' => 'У тебе грошей, як у козла молока!', + 'failed-negative' => 'Ви не можете залишити від\'ємну суму чайових!', + 'pm-subject' => 'Активовано персональний 24-годинний фріліч', + 'pm-message' => 'Ваш [b]Персональний 24-годинний фріліч[/b] розпочався! Термін його дії закінчується %s [b]', + 'points' => 'Бали', + 'success' => 'Обмін бонусів пройшов успішно', + 'success-tip' => 'Ваша порада була успішно застосована!', ]; diff --git a/lang/uk/bot.php b/lang/uk/bot.php index e29e4cc4f..03616501b 100644 --- a/lang/uk/bot.php +++ b/lang/uk/bot.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'about' => 'Про', - 'bot' => 'Бот', - 'bots' => 'Боти', - 'color' => 'Колір', - 'command' => 'Команда', - 'edit-bot' => 'Редагувати Bot', + 'about' => 'Розділ "Про нас"', + 'bot' => 'Бот', + 'bots' => 'Боти', + 'color' => 'Колір', + 'command' => 'Команда', + 'edit-bot' => 'Редагувати Bot', 'emoji-code' => 'Код Emoji', - 'help' => 'Довідка', - 'icon' => 'Значок', - 'info' => 'Інформація', - 'name' => 'Ім я', + 'help' => 'Довідник', + 'icon' => 'Піктограма', + 'info' => 'Інформація', + 'name' => 'Ім\'я', ]; diff --git a/lang/uk/bug.php b/lang/uk/bug.php index 03f00ba4e..074c973f0 100644 --- a/lang/uk/bug.php +++ b/lang/uk/bug.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'bug-report' => 'Повідомлення про помилку', - 'bug-report-description' => 'Повідомити про помилку сайту', - 'enter-description' => 'Опишіть проблему якомога краще', - 'enter-email' => 'Введіть свою електронну пошту', - 'enter-title' => 'Виберіть належну назву', - 'enter-username' => 'Введіть своє ім\'я користувача', - 'high' => 'Високий', - 'low' => 'Низький', - 'priority' => 'Пріоритет', - 'priority-description' => 'Виберіть лише дуже високий рівень, якщо помилка дійсно є проблемою для використання сайту.', - 'very-high' => 'Дуже високо', + 'bug-report' => 'Повідомлення про помилку', + 'bug-report-description' => 'Повідомити про помилку', + 'enter-description' => 'Опишіть проблему якомога детальніше', + 'enter-email' => 'Введіть свій e-mail', + 'enter-title' => 'Виберіть належну назву', + 'enter-username' => 'Невже ще не ввели? Ваше ім\'я користувача, будь ласка', + 'high' => 'Високий', + 'low' => 'Низький', + 'priority' => 'Пріоритет', + 'priority-description' => 'Встановлюйте «дуже високий» пріоритет, коли баг істотно ускладнює роботу з сайтом.', + 'very-high' => 'Дуже високо', ]; diff --git a/lang/uk/comment.php b/lang/uk/comment.php index a49506995..7cf143385 100644 --- a/lang/uk/comment.php +++ b/lang/uk/comment.php @@ -14,7 +14,7 @@ return [ 'added' => 'Ваш коментар було додано!', 'deleted' => 'Коментар було видалено.', 'edited' => 'Коментар було відредаговано.', - 'rights-revoked' => 'Право коментування відібрано!', + 'rights-revoked' => 'Ваші права на коментування анульовано!', 'slow-down' => 'Не поспішайте - забагато коментарів!', 'torrent-status' => 'Торрент повинен пройти модерацію, перш ніж ви зможете його коментувати.', ]; diff --git a/lang/uk/common.php b/lang/uk/common.php index ad82491fd..b2eafd303 100644 --- a/lang/uk/common.php +++ b/lang/uk/common.php @@ -7,12 +7,12 @@ return [ 'abbrev-seconds' => 'с', 'abbrev-weeks' => 'Т ', 'abbrev-years' => 'Р ', - 'about' => 'Про нас', + 'about' => 'Розділ "Про нас"', 'account' => 'Профіль', 'achievement-title' => 'Високий', - 'achievement-unlocked' => 'Ви розблокували досягнення ": name"', + 'achievement-unlocked' => 'Ви розблокували досягнення : name', 'active' => 'Активний', - 'active-warning' => 'Активне попередження', + 'active-warning' => 'Дійсне попередження', 'add' => 'Додати', 'added' => 'Додано', 'and' => 'і', @@ -43,7 +43,7 @@ return [ 'contact-desc' => 'Цей контактний запит буде надіслано власнику і буде зв’язано з вами якнайшвидше', 'contact-header' => 'Привіт', 'create' => 'Створити', - 'created_at' => 'Створено в', + 'created_at' => 'Створено', 'day' => 'Днів', 'delete' => 'Видалити', 'delete-your-comment' => 'Видалити свій коментар', @@ -84,7 +84,7 @@ return [ 'hot' => 'Гаряче!', 'hour' => 'Годин', 'huge' => 'Величезний', - 'icon' => 'Іконка', + 'icon' => 'Піктограма', 'image' => 'Зображення', 'info' => 'Інформація', 'internal' => 'Внутрішній', @@ -94,8 +94,8 @@ return [ 'languages' => 'Мови', 'large' => 'Великий', 'latest' => 'Останні', - 'latest-posts' => 'Останні повідомлення', - 'latest-topics' => 'Останні теми', + 'latest-posts' => 'Останні дописи', + 'latest-topics' => 'Актуальні обговорення', 'legal' => 'Юридична', 'legend' => 'Легенда', 'lists' => 'Списки', @@ -115,7 +115,7 @@ return [ 'month' => 'Місяць', 'months' => 'Місяці', 'my' => 'Мій', - 'name' => 'Назва', + 'name' => 'Ім\'я', 'navigation' => 'Навігація', 'new' => 'Нове!', 'new-adj' => 'Нове', @@ -138,7 +138,7 @@ return [ 'personal' => 'Особистий', 'port' => 'Порт', 'position' => 'Позиція', - 'posts' => 'Повідомлення', + 'posts' => 'Публікації', 'powered-by' => 'Працює на UNIT3D', 'preview' => 'Попередній перегляд', 'previous' => 'Попередній', @@ -149,7 +149,7 @@ return [ 'ratio' => 'Рейтинг', 'reason' => 'Причина', 'remove' => 'Видалити', - 'report' => 'Доповідь', + 'report' => '"Лист щастя"', 'resend' => 'Повторно надіслати', 'resolution' => 'Якість', 'resolutions' => 'Якість', @@ -183,11 +183,11 @@ return [ 'system-message' => 'ЦЕ АВТОМАТИЗОВАНЕ СИСТЕМНЕ ПОВІДОМЛЕННЯ,БУДЬ ЛАСКА НЕ ВІДПОВІДАЙТЕ!', 'teams' => 'Команди', 'terms' => 'Умови використання', - 'times' => 'Times', + 'times' => 'Разів', 'title' => 'Лого', - 'top-bountied' => 'Топ винагород', + 'top-bountied' => 'Топ Скруджів', 'top-10' => 'Топ 10', - 'topics' => 'Теми', + 'topics' => 'Обговорення', 'tracker-codes' => 'Коди трекера', 'type' => 'Тип', 'type-verb' => 'Тип', @@ -198,18 +198,34 @@ return [ 'actions' => 'Дії', 'unknown' => 'Невідомо', 'unlocked-achievement' => 'Ви розблокували: achievement досягнення', - 'upload' => 'Відвантажено', + 'upload' => 'Додати торрент', 'upload-guide' => 'Додати посібник', 'user' => 'Користувач', 'username' => 'Логін', 'users' => 'Користувачі', 'view' => 'Переглянути', 'view-all' => 'Переглянути все', - 'warnings' => 'Попередження', + 'warnings' => 'Усі попередження', 'year' => 'Рік', 'yes' => 'Так', 'your' => 'Ваш', 'your-comment' => 'Ваш коментар', 'subject' => 'Тема', 'send' => 'Надіслати', + 'alive' => 'Живий', + 'bookmarked' => 'Додано в закладки', + 'content' => 'Опис', + 'connected' => 'Підключено', + 'a-an-art' => '/** * ПОВІДОМЛЕННЯ ПРО ЛІЦЕНЗІЮ. * * UNIT3D Community Edition це програмне забезпечення з відкритим вихідним кодом, ліцензоване під GNU Affero General Public License v3.0 * Детальна інформація додається до цього проекту у файлі LICENSE.txt. * * @project UNIT3D Community Edition * * @author HDVinnie * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */||', + 'date' => 'Дата', + 'dead' => 'Мертвий', + 'deleted_at' => 'Видалено', + 'descending' => 'За спаданням', + 'total' => 'Усього', + 'extras' => 'Додаткове', + 'sponsor' => 'Стати спонсором', + 'this' => 'цей', + 'trending' => 'Тенденції', + 'wished' => 'Бажаний', + 'test' => 'тест', ]; diff --git a/lang/uk/email.php b/lang/uk/email.php index a29b7c52a..35e4ccd31 100644 --- a/lang/uk/email.php +++ b/lang/uk/email.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'activate-account' => 'Активувати обліковий запис', - 'ban-reason' => 'Причина', - 'banned-footer' => 'Ось що буває з тими, хто не дотримується правил', - 'banned-header' => 'Вас забанили', - 'bug-description' => 'Проблема', - 'bug-footer' => 'Виправити це лайно', - 'bug-header' => 'Новий звіт про помилку від', - 'bug-priority' => 'Пріоритет', - 'bug-title' => 'Назва помилки', - 'contact-header' => 'Нова контактна пошта від', - 'contact-message' => 'Повідомлення', - 'contact-name' => 'Імя', + 'activate-account' => 'Активувати обліковий запис', + 'ban-reason' => 'Причина', + 'banned-footer' => 'Ось що буває з тими, хто не дотримується правил', + 'banned-header' => 'Вас забанили', + 'bug-description' => 'Проблема', + 'bug-footer' => 'Виправте це лайно, будь ласка!', + 'bug-header' => 'Новий звіт про помилку від', + 'bug-priority' => 'Пріоритет', + 'bug-title' => 'Назва помилки', + 'contact-header' => 'Нова контактна пошта від', + 'contact-message' => 'Повідомлення', + 'contact-name' => 'Ім\'я', 'fail-login-greeting' => 'Помилка входу до облікового запису!', - 'fail-login-line1' => 'У вашому обліковому записі виявлено помилку входу.', - 'fail-login-line2' => 'Цей запит походить від: ip (: host) at: time', - 'fail-login-subject' => 'Помилка повідомлення про вхід', - 'footer-link' => 'Якщо у вас виникли проблеми з натисканням кнопки: actionText, скопіюйте та вставте URL-адресу нижче у веб-переглядач:', - 'invite-header' => 'Запрошення до', - 'invite-invited' => 'Вас запросили', - 'invite-message' => 'Повідомлення', - 'invite-signup' => 'Зареєструватися зараз', - 'newreply-header' => 'У вашій темі є нова відповідь', - 'newreply-message' => 'Повідомлення', - 'newreply-replied' => 'Відповів на вашу тему', - 'newreply-view' => 'Переглянути зараз', - 'no-email-found' => 'Ми не змогли знайти цю електронну пошту в нашій системі!', - 'register-code' => 'Щоб завершити активацію облікового запису, натисніть кнопку нижче', - 'register-footer' => 'Якщо кнопка вище не працює, скопіюйте та вставте URL-адресу в адресний рядок веб-переглядача', - 'register-header' => 'Привіт! Дякуємо за реєстрацію', - 'report-comment' => 'Коментар', - 'report-email' => 'Електронна пошта', - 'report-header' => 'Привіт, адміністратор повідомлено про посилання', - 'report-link' => 'Посилання', - 'report-link-hash' => 'Фактичне посилання', - 'thanks' => 'Дякуємо за використання', - 'unban-footer' => 'З поверненням!', - 'unban-header' => 'Ви заборонили', - 'unban-reason' => 'Причина', - 'username-reminder' => 'Нещодавно ви надіслали нам запит на нагадування вашого логіну. Ваш логін', - 'username-sent' => 'Ваш логін надіслано на вашу адресу електронної пошти!', - 'disabled-header' => 'Ваш обліковий запис вимкнено', - 'pruned-header' => 'Ваш обліковий запис було скасовано', + 'fail-login-line1' => 'Виявлено невдалу спробу входу до вашого облікового запису.', + 'fail-login-line2' => 'Цей запит надійшов від :ip ( :host ) о :time', + 'fail-login-subject' => 'Повідомлення про помилку входу', + 'footer-link' => 'Якщо у вас виникли проблеми з натисканням кнопки :actionText, скопіюйте та вставте URL-адресу нижче у веб-браузер:', + 'invite-header' => 'Запрошення до', + 'invite-invited' => 'Вас запросили', + 'invite-message' => 'Повідомлення', + 'invite-signup' => 'Зареєструватися зараз', + 'newreply-header' => 'У вашій темі є нова відповідь', + 'newreply-message' => 'Повідомлення', + 'newreply-replied' => 'Відповів у вашій темі', + 'newreply-view' => 'Переглянути зараз', + 'no-email-found' => 'Ми не змогли знайти цю електронну пошту в нашій системі!', + 'register-code' => 'Щоб завершити активацію облікового запису, натисніть кнопку нижче', + 'register-footer' => 'Якщо кнопка вище не працює, скопіюйте та вставте URL-адресу в адресний рядок веб-переглядача', + 'register-header' => 'Привіт! Дякуємо за реєстрацію', + 'report-comment' => 'Коментар', + 'report-email' => 'Електронна пошта', + 'report-header' => 'Привіт, адміністраторе, повідомлено про посилання', + 'report-link' => 'Посилання', + 'report-link-hash' => 'Фактичне посилання', + 'thanks' => 'Дякуємо за використання', + 'unban-footer' => 'З поверненням!', + 'unban-header' => 'Вас розбанили', + 'unban-reason' => 'Причина', + 'username-reminder' => 'Нещодавно ви надіслали нам запит на нагадування вашого логіну. Ваш логін', + 'username-sent' => 'Ваш логін надіслано на вашу адресу електронної пошти!', + 'disabled-header' => 'Ваш обліковий запис вимкнено', + 'pruned-header' => 'Ваш обліковий запис було скасовано', ]; diff --git a/lang/uk/forum.php b/lang/uk/forum.php index 202bc7135..8ced5e51d 100644 --- a/lang/uk/forum.php +++ b/lang/uk/forum.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'action' => 'Дія', - 'activity' => 'Діяльність', - 'approved' => 'Затверджено', - 'author' => 'Автор', - 'bug' => 'Помилка', - 'category-quick-search' => 'Швидкий пошук назви теми (у межах категорії)', - 'close-topic' => 'Закрити тему', - 'closed' => 'Закрито', - 'create-new-topic' => 'Створити нову тему', - 'created' => 'Створено', - 'created-at' => 'Створено', - 'current' => 'Поточний', - 'delete-topic' => 'Видалити цю тему', - 'delete-post-success' => 'Повідомлення було видалено!', - 'denied' => 'Відмовлено', - 'dislike-post' => 'Не подобається', - 'display-forum' => 'Показати теми в', - 'edit-post' => 'Редагувати повідомлення', - 'edit-post-success' => 'Повідомлення відредаговано!', - 'edit-topic' => 'Редагувати тему', - 'forum' => 'Форум', - 'forums' => 'Форуми', - 'forums-post-search' => 'Пошук по повідомленнях', - 'forums-topic-search' => 'Пошук по темах', - 'implemented' => 'Реалізовано', - 'in' => 'В', - 'invalid' => 'Недійсний', - 'label' => 'Мітка', - 'label-system' => 'Система міток', - 'last-message' => 'Останнє повідомлення', - 'last-post-info' => 'Останнє повідомлення', - 'latest' => 'Останні', - 'like-post' => 'Подобається', - 'meta-category' => 'Список форумів у категорії', - 'moderation' => 'Модерація', - 'name' => 'Назва', - 'not-connected' => 'Ви повинні бути підключені', - 'not-subscribed' => 'Не підписано', - 'open' => 'Відкрито', - 'open-topic' => 'Відкрити цю тему', - 'permalink' => 'Постійне посилання', - 'pin' => 'Закріпити', - 'post' => 'Повідомлення', - 'post-quick-search' => 'Швидкий пошук тіла повідомлення', - 'posts' => 'Повідомлення', - 'quote' => 'Цитата', - 'read-topic' => 'Прочитайте тему', - 'replies' => 'Відповіді', - 'reply-topic-error' => 'Ви не можете відповідати в цій темі!', - 'reply-topic-success' => 'Повідомлення успішно опубліковано', - 'send-new-topic' => 'Зберегти цю тему', - 'solved' => 'Вирішено', - 'state' => 'Статус', - 'stats' => 'Статистика', - 'select-all-forum' => 'Всі Категорії/Форуми', - 'subscribe' => 'Підписатись', - 'subscribed' => 'Підписаний', + 'action' => 'Дія', + 'activity' => 'Діяльність', + 'approved' => 'Схвалено', + 'author' => 'Автор', + 'bug' => 'Помилка', + 'category-quick-search' => 'Швидкий пошук по назвах тем (у межах категорії)', + 'close-topic' => 'Закрити тему', + 'closed' => 'Закрито', + 'create-new-topic' => 'Створити нове обговорення', + 'created' => 'Створено', + 'created-at' => 'Створено', + 'current' => 'Поточний', + 'delete-topic' => 'Видалити обговорення', + 'delete-post-success' => 'Повідомлення було видалено!', + 'denied' => 'Відмовлено', + 'dislike-post' => 'Не подобається', + 'display-forum' => 'Показати обговорення в ', + 'edit-post' => 'Редагувати повідомлення', + 'edit-post-success' => 'Повідомлення відредаговано!', + 'edit-topic' => 'Редагувати обговорення', + 'forum' => 'Форум', + 'forums' => 'Форуми', + 'forums-post-search' => 'Пошук по повідомленнях', + 'forums-topic-search' => 'Пошук обговорення', + 'implemented' => 'Реалізовано', + 'in' => 'В', + 'invalid' => 'Недійсний', + 'label' => 'Мітка', + 'label-system' => 'Система міток', + 'last-message' => 'Останнє повідомлення', + 'last-post-info' => 'Останнє повідомлення', + 'latest' => 'Останні', + 'like-post' => 'Подобається', + 'meta-category' => 'Список форумів у категорії', + 'moderation' => 'Модерація', + 'name' => 'Ім\'я', + 'not-connected' => 'Ви повинні бути підключені', + 'not-subscribed' => 'Не підписано', + 'open' => 'Відкрито', + 'open-topic' => 'Відкрити цю тему', + 'permalink' => 'Постійне посилання', + 'pin' => 'Закріпити', + 'post' => 'Повідомлення', + 'post-quick-search' => 'Швидкий пошук тіла повідомлення', + 'posts' => 'Публікації', + 'quote' => 'Цитата', + 'read-topic' => 'Прочитайте тему', + 'replies' => 'Відповіді', + 'reply-topic-error' => 'Ви не можете відповідати в цій темі!', + 'reply-topic-success' => 'Повідомлення успішно опубліковано', + 'send-new-topic' => 'Зберегти цю тему', + 'solved' => 'Вирішено', + 'state' => 'Статус', + 'stats' => 'Статистика', + 'select-all-forum' => 'Всі Категорії/Форуми', + 'subscribe' => 'Підписатись', + 'subscribed' => 'Підписаний', 'subscription-quick-search' => 'Швидкий пошук назви теми (у межах підписок)', - 'suggestion' => 'Пропозиція', - 'tip-post-total' => 'Всього було надано чайових', - 'tip-this-post' => 'Надати чайові', - 'topic' => 'Тема', - 'topic-closed' => 'Ця тема закрита', - 'topic-name' => 'Назва теми', - 'topic-quick-search' => 'Назва теми швидкого пошуку', - 'topic-title' => 'Назва цієї теми', - 'topics' => 'Теми', - 'unpin' => 'Відкріпити', - 'updated-at' => 'Оновлено', - 'unsubscribe' => 'Відписатись', - 'view-all' => 'Переглянути всі теми', - 'views' => 'Перегляди', + 'suggestion' => 'Пропозиція', + 'tip-post-total' => 'Всього було надано чайових', + 'tip-this-post' => 'Залишити чайові', + 'topic' => 'Тема', + 'topic-closed' => 'Ця тема закрита', + 'topic-name' => 'Назва теми', + 'topic-quick-search' => 'Назва теми швидкого пошуку', + 'topic-title' => 'Назва цієї теми', + 'topics' => 'Обговорення', + 'unpin' => 'Відкріпити', + 'updated-at' => 'Оновлено', + 'unsubscribe' => 'Відписатись', + 'view-all' => 'Переглянути всі теми', + 'views' => 'Перегляди', ]; diff --git a/lang/uk/graveyard.php b/lang/uk/graveyard.php index 39674e631..57ada1047 100644 --- a/lang/uk/graveyard.php +++ b/lang/uk/graveyard.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'dead' => 'Помер', - 'graveyard' => 'Кладовище', - 'guidelines' => 'Правила', - 'guidelines-content' => '1) Ви не можете відновити власні завантаження.
2) Dont воскресити те, що ви не можете зробити.', - 'howto' => 'Тут правило', - 'howto-desc1' => 'Ви повинні насіння : ім я 30 днів для успішного ressurection. У цьому випадку, коли поточне час насіння', - 'howto-desc2' => 'Ви будете винагороджені', - 'howto-hits' => 'Хіти', - 'pending' => 'Очікує', - 'resurrect' => 'Воскресити', - 'reward' => 'Флеолікери', + 'dead' => 'Мертвий', + 'graveyard' => 'Кладовище', + 'guidelines' => 'Правила', + 'guidelines-content' => '1) Ви не можете відродити власний реліз.
2) Не беріться відроджувати те, що не зможете сідувати тривалий час.', + 'howto' => 'Ось правило', + 'howto-desc1' => 'Щоб успішно відродити :name, потрібно сидувати його протягом 30 днів. У цьому випадку, коли поточний час сідування', + 'howto-desc2' => 'Вас очікує винагорода', + 'howto-hits' => 'Хіти', + 'pending' => 'Очікує', + 'resurrect' => 'Відродити', + 'reward' => 'Freeleech-токени', + 'resurrect-complete' => 'Торрент повернуто до життя! Нагорода стане доступною одразу, як тільки ви виконаєте норму щодо часу сидування.', + 'resurrect-canceled' => 'Процес відродження успішно припинено!', + 'resurrect-date' => 'Дата відродження', + 'rewarded' => 'Винагороду отримано', + 'not-rewarded' => 'Нагорода не нараховується', + 'resurrect-failed-own' => 'Відродження торренту не вдалося! Ви не можете відновлювати власні релізи.', + 'resurrect-failed-pending' => 'Відродження торренту не вдалося! Цей торрент уже очікує на відновлення.', + 'current-seedtime' => 'Поточний час сідування', + 'seedtime-goal' => 'Норма часу сідування', ]; diff --git a/lang/uk/mediahub.php b/lang/uk/mediahub.php index 7ae36fdeb..3071d69e1 100644 --- a/lang/uk/mediahub.php +++ b/lang/uk/mediahub.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'born' => 'Дата нар.:', - 'collections' => 'Колекції', - 'companies' => 'Компанії', - 'disclaimer' => 'Цей продукт використовує API TMDb, але не схвалений і не сертифікований TMDb.', - 'episodes' => 'Епізоди', - 'first-seen' => 'Перша поява:', - 'genres' => 'Жанри', - 'includes' => 'Включає:', - 'latest-project' => 'Останній проект:', - 'networks' => 'Мережі', - 'no-data' => 'Немає даних!', - 'movie' => 'Фільм', - 'movies' => 'Фільми', - 'movie-credits' => 'В титрах фільму:', - 'persons' => 'Персони', - 'plot' => 'Сюжет:', - 'release-date' => 'Дата виходу:', - 'seasons' => 'Сезони', - 'select-hub' => 'Будь ласка виберіть хаб', - 'show' => 'Серіал', - 'shows' => 'Серіали', - 'title' => 'MediaHub', - 'tv-credits' => 'В титрах серіалу:', + 'born' => 'Дата нар.:', + 'collections' => 'Колекції', + 'companies' => 'Компанії', + 'disclaimer' => 'Цей продукт використовує API TMDb, проте не сертифікований і не підтримується TMDb.', + 'episodes' => 'Епізоди', + 'first-seen' => 'Перша поява:', + 'genres' => 'Жанри', + 'includes' => 'Включає:', + 'latest-project' => 'Останній проект:', + 'networks' => 'Мережі', + 'no-data' => 'Немає даних!', + 'movie' => 'Фільм', + 'movies' => 'Фільми', + 'movie-credits' => 'В титрах фільму:', + 'persons' => 'Персони', + 'plot' => 'Сюжет:', + 'release-date' => 'Дата виходу:', + 'seasons' => 'Сезони', + 'select-hub' => 'Будь ласка, виберіть хаб', + 'show' => 'Серіал', + 'shows' => 'Серіали', + 'title' => 'MediaHub', + 'tv-credits' => 'В титрах серіалу:', 'view-collection' => 'Переглянути колекцію', - 'wiki-read' => 'Прочитати біографію на Wikipedia:', + 'wiki-read' => 'Прочитати біографію на Wikipedia:', + 'collection' => 'Колекція', ]; diff --git a/lang/uk/notification.php b/lang/uk/notification.php index 03dc02c67..966949138 100644 --- a/lang/uk/notification.php +++ b/lang/uk/notification.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ 'already-marked-read' => 'Сповіщення вже помічені як прочитані!', - 'all-deleted' => 'Всі сповіщення видалено!', - 'all-marked-read' => 'Всі сповіщення помічено як прочитані!', - 'bon-gifts' => 'Подарунки бонусів', - 'comment-tags' => 'Згадки в коментарях', - 'date' => 'Дата', - 'delete' => 'Видалити', - 'delete-all' => 'Видалити всі сповіщення', - 'deleted' => 'Сповіщення видалено!', - 'filter-by-type' => 'Відбір по типам сповіщень', - 'mark-all-read' => 'Позначити всі як прочитані', - 'mark-read' => 'Позначити як прочитане', - 'marked-read' => 'Сповіщення позначене як прочитане!', - 'message' => 'Повідомлення', - 'no-notifications' => 'Не знайдено жодних сповіщень', - 'not-existent' => 'Сповіщень немає!', - 'notifications' => 'Сповіщення', - 'post-tags' => 'Згадки в повідомленнях', - 'post-tips' => 'Чайові в повідомленнях', - 'read' => 'Прочитано', - 'request-approvals' => 'Виконання замовлень', - 'request-bounties' => 'Підтримка замовлень', - 'request-claims' => 'Заявка на замовлення', - 'request-fills' => 'Виконання замовлень', - 'request-rejections' => 'Відхилення заявки на замовлення', - 'request-unclaims' => 'Відмова заявки на замовлення', - 'reseed-requests' => 'Запит сідування', - 'title' => 'Назва', - 'unfollows' => 'Скасування підписки', + 'all-deleted' => 'Всі сповіщення видалено!', + 'all-marked-read' => 'Всі сповіщення помічено як прочитані!', + 'bon-gifts' => 'Подарунки бонусів', + 'comment-tags' => 'Згадки в коментарях', + 'date' => 'Дата', + 'delete' => 'Видалити', + 'delete-all' => 'Видалити всі сповіщення', + 'deleted' => 'Сповіщення видалено!', + 'filter-by-type' => 'Фільтрувати за типами сповіщень', + 'mark-all-read' => 'Відмітити все як прочитане', + 'mark-read' => 'Позначити як прочитане', + 'marked-read' => 'Сповіщення позначене як прочитане!', + 'message' => 'Повідомлення', + 'no-notifications' => 'Не знайдено жодних сповіщень', + 'not-existent' => 'Сповіщень немає!', + 'notifications' => 'Сповіщення', + 'post-tags' => 'Згадки в повідомленнях', + 'post-tips' => 'Чайові за повідомлення', + 'read' => 'Прочитано', + 'request-approvals' => 'Виконання замовлень', + 'request-bounties' => 'Підтримка замовлень', + 'request-claims' => 'Заявка на замовлення', + 'request-fills' => 'Виконання замовлень', + 'request-rejections' => 'Відхилення заявки на замовлення', + 'request-unclaims' => 'Відмова заявки на замовлення', + 'reseed-requests' => 'Запит сідування', + 'title' => 'Назва', + 'unfollows' => 'Скасування підписки', ]; diff --git a/lang/uk/page.php b/lang/uk/page.php index 23fc3ab83..f4aa6aacf 100644 --- a/lang/uk/page.php +++ b/lang/uk/page.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'aboutus-advantage' => 'Переваги', - 'aboutus-advantage1' => 'UNIT3D - це приватний торрент трекер нового покоління з чудовим візуальним оформленням і прогресивним функціоналом.', - 'aboutus-advantage2' => 'UNIT3D створено з метою поширення і полуляризації україномовного контенту. Тому кожний фільм чи серіал, який є на сайті має українське озвучення.', - 'aboutus-advantage3' => 'Хоча ми приймаємо пожертвування, для підтримки і стабільної роботи сайту, в нас немає жодної реклами на сайті.', - 'aboutus-advantage4' => 'UNIT3D немає відкритої реєстрації, кожний учасник спільноти був ретельно відібраний і запрошений іншим учасником. Це дозволяє нам сформувати спільноту однодумців, тих людей, яким можна довіряти, і які обєднані однією ідеєю.', - 'aboutus-advantage5' => 'Наш сервіс піклується про збереження Вашої конфіденційності і Ваших приватних даних. Те, що саме буде видимим для інших вирішуєте Ви самі.', - 'aboutus-header' => 'Привіт', - 'aboutus-rules' => 'Що нам потрібно від Вас', - 'aboutus-rules1' => 'Бути активним учасником спільноти! Це означає брати продуктивну участь у бесідах, створювати нові релізи, підтримувати наявні релізи та допомагати іншим учасникам, якщо це можливо.', - 'aboutus-rules2' => 'Щоб Ви прочитали наші правила, поважали та дотримувалися їх!', - 'aboutus-rules3' => 'Вносьте свої пропозиції! Ми прагнемо зробити UNIT3D ще кращою. Ми не гарантуємо, що кожна пропозиція буде реалізована, але кожна буде розглянута. Дякуємо!', - 'aboutus-welcome' => 'Давайте поговоримо про', - 'aboutus-welcome-desc' => 'UNIT3D – це створена спільнотою база даних фільмів/серіалів. Всі дані були додані нашими чудовими учасниками. Основний фокус UNIT3D зосереджено на HD+ контенті, розвитку проактивної спільноти та якісному сервісі.', - 'blacklist-browsers' => 'Браузери', - 'blacklist-btclient' => 'Клієнт BitTorrent', - 'blacklist-clients' => 'Клієнти', - 'blacklist-desc' => 'Наступні браузери та клієнти Bittorrent внесені до чорного списку / заборонені від використання: назва', - 'blacklist-webbrowser' => 'Веб-браузер', + 'aboutus-advantage' => 'Переваги', + 'aboutus-advantage1' => 'Наш колектив складається з майстрів своєї справи — знавців у сфері HD-відео та аудіо, які не лише досконало володіють технічними знаннями, а й завжди поруч, аби підтримати та вирішити будь-яке завдання з філігранною точністю.', + 'aboutus-advantage2' => 'Ми не просто захоплюємося фільмами й серіалами — це наша пристрасть, наше натхнення. Та крім цього, ми пропонуємо дещо справді унікальне, чого майже ніде не знайдеш — добірку FANRES! Щира подяка тим, хто наповнює наш простір контентом — без вас це було б неможливо.', + 'aboutus-advantage3' => 'Хоч ми й приймаємо донати для підтримки роботи сайту, ви не побачите нав’язливих повідомлень чи банерів. Жодного жебракування — це не наш шлях.', + 'aboutus-advantage4' => 'Незважаючи на свій ще молодий вік, наша спільнота не має рівних. І команда, і користувачі завжди готові допомогти. Ми — це команда й користувачі, які завжди поруч, аби допомогти. І понад усе ми прагнемо, щоб ваш досвід на :title був винятковим.', + 'aboutus-advantage5' => 'Щодня наш сервіс об’єднує користувачів з різних куточків світу. Ми дбаємо про безпеку, стабільність і ефективність — і саме цим здобули довіру. Наша команда розробників невпинно працює, створюючи сучасну, технологічно досконалу платформу майбутнього.', + 'aboutus-header' => 'Привіт', + 'aboutus-rules' => 'Що від вас вимагається', + 'aboutus-rules1' => 'Активність у спільноті — це участь у змістовних розмовах, додавання якісного контенту і готовність допомогти іншим.', + 'aboutus-rules2' => 'Щоб Ви прочитали наші правила, поважали та дотримувалися їх!', + 'aboutus-rules3' => 'Діліться своїми ідеями! Ми щодня працюємо над тим, щоб зробити :title ще кращим. Обіцяти, що втілимо кожну пропозицію — не можемо, але нові думки завжди надихають.', + 'aboutus-welcome' => 'Поговорімо про', + 'aboutus-welcome-desc' => ':title – це не просто база даних фільмів, серіалів та FANRES, а спільний проєкт, створений користувачами для користувачів. Уся інформація тут – результат зусиль нашої чудової спільноти. У центрі уваги :title — світ високоякісного HD-контенту, підтримка активної та залученої спільноти, а також прагнення до бездоганного сервісу. І все це підкріплено командою, щирою та самовідданою, яка завжди поруч, аби допомогти, підказати й зробити ваш досвід ще приємнішим.', + 'blacklist-browsers' => 'Браузери', + 'blacklist-btclient' => 'Клієнт BitTorrent', + 'blacklist-clients' => 'Клієнти', + 'blacklist-desc' => 'Bittorrent-клієнти із цього списку заборонені до використання на :title', + 'blacklist-webbrowser' => 'Веб-браузер', 'blacklist-emaildomain' => 'Заблокований домен', - 'email-blacklist-desc' => 'Наступні домени електронної пошти заблоковані від використання. Ви не можете зареєструватися або надіслати запрошення до наступного.', - 'email-whitelist-desc' => 'Наступні домени електронної пошти є єдиними домену, які можна використовувати. Ви можете тільки зареєструвати або надіслати запрошення за допомогою наступного.', - 'staff-group' => 'Група', - 'staff-title' => 'Назва', + 'email-blacklist-desc' => 'Наступні домени електронної пошти заблоковані для використання. Ви не зможете зареєструватися або надіслати запрошення на них.', + 'email-whitelist-desc' => 'Дозволено реєструватися або надсилати запрошення лише з використанням наступних доменів електронної пошти. Будь ласка, використовуйте виключно їх.', + 'staff-group' => 'Група', + 'staff-title' => 'Назва', 'whitelist-emaildomain' => 'Довірений домен', ]; diff --git a/lang/uk/passwords.php b/lang/uk/passwords.php index 6cd780248..6485fe213 100644 --- a/lang/uk/passwords.php +++ b/lang/uk/passwords.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ /* |-------------------------------------------------------------------------- | Мовні ресурси для нагадування пароля @@ -24,10 +21,9 @@ return [ | за недійсного коду зміни пароля або неправильному новому паролі. | */ - - 'password' => 'Пароль повинен бути щонайменше 6 символів довжиною та співпадати з підтвердженням.', - 'reset' => 'Ваш пароль змінено!', - 'sent' => 'Ми надіслали на Вашу електронну адресу посилання для зміни пароля!', - 'token' => 'Помилковий код для зміни пароля.', - 'user' => 'Користувача з такою електронною адресою не знайдено.', + 'password' => 'Пароль має складатися щонайменше з шести символів і відповідати полю підтвердження.', + 'reset' => 'Ваш пароль змінено!', + 'sent' => 'Дякуємо! Якщо адреса електронної пошти відповідає обліковому запису, буде надіслано посилання для відновлення пароля.', + 'token' => 'Токен для відновлення пароля недійсний.', + 'user' => 'Не знайдено жодного користувача з таким e-mail.', ]; diff --git a/lang/uk/playlist.php b/lang/uk/playlist.php index ada622f08..fb96b1cff 100644 --- a/lang/uk/playlist.php +++ b/lang/uk/playlist.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'about' => 'Тут ви знайдете створені користувачами підбірки!', - 'attached-success' => 'Торрент був успішно привязаний до вашої підбірки.', - 'add-to-playlist' => 'Додати торрент до підбірки', - 'add-torrent' => 'Додати торрент', - 'added-by' => 'Ким:', - 'cover' => 'Виберіть постер', - 'create' => 'Створити нову підбірку', - 'delete-playlist' => 'Видалити підбірку', - 'deleted' => 'Підбірка видалена!', - 'detached-success' => 'Торрент був успішно відв\'язаний від вашої підбірки.', - 'desc' => 'Опис', - 'download-all' => 'Завантажити всі торренти підбірки', - 'edit-playlist' => 'Редагувати підбірку', - 'list-by' => 'Список був створений:', - 'list-about' => 'Опис:', - 'is-private' => 'Приватна підбірка?', - 'playlists' => 'Підбірки', - 'private-error' => 'Це приватна підбірка! Ви не маєте доступу до приватних підбірок користувачів!', + 'about' => 'Тут ви знайдете створені користувачами підбірки!', + 'attached-success' => 'Торрент успішно додано до вашої добірки.', + 'add-to-playlist' => 'Додати торрент до підбірки', + 'add-torrent' => 'Додати торрент', + 'added-by' => 'Ким:', + 'cover' => 'Виберіть постер', + 'create' => 'Створити нову підбірку', + 'delete-playlist' => 'Видалити добірку', + 'deleted' => 'Добірку видалено!', + 'detached-success' => 'Торрент успішно вилучено з вашої добірки.', + 'desc' => 'Опис', + 'download-all' => 'Завантажити всі торренти підбірки', + 'edit-playlist' => 'Редагувати добірку', + 'list-by' => 'Підготував:', + 'list-about' => 'Опис:', + 'is-private' => 'Приватна добірка?', + 'playlists' => 'Підбірки', + 'private-error' => 'Це приватна підбірка! Ви не маєте доступу до приватних підбірок користувачів!', 'published-success' => 'Ваша підбірка успішно створена!', - 'title' => 'Назва', - 'titles' => 'Назви', - 'update-success' => 'Ваша підбірка успішно оновлена!', + 'title' => 'Назва', + 'titles' => 'Назви', + 'update-success' => 'Ваша підбірка успішно оновлена!', + 'playlist-suggestions' => 'Пропозиції щодо плейлистів', + 'playlist-suggestion-rejections' => 'Відхилення пропозицій щодо підбірки', + 'suggest-torrent' => 'Запропонувати торрент', + 'suggestion-review' => 'Вашу пропозицію відправлено на модерацію автору підбірки', + 'suggestion-approved' => 'Пропозицію додано до підбірки', + 'suggestion-rejected' => 'Пропозицію до підбірки відхилено', + 'last-addition-at' => 'Останнє доповнення на', ]; diff --git a/lang/uk/pm.php b/lang/uk/pm.php index 6e7ea8a22..a9f2aad5d 100644 --- a/lang/uk/pm.php +++ b/lang/uk/pm.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'create' => 'Створити', - 'delete' => 'Видалити', + 'create' => 'Створити', + 'delete' => 'Видалити', 'enter-subject' => 'Введіть тему', - 'from' => 'Від', - 'inbox' => 'Вхідні', - 'mark-all-read' => 'Позначити всі повідомлення як прочитані', - 'message' => 'Повідомлення', - 'messages' => 'Повідомлення', - 'new' => 'Нове повідомлення', - 'outbox' => 'Вихідні', - 'private' => 'Приватне', - 'read' => 'Прочитано', - 'received-at' => 'Отримано в', - 'refresh' => 'Оновити', - 'reply' => 'Відповісти', - 'search' => 'Пошук за темою', - 'select' => 'Виберіть користувача', - 'send' => 'Надіслати ПП', - 'send-to' => 'Надіслати ПП до', - 'sent' => 'Надіслано', - 'sent-at' => 'Надіслано', - 'subject' => 'Тема', - 'to' => 'До', - 'unread' => 'Непрочитані', - 'empty-inbox' => 'Очистити поштову скриньку', + 'from' => 'Від', + 'inbox' => 'Вхідні', + 'mark-all-read' => 'Відмітити все як прочитане', + 'message' => 'Повідомлення', + 'messages' => 'Повідомлення', + 'new' => 'Нове повідомлення', + 'outbox' => 'Вихідні', + 'private' => 'Приватне', + 'read' => 'Прочитано', + 'received-at' => 'Отримано', + 'refresh' => 'Оновити', + 'reply' => 'Відповісти', + 'search' => 'Пошук за темою', + 'select' => 'Виберіть користувача', + 'send' => 'Надіслати ПП', + 'send-to' => 'Надіслати ПП до', + 'sent' => 'Надіслано', + 'sent-at' => 'Дата відправлення', + 'subject' => 'Тема', + 'to' => 'Кому', + 'unread' => 'Непрочитані', + 'empty-inbox' => 'Очистити поштову скриньку', + 'delete-success' => 'Повідомлення успішно видалено!', + 'error' => 'Що ви намагаєтесь тут зробити!', + 'sent-success' => 'Повідомлення відправлено!', + 'all-marked-read' => 'Усі повідомлення позначені як прочитані!', ]; diff --git a/lang/uk/poll.php b/lang/uk/poll.php index 74c81216c..62cd302c3 100644 --- a/lang/uk/poll.php +++ b/lang/uk/poll.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'add-option' => 'Додати варіант', - 'create-poll' => 'Створити голосування', - 'current' => 'Поточне голосування', - 'delete-option' => 'Видалити варіант', - 'multiple-choice' => 'Це голосування з декількома варіантами вибору. Виберіть стільки відповідей, скільки бажаєте.', - 'option' => 'Варіант', - 'poll' => 'Голосування', - 'polls' => 'Голосування', - 'results' => 'Результати голосування', - 'title' => 'Назва', - 'total' => 'Всього голосів', - 'vote' => 'Голосувати', - 'vote-now' => 'Віддайте свій голос зараз!', - 'votes' => 'Голосів', + 'add-option' => 'Додати варіант', + 'create-poll' => 'Створити голосування', + 'current' => 'Поточні голосування', + 'delete-option' => 'Видалити варіант', + 'multiple-choice' => 'Опитування дозволяє вибирати кілька варіантів відповідей одночасно.', + 'option' => 'Варіант', + 'poll' => 'Голосування', + 'polls' => 'Голосування', + 'results' => 'Результати голосування', + 'title' => 'Назва', + 'total' => 'Всього голосів', + 'vote' => 'Голосувати', + 'vote-now' => 'Віддайте свій голос зараз!', + 'votes' => 'Голосів', + 'already-voted-error' => 'Ви вже зробили свій вибір. Голос не зараховано.', + 'already-voted-result' => 'Ви вже проголосували в цьому опитуванні. Ось результати.', + 'expired-voted-result' => 'Опитування завершилося. Пропонуємо вашій увазі результати.', + 'edit-poll' => 'Редагувати опитування', + 'vote-counted' => 'Ваш голос зараховано.', + 'close-date' => 'Закрити опитування після', ]; diff --git a/lang/uk/regions.php b/lang/uk/regions.php index 1f6a841dc..1ae095006 100644 --- a/lang/uk/regions.php +++ b/lang/uk/regions.php @@ -1,6 +1,245 @@ 'Анґілья', + 'ALA' => 'Аландські острови', + 'ALG' => 'Алжир', + 'AND' => 'Андорра', + 'ANG' => 'Анґола', + 'ARG' => 'Аргентина', + 'ARM' => 'Вірменія', + 'ARU' => 'Аруба', + 'ATG' => 'Антигуа і Барбуда', + 'AUS' => 'Австралія', + 'ASA' => 'Американське Самоа', + 'ATA' => 'Антарктида', + 'ATF' => 'Французькі південні та антарктичні землі', + 'AUT' => 'Австрія', + 'BAN' => 'Бангладеш', + 'BDI' => 'Бурунді', + 'BEL' => 'Бельгія', + 'BEN' => 'Бенін', + 'BER' => 'Бермудські острови', + 'AZE' => 'Азербайджан', + 'BAH' => 'Багамські острови', + 'BES' => 'Карибські Нідерланди: Бонайре, Сінт-Естатіус і Саба', + 'BFA' => 'Буркіна-Фасо', + 'BHR' => 'Бахрейн', + 'BHU' => 'Бутан', + 'BIH' => 'Боснія і Герцеговина', + 'BLM' => 'Святий Варфоломій', + 'AFG' => 'Афганістан', + 'BLR' => 'Білорусь', + 'BLZ' => 'Беліз', + 'BOL' => 'Болівія', + 'BOT' => 'Ботсвана', + 'BRA' => 'Бразилія', + 'BRB' => 'Барбадос', + 'BRU' => 'Бруней', + 'BVT' => 'Острів Буве', + 'CAM' => 'Камбоджа', + 'COD' => 'Конго, Демократична Республіка', + 'COK' => 'Острови Кука', + 'COL' => 'Колумбія', + 'COM' => 'Коморські острови', + 'CAN' => 'Канада', + 'CAY' => 'Кайманові острови', + 'CCK' => 'Кокосові (Кілінг) острови', + 'CEE' => 'Центральна та Східна Європа', + 'CGO' => 'Конго, Республіка Конго', + 'CHA' => 'Чад', + 'CHI' => 'Чилі', + 'CHN' => 'Китай', + 'CIV' => 'Берег Слонової Кістки', + 'CMR' => 'Камерун', + 'CZE' => 'Чеська Республіка', + 'CRC' => 'Коста-Ріка', + 'CPV' => 'Кабо-Верде', + 'CRO' => 'Хорватія', + 'CTA' => 'Центральноафриканська Республіка', + 'CUB' => 'Куба', + 'CUW' => 'Кюрасао', + 'CXR' => 'Острів Різдва', + 'CYP' => 'Кіпр', + 'DJI' => 'Джибуті', + 'DMA' => 'Домініка', + 'DOM' => 'Домініканська Республіка', + 'ECU' => 'Еквадор', + 'EGY' => 'Єгипет', + 'ENG' => 'Англія', + 'EQG' => 'Екваторіальна Гвінея', + 'ERI' => 'Еритрея', + 'ESH' => 'Західна Сахара', + 'ESP' => 'Іспанія', + 'ETH' => 'Ефіопія', + 'EUR' => 'Європа / Міжнародний', + 'FIJ' => 'Фіджі', + 'FLK' => 'Фолклендські острови', + 'FRA' => 'Франція', + 'FRO' => 'Фарерські острови', + 'GRN' => 'Гренада', + 'GRL' => 'Гренландія', + 'FSM' => 'Мікронезія, Федеративні Штати', + 'GAB' => 'Габон', + 'GAM' => 'Гамбія', + 'GBR' => 'Сполучене Королівство', + 'GEO' => 'Грузія', + 'GER' => 'Німеччина', + 'GGY' => 'Гернсі', + 'GHA' => 'Гана', + 'GIB' => 'Гібралтар', + 'GLP' => 'Гваделупа', + 'GNB' => 'Гвінея-Бісау', + 'GRE' => 'Греція', + 'HUN' => 'Орбаноїди', + 'IDN' => 'Індонезія', + 'IMN' => 'Острів Мен', + 'IND' => 'Індія', + 'IOT' => 'Британська територія в Індійському океані', + 'IRL' => 'Ірландія', + 'IRN' => 'Іран', + 'IRQ' => 'Ірак', + 'ISL' => 'Ісландія', + 'ISR' => 'Ізраїль', + 'ITA' => 'Італія', + 'JAM' => 'Ямайка', + 'JEY' => 'Джерсі', + 'JOR' => 'Йорданія', + 'JPN' => 'Японія', + 'KAZ' => 'Казахстан', + 'KEN' => 'Кенія', + 'KGZ' => 'Киргизстан', + 'KIR' => 'Кірібаті', + 'KNA' => 'Сент-Кітс і Невіс', + 'KOR' => 'Корея, Республіка (Південна)', + 'KSA' => 'Саудівська Аравія', + 'KUW' => 'Кувейт', + 'MAR' => 'Марокко', + 'MAS' => 'Малайзія', + 'MDA' => 'Молдова', + 'MDV' => 'Мальдіви', + 'MEX' => 'Мексика', + 'MHL' => 'Маршаллові острови', + 'MKD' => 'Північна Македонія', + 'MLI' => 'Малі', + 'MLT' => 'Мальта', + 'MNG' => 'Монголія', + 'GUA' => 'Гватемала', + 'GUF' => 'Французька Гвіана', + 'GUI' => 'Гвінея', + 'GUM' => 'Гуам', + 'GUY' => 'Гайана', + 'HAI' => 'Гаїті', + 'HKG' => 'Гонконг', + 'HMD' => 'Острів Херд та острови Макдональд', + 'HON' => 'Гондурас', + 'LAO' => 'Лаос', + 'LBN' => 'Ліван', + 'LBR' => 'Ліберія', + 'LBY' => 'Лівія', + 'LCA' => 'Сент-Люсія', + 'LES' => 'Лесото', + 'LIE' => 'Ліхтенштейн', + 'LKA' => 'Шрі-Ланка', + 'LUX' => 'Люксембург', + 'MAC' => 'Макао', + 'MAD' => 'Мадагаскар', + 'MAF' => 'Сен-Мартен, Спільнота святого Мартіна', + 'MNP' => 'Північні Маріанські острови', + 'MON' => 'Монако', + 'MOZ' => 'Мозамбік', + 'MRI' => 'Маврикій', + 'MSR' => 'Монтсеррат', + 'MTN' => 'Мавританія', + 'MTQ' => 'Мартініка', + 'MWI' => 'Малаві', + 'MYA' => 'М\'янма', + 'MYT' => 'Майотта', + 'NAM' => 'Намібія', + 'NCA' => 'Нікарагуа', + 'NCL' => 'Нова Каледонія', + 'NEP' => 'Непал', + 'NFK' => 'Острів Норфолк', + 'NIG' => 'Нігер', + 'NIR' => 'Північна Ірландія', + 'NIU' => 'Ніуе', + 'NLD' => 'Нідерланди', + 'NOR' => 'Скандинавський', + 'NRU' => 'Науру', + 'NZL' => 'Нова Зеландія', + 'OMA' => 'Оман', + 'PAK' => 'Пакистан', + 'PAN' => 'Панама', + 'PAR' => 'Парагвай', + 'PCN' => 'Острови Піткерн', + 'PER' => 'Перу', + 'PHI' => 'Філіппіни', + 'PLE' => 'Держава Палестина', + 'PLW' => 'Палау', + 'PNG' => 'Папуа-Нова Гвінея', + 'POL' => 'Польща', + 'POR' => 'Португалія', + 'PRK' => 'Корея, Корейська Народно-Демократична Республіка (Північна)', + 'PUR' => 'Пуерто-Ріко', + 'QAT' => 'Катар', + 'RSA' => 'Південна Африка', + 'RUS' => '404', + 'RWA' => 'Руанда', + 'SAM' => 'Самоа', + 'SCO' => 'Шотландія', + 'SDN' => 'Судан', + 'SEN' => 'Сенегал', + 'SEY' => 'Сейшельські острови', + 'SGS' => 'Південна Джорджія та Південні Сандвічеві острови', + 'SHN' => 'Свята Гелана, Вознесіння і Трістан-да-Кунья', + 'SJM' => 'Шпіцберген і Ян-Майєн', + 'SLE' => 'Сьєрра-Леоне', + 'SLV' => 'Сальвадор', + 'SMR' => 'Сан-Марино', + 'SOL' => 'Соломонові острови', + 'SOM' => 'Сомалі', + 'SPM' => 'Сен-П\'єр і Мікелон', + 'SRB' => 'Сербія', + 'ROU' => 'Румунія', + 'SSD' => 'Південний Судан', + 'STP' => 'Сан-Томе і Принсіпі', + 'SUI' => 'Швейцарія', + 'SUR' => 'Суринам', + 'SWZ' => 'Есватіні', + 'SXM' => 'Сен-Мартен', + 'SYR' => 'Сирія', + 'TAH' => 'Французька Полінезія', + 'TAN' => 'Танзанія', + 'TCA' => 'Острови Теркс і Кайкос', + 'TGA' => 'Тонга', + 'THA' => 'Таїланд', + 'TJK' => 'Таджикистан', + 'TKL' => 'Токелау', + 'TKM' => 'Туркменістан', + 'TLS' => 'Східний Тимор', + 'TOG' => 'Того', + 'TRI' => 'Тринідад і Тобаго', + 'TUN' => 'Туніс', + 'TUR' => 'Туреччина', + 'TUV' => 'Тувалу', + 'TWN' => 'Тайвань', + 'UAE' => 'Об\'єднані Арабські Емірати', + 'UGA' => 'Уганда', + 'UKR' => 'Україна', + 'UMI' => 'Малі віддалені острови Сполучених Штатів', + 'URU' => 'Уругвай', + 'USA' => 'Сполучені Штати Америки', + 'UZB' => 'Узбекистан', + 'VAN' => 'Вануату', + 'VAT' => 'Держава Ватикан', + 'VEN' => 'Венесуела', + 'VGB' => 'Британські Віргінські острови', + 'VIE' => 'В\'єтнам', + 'VIN' => 'Сент-Вінсент і Гренадини', + 'VIR' => 'Віргінські острови Сполучених Штатів Америки', + 'WAL' => 'Уельс', + 'WLF' => 'Уолліс і Футуна', + 'YEM' => 'Ємен', + 'ZAM' => 'Замбія', + 'ZIM' => 'Зімбабве', + 'REU' => 'Реюньйон', ]; diff --git a/lang/uk/request.php b/lang/uk/request.php index c2be74da7..16d25596b 100644 --- a/lang/uk/request.php +++ b/lang/uk/request.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'access-error' => 'Ви не маєте прав на затвердження цього замовлення.', + 'access-error' => 'Ви не маєте прав на затвердження цього замовлення.', 'access-delete-error' => 'Ви не маєте прав на видалення цього замовлення.', - 'add-request' => 'Додати замовлення', - 'added-bonus' => 'Ваші бонуси були успішно додані до винагороди.', - 'added-request' => 'Замовлення створено.', - 'age' => 'Створено', - 'all-requests' => 'Всі замовлення', - 'already-approved' => 'Це замовлення вже виконано', - 'already-claimed' => 'Хтось інший вже взяв це замовлення на виконання.', - 'already-rejected' => 'Це замовлення вже було відхилено', - 'approve' => 'Затвердити', - 'approved-anon' => 'Ви затвердили %s і винагорода була надіслана анонімному користувачу', - 'approved-user' => 'Ви затвердили %s і винагорода була надіслана %s', - 'bounty' => 'Винагорода', - 'bounty-claimed' => 'Винагород отримано', - 'bounty-unclaimed' => 'Винагород неотримано', - 'category' => 'Категорія', - 'claim' => 'Заявка на виконання', - 'claim-anon-choose' => 'Будь ласка, робіть свій вибір уважно', - 'claim-as-anon' => 'Чи хотіли б Ви створити заявку анонімно?', - 'claim-now' => 'Створити заявку на виконання', - 'claimed' => 'Заявлено', - 'claimed-success' => 'Заявка успішно прийнята', - 'current' => 'Поточний', - 'delete' => 'Видалити це замовлення', + 'add-request' => 'Додати замовлення', + 'added-bonus' => 'Ваші бонуси успішно додані до винагороди.', + 'added-request' => 'Замовлення створено.', + 'age' => 'Вік', + 'all-requests' => 'Всі замовлення', + 'already-approved' => 'Цей запит, схоже, вже було схвалено', + 'already-claimed' => 'Хтось інший вже взяв це замовлення на виконання.', + 'already-rejected' => 'Здається, цей запит уже відхилено', + 'approve' => 'Схвалити', + 'approved-anon' => 'Ви затвердили %s і винагорода була надіслана анонімному користувачу', + 'approved-user' => 'Ви затвердили %s і винагорода була надіслана %s', + 'bounty' => 'Винагорода', + 'bounty-claimed' => 'Винагород отримано', + 'bounty-unclaimed' => 'Винагород неотримано', + 'category' => 'Категорія', + 'claim' => 'Заявка на виконання', + 'claim-anon-choose' => 'Будь ласка, робіть свій вибір уважно', + 'claim-as-anon' => 'Чи хотіли б Ви створити заявку анонімно?', + 'claim-now' => 'Створити заявку на виконання', + 'claimed' => 'Заявлено', + 'claimed-success' => 'Заявка успішно прийнята', + 'current' => 'Поточний', + 'delete' => 'Видалити це замовлення', 'delete-confirmation' => 'Дійсно видалити це замовлення', - 'delete-filled' => 'Це замовлення можна видалити, лише якщо воно було невиконане', - 'deleted' => 'Ви видалили %s', - 'description' => 'Опис', - 'dont-have-bps' => 'Ви не маєте достатньо бонусів', - 'edit-request' => 'Редагувати замовлення', - 'edited-request' => 'Замовлення успішно відредаговано.', - 'enter-bp' => 'Введіть бонусні бали (мінімум 100)', - 'enter-hash' => 'Введіть інформаційний хеш завантаженого торренту', - 'fill' => 'Виконати', - 'fill-request' => 'Виконайте цей запит', - 'filled' => 'Виконано', - 'filled-by' => 'Виконано', - 'for' => 'для', - 'fulfill' => 'Виконайте', - 'last-vote' => 'Додано', - 'my-requests' => 'Мої замовлення', - 'my-filled' => 'Мої виконані замовлення', - 'my-claims' => 'Mої заявки на виконання', - 'my-voted' => 'Мною підтримані замовлення', - 'no' => 'Ні,', - 'no-imdb-id' => 'Всі замовлення повинні містити TMDB/IMDB ID', - 'no-privileges' => 'Помилка: Ваші права на створення замовлень вимкнено', - 'no-privileges-desc' => 'Якщо ви вважаєте, що це помилка, зверніться до адміністрації', - 'no-refunds' => 'Суму винагороди буде відмінусована від Ваших бонусів!
ПОВЕРНЕННЯ НЕМОЖЛИВЕ!', - 'pending' => 'Очікує', - 'pending-approval' => 'Ваш запит очікує на схвалення заявником.', - 'pending-moderation' => 'Торрент info_hash, який ви намагаєтесь використати, є в нашій базі даних, але все ще перебуває на модерації. Будь ласка, зачекайте, поки ваш торрент буде схвалено, а потім спробуйте ще раз.', - 'reason' => 'Причина', - 'reject' => 'Відхилити', - 'report' => 'Доповідь', - 'request' => 'Замовлення', - 'request-details' => 'Деталі замовлення', - 'request-reset' => 'Це замовлення було скинуто в початковий стан.', - 'requested-by' => 'Автор замовлення', - 'requests' => 'Замовлення', - 'required' => 'вимагається', - 'reset' => 'Скинути', - 'reset-confirmation' => 'Дійсно скинути цей запит', - 'reset-request' => 'Скинути цей запит', - 'resolution' => 'Якість', - 'resolutions' => 'Якість', - 'reward' => 'Винагорода', - 'reward-desc' => 'Скільки бонусів Ви хочете надати? Мінімум 100', - 'reward-from' => 'Від', - 'title' => 'Назва', - 'torrent-hash' => 'Торрент хеш', - 'total-bounty' => 'Всього бонусів', - 'type' => 'Тип', - 'unclaim' => 'Відхилити заявку на виконання', - 'unclaim-error' => 'Нічого до відхилення.', - 'unclaimed-success' => 'Заявка успішно відхилена', - 'unfilled' => 'Невиконано', - 'view-filled' => 'Переглянути виконані', - 'view-unfilled' => 'Переглянути невиконані', - 'vote' => 'Підтримати', - 'vote-that' => 'Підтримати це замовлення', - 'voters' => 'Замовники', - 'votes' => 'Замовників', - 'yes' => 'Так', + 'delete-filled' => 'Це замовлення можна видалити, лише якщо воно було невиконане', + 'deleted' => 'Ви видалили %s', + 'description' => 'Опис', + 'dont-have-bps' => 'Ви не маєте достатньо бонусів', + 'edit-request' => 'Редагувати замовлення', + 'edited-request' => 'Замовлення успішно відредаговано.', + 'enter-bp' => 'Введіть кількість бонусів (мінімум 100)', + 'enter-hash' => 'Введіть інформаційний хеш завантаженого торренту', + 'fill' => 'Виконати', + 'fill-request' => 'Виконайте цей запит', + 'filled' => 'Виконано', + 'filled-by' => 'Виконано', + 'for' => 'для', + 'fulfill' => 'Виконайте', + 'last-vote' => 'Додано', + 'my-requests' => 'Мої замовлення', + 'my-filled' => 'Мої виконані замовлення', + 'my-claims' => 'Mої заявки на виконання', + 'my-voted' => 'Мною підтримані замовлення', + 'no' => 'Ні,', + 'no-imdb-id' => 'Всі замовлення повинні містити TMDB/IMDB ID', + 'no-privileges' => 'Помилка: Ваші права на створення замовлень вимкнено', + 'no-privileges-desc' => 'Якщо ви вважаєте, що це помилка, зверніться до адміністрації', + 'no-refunds' => 'Сума буде відмінусована від Ваших бонусів!
ПОВЕРНЕННЯ НЕМОЖЛИВЕ!', + 'pending' => 'Очікує', + 'pending-approval' => 'Ваш запит очікує на схвалення заявником.', + 'pending-moderation' => 'Торрент id, який ви намагаєтесь використати, є в нашій базі даних, але все ще перебуває на модерації. Будь ласка, зачекайте, поки ваш торрент буде схвалено, а потім спробуйте ще раз.', + 'reason' => 'Причина', + 'reject' => 'Відхилити', + 'report' => 'Доповідь', + 'request' => 'Замовлення', + 'request-details' => 'Деталі замовлення', + 'request-reset' => 'Це замовлення було скинуто в початковий стан.', + 'requested-by' => 'Автор замовлення', + 'requests' => 'Замовлення', + 'required' => 'вимагається', + 'reset' => 'Скинути', + 'reset-confirmation' => 'Дійсно скинути цей запит', + 'reset-request' => 'Скинути цей запит', + 'resolution' => 'Якість', + 'resolutions' => 'Якість', + 'reward' => 'Винагорода', + 'reward-desc' => 'Скільки бонусів Ви хочете надати? Мінімум 100', + 'reward-from' => 'Від', + 'title' => 'Назва', + 'torrent-hash' => 'Торрент хеш', + 'total-bounty' => 'Всього бонусів', + 'type' => 'Тип', + 'unclaim' => 'Відкликати заявку на виконання', + 'unclaim-error' => 'Нічого до відхилення.', + 'unclaimed-success' => 'Заявка успішно відхилена', + 'unfilled' => 'Невиконано', + 'view-filled' => 'Переглянути виконані', + 'view-unfilled' => 'Переглянути невиконані', + 'vote' => 'Підтримати', + 'vote-that' => 'Підтримати це замовлення', + 'voters' => 'Замовники', + 'votes' => 'Замовників', + 'yes' => 'Так', ]; diff --git a/lang/uk/rss.php b/lang/uk/rss.php index ebf5594a8..20641903e 100644 --- a/lang/uk/rss.php +++ b/lang/uk/rss.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'create' => 'Створити', + 'create' => 'Створити', 'create-private-feed' => 'Створити приватний RSS-канал', - 'create-public-feed' => 'Створити загальнодоступний RSS-канал', - 'created' => 'Приватний RSS-канал створено', - 'delete' => 'Видалити', - 'deleted' => 'RSS-канал видалено!', - 'edit' => 'Редагувати', - 'edit-private-feed' => 'Редагувати приватний RSS-канал', - 'edit-public-feed' => 'Редагувати загальнодоступний RSS-канал', - 'error' => 'Неможливо завершити дію', - 'feed' => 'Канал', - 'feeds' => 'Канали', - 'name' => 'Назва', - 'public' => 'Публічний', - 'private' => 'Приватний', - 'rss' => 'RSS', - 'rss-feed' => 'RSS-канал', - 'type' => 'Тип', - 'updated' => 'Приватний RSS-канал оновлено', + 'create-public-feed' => 'Створити загальнодоступний RSS-канал', + 'created' => 'Приватний RSS-канал створено', + 'delete' => 'Видалити', + 'deleted' => 'RSS-канал видалено!', + 'edit' => 'Редагувати', + 'edit-private-feed' => 'Редагувати приватний RSS-канал', + 'edit-public-feed' => 'Редагувати загальнодоступний RSS-канал', + 'error' => 'Неможливо завершити дію', + 'feed' => 'Канал', + 'feeds' => 'Канали', + 'name' => 'Ім\'я', + 'public' => 'Публічний', + 'private' => 'Приватний', + 'rss' => 'RSS', + 'rss-feed' => 'RSS-канал', + 'type' => 'Тип', + 'updated' => 'Приватний RSS-канал оновлено', ]; diff --git a/lang/uk/staff.php b/lang/uk/staff.php index da2d0b7e1..6b49fac8b 100644 --- a/lang/uk/staff.php +++ b/lang/uk/staff.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'audit-log' => 'Журнал активності', - 'articles' => 'Статті', - 'application' => 'Заявка', - 'applications' => 'Заявки', - 'application-type' => 'Тип', + 'audit-log' => 'Журнал активності', + 'articles' => 'Статті', + 'application' => 'Заявка', + 'applications' => 'Заявки', + 'application-type' => 'Тип', 'application-image-proofs' => 'Скріншоти', - 'application-referrer' => 'Заявник', - 'article-content' => 'Опис', - 'bans-log' => 'Журнал заборон', - 'blocks' => 'Блоки', - 'bot' => 'Бот', - 'bots' => 'Боти', - 'chat' => 'Чат', - 'config-manager' => 'Менеджер налаштувань', - 'dashboard' => 'Дашборд', - 'failed-login-log' => 'Журнал помилок логування', - 'flush-ghost-peers' => 'Очистити піри-привиди', - 'forums' => 'Форуми', - 'frontend' => 'Фронтенд', - 'general-tools' => 'Загальні інструменти', - 'groups' => 'Групи', - 'invites-log' => 'Журнал інвайтів', - 'laravel-log' => 'Журнал Laravel', - 'link' => 'Посилання', - 'links' => 'Посилання', - 'logs' => 'Журнали', - 'mass-pm' => 'Масова відправка ПП', - 'mass-validate-users' => 'Масова валідація користувачів', - 'media-languages-desc' => '(Мови для списків Субтитри / Аудіо / Інше.)', - 'moderation' => 'Модерація', - 'moderation-since' => 'Модерований', - 'page' => 'Сторінка', - 'pages' => 'Сторінки', - 'please-moderate' => 'Будь ласка, промодеруйте цей торрент!', - 'polls' => 'Опитування', - 'reports-log' => 'Журнал скарг', - 'rooms' => 'Кімнати', - 'rss' => 'RSS', - 'staff-dashboard' => 'Інформаційна панель персоналу', - 'status' => 'Статус', - 'statuses' => 'Статуси', - 'torrent-categories' => 'Торрент Категорії', - 'torrent-moderation' => 'Модерація торрентів', - 'torrent-tools' => 'Торрент інструменти', - 'torrent-types' => 'Типи торрентів', - 'torrent-resolutions' => 'Якість торрентів', - 'torrents' => 'Торренти', - 'user-gifting' => 'Подарунок користувача', - 'user-notes' => 'Журнал користувача', - 'user-search' => 'Пошук користувачів', - 'user-tools' => 'Інструменти користувача', - 'warnings-log' => 'Журнал попереджень', - 'you-have' => 'Ви маєте', - 'possible-leech-cheaters' => 'Можливі шахраї', - 'chat-tools' => 'Інструменти чату', - 'flush-chat' => 'Очистити чат', - 'seedboxes' => 'Зареєстровані Сідбокси', + 'application-referrer' => 'Заявник', + 'article-content' => 'Опис', + 'bans-log' => 'Журнал банів', + 'blocks' => 'Блокування', + 'bot' => 'Бот', + 'bots' => 'Боти', + 'chat' => 'Чат', + 'config-manager' => 'Менеджер налаштувань', + 'dashboard' => 'Інформаційна панель', + 'failed-login-log' => 'Журнал помилок входу', + 'flush-ghost-peers' => 'Очистити піри-привиди', + 'forums' => 'Форуми', + 'frontend' => 'Фронтенд', + 'general-tools' => 'Загальні інструменти', + 'groups' => 'Групи', + 'invites-log' => 'Журнал запрошень', + 'laravel-log' => 'Журнал Laravel', + 'link' => 'Посилання', + 'links' => 'Посилання', + 'logs' => 'Журнали', + 'mass-pm' => 'Масова відправка ПП', + 'mass-validate-users' => 'Масова валідація користувачів', + 'media-languages-desc' => '(Мови для списків Субтитри / Аудіо / Інше.)', + 'moderation' => 'Модерація', + 'moderation-since' => 'Модерований', + 'page' => 'Сторінка', + 'pages' => 'Сторінки', + 'please-moderate' => 'Будь ласка, здійсніть модерацію цього торрента!', + 'polls' => 'Опитування', + 'reports-log' => 'Журнал скарг', + 'rooms' => 'Кімнати', + 'rss' => 'RSS', + 'staff-dashboard' => 'Інформаційна панель для персоналу', + 'status' => 'Статус', + 'statuses' => 'Статуси', + 'torrent-categories' => 'Категорії торрентів', + 'torrent-moderation' => 'Модерація торрентів', + 'torrent-tools' => 'Торрент інструменти', + 'torrent-types' => 'Типи торрентів', + 'torrent-resolutions' => 'Роздільна здатність торрентів', + 'torrents' => 'Торенти', + 'user-gifting' => 'Подарунок користувача', + 'user-notes' => 'Журнал користувача', + 'user-search' => 'Пошук користувачів', + 'user-tools' => 'Інструменти користувача', + 'warnings-log' => 'Журнал попереджень', + 'you-have' => 'Ви маєте', + 'possible-leech-cheaters' => 'Можливі шахраї', + 'chat-tools' => 'Інструменти чату', + 'flush-chat' => 'Очистити чат', + 'seedboxes' => 'Зареєстровані Сідбокси', + 'blocked-ips' => 'Заблоковані IP-адреси', + 'bon-exchange' => 'Обмін BON\'ів', + 'bon-earnings' => 'Заробіток BON', + 'gifts-log' => 'Журнал подарунків', + 'mass-email' => 'Масова розсилка', + 'notes' => 'Примітки', + 'passkeys' => 'Passkeys', ]; diff --git a/lang/uk/stat.php b/lang/uk/stat.php index daa78ded9..9b944554d 100644 --- a/lang/uk/stat.php +++ b/lang/uk/stat.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'active' => 'Активні', - 'all' => 'Всі', - 'all-time' => 'За весь час', - 'banned' => 'Заблоковані', - 'by-count' => 'За кількістю', - 'by-data' => 'За даними', - 'by-volume' => 'За обсягом', - 'credited' => 'Записаний', - 'disabled' => 'Неактивні', - 'group' => 'Група', - 'groups' => 'Групи', - 'last30days' => 'Останні 30 Днів', - 'nerd-stats' => 'Статистика', - 'nerd-stats-desc' => 'Ми всі любимо цікаву статистику. Ось статистика, яку ми вважаємо цікавою', - 'languages' => 'Мови', - 'place' => 'Місце', - 'pruned' => 'Обмежені', - 'real' => 'Реальний', - 'registration-date' => 'Дата реєстрації', - 'request-fulfilled' => 'Заповнені запити', - 'request-not-fulfilled' => 'Незаповнені запити', + 'active' => 'Активні', + 'all' => 'Всі', + 'all-time' => 'За весь час', + 'banned' => 'Заблоковані', + 'by-count' => 'За кількістю', + 'by-data' => 'За даними', + 'by-volume' => 'За обсягом', + 'credited' => 'Записаний', + 'disabled' => 'Неактивні', + 'group' => 'Група', + 'groups' => 'Групи', + 'last30days' => 'Останні 30 Днів', + 'nerd-stats' => 'Статистика', + 'nerd-stats-desc' => 'Статистика — це завжди цікаво. Ось кілька ключових показників, які варто знати', + 'languages' => 'Мови', + 'place' => 'Місце', + 'pruned' => 'Обмежені', + 'real' => 'Реальний', + 'registration-date' => 'Дата реєстрації', + 'request-fulfilled' => 'Виконані запити', + 'request-not-fulfilled' => 'Невиконані запити', 'request-pending-aproval' => 'Запити очікують підтвердження', - 'select-category' => 'Будь ласка виберіть категорію нижче', - 'site-stats' => 'Статистика сайту', - 'stats' => 'Статистика', - 'stats-format' => 'Вся статистика відображаються у форматі Топ 100', - 'top-bankers' => 'Топ Магнатів', - 'top-bountied' => 'Топ Винагороджених', - 'top-completed' => 'Топ Завершених', - 'top-dead' => 'Топ Мертвих', - 'top-downloaded' => 'Топ Завантажених Торрентів', - 'top-downloaders' => 'Топ Завантажувачів', - 'top-dying' => 'Топ Вмираючих', - 'top-leeched' => 'Топ Торрентів По Кількості Лічерів', - 'top-leechers' => 'Топ Лічерів', - 'top-seeded' => 'Топ Торрентів По Кількості Сідерів', - 'top-seeding' => 'Топ Сідуючих', - 'top-seeders' => 'Топ Сідерів', - 'top-seedsize' => 'Топ По Розміру Сідування', - 'top-seedtime' => 'Топ По Часу Сідування', - 'top-uploaders' => 'Топ Релізерів', - 'total-download' => 'Всього завантажено', - 'total-torrents' => 'Всього торрентів', - 'total-traffic' => 'Загальний трафік', - 'total-upload' => 'Всього віддано', - 'updated' => '(Оновлюється кожні 10 хвилин!)', - 'users-in-group' => 'Користувачів в групі', - 'users-per-group' => 'Користувачів на групу', + 'select-category' => 'Будь ласка, виберіть категорію нижче', + 'site-stats' => 'Статистика сайту', + 'stats' => 'Статистика', + 'stats-format' => 'Вся статистика відображаються у форматі Топ 100', + 'top-bankers' => 'Топ Магнатів', + 'top-bountied' => 'Топ Скруджів', + 'top-completed' => 'Топ завантажень', + 'top-dead' => 'Топ "мертвих"', + 'top-downloaded' => 'Топ Завантажених Торрентів', + 'top-downloaders' => 'Топ Завантажувачів', + 'top-dying' => 'Топ "помираючих"', + 'top-leeched' => 'Топ торрентів за кількістю лічерів', + 'top-leechers' => 'Топ Лічерів', + 'top-seeded' => 'Топ торрентів за кількістю сідерів', + 'top-seeding' => 'Топ Сідуючих', + 'top-seeders' => 'Топ Сідерів', + 'top-seedsize' => 'Топ за розміром сідування', + 'top-seedtime' => 'Топ за часом сідування', + 'top-uploaders' => 'Топ Релізерів', + 'total-download' => 'Завантажено загалом', + 'total-torrents' => 'Всього торрентів', + 'total-traffic' => 'Загальний трафік', + 'total-upload' => 'Всього віддано', + 'updated' => '(Оновлюється кожні 10 хвилин!)', + 'users-in-group' => 'Користувачів в групі', + 'users-per-group' => 'Користувачів на групу', + 'last60days' => 'Останні 60 днів', ]; diff --git a/lang/uk/subtitle.php b/lang/uk/subtitle.php index e42ad4002..8031959be 100644 --- a/lang/uk/subtitle.php +++ b/lang/uk/subtitle.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'downloads' => 'Завантажено', - 'extension' => 'Розширення', + 'downloads' => 'Звантажено', + 'extension' => 'Розширення', 'delete-confirm' => 'Ви дійсно впевнені, що хочете видалити це?', - 'note' => 'Примітка', - 'note-help' => 'Додаткова інформація про ці субтитри', - 'rules-title' => 'Правила субтитрів', - 'rules' => '
    -
  • Допускаються лише точні субтитри (правильна частота кадрів, переклад, орфографія, хронометраж)
  • + 'note' => 'Примітка', + 'note-help' => 'Додаткова інформація про ці субтитри', + 'rules-title' => 'Правила субтитрів', + 'rules' => '
      +
    • Допускаються лише субтитри належної якості (правильна частота кадрів, переклад, орфографія, хронометраж)
    • Без гугл-перекладу, машинного перекладу та некоректних субтитрів
    • Субтитри повинні бути синхронізовані з відео
    • ZIP-архіви дозволені лише для SUB+IDX або як пакети однієї мови для пакету телесезонів
    • -
    • Повторне завантаження неякісного контенту буде вважатися порушенням і може призвести до дисциплінарних стягнень.
    • +
    • Повторне завантаження неякісного контенту буде вважатися порушенням і може призвести до дисциплінарних покарань.
    • Зробіть примітку до субтитрів короткою, НІЯКІ URL-адреси/посилання не допускаються
    ', - 'size' => 'Розмір', - 'subtitle-file' => 'Файл субтитрів', - 'subtitle-file-types' => 'Прийнятними файлами є SRT, ASS, SUP та ZIP', - 'uploaded' => 'Додано', - 'uploader' => 'Додав', + 'size' => 'Розмір', + 'subtitle-file' => 'Файл субтитрів', + 'subtitle-file-types' => 'Дозволеними файлами є SRT, ASS, SUP та ZIP', + 'uploaded' => 'Додано', + 'uploader' => 'Додав', ]; diff --git a/lang/uk/ticket.php b/lang/uk/ticket.php index bb2c85f76..24e3a3df1 100644 --- a/lang/uk/ticket.php +++ b/lang/uk/ticket.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'assign' => 'Призначити', - 'assigned-staff' => 'Відповідальний', - 'assigned-success' => 'В заявці успішно призначено відповідального!', - 'attachments' => 'Вкладення', - 'attachments-save' => 'Зберегти вкладення', - 'body' => 'Зміст', - 'body-enter' => 'Опишіть зміст тут...', - 'category' => 'Котегорія', - 'close' => 'Закрити', - 'closed' => 'Закрито', - 'closed-success' => 'Заявка успішно закрита!', - 'create-ticket' => 'Створити заявку', - 'created' => 'Створено', - 'created-success' => 'Ваша заявка успішно створена!', - 'delete' => 'Видалити', - 'deleted-success' => 'Ваша заявка успішно видалена!', - 'description' => 'Опис', - 'download' => 'Завантажити', - 'fix-errors' => 'Будь ласка виправіть наступні помилки і спробуйте ще раз:', - 'helpdesk' => 'Техпідтримка', - 'no-attach' => 'Вкладень не знайдено', - 'priority' => 'Пріоритет', - 'opened-by' => 'Ким відкрито:', - 'reset' => 'Очистити', - 'subject' => 'Тема', - 'subject-enter' => 'Введіть тему тут...', - 'submit-ticket' => 'Створити заявку', - 'show-closed' => 'Показати виконані зявки', - 'ticket' => 'Заявка', - 'unassign' => 'Скасувати призначення', + 'assign' => 'Призначити', + 'assigned-staff' => 'Відповідальний', + 'assigned-success' => 'Ваш запит успішно переданий до служби підтримки!', + 'attachments' => 'Вкладення', + 'attachments-save' => 'Зберегти вкладення', + 'body' => 'Зміст', + 'body-enter' => 'Опишіть зміст тут...', + 'category' => 'Категорія', + 'close' => 'Закрити', + 'closed' => 'Закрито', + 'closed-success' => 'Заявка успішно закрита!', + 'create-ticket' => 'Створити заявку', + 'created' => 'Створено', + 'created-success' => 'Ваш запит до служби підтримки успішно створено!', + 'delete' => 'Видалити', + 'deleted-success' => 'Ваша заявка успішно видалена!', + 'description' => 'Опис', + 'download' => 'Завантажити', + 'fix-errors' => 'Будь ласка, виправте наступні помилки і спробуйте ще раз:', + 'helpdesk' => 'Техпідтримка', + 'no-attach' => 'Вкладень не знайдено', + 'priority' => 'Пріоритет', + 'opened-by' => 'Ким відкрито:', + 'reset' => 'Очистити', + 'subject' => 'Тема', + 'subject-enter' => 'Введіть тему тут...', + 'submit-ticket' => 'Створити заявку', + 'show-closed' => 'Показати виконані зявки', + 'ticket' => 'Заявка', + 'unassign' => 'Скасувати призначення', 'unassigned-success' => 'В заявці успішно скасоване призначення відповідального!', - 'updated-success' => 'Ваша заявка була успішно оновлена!', + 'updated-success' => 'Ваша заявка була успішно оновлена!', + 'attachment-limit' => '(макс. 1 Мб на зображення)', + 'note-create-success' => 'Записка персоналу успішно збережена!', + 'note-destroy-success' => 'Примітка для персоналу видалена успішно!', + 'reopen' => 'Повторно відкрито', + 'reopen-success' => 'Ваш запит до служби підтримки успішно повторно відкрито', + 'staff-notes' => 'Примітки для персоналу', ]; diff --git a/lang/uk/torrent.php b/lang/uk/torrent.php index 822fb28f7..c082363af 100644 --- a/lang/uk/torrent.php +++ b/lang/uk/torrent.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'activity' => 'Діяльність', - 'add-to-playlist' => 'Додати до підбірки', - 'age' => 'Вік', - 'agent' => 'Агент', - 'alive' => 'Живий', - 'announce-url' => 'Адрес трекеру', - 'announce-url-desc' => 'Використовуйте вищенаведену адресу при створенні нового торрент-файлу. Якщо Ви хочете використовувати свій торрент-файл, не завантажуючи його з сайту, Вам необхідно встановити прапорець "Приватний торрент" і в полі "Джерело" вказати ":source"', - 'announce-url-desc-url' => 'Маєте проблеми? Перегляньте нашу інструкцію ТУТ', - 'announce-url-desc2' => 'Поля TMDB ID та IMDB ID необхідно заповнити для всіх релізів! Вони використовуються для завантаження постерів / фонів і описів', - 'approved' => 'Затверджено', - 'audio' => 'Аудіо', - 'bon-tipped' => 'БОН відправляється', - 'bookmark' => 'Закладка', - 'bookmarks' => 'Закладки', - 'bump' => 'Підняти', - 'cant-upload' => 'Помилка: Ваші права на створення релізів вимкнено', - 'cant-upload-desc' => 'Якщо ви відчуваєте, що це помилка, зверніться до адміністрації', - 'cards' => 'Карти', - 'cards-view' => 'Карти перегляду Торрентів', - 'categories' => 'Категорії', - 'category' => 'Категорія', - 'client' => 'Клієнт', - 'commited' => 'Здійснено', - 'completed' => 'Завантажено', - 'completed_at' => 'Завантажено в', - 'completed-not-seeding' => 'Ви завантажили торрент, але більше не сідуєте його', - 'completed-times' => 'Разів завершено', - 'created_at' => 'Створено в', - 'credited' => 'Зараховано', - 'current' => 'Поточний', - 'current-filters' => 'Поточні фільтри', - 'currently-leeching' => 'В даний час завантажують', - 'currently-seeding' => 'В даний час роздають', - 'date' => 'Дата', - 'dead-torrent' => 'Мертвий торрент', - 'dead-torrents' => 'Мертві торренти', - 'define-tip-amount' => 'Вкажіть суму чайових', - 'delete-bookmark' => 'Видалити закладку', - 'description' => 'Опис', - 'discounts' => 'Знижки', - 'distributor' => 'Дистриб\'ютор', - 'double-upload' => 'Подвійна віддача', - 'download-all' => 'Завантажити все', - 'download-check' => 'Завантажити перевірку', - 'download-rights-active' => 'Право на завантаження активне', - 'downloaded' => 'Завантажено', - 'dying-torrent' => 'Вмирачий торрент', - 'dying-torrents' => 'Вмираючі торренти', - 'encode-settings' => 'Налаштування кодування', - 'end-year' => 'Рік По', - 'episode-number' => 'Номер епізоду', - 'estimated-ratio' => 'Орієнтовний рейтинг після завантаження', - 'failed' => 'Помилка', - 'feature' => 'Рекомендація', - 'featured' => 'Рекомендовані', - 'featured-desc' => 'Рекомендовані торренти є 100% безкоштовні і з подвійною віддачею!', - 'featured-until' => 'Це рекомендований торент до', - 'file' => 'Файл', - 'filters' => 'Фільтри', - 'fl-tokens-left' => 'Ви маєте : залишені маркери', - 'freeleech' => 'Фріліч', - 'freeleech-token' => 'Токент фрілічу', - 'general' => 'Загальні', - 'genre' => 'Жанр', - 'genre-tags' => 'Жанри', - 'global-double-upload' => 'Глобальна Подвійна Віддача', - 'global-freeleech' => 'Глобальний Фріліч', - 'grant' => 'Надати', - 'greater-than' => 'Більш чим', - 'grouping' => 'Групування', - 'groupings' => 'Групи', - 'grouping-categories' => 'Групування категорій', + 'activity' => 'Діяльність', + 'add-to-playlist' => 'Додати до підбірки', + 'age' => 'Вік', + 'agent' => 'Агент', + 'alive' => 'Живий', + 'announce-url' => 'Адреса трекеру', + 'announce-url-desc' => 'Використовуйте вищенаведену адресу при створенні нового торрент-файлу. Якщо Ви хочете використовувати свій торрент-файл, не завантажуючи його з сайту, Вам необхідно встановити прапорець "Приватний торрент" і в полі "Джерело" вказати ":source"', + 'announce-url-desc-url' => 'Виникли труднощі? Ознайомтесь з інструкцією ТУТ', + 'announce-url-desc2' => 'Поля TMDB ID та IMDB ID обов\'язкові до заповнення! Вони забезпечують отримання постерів, бекдропів та додаткової інформації', + 'approved' => 'Схвалено', + 'audio' => 'Аудіо', + 'bon-tipped' => 'БОН відправляється', + 'bookmark' => 'Закладка', + 'bookmarks' => 'Закладки', + 'bump' => 'Підняти', + 'cant-upload' => 'Помилка: Ваші права на створення релізів відкликано', + 'cant-upload-desc' => 'Якщо ви вважаєте, що це помилка, зверніться до адміністрації', + 'cards' => 'Картки', + 'cards-view' => 'Карти перегляду Торрентів', + 'categories' => 'Категорії', + 'category' => 'Категорія', + 'client' => 'Клієнт', + 'commited' => 'Здійснено', + 'completed' => 'Завантажено', + 'completed_at' => 'Завершено', + 'completed-not-seeding' => 'Ви завантажили торрент, але більше не сідуєте його', + 'completed-times' => 'Разів завершено', + 'created_at' => 'Створено', + 'credited' => 'Зараховано', + 'current' => 'Поточний', + 'current-filters' => 'Поточні фільтри', + 'currently-leeching' => 'В даний час завантажують', + 'currently-seeding' => 'В даний час роздають', + 'date' => 'Дата', + 'dead-torrent' => 'Мертвий торрент', + 'dead-torrents' => 'Мертві торренти', + 'define-tip-amount' => 'Вкажіть суму чайових', + 'delete-bookmark' => 'Видалити закладку', + 'description' => 'Опис', + 'discounts' => 'Знижки', + 'distributor' => 'Дистриб\'ютор', + 'double-upload' => 'Подвійна віддача', + 'download-all' => 'Завантажити все', + 'download-check' => 'Перевірка завантаження', + 'download-rights-active' => 'Право на завантаження активне', + 'downloaded' => 'Завантажено', + 'dying-torrent' => 'Вмирачий торрент', + 'dying-torrents' => 'Вмираючі торренти', + 'encode-settings' => 'Налаштування кодування', + 'end-year' => 'Рік По', + 'episode-number' => 'Номер епізоду', + 'estimated-ratio' => 'Орієнтовний рейтинг після завантаження', + 'failed' => 'Помилка', + 'feature' => 'Рекомендація', + 'featured' => 'Рекомендовані', + 'featured-desc' => 'Рекомендовані торренти є 100% безкоштовні і з подвійною віддачею!', + 'featured-until' => 'Це рекомендований торент до', + 'file' => 'Файл', + 'filters' => 'Фільтри', + 'fl-tokens-left' => 'У вас лишилося токенів: :tokens', + 'freeleech' => 'Фріліч', + 'freeleech-token' => 'Фріліч-токен', + 'general' => 'Загальні', + 'genre' => 'Жанр', + 'genre-tags' => 'Жанри', + 'global-double-upload' => 'Глобальна Подвійна Віддача', + 'global-freeleech' => 'Глобальний Фріліч', + 'grant' => 'Надати', + 'greater-than' => 'Більш ніж', + 'grouping' => 'Групування', + 'groupings' => 'Групи', + 'grouping-categories' => 'Групування категорій', 'grouping-categories-desc' => 'Яку категорію ви бажаєте групувати?', - 'grouping-results' => 'Результати групування', - 'groupings-view' => 'Перегляд груп', - 'have-completed' => 'Завершено', - 'have-downloaded' => 'Завантажено', - 'have-not-completed' => 'Не завершено', - 'have-not-downloaded' => 'Не завантажено', - 'health' => 'Статус', - 'history' => 'Історія', - 'hitrun' => 'ЗіВ?', - 'hit-and-runs' => 'Завантажив і втік', - 'immune' => 'Імунітет?', - 'info' => 'Інформація', - 'info-hash' => 'Інфо Хеш', - 'internal' => 'Внутрішній', - 'internal-release' => 'Внутрішній реліз', - 'keywords' => 'Ключові слова', - 'keywords-example' => 'Наприклад: superhero, dc comics, marvel', - 'last-seed-activity' => 'Останній раз сідувався', - 'last-seeder' => 'Ви - Останній Сідер! (завантажено принаймні 3 рази)', - 'last-update' => 'Останнє оновлення', - 'leave-tip' => 'Залиште чайові', - 'leecher' => 'Лічер', - 'leechers' => 'Лічери', - 'leeching' => 'Лічує', - 'left' => 'Залишилось', - 'legendary-seeder' => 'Легендарний сідер', - 'legendary-torrent' => 'Легендарний торрент', - 'list' => 'Список', - 'me' => 'Я', - 'media-info' => 'MediaInfo', - 'media-info-parser' => 'MediaInfo Парсер', - 'media-info-paste' => 'Вставте дамп MediaInfo тут', - 'meta-desc' => 'Завантажити: імя з максимальною швидкістю', - 'moderation' => 'Модерація', - 'movies' => 'Фільми', - 'mvp' => 'MVP', - 'my-active-torrents' => 'Мої активні торренти', - 'name' => 'Назва', - 'no-bookmarks' => 'Не знайдено жодних закладок.', - 'no-discounts' => 'В даний час знижок немає', - 'no-meta' => 'Метаданих не знайдено', - 'no-privileges' => 'Ви не можете завантажити цей файл - перевірте нижче', - 'no-privileges-desc' => 'Вирішіть невдалих результатів вище, щоб кнопка завантаження з явилася', - 'not-completed' => 'Почалося завантаження, але ніколи не завершено', - 'not-downloaded' => 'Не завантажено', - 'not-seeding' => 'Не сідується', - 'old-torrent' => 'Старий торрент', - 'optional' => 'Необов\'язково', - 'original-output' => 'Показати / сховати вихідний вихід', - 'participant' => 'Учасник', - 'passed' => 'Пройшло', - 'peers' => 'Піри', - 'pending' => 'Очікує', - 'personal-freeleech' => 'Персональний Фріліч', - 'personal-release' => 'Персональний реліз', - 'poster' => 'Постер', - 'poster-view' => 'Перегляд постеру', - 'posters' => 'Постери', - 'postponed-torrents' => 'Відкладені Торренти', - 'prewarn' => 'Попередження?', - 'progress' => 'Прогрес', - 'publish-time' => 'Опубліковано', - 'quick-comment' => 'Швидкий коментар', - 'quick-tip' => 'Швидкі чайові', - 'rated' => 'Оцінено', - 'rating' => 'Рейтинг', - 'ready' => 'Цей файл готовий до завантаження', - 'recent-bumped' => 'Недавно Закріплено', - 'recommendations' => 'Рекомендації', - 'rejected' => 'Відхилено', - 'region' => 'Регіон', - 'released' => 'Випущено', - 'remaining' => 'Залишилося', - 'request-reseed' => 'Запит на перероздачу', - 'required' => 'Обов\'язково', - 'required-anime' => 'Обов\'язково для Аніме', - 'required-games' => 'Обов\'язково для Ігор', - 'requires-reseed' => 'Потрібна перероздача', - 'resolution' => 'Якість', - 'resolutions' => 'Якість', - 'resurrections' => 'Відновлення', - 'revoke' => 'Скасувати', - 'revokefeatured' => 'Скасувати Рекомендацію', - 'rss' => 'RSS', - 'runtime' => 'Тривалість', - 'satisfied_in' => 'Задоволений', - 'say-thanks' => 'Будь ласка, пам\'ятайте, казати дякую і сідувати до тих пір, поки ви можете', - 'search' => 'Пошук', - 'search-by-name' => 'Пошук по назві', - 'season-number' => 'Номер сезону', - 'seed-time' => 'Час сідування', - 'seeder' => 'Сідер', - 'seeders' => 'Сідери', - 'seeding' => 'Сідування', - 'seedsize' => 'Сідування: розмір', - 'seedtime' => 'Сідування: час', - 'short-completed' => 'C', - 'short-leechs' => 'L', - 'short-seeds' => 'S', - 'show-files' => 'Показати файли', - 'similar' => 'Подібні торренти', - 'size' => 'Розмір', - 'special' => 'Спеціальний', - 'special-double_upload' => 'Спеціальна Подвійна Віддача', - 'special-freeleech' => 'Спеціальний Фріліч', - 'staff-tools' => 'Інструменти модерації', - 'start-year' => 'Рік З', - 'started' => 'Почав', - 'status' => 'Статус', - 'statistics' => 'Статистика', - 'stats' => 'Статистика', - 'sticky' => 'Закріплено', - 'subtitle' => 'Підзаголовок', - 'subtitle-included' => 'Цей торрент вже містить наступні субтитри:', - 'team-player' => 'Командний гравець', - 'thank' => 'Дякую', - 'thanked' => 'Подякували', - 'thanks' => 'Дякую', - 'thanks-given' => 'Подяк отримано', - 'times' => 'Разів', - 'tip-jar' => 'Чайові', - 'title' => 'Назва', - 'titles' => 'Назви', - 'top-completed' => 'Топ завершених', - 'top-dead' => 'Топ мертвих', - 'top-dying' => 'Топ вмираючих', - 'top-leeched' => 'Топ завантажуючих', - 'top-seeded' => 'Топ розданих', - 'torrent' => 'Торрент', - 'torrent-request' => 'Замовлення на реліз', - 'torrent-tips' => 'Всього :total BON було передано релізеру, з яких :user - від вас', - 'torrent-tips-desc' => 'Чайові будуть відніматися від ваших наявних бонусів', - 'torrents' => 'Торренти', - 'torrents-matched' => 'Торренти збігаються', - 'trailer' => 'Переглянути трейлер', - 'type' => 'Тип', - 'types' => 'Типи', - 'unbookmark' => 'Видалити закладку', - 'unsatisfieds' => 'Незадоволені', - 'unsticky' => 'Непомітний', - 'updated' => 'Оновлено', - 'updated_at' => 'Оновлено в', - 'uploaded' => 'Додано', - 'uploaded-by' => 'Додано', - 'uploader' => 'Релізер', - 'use-fl-token' => 'Використати Фріліч Токен', - 'video' => 'Відео', - 'view-more' => 'Дивитись більше', - 'view-trailer' => 'Переглянути трейлер', - 'votes' => 'Голосів', - 'year-range' => 'Діапазон років', + 'grouping-results' => 'Результати групування', + 'groupings-view' => 'Перегляд груп', + 'have-completed' => 'Завершено', + 'have-downloaded' => 'Завантажено', + 'have-not-completed' => 'Не завершено', + 'have-not-downloaded' => 'Не завантажено', + 'health' => 'Статус', + 'history' => 'Історія', + 'hitrun' => 'H&R?', + 'hit-and-runs' => 'Завантажив і втік (H&R)', + 'immune' => 'Імунітет?', + 'info' => 'Інформація', + 'info-hash' => 'Інфо хеш', + 'internal' => 'Внутрішній', + 'internal-release' => 'Внутрішній реліз', + 'keywords' => 'Ключові слова', + 'keywords-example' => 'Наприклад: superhero, dc comics, marvel', + 'last-seed-activity' => 'Останній раз сідувався', + 'last-seeder' => 'Ви - Останній Сідер! (завантажено принаймні 3 рази)', + 'last-update' => 'Останнє оновлення', + 'leave-tip' => 'Залиште чайові', + 'leecher' => 'Лічер', + 'leechers' => 'Лічери', + 'leeching' => 'Лічує', + 'left' => 'Залишилось', + 'legendary-seeder' => 'Легендарний сідер', + 'legendary-torrent' => 'Легендарний торрент', + 'list' => 'Список', + 'me' => 'Я', + 'media-info' => 'Інформація про файл (MediaInfo)', + 'media-info-parser' => 'MediaInfo Парсер', + 'media-info-paste' => 'Вставте звіт MediaInfo тут', + 'meta-desc' => 'Завантажити :name з максимальною швидкістю', + 'moderation' => 'Модерація', + 'movies' => 'Фільми', + 'mvp' => 'MVP', + 'my-active-torrents' => 'Мої активні торренти', + 'name' => 'Ім\'я', + 'no-bookmarks' => 'Не знайдено жодних закладок.', + 'no-discounts' => 'В даний час знижок немає', + 'no-meta' => 'Метаданих не знайдено', + 'no-privileges' => 'Ви не можете завантажити цей файл - перевірте нижче', + 'no-privileges-desc' => 'Виправить проблеми вище, щоб кнопка завантаження з\'явилася', + 'not-completed' => 'Завантаження почалося, але так і не було завершено', + 'not-downloaded' => 'Не завантажено', + 'not-seeding' => 'Не сідується', + 'old-torrent' => 'Старий торрент', + 'optional' => 'Необов\'язково', + 'original-output' => 'Показати / сховати початковий вихід', + 'participant' => 'Учасник', + 'passed' => 'Пройшло', + 'peers' => 'Піри', + 'pending' => 'Очікує', + 'personal-freeleech' => 'Персональний Фріліч', + 'personal-release' => 'Персональний реліз', + 'poster' => 'Постер', + 'poster-view' => 'Постери', + 'posters' => 'Постери', + 'postponed-torrents' => 'Відкладені Торренти', + 'prewarn' => 'Потенційне попередження?', + 'progress' => 'Прогрес', + 'publish-time' => 'Опубліковано', + 'quick-comment' => 'Швидкий коментар', + 'quick-tip' => 'Швидкі чайові', + 'rated' => 'Оцінено', + 'rating' => 'Рейтинг', + 'ready' => 'Цей файл готовий до завантаження', + 'recent-bumped' => 'Недавно Закріплено', + 'recommendations' => 'Рекомендації', + 'rejected' => 'Відхилено', + 'region' => 'Регіон', + 'released' => 'Випущено', + 'remaining' => 'Залишилося', + 'request-reseed' => 'Покликати сідерів', + 'required' => 'Обов\'язково', + 'required-anime' => 'Обов\'язково для Аніме', + 'required-games' => 'Обов\'язково для Ігор', + 'requires-reseed' => 'Потрібна перероздача', + 'resolution' => 'Якість', + 'resolutions' => 'Якість', + 'resurrections' => 'Відроджені релізи', + 'revoke' => 'Скасувати', + 'revokefeatured' => 'Скасувати Рекомендацію', + 'rss' => 'RSS', + 'runtime' => 'Тривалість', + 'satisfied_in' => 'Задоволений', + 'say-thanks' => 'Будь ласка, пам\'ятайте, казати дякую і сідувати до тих пір, поки ви можете', + 'search' => 'Пошук', + 'search-by-name' => 'Пошук по назві', + 'season-number' => 'Номер сезону', + 'seed-time' => 'Час сідування', + 'seeder' => 'Сідер', + 'seeders' => 'Сідери', + 'seeding' => 'Сідування', + 'seedsize' => 'Сідування: розмір', + 'seedtime' => 'Сідування: час', + 'short-completed' => 'C', + 'short-leechs' => 'L', + 'short-seeds' => 'S', + 'show-files' => 'Показати файли', + 'similar' => 'Подібні торренти', + 'size' => 'Розмір', + 'special' => 'Спеціальний', + 'special-double_upload' => 'Спеціальна Подвійна Віддача', + 'special-freeleech' => 'Спеціальний Фріліч', + 'staff-tools' => 'Інструменти модерації', + 'start-year' => 'Рік З', + 'started' => 'Почав', + 'status' => 'Статус', + 'statistics' => 'Статистика', + 'stats' => 'Статистика', + 'sticky' => 'Закріплено', + 'subtitle' => 'Підзаголовок', + 'subtitle-included' => 'Цей торрент вже містить наступні субтитри:', + 'team-player' => 'Командний гравець', + 'thank' => 'Дякую', + 'thanked' => 'Подякували', + 'thanks' => 'Дякую', + 'thanks-given' => 'Висловлені подяки', + 'times' => 'Разів', + 'tip-jar' => 'Чайові', + 'title' => 'Назва', + 'titles' => 'Назви', + 'top-completed' => 'Топ завантажень', + 'top-dead' => 'Топ "мертвих"', + 'top-dying' => 'Топ "помираючих"', + 'top-leeched' => 'Топ торрентів за кількістю лічерів', + 'top-seeded' => 'Топ торрентів за кількістю сідерів', + 'torrent' => 'Торрент', + 'torrent-request' => 'Замовлення релізу', + 'torrent-tips' => 'Всього :total BON було передано релізеру, з яких :user - від вас', + 'torrent-tips-desc' => 'Чайові будуть відмінусовані від ваших наявних бонусів', + 'torrents' => 'Торенти', + 'torrents-matched' => 'Торренти збігаються', + 'trailer' => 'Переглянути трейлер', + 'type' => 'Тип', + 'types' => 'Типи', + 'unbookmark' => 'Видалити закладку', + 'unsatisfieds' => 'Незадоволені', + 'unsticky' => 'Неприкріплений', + 'updated' => 'Оновлено', + 'updated_at' => 'Оновлено', + 'uploaded' => 'Додано', + 'uploaded-by' => 'Додано', + 'uploader' => 'Релізер', + 'use-fl-token' => 'Використати фріліч-токен', + 'video' => 'Відео', + 'view-more' => 'Дивитись більше', + 'view-trailer' => 'Переглянути трейлер', + 'votes' => 'Голосів', + 'year-range' => 'Діапазон років', + 'comments-left' => 'Залишені коментарі', + 'not-personal-release' => 'Не персональний реліз', + 'postponed' => 'Відкладено', + 'season' => 'Сезон', + 'refundable' => 'Підлягає відшкодуванню', + 'refunded' => 'Відшкодовано', ]; diff --git a/lang/uk/user.php b/lang/uk/user.php index a1c31614a..c3ad3d470 100644 --- a/lang/uk/user.php +++ b/lang/uk/user.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ - 'about' => 'Про мене', - 'about-me' => 'Про мене', - 'accepted-at' => 'Прийнято в', - 'accepted-by' => 'Прийнято', - 'account-notification' => 'Налаштування сповіщень облікового запису', - 'account-notification-follow' => 'Отримувати сповіщення, коли користувач слідкує за вашим обліковим записом', - 'account-notification-unfollow' => 'Отримайте сповіщення, коли користувач не відповідає вашому обліковому запису', - 'account-notification-help' => 'Контролюйте, які сповіщення надсилаються стосовно вашого облікового запису. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення про ваш обліковий запис або якщо вимкнути сповіщення', - 'account-settings' => 'Налаштування аккаунта', - 'achievement-privacy' => 'Налаштування досягнення', - 'achievement-privacy-list' => 'Дозволити користувачам переглядати список ваших досягнень', - 'achievement-help' => 'Керуйте спільним доступом до інформації, пов язаної з досягненням, з групами, яким дозволено доступ до вашого профілю. Ці налаштування перевизначаються, якщо ви не дозволяєте жодним групам отримувати доступ до ваших досягнень або якщо ви йдете на приват', - 'achievements' => 'Досягнення', - 'active' => 'Активний', - 'active-table' => 'Моя активна таблиця', - 'active-torrents' => 'Активні потоки', - 'active-warning' => 'Активне попередження', - 'active-warnings' => 'Активні попередження', - 'add-seedbox' => 'Додати сідбокс', - 'all-torrents' => 'Всі торренти', - 'article-comments' => 'Статтей прокоментовано', - 'avatar' => 'Аватар', - 'avg-seedtime' => 'Середній час сідування', - 'badges' => 'Значки', - 'ban' => 'Забанити користувача', - 'ban-log' => 'Заборонити журнал', - 'become-hidden' => 'Стати невидимим', - 'become-visible' => 'Стати видимим', - 'bon' => 'BON', - 'bon-notification' => 'Налаштування сповіщень BON', - 'bon-notification-gift' => 'Отримайте повідомлення, коли користувач подарує вам бонус', - 'bon-notification-help' => 'Контролювати, які повідомлення надсилаються стосовно операцій BON. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення про BON або якщо вимкнути сповіщення', - 'bookmarks' => 'Закладки', - 'bounty-given' => 'Винагород відправлено', - 'bounty-received' => 'Винагород отримано', - 'can-chat' => 'Може чатитись', - 'can-comment' => 'Може коментувати', - 'can-download' => 'Може завантажувати', - 'can-invite' => 'Може запрошувати', - 'can-request' => 'Може запитувати', - 'can-upload' => 'Може додавати', - 'certified-banker' => 'Сертифікований Банкір', - 'certified-banker-desc' => 'Має 50 000 або більше BON в банку', - 'certified-downloader' => 'Сертифікований Завантажувач', - 'certified-downloader-desc' => 'Завантажено 100 або більше торрентів!', - 'certified-seeder' => 'Сертифікована Сідер', - 'certified-seeder-desc' => 'Сідує 150 або більше торрентів!', - 'change-email' => 'Змінити електронну пошту', - 'change-email-help' => 'Після зміни електронної пошти вам доведеться повторно підтвердити свій обліковий запис', - 'change-password' => 'Змінити пароль', - 'change-password-help' => 'Після зміни пароля вам доведеться ввійти знову', - 'client-list' => 'Клієнти та IP-адреси', - 'client-ip-address' => 'IP-адрес клієнта', - 'code' => 'Код', - 'comments' => 'Коментарі', - 'created-on' => 'Створено на', - 'credited-download' => 'Завантажено', - 'credited-upload' => 'Віддано', - 'current-password' => 'Поточний пароль', - 'custom-title' => 'Користувацька назва', - 'delete' => 'Видалити користувача', - 'disable-notifications' => 'Вимкнути сповіщення', - 'disclaimer' => 'Відмова від відповідальності', - 'disclaimer-info' => 'Ми за замовчуванням не реєструємо IP-адреси користувачів, як більшість трекерів. Додавши нижче IP-адресу, ви очікуєте, що ви знаєте, що ваші IP-адреси, наведені нижче, зберігаються в нашій базі даних, якщо ви не видалите записи.', - 'disclaimer-info-bordered' => 'Додані IP-адреси Seedbox призведуть до виникнення тегів на високошвидкісних потоках на торрентах, перенесених з IP-адрес, перерахованих нижче', - 'download-bon' => 'Завантаження видалено з магазину BON', - 'download-recorded' => 'Завантаження (записане)', - 'download-true' => 'Завантаження (справжнє)', - 'downloads' => 'Завантаження', - 'edit' => 'Редагувати користувача', - 'edit-profile' => 'Редагувати профіль', - 'enable-notifications' => 'Включити сповіщення', - 'expired' => 'Минуло', - 'expires-on' => 'Закінчується', - 'extra' => 'Екстра', - 'filled-request' => 'Заповнені запити учасників', - 'follow' => 'Підписатись', - 'follower-privacy' => 'Налаштування підписників', - 'follower-privacy-list' => 'Дозволити користувачам переглядати список ваших підписників', - 'follower-help' => 'Керуйте спільним доступом до конкретної інформації, пов язаної з послідовником, з групами, яким дозволено доступ до вашого профілю. Ці налаштування перевизначаються, якщо ви не дозволяєте жодним групам отримувати доступ до ваших послідовників або якщо ви йдете на приват', - 'followers' => 'Підписники', - 'following-notification' => 'Далі йдуть налаштування сповіщень користувача', - 'following-notification-upload' => 'Отримувати сповіщення, коли користувач, який пішов, завантажує торрент', - 'following-notification-help' => 'Контролювати, які сповіщення надсилаються стосовно наступних дій користувачів сайту. Ці налаштування перевизначаються, якщо ви не дозволяєте жодним групам надсилати сповіщення щодо користувачів, які відстежують, або якщо ви вимкнули сповіщення', - 'formats-are-supported' => ': підтримуються формати', - 'forum-notification' => 'Налаштування сповіщень форуму', - 'forum-notification-topic' => 'Отримайте сповіщення, коли тема, яку ви почали, отримує нову публікацію', - 'forum-notification-help' => 'Контролювати, які повідомлення надсилаються щодо діяльності на форумі. Ці параметри перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення про діяльність форуму або якщо вимкнути сповіщення', - 'forum-privacy' => 'Налаштування форуму', - 'forum-privacy-post' => 'Дозволити користувачам переглядати список повідомлень на форумі, які ви опублікували', - 'forum-privacy-topic' => 'Дозволити користувачам переглядати список запущених тем форуму', - 'forum-help' => 'Керуйте спільним доступом до певної статистики, пов язаної з форумом, та інформації з групами, яким дозволено доступ до вашого профілю. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам отримувати доступ до статистики та інформації, пов язаної з форумом, або якщо ви йдете на приват', - 'forum-signature' => 'Підпис форуму', - 'forums' => 'Форуми', - 'general' => 'Загальні', - 'general-settings' => 'Загальні налаштування', - 'gift-given' => 'Подарунок надіслано', - 'gift-received' => 'Подарунок отримано', - 'go-public' => 'Перейти в публічний режим', - 'go-private' => 'Перейти в приватний режим', - 'history' => 'Історія', - 'history-table' => 'Моя таблиця історії', - 'hit-n-runs' => 'Попередження', - 'hit-n-runs-count' => 'Попередження кількість', - 'hit-n-runs-history' => 'Попередження історія', - 'image' => 'Зображення', - 'important' => 'Важливо', - 'important-info' => 'Важлива інформація', - 'information' => 'Інформація', - 'invite-friend' => 'Запросити друга (електронна пошта + Повідомлення обовязкове)', - 'invite-tree' => 'Дерево інвайтів', - 'invites' => 'Інвайти', - 'invites-banned' => 'Помилка: Ваші інвайти вимкнуті', - 'invites-banned-desc' => 'Якщо ви вважаєте, що це помилка, зверніться до адміністрації!', - 'invites-count' => 'Ви маєте :count інвайтів', - 'invites-disabled' => 'Увага: інвайти відключено через відкриту реєстрацію!', - 'invites-disabled-desc' => 'Будь ласка, перевірте назад!', - 'invites-rules' => '
  • Запрошуйте людей, яких ви знаєте і яким довіряєте.
  • Ви будете особисто відповідальні за тих, кого ви запрошуєте.
  • Не запрошуйте себе, ми перевіряємо кожного запрошеного користувача.
  • Не торгуйте інвайтами.
  • Якщо особа, яку ви запросили, буде спіймана на торгівлі/купівлі інвайтів, ви отримаєте попередження.
  • ', - 'invites-send' => 'Інвайтів надіслано', - 'last-login' => 'Останній вхід', - 'locked' => 'Заблоковано', - 'locked-achievements' => 'Заблоковані досягнення', - 'member-since' => 'Учасник з', - 'members-desc' => 'Список зареєстрованих користувачів: title з усіма групами. Знайдіть користувача зараз.', - 'mention-notification' => '@ Параметри сповіщення сповіщення', - 'mention-notification-article-comment' => 'Отримуйте сповіщення, коли ви @ вказуєте в коментарі до статті', - 'mention-notification-torrent-comment' => 'Отримуйте сповіщення, коли ви вказуєте @ в коментарі до торрента', - 'mention-notification-request-comment' => 'Отримати сповіщення, коли ви @ вказуєте в коментарі запиту', - 'mention-notification-forum-post' => 'Отримувати сповіщення, коли ви @ вказуєтеся на форумі', - 'mention-notification-help' => 'Контролюйте, які сповіщення надсилаються, коли користувач @mentions. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення, якщо користувач @mentions ви чи вимкнули сповіщення', - 'moderated-by' => 'Модерується: mod on', - 'my-achievements' => 'Мої досягнення', - 'my-bonus-points' => 'Мої бонусни', - 'my-bookmarks' => 'Мої закладки', - 'my-fl-tokens' => 'Мої фріліч-токени', - 'my-general-settings' => 'Мої загальні налаштування', - 'my-notification' => 'Моє повідомлення', - 'my-notification-settings' => 'Мої параметри сповіщень', - 'my-privacy' => 'Моя приватність', - 'my-privacy-settings' => 'Мої параметри приватності', - 'my-profile' => 'Мій профіль', - 'my-requested' => 'Мої запити', - 'my-security' => 'Моя безпека', - 'my-security-settings' => 'Мої параметри безпеки', - 'my-seedboxes' => 'Мої сідбокси', - 'my-settings' => 'Мої параметри', - 'my-wishlist' => 'Мій список бажань', - 'my-uploads' => 'Мої релізи', - 'no-logs' => 'У базі даних для цього користувача немає журналів запрошень!', - 'no-seedboxes' => 'Ніяких сідерів 😔', - 'not-authorized' => 'Ви не маєте дозволу на перегляд цієї сторінки. Цей користувач вважає за краще сховатися як ніндзя!', - 'note' => 'Примітка', - 'notification' => 'Сповіщення', - 'notification-settings' => 'Параметри сповіщень', - 'notification-from-account' => 'Отримувати сповіщення про обліковий запис від', - 'notification-from-account-help' => 'Ви отримуватимете сповіщення з облікового запису системи, персоналу та наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-bon' => 'Отримайте сповіщення BON від', - 'notification-from-bon-help' => 'Ви отримуватимете лише сповіщення від системи, персоналу та наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-following' => 'Отримувати сповіщення користувача про це з', - 'notification-from-following-help' => 'Ви отримуватимете лише наступні сповіщення користувача з наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-forum' => 'Отримати сповіщення форуму від', - 'notification-from-forum-help' => 'Ви отримуватимете сповіщення з форуму, персоналу та наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-subscription' => 'Отримувати сповіщення від підписки від', - 'notification-from-subscription-help' => 'Ви отримуватимете сповіщення з форуму, персоналу та наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-torrent' => 'Отримувати сповіщення від Torrent від', - 'notification-from-torrent-help' => 'Ви отримуватимете лише сповіщення від системи, персоналу та наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-mention' => 'Отримати сповіщення @Mention від', - 'notification-from-mention-help' => 'Ви отримаєте лише сповіщення @mention від системи, співробітників і наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notification-from-request' => 'Отримувати повідомлення про запити від', - 'notification-from-request-help' => 'Ви отримуватимете сповіщення про запити лише від системи, персоналу та наступних груп. Ці налаштування перевизначаються, якщо вимкнути сповіщення', - 'notifications' => 'Сповіщення', - 'offline' => 'Користувач офлайн!', - 'online' => 'Користувач онлайн!', - 'options' => 'Опції', - 'other-help' => 'Контролюйте обмін іншими статистичними даними та інформацією з групами, яким дозволено доступ до вашого профілю. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам отримувати доступ до вашої іншої статистики та інформації, або якщо ви переходите до приватної', - 'other-privacy' => 'Інші параметри', - 'other-privacy-online' => 'Дозволити користувачам бачити вас у блоці онлайн-користувачів', - 'passkey' => 'PID', - 'passkey-warning' => 'PID - це ваш пароль, ви повинні тримати його в безпеці!', - 'pending-achievements' => 'Очікувані досягнення', - 'per-torrent' => 'За торрент', - 'posts' => 'Повідомлення', - 'posts-posted' => 'Повідомлення на форумі', - 'privacy' => 'Приватність', - 'privacy-settings' => 'Параметри приватності', - 'private-info' => 'Приватна інформація', - 'private-forum-profile' => 'Увага: Цей учасник Тема & Історія публікацій встановлено в PRIVATE!', - 'private-profile' => 'Увага: цей профіль налаштований на приватний!', - 'profile' => 'Профіль', - 'profile-desc' => 'Користувач: профіль користувача зареєстрований на: title', - 'profile-privacy' => 'Налаштування профілю', - 'profile-privacy-torrent-count' => 'Поділіться загальною кількістю завантажень, завантажень, насіння та п явок', - 'profile-privacy-torrent-ratio' => 'Поділіться своїми загальними даними завантаження / завантаження разом із записаним співвідношенням', - 'profile-privacy-torrent-seed' => 'Частка вашого загального часу посіву та середнього', - 'profile-privacy-title' => 'Поділіться своєю персональною інформацією про назву', - 'profile-privacy-about' => 'Поділіться своєю особистою інформацією про мене', - 'profile-privacy-bon-extra' => 'Поділіться статистикою BON', - 'profile-privacy-comment-extra' => 'Поділіться статистикою коментарів', - 'profile-privacy-forum-extra' => 'Поділіться статистикою форуму', - 'profile-privacy-request-extra' => 'Поділіться статистикою запитів', - 'profile-privacy-torrent-extra' => 'Поділіться своєю статистикою торрентів', - 'profile-privacy-badge' => 'Поділіться своїми заробленими значками', - 'profile-privacy-achievement' => 'Поділіться своїми останніми досягненнями', - 'profile-privacy-follower' => 'Поділіться своїми останніми підписниками', - 'profile-privacy-warning' => 'Поділіться своїми попередженнями', - 'profile-privacy-help' => 'Контролюйте, які статистичні дані та відомості відображатимуться у вашому профілі. Ці налаштування перевизначаються, якщо ви не дозволяєте жодним групам отримувати доступ до вашого профілю або якщо ви йдете в Приватний', - 'public-info' => 'Публічна інформація', - 'recent-achievements' => 'Останні досягнення', - 'recent-followers' => 'Останні послідовники', - 'registration-date' => 'Дата реєстрації', - 'report' => 'Доповідь', - 'request-help' => 'Керуйте спільним доступом до певної статистики, пов язаної з запитом, та інформацією з групами, яким дозволено доступ до вашого профілю. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам отримувати доступ до запитаної статистики та інформації, або якщо ви йдете на приват', - 'request' => 'Запит', - 'requested' => 'Запитано', - 'requests' => 'Запити', - 'request-comments' => 'Запит на коментарі зроблено', - 'request-notification' => 'Надіслати запит на налаштування сповіщень', - 'request-notification-bounty' => 'Отримати сповіщення, коли запитуваний торрент отримує нову баунті', - 'request-notification-comment' => 'Отримайте сповіщення, коли запитаний торрент отримає новий коментар', - 'request-notification-fill' => 'Отримайте сповіщення, коли запитаний торрент заповнюється', - 'request-notification-fill-approve' => 'Отримувати сповіщення, коли затверджено запит на завантаження торентів', - 'request-notification-fill-reject' => 'Отримайте сповіщення про відхилення запиту на завантаження', - 'request-notification-claim' => 'Отримувати сповіщення, коли запитується запитуваний торрент', - 'request-notification-unclaim' => 'Отримайте сповіщення, коли запитуваний торрент не отримає претензії', - 'request-notification-help' => 'Контролювати, які повідомлення надсилаються щодо діяльності запиту. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення про діяльність запиту або якщо вимкнути сповіщення', - 'request-privacy' => 'Параметри запиту', - 'request-privacy-requested' => 'Дозволити користувачам переглядати список зроблених запитів', - 'reset-passkey' => 'Скинути ключ передачі (PID)', - 'reset-passkey-help' => 'Вам доведеться повторно завантажити / перезавантажити всі активні потоки, після скидання PID', - 'reset-rss' => 'Скинути ключ RSS (RID)', - 'reset-rss-help' => 'Вам доведеться повторно завантажити всі активні канали RSS після скидання RID', - 'resurrections' => 'Воскресіння', - 'search' => 'Швидкий пошук за логіном користувача', - 'security' => 'Безпека', - 'security-settings' => 'Параметри безпеки', - 'seedboxes' => 'Сідбокси', - 'seeds' => 'Сідери', - 'send-invite' => 'Надіслати інвайт', - 'sender' => 'Відправник', - 'settings' => 'Налаштування', - 'show-passkey' => 'Показати PID', - 'staff-noted' => 'Примітка адміністрації', - 'statistics' => 'Статистика', - 'subscription-notification' => 'Налаштування сповіщень підписки', - 'subscription-notification-forum' => 'Отримувати сповіщення, коли підписаний форум отримує нову тему', - 'subscription-notification-topic' => 'Отримайте сповіщення, коли підписана тема отримає нову публікацію', - 'subscription-notification-help' => 'Контролювати, які сповіщення надсилатимуться щодо ваших підписок. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення про ваші підписки або ви вимикаєте сповіщення', - 'thanks-given' => 'Подяк передано', - 'thanks-received' => 'Подяк отримано', - 'tips-given' => 'Чайових передано', - 'tips-received' => 'Чайових отримано', - 'title' => 'Назва', - 'top-bankers' => 'Топ банкірів', - 'top-downloaders-data' => 'Топ завантажувачів (дані)', - 'top-leechers' => 'Топ лічерів', - 'top-leechers-count' => 'Топ лічерів (кількість)', - 'top-seeders' => 'Топ сідерів', - 'top-seeders-count' => 'Найпопулярніші сіди (кількість)', - 'top-seeding-size' => 'Найпопулярніші сіди (розмір)', - 'top-seedtime' => 'Найпопулярніші по часу сідування', - 'top-uploaders-data' => 'Найпопулярніші релізери (дані)', - 'top-uploaders-count' => 'Найпопулярніші релізери (кількість)', - 'topics' => 'Теми', - 'topics-started' => 'Розпочато теми форуму', - 'torrent-comments' => 'Торрентів прокоментовано', - 'torrent-help' => 'Контролюйте обмін певними статистичними даними, пов язаними з торрентами, та інформацію з групами, яким дозволено доступ до вашого профілю. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам отримувати доступ до статистики та інформації, пов язаної з торрентами, або якщо ви йдете на приват', - 'torrent-notification' => 'Параметри сповіщень торрентів', - 'torrent-notification-comment' => 'Отримайте сповіщення, коли завантажений торрент отримає новий коментар', - 'torrent-notification-thank' => 'Отримайте сповіщення, коли завантажений торрент отримує нове подяку', - 'torrent-notification-tip' => 'Отримайте сповіщення, коли завантажений торрент отримає новий відгук', - 'torrent-notification-help' => 'Контролювати, які повідомлення надсилаються щодо діяльності торрентів. Ці налаштування перевизначаються, якщо ви не дозволяєте будь-яким групам надсилати сповіщення про діяльність торрентів або якщо вимкнути сповіщення', - 'torrent-privacy' => 'Параметри потоку', - 'torrent-privacy-download' => 'Дозволити користувачам переглядати список завантажених торентів', - 'torrent-privacy-upload' => 'Дозволити користувачам переглядати список завантажених торентів', - 'torrent-privacy-peer' => 'Дозволити користувачам бачити вас у таблиці історії однолітків', - 'torrents' => 'Торренти', - 'torrents-history' => 'Історія торентів', - 'total-download' => 'Всього завантаження', - 'total-downloads' => 'Всього завантажень', - 'total-leeching' => 'Всього завантажується', - 'total-seeding' => 'Всього сідерів', - 'total-seedtime' => 'Всього час сідування', - 'total-upload' => 'Всього віддано', - 'total-uploads' => 'Всього віддач', - 'unban' => 'Розбанити користувача', - 'unfollow' => 'Відписатися', - 'unlocked' => 'Розблоковано', - 'unlocked-achievements' => 'Розблоковані досягнення', - 'unsatisfieds' => 'Незабезпечені', - 'upload-bon' => 'Віддано з магазину BON', - 'upload-recorded' => 'Віддано (записано)', - 'upload-true' => 'Віддано (справжнє)', - 'uploads' => 'Віддачі', - 'uploads-table' => 'Таблиця віддач', - 'user' => 'Користувач', - 'user-id' => 'ID користувача', - 'username-seedbox' => 'Імя користувача сідбокс', - 'visible-to-achievement' => 'Досягнення, видимі для', - 'visible-to-achievement-help' => 'Ваші досягнення будуть видимі тільки для співробітників і наступних груп. Ці налаштування перевизначаються, якщо ви перейдете до приватного', - 'visible-to-follower' => 'Підписники видимі для', - 'visible-to-follower-help' => 'Ваші підписники будуть видимі лише для співробітників і наступних груп. Ці налаштування перевизначаються, якщо ви перейдете до приватного', - 'visible-to-forum' => 'Інформація про форум видима для', - 'visible-to-forum-help' => 'Інформація про ваш форум буде доступна лише для співробітників і наступних груп. Ці налаштування перевизначаються, якщо ви перейдете до приватного', - 'visible-to-other' => 'Інші видимі для', - 'visible-to-other-help' => 'Інша інформація, що стосується вашого облікового запису, буде видимою лише для персоналу та наступних груп. Ці налаштування перевизначаються, якщо ви йдете Приватним або якщо Ви хочете приховати', - 'visible-to-profile' => 'Профіль доступний для', - 'visible-to-profile-help' => 'Ваш профіль буде видно лише для співробітників і наступних груп. Ці налаштування перевизначаються, якщо ви перейдете до приватного', - 'visible-to-request' => 'Запит інформації, видимий для', - 'visible-to-request-help' => 'Інформація про ваш запит буде доступна лише для співробітників та наступних груп. Ці налаштування перевизначаються, якщо ви перейдете до приватного', - 'visible-to-torrent' => 'Інформація про торрент, видиму для', - 'visible-to-torrent-help' => 'Ваша інформація про потік буде видно лише для співробітників і наступних груп. Ці налаштування перевизначаються, якщо ви йдете Приватним або якщо Ви хочете приховати', - 'warned-on' => 'Попереджено на', - 'warning' => 'Увага', - 'warning-log' => 'Журнал попередження', - 'wishlist' => 'Список бажань', + 'about' => 'Розділ "Про нас"', + 'about-me' => 'Про мене', + 'accepted-at' => 'Дата затвердження', + 'accepted-by' => 'Прийнято', + 'account-notification' => 'Налаштування сповіщень облікового запису', + 'account-notification-follow' => 'Отримувати сповіщення, коли хтось підписується на вас', + 'account-notification-unfollow' => 'Отримувати сповіщення, коли хтось відписується від вас', + 'account-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо вашого облікового запису. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про ваш акаунт або якщо ви вимкнете сповіщення', + 'account-settings' => 'Налаштування облікового запису', + 'achievement-privacy' => 'Налаштування досягнень', + 'achievement-privacy-list' => 'Дозволити користувачам переглядати список ваших досягнень', + 'achievement-help' => 'Керуйте поширенням певної інформації про досягнення серед груп, які мають доступ до вашого профілю. + Ці налаштування не діятимуть, якщо ви не надасте жодній групі доступ до своїх досягнень або якщо активуєте режим Приватності', + 'achievements' => 'Досягнення', + 'active' => 'Активний', + 'active-table' => 'Таблиця активних роздач', + 'active-torrents' => 'Активні роздачі', + 'active-warning' => 'Дійсне попередження', + 'active-warnings' => 'Дійсні попередження', + 'add-seedbox' => 'Додати сідбокс', + 'all-torrents' => 'Всі торренти', + 'article-comments' => 'Коментарі до статей', + 'avatar' => 'Аватар', + 'avg-seedtime' => 'Середній час сідування', + 'badges' => 'Відзнаки', + 'ban' => 'Забанити користувача', + 'ban-log' => 'Журнал банів', + 'become-hidden' => 'Стати невидимим', + 'become-visible' => 'Стати видимим', + 'bon' => 'BON', + 'bon-notification' => 'Налаштування сповіщень BON', + 'bon-notification-gift' => 'Сповіщати про отримання BON у подарунок від користувачів', + 'bon-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо транзакцій з BON. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про BON або якщо ви вимкнете сповіщення', + 'bookmarks' => 'Закладки', + 'bounty-given' => 'Винагород відправлено', + 'bounty-received' => 'Винагород отримано', + 'can-chat' => 'Доступ до чату', + 'can-comment' => 'Може коментувати', + 'can-download' => 'Може завантажувати', + 'can-invite' => 'Доступне запрошення користувачів', + 'can-request' => 'Може створювати замовлення', + 'can-upload' => 'Доступне додавання торрентів', + 'certified-banker' => 'Сертифікований Банкір', + 'certified-banker-desc' => 'На балансі 50 000+ BON', + 'certified-downloader' => 'Сертифікований Завантажувач', + 'certified-downloader-desc' => 'Завантажено 100+ торрентів!', + 'certified-seeder' => 'Сертифікований Сідер', + 'certified-seeder-desc' => 'Сідує 150+ торрентів!', + 'change-email' => 'Змінити електронну пошту', + 'change-email-help' => 'Зміну електронної пошти буде завершено лише після повторного підтвердження облікового запису', + 'change-password' => 'Змінити пароль', + 'change-password-help' => 'Після оновлення пароля необхідно буде знову виконати вхід', + 'client-list' => 'Клієнти та IP-адреси', + 'client-ip-address' => 'IP-адреса клієнта', + 'code' => 'Код', + 'comments' => 'Коментарі', + 'created-on' => 'Дата створення', + 'credited-download' => 'Зараховане завантаження', + 'credited-upload' => 'Зараховане відвантажене', + 'current-password' => 'Поточний пароль', + 'custom-title' => 'Індивідуальний слоган', + 'delete' => 'Видалити користувача', + 'disable-notifications' => 'Вимкнути сповіщення', + 'disclaimer' => 'Відмова від відповідальності', + 'disclaimer-info' => 'На відміну від більшості трекерів, за замовчуванням, ми не зберігаємо IP-адреси користувачів. Проте, додаючи IP-адресу свого сидбоксу нижче, ви погоджуєтесь із тим, що ці IP-адреси зберігатимуться в нашій базі даних — доки ви самі не видалите їх.', + 'disclaimer-info-bordered' => 'IP-адреси сидбоксів, додані нижче, автоматично активуватимуть тег "високошвидкісний торрент" для всіх торрентів, які будуть сидуватися з вказаних IP', + 'download-bon' => 'Завантаження видалено з магазину BON', + 'download-recorded' => 'Об’єм завантаженого (зафіксовано)', + 'download-true' => 'Об’єм завантаженого (фактично)', + 'downloads' => 'Звантажено', + 'edit' => 'Редагувати користувача', + 'edit-profile' => 'Редагувати профіль', + 'enable-notifications' => 'Увімкнути сповіщення', + 'expired' => 'Минуло', + 'expires-on' => 'Закінчується', + 'extra' => 'Екстра', + 'filled-request' => 'Виконано замовлень користувачів', + 'follow' => 'Стежити', + 'follower-privacy' => 'Налаштування підписників', + 'follower-privacy-list' => 'Дозволити користувачам переглядати список ваших підписників', + 'follower-help' => 'Керуйте поширенням конкретної інформації про ваших підписників серед груп, яким дозволено доступ до вашого профілю. + Ці налаштування не діятимуть, якщо ви не надасте жодній групі доступ до своїх підписників або якщо увімкнете режим Приватності', + 'followers' => 'Підписники', + 'following-notification' => 'Налаштування сповіщень про користувачів, за якими ви стежите', + 'following-notification-upload' => 'Отримувати сповіщення, коли користувач, за яким ви стежите створює реліз', + 'following-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо дій користувачів, за якими ви стежите. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про таких користувачів або якщо ви вимкнете сповіщення', + 'formats-are-supported' => ':formats, формати що підтримуються', + 'forum-notification' => 'Налаштування сповіщень форуму', + 'forum-notification-topic' => 'Отримувати сповіщення, коли хтось відповідає в темі, яку ви почали', + 'forum-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо активності на форумі. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про активність на форумі або якщо ви вимкнете сповіщення', + 'forum-privacy' => 'Налаштування форуму', + 'forum-privacy-post' => 'Дозволити користувачам переглядати список опублікованих повідомлень на форумі', + 'forum-privacy-topic' => 'Дозволити користувачам переглядати список обговорень на форумі, які ви почали', + 'forum-help' => 'Керуйте поширенням певної статистики та інформації, пов’язаної з форумом, серед груп, які мають доступ до вашого профілю. + Ці налаштування не враховуються, якщо ви не надаєте жодній групі доступ до своїх даних або якщо активуєте режим Приватності', + 'forum-signature' => 'Підпис на форумі', + 'forums' => 'Форуми', + 'general' => 'Загальні', + 'general-settings' => 'Загальні налаштування', + 'gift-given' => 'Подарунків надіслано', + 'gift-received' => 'Подарунків отримано', + 'go-public' => 'Активувати публічний режим', + 'go-private' => 'Активувати режим приватності', + 'history' => 'Історія', + 'history-table' => 'Моя таблиця історії', + 'hit-n-runs' => 'Попередження (H&R)', + 'hit-n-runs-count' => 'Попередження (H&R) за увесь час', + 'hit-n-runs-history' => 'Історія попереджень (H&R)', + 'image' => 'Зображення', + 'important' => 'Важливо', + 'important-info' => 'Важлива інформація', + 'information' => 'Інформація', + 'invite-friend' => 'Запросити друга (обов’язково вказажіть email та повідомлення)', + 'invite-tree' => 'Ієрархія запрошень', + 'invites' => 'Запрошення', + 'invites-banned' => 'Помилка: Можливість надсилати запрошення вимкнена', + 'invites-banned-desc' => 'Якщо ви вважаєте, що це помилка, будь ласка, зв’яжіться з адміністрацією!', + 'invites-count' => 'В наявності :count токенів для запрошення інших', + 'invites-disabled' => 'Увага: відкрита реєстрація, тому запрошення не використовуються!', + 'invites-disabled-desc' => 'Зачекайте хвильку — ми скоро повернемося!', + 'invites-rules' => '
  • Запрошуйте лише тих, кого ви добре знаєте і кому довіряєте.
  • Ви несете особисту відповідальність за осіб, яких запросили.
  • Реєстрація через власне запрошення заборонена — ми ретельно перевіряємо кожного нового користувача.
  • Не передавайте запрошення в обмін або за гроші.
  • Якщо запрошена вами особа буде спіймана на шахрайстві, передачі акаунту або продажу/торгівлі запрошеннями, вам буде винесено попередження.
  • ', + 'invites-send' => 'Запрошень надіслано', + 'last-login' => 'Останній вхід', + 'locked' => 'Ще не відкрито', + 'locked-achievements' => 'Досягнення, які ще не відкриті', + 'member-since' => 'Учасник починаючи з', + 'members-desc' => 'Список усіх зареєстрованих на :title користувачів. Знайдіть користувача вже зараз.', + 'mention-notification' => 'Налаштування сповіщень про згадки (@)', + 'mention-notification-article-comment' => 'Отримувати сповіщення, коли вас згадують (@) в коментарях до статті', + 'mention-notification-torrent-comment' => 'Отримувати сповіщення, коли вас згадують (@) в коментарях до торренту', + 'mention-notification-request-comment' => 'Отримувати сповіщення, коли вас згадують (@) в коментарях до замовлення', + 'mention-notification-forum-post' => 'Отримувати сповіщення, коли вас згадують (@) в темі на форумі', + 'mention-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться, коли вас згадують за допомогою @. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про згадування або якщо ви вимкнете сповіщення', + 'moderated-by' => 'Модерація від :mod станом на', + 'my-achievements' => 'Досягнення', + 'my-bonus-points' => 'Бонусні бали', + 'my-bookmarks' => 'Закладки', + 'my-fl-tokens' => 'Фріліч-токени', + 'my-general-settings' => 'Загальні налаштування', + 'my-notification' => 'Сповіщення', + 'my-notification-settings' => 'Налаштування сповіщень', + 'my-privacy' => 'Приватність', + 'my-privacy-settings' => 'Налаштування приватності', + 'my-profile' => 'Профіль', + 'my-requested' => 'Мої замовлення', + 'my-security' => 'Безпека', + 'my-security-settings' => 'Налаштування безпеки', + 'my-seedboxes' => 'Сідбокси', + 'my-settings' => 'Налаштування', + 'my-wishlist' => 'Список бажань', + 'my-uploads' => 'Релізи', + 'no-logs' => 'Історія запрошеннь від цього користувача відсутня у базі даних!', + 'no-seedboxes' => 'Немає сідбоксів 😔', + 'not-authorized' => 'Вибачте, але цей користувач ховається краще за лінь у понеділок ранком, тож шукайте його в іншому місці!', + 'note' => 'Примітка', + 'notification' => 'Сповіщення', + 'notification-settings' => 'Налаштування сповіщень', + 'notification-from-account' => 'Отримувати сповіщення про обліковий запис від', + 'notification-from-account-help' => 'Вам надходитимуть сповіщення про обліковий запис виключно від системи, персоналу та зазначених нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-bon' => 'Отримувати сповіщення про транзакції з BON від', + 'notification-from-bon-help' => 'Вам надходитимуть сповіщення щодо транзакцій з BON виключно від системи, персоналу та перелічених нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-following' => 'Отримувати сповіщення від підписаних користувачів від', + 'notification-from-following-help' => 'Ви отримуватимете сповіщення про відстежуваних користувачів лише від наведених нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-forum' => 'Отримувати сповіщення про активність на форумі від', + 'notification-from-forum-help' => 'Сповіщення з форуму надходитимуть вам лише від системи, персоналу та вибраних нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-subscription' => 'Отримувати сповіщення про дії, пов’язані з підписками, від', + 'notification-from-subscription-help' => 'Сповіщення з форуму надходитимуть вам лише від системи, персоналу та вибраних нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-torrent' => 'Отримувати сповіщення про дії, пов’язані з релізами, від', + 'notification-from-torrent-help' => 'Ви отримуватимете сповіщення щодо змін у релізах лише від системи, персоналу та зазначених нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-mention' => 'Отримувати сповіщення про згадки (@) від', + 'notification-from-mention-help' => 'Ви отримуватимете сповіщення про згадки (@mention) лише від системи, персоналу та зазначених нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notification-from-request' => 'Отримувати сповіщення про дії, пов’язані з запитами, від', + 'notification-from-request-help' => 'Ви отримуватимете сповіщення про запити лише від системи, персоналу та зазначених нижче груп. + Ці налаштування не діятимуть, якщо ви вимкнете сповіщення', + 'notifications' => 'Сповіщення', + 'offline' => 'Користувач офлайн!', + 'online' => 'Користувач онлайн!', + 'options' => 'Опції', + 'other-help' => 'Керуйте доступом до інших статистичних даних та інформації для груп, яким дозволено перегляд вашого профілю. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі переглядати ці дані або якщо ви увімкнете приватний режим', + 'other-privacy' => 'Інші налаштування', + 'other-privacy-online' => 'Дозволити користувачам бачити вас у блоці онлайн-користувачів', + 'passkey' => 'PID', + 'passkey-warning' => 'PID - це наче ваш пароль, ви повинні тримати його в безпеці!', + 'pending-achievements' => 'Очікувані досягнення', + 'per-torrent' => 'За торрент', + 'posts' => 'Публікації', + 'posts-posted' => 'Публікації на форумі', + 'privacy' => 'Приватність', + 'privacy-settings' => 'Налаштування приватності', + 'private-info' => 'Приватна інформація', + 'private-forum-profile' => 'Увага! Історія тем і дописів цього учасника закрита для перегляду!', + 'private-profile' => 'Увага: Особа за цим профілем ховається краще, ніж твої шкарпетки після прання!', + 'profile' => 'Профіль', + 'profile-desc' => 'Профіль користувача :user зареєстровано на :title', + 'profile-privacy' => 'Налаштування профілю', + 'profile-privacy-torrent-count' => 'Поділіться загальною кількістю завантажень, релізів та торрентів, які ви сідуєте або завантажуєте', + 'profile-privacy-torrent-ratio' => 'Поділіться своїм загальним обсягом завантаженого / відданого, а також рейтингом', + 'profile-privacy-torrent-seed' => 'Поділіться вашим загальним і середнім часом сідування', + 'profile-privacy-title' => 'Поділіться своїм індивідуальним слоганом', + 'profile-privacy-about' => 'Поділіться інформацією про себе', + 'profile-privacy-bon-extra' => 'Поділіться статистикою BON', + 'profile-privacy-comment-extra' => 'Поділіться статистикою коментарів', + 'profile-privacy-forum-extra' => 'Поширювати статистику ваших дій на форумі', + 'profile-privacy-request-extra' => 'Поділіться статистикою замовлень', + 'profile-privacy-torrent-extra' => 'Поділіться своєю статистикою торрентів', + 'profile-privacy-badge' => 'Поділіться своїми здобутими відзнаками', + 'profile-privacy-achievement' => 'Поділіться своїми останніми відзнаками', + 'profile-privacy-follower' => 'Поділіться своїми останніми підписниками', + 'profile-privacy-warning' => 'Поділіться своїми попередженнями (H&R)', + 'profile-privacy-help' => 'Керуйте тим, які статистичні дані та інформація відображатимуться у вашому профілі. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі доступ до вашого профілю або якщо увімкнете приватний режим', + 'public-info' => 'Публічна інформація', + 'recent-achievements' => 'Останні досягнення', + 'recent-followers' => 'Останні послідовники', + 'registration-date' => 'Дата реєстрації', + 'report' => '"Лист щастя"', + 'request-help' => 'Керуйте доступом до конкретної статистики та інформації, пов’язаної з вашими запитами, для груп, яким дозволено переглядати ваш профіль. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі доступ до статистики та інформації про ваші запити або якщо увімкнете приватний режим', + 'request' => 'Замовлення', + 'requested' => 'Запитано', + 'requests' => 'Замовлення', + 'request-comments' => 'Коментарі, залишені у запитах', + 'request-notification' => 'Налаштування сповіщень замовлень', + 'request-notification-bounty' => 'Отримувати сповіщення, коли замовлення підтримують бонусами', + 'request-notification-comment' => 'Отримувати сповіщення, коли до замовлення додають новий коментар', + 'request-notification-fill' => 'Отримувати сповіщення, коли запит виконано', + 'request-notification-fill-approve' => 'Отримувати сповіщення, коли запит підтверджено', + 'request-notification-fill-reject' => 'Отримувати сповіщення, коли запит відхилено', + 'request-notification-claim' => 'Отримувати сповіщення, коли хтось бере замовлення на виконання', + 'request-notification-unclaim' => 'Отримувати сповіщення, коли заявку на виконання замовлення скасовують', + 'request-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо активності у запитах. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про активність у запитах або якщо ви вимкнете сповіщення', + 'request-privacy' => 'Налаштування замовлень', + 'request-privacy-requested' => 'Дозволити користувачам переглядати список зроблених замовлень', + 'reset-passkey' => 'Скинути passkey (PID)', + 'reset-passkey-help' => 'Вам доведеться повторно завантажити всі активні торренти після скидання PID', + 'reset-rss' => 'Скинути ключ RSS (RID)', + 'reset-rss-help' => 'Вам доведеться повторно завантажити всі активні канали RSS після скидання RID', + 'resurrections' => 'Відроджені релізи', + 'search' => 'Швидкий пошук за ім\'ям користувача чи електронною поштою', + 'security' => 'Безпека', + 'security-settings' => 'Налаштування безпеки', + 'seedboxes' => 'Сідбокси', + 'seeds' => 'Сідери', + 'send-invite' => 'Надіслати запрошення', + 'sender' => 'Відправник', + 'settings' => 'Налаштування', + 'show-passkey' => 'Показати PID', + 'staff-noted' => 'Персонал зацінив цього користувача. І тепер стежить 👀', + 'statistics' => 'Статистика', + 'subscription-notification' => 'Налаштування сповіщень підписки', + 'subscription-notification-forum' => 'Повідомляти, коли хтось створює нове обговорення на форумі, на який ви підписані', + 'subscription-notification-topic' => 'Повідомляти про нові відповіді в обговореннях, на які ви підписані', + 'subscription-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо ваших підписок. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про ваші підписки або якщо ви вимкнете сповіщення', + 'thanks-given' => 'Висловлені подяки', + 'thanks-received' => 'Подяк отримано', + 'tips-given' => 'Надані пожертви', + 'tips-received' => 'Пожертв отримано', + 'title' => 'Назва', + 'top-bankers' => 'Топ банкірів', + 'top-downloaders-data' => 'Топ завантажувачів (дані)', + 'top-leechers' => 'Топ лічерів', + 'top-leechers-count' => 'Топ лічерів (кількість)', + 'top-seeders' => 'Топ сідерів', + 'top-seeders-count' => 'Топ сідерів (кількість)', + 'top-seeding-size' => 'Топ сідерів (розмір)', + 'top-seedtime' => 'Топ за часом сідування', + 'top-uploaders-data' => 'Топ релізерів (дані)', + 'top-uploaders-count' => 'Топ релізерів (кількість)', + 'topics' => 'Обговорення', + 'topics-started' => 'Розпочаті обговорення на форумі', + 'torrent-comments' => 'Залишено коментарів до торрентів', + 'torrent-help' => 'Керуйте доступом до конкретної статистики та інформації, пов’язаної з торрентами, для груп, яким дозволено переглядати ваш профіль. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі доступ до статистики та інформації про торренти або якщо ви увімкнете приватний режим', + 'torrent-notification' => 'Налаштування сповіщень торрентів', + 'torrent-notification-comment' => 'Отримувати сповіщення, коли Ваш реліз отримує новий коментар', + 'torrent-notification-thank' => 'Отримувати сповіщення, коли Вам дякують за реліз', + 'torrent-notification-tip' => 'Отримувати сповіщення, коли Вам дають чайові за реліз', + 'torrent-notification-help' => 'Керуйте тим, які сповіщення надсилатимуться щодо активності з торрентами. + Ці налаштування не діятимуть, якщо ви не дозволите жодній групі надсилати сповіщення про активність з торрентами або якщо ви вимкнете сповіщення', + 'torrent-privacy' => 'Налаштування торрентів', + 'torrent-privacy-download' => 'Дозволити користувачам переглядати список завантажених Вами торентів', + 'torrent-privacy-upload' => 'Дозволити користувачам переглядати список Ваших релізів', + 'torrent-privacy-peer' => 'Дозволити користувачам бачити вас у таблиці історії пірів', + 'torrents' => 'Торенти', + 'torrents-history' => 'Історія торентів', + 'total-download' => 'Завантажено загалом', + 'total-downloads' => 'Всього завантажень', + 'total-leeching' => 'Всього завантажується', + 'total-seeding' => 'Всього відвантажується', + 'total-seedtime' => 'Загальний час сідування', + 'total-upload' => 'Всього віддано', + 'total-uploads' => 'Всього віддач', + 'unban' => 'Розбанити користувача', + 'unfollow' => 'Не слідкувати', + 'unlocked' => 'Розблоковано', + 'unlocked-achievements' => 'Отримані досягнення', + 'unsatisfieds' => 'Незабезпечені', + 'upload-bon' => 'Об’єм відвантаженого (за BON-и)', + 'upload-recorded' => 'Об’єм відвантаженого (зафіксовано)', + 'upload-true' => 'Об’єм відвантаженого (фактично)', + 'uploads' => 'Віддачі', + 'uploads-table' => 'Таблиця віддач', + 'user' => 'Користувач', + 'user-id' => 'ID користувача', + 'username-seedbox' => 'Ім’я користувача Seedbox', + 'visible-to-achievement' => 'Кому доступна інформація про ваші досягнення', + 'visible-to-achievement-help' => 'Ваші досягнення будуть видимі лише для адміністрації та наступних груп. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим', + 'visible-to-follower' => 'Кому доступна інформація щодо підписників', + 'visible-to-follower-help' => 'Ваші підписники будуть видимі лише для адміністрації та наступних груп. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим', + 'visible-to-forum' => 'Кому доступна інформація щодо активності на форумі', + 'visible-to-forum-help' => 'Ваша інформація з форуму буде видимою лише для адміністрації та наступних груп. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим', + 'visible-to-other' => 'Інші секції видимі для', + 'visible-to-other-help' => 'Додаткова інформація про ваш обліковий запис буде видимою лише для адміністрації та наступних груп. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим або опцію Стати невидимим', + 'visible-to-profile' => 'Видимість профілю', + 'visible-to-profile-help' => 'Ваш профіль буде видимий лише адміністрації та наступним групам. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим', + 'visible-to-request' => 'Кому доступна інформація про запити', + 'visible-to-request-help' => 'Інформація про ваші запити буде видимою лише для адміністрації та наступних груп. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим', + 'visible-to-torrent' => 'Кому доступна інформація про торренти (релізи)', + 'visible-to-torrent-help' => 'Інформація про ваші торренти (релізи) буде видимою лише для адміністрації та наступних груп. + Ці налаштування не діятимуть, якщо ви увімкнете приватний режим або опцію Стати невидимим', + 'warned-on' => 'Дата видачі попередження', + 'warning' => 'Попередження', + 'warning-log' => 'Історія попереджень', + 'wishlist' => 'Список бажаного', + 'warnings' => 'Усі попередження', + 'personal-releases' => 'Персональні релізи', + 'apikey' => 'Ключ API', + 'apikeys' => 'Ключі API', + 'bans' => 'Бани', + 'created' => 'Створено', + 'deactivate' => 'Деактивувати', + 'deactivate-all' => 'Деактивувати все', + 'delete-all' => 'Видалити все', + 'deleted-by' => 'Видалено користувачем', + 'follow-already' => 'Ви вже стежите за цим користувачем', + 'internal-releases' => 'Внутрішні релізи', + 'invited-by' => 'Запросив(ла)', + 'invite-already-sent' => 'Запрошення вже було надіслано на цю електронну адресу.', + 'invite-already-used' => 'Запрошення, яке ви намагаєтеся повторно надіслати, вже було використане.', + 'invite-expired' => 'Термін дії запрошення, яке ви намагаєтеся надіслати повторно, закінчився.', + 'follow-yourself' => 'Гарна спроба, але, на жаль, ви не можете стежити за собою.', + 'homepage-block-chat-visible' => 'Показати вікно чату', + 'homepage-block-featured-visible' => 'Показати рекомендовані торренти', + 'homepage-block-latest-comments-visible' => 'Показати останні коментарі', + 'homepage-block-latest-posts-visible' => 'Показати останні повідомлення', + 'homepage-block-latest-topics-visible' => 'Показати останні обговорення', + 'homepage-block-news-visible' => 'Показати останні новини', + 'homepage-block-online-visible' => 'Показати користувачів, які зараз в мережі', + 'homepage-block-poll-visible' => 'Показати останнє опитування', + 'homepage-block-random-media-visible' => 'Показати довільне медіа', + 'homepage-block-top-torrents-visible' => 'Відобразити найпопулярніші торренти', + 'homepage-block-top-users-visible' => 'Відобразити провідних користувачів', + 'invite-sent-success' => 'Запрошення успішно надіслано!', + 'invites-disabled-group' => 'Для вашої групи користувачів, функція запрошень тимчасово недоступна.', + 'last-action' => 'Остання дія', + 'my-downloads' => 'Завантаження', + 'my-playlists' => 'Мої підбірки', + 'no-ban' => 'Історія банів для цього користувача відсутня у базі даних!', + 'no-warning' => 'Жодних попереджень для цього користувача у базі даних не зафіксовано!', + 'not-enough-invites' => 'Ой, вибачте, але ваших запрошень вистачає хіба що на каву з самим собою!', + 'not-satisfied-not-immune' => 'Не виконано вимоги / Без імунітету', + 'judge' => 'Арбітр', + 'open-registration' => 'Відкрита реєстрація', + 'password-resets' => 'Скидання пароля', + 'reactivate' => 'Реактивувати', + 'reason-ban' => 'Причина бану', + 'reason-unban' => 'Причина розбану', + 'removed' => 'Видалено', + 'report-sent' => 'Скаргу надіслано', + 'reset-api-token' => 'Скинути токен API', + 'reset-api-help' => 'Після скидання API-токена обов’язково оновіть токен на новий у всіх відповідних скриптах та програмах', + 'restore' => 'Відновити', + 'rsskey' => 'Ключ RSS', + 'rsskeys' => 'RSS ключі', + 'seedbox-added-success' => 'Seedbox успішно додано!', + 'seedbox-deleted-success' => 'Seedbox успішно видалено', + 'seeding-size' => 'Об’єм поширюваного контенту', + 'top-bountied' => 'Топ Скруджів', + 'top-dead' => 'Топ "мертвих"', + 'top-dying' => 'Топ "помираючих"', + 'total-internal-releases' => 'Загальна кількість внутрішніх релізів', + 'total-personal-releases' => 'Загальна кількість персональних релізів', + 'two-step-auth' => [ + 'title' => 'Двофакторна автентифікація', + 'totp-is-enabled' => 'Наразі автентифікація TOTP увімкнена. Щоб вимкнути її, натисніть кнопку "Вимкнути" нижче.', + 'totp-is-disabled' => 'TOTP-аутентифікація наразі вимкнена. Щоб увімкнути її, натисніть кнопку "Увімкнути" нижче.', + 'password-confirm' => 'Потребує підтвердження пароля', + 'upon-enabling' => 'У разі активації система запросить чинний код двофакторної перевірки.', + 'complete-setup' => 'Для завершення налаштування TOTP проскануйте цей штрихкод у своєму додатку для автентифікації (наприклад, Google Authenticator, Authy, Bitwarden) і введіть згенерований код у поле нижче.', + 'confirm-code' => 'Підтвердити код TOTP', + 'recovery-code-reset' => 'Скинути', + 'totp' => 'Аутентифікація за допомогою тимчасового одноразового пароля (TOTP)', + 'email' => 'Аутентифікація особи за допомогою електронної пошти', + 'recovery-code' => 'Резервні коди відновлення для TOTP-аутентифікації', + 'recovery-code-description' => 'Натисніть кнопку «Показати», щоб побачити коди відновлення для вашого облікового запису. Збережіть ці коди в надійному місці офлайн на випадок втрати доступу до вашого пристрою TOTP. Якщо ви вважаєте, що коди могли бути скомпрометовані, будь ласка, натисніть кнопку «Скинути», щоб згенерувати новий набір кодів.', + 'recovery-code-reveal' => 'Показати', + ], + 'top-leeched' => 'Топ торрентів за кількістю лічерів', + 'top-seeded' => 'Топ торрентів за кількістю сідерів', + 'deleted-on' => 'Дата видалення', + 'homepage-blocks' => 'Секції на головній сторінці', + 'top-completed' => 'Топ завантажень', + 'email-updates' => 'Інформаційні листи', + 'follow-revoked' => 'Ви більше не стежите за %s', + 'follow-user' => 'Ви тепер стежите за %s', + 'follow-not-to-begin-with' => 'Ви ще не стежите за цим користувачем', + 'id-permissions' => 'ID та дозволи', + 'invite-resent-success' => 'Повторна відправка запрошення пройшла успішно!', + 'no-soft-warning' => 'Попереджень для цього користувача зі статусом «м’яке видалення» в базі даних не знайдено!', + 'satisfied-immune' => 'Вимогу задоволено / Імунітет', + 'soft-deleted-warnings' => 'Попередження зі статусом "м’яке видалення"', + 'unregistered-info-hashes' => 'Незареєстровані інфо-хеші', + 'upload-snatches' => 'Скачування усіх ваших роздач', + 'warned-by' => 'Попереджений(а) ким', + 'following' => 'За ким слідкую', ]; diff --git a/lang/uk/validation.php b/lang/uk/validation.php index 7d1ba949b..74358ccbe 100644 --- a/lang/uk/validation.php +++ b/lang/uk/validation.php @@ -1,7 +1,6 @@ * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ - -return [ /* |-------------------------------------------------------------------------- | Мовні ресурси перевірки введення @@ -24,111 +21,111 @@ return [ | наприклад, size. Ви можете змінити будь-яке з цих повідомлень. | */ - - 'accepted' => 'Ви повинні прийняти :attribute.', - 'active_url' => 'Поле :attribute не є правильним URL.', - 'after' => 'Поле :attribute має містити дату не раніше :date.', - 'after_or_equal' => 'Поле :attribute має містити дату не раніше або дорівнюватися :date.', - 'alpha' => 'Поле :attribute має містити лише літери.', - 'alpha_dash' => 'Поле :attribute має містити лише літери, цифри та підкреслення.', - 'alpha_num' => 'Поле :attribute має містити лише літери та цифри.', - 'array' => 'Поле :attribute має бути масивом.', - 'before' => 'Поле :attribute має містити дату не пізніше :date.', - 'before_or_equal' => 'Поле :attribute має містити дату не пізніше або дорівнюватися :date.', - 'between' => [ + 'accepted' => 'Ви повинні прийняти :attribute.', + 'active_url' => 'Поле :attribute не є коректним URL.', + 'after' => 'Поле :attribute має містити дату не раніше :date.', + 'after_or_equal' => 'Поле :attribute має містити дату не раніше :date.', + 'alpha' => 'Поле :attribute має містити лише літери.', + 'alpha_dash' => 'Поле :attribute має містити лише літери, цифри, дефіс та підкреслення.', + 'alpha_num' => 'Поле :attribute має містити лише літери та цифри.', + 'array' => 'Поле :attribute має бути масивом.', + 'before' => 'Поле :attribute має містити дату не пізніше :date.', + 'before_or_equal' => 'Поле :attribute має містити дату не пізніше :date.', + 'between' => [ 'numeric' => 'Поле :attribute має бути між :min та :max.', - 'file' => 'Розмір файлу в полі :attribute має бути не менше :min та не більше :max кілобайт.', - 'string' => 'Текст в полі :attribute має бути не менше :min та не більше :max символів.', - 'array' => 'Поле :attribute має містити від :min до :max елементів.', + 'file' => 'Розмір файлу в полі :attribute має бути не менше :min та не більше :max кілобайт.', + 'string' => 'Текст в полі :attribute має бути не менше :min та не більше :max символів.', + 'array' => 'Поле :attribute має містити від :min до :max елементів.', ], - 'boolean' => 'Поле :attribute повинне містити логічний тип.', - 'confirmed' => 'Поле :attribute не збігається з підтвердженням.', - 'date' => 'Поле :attribute не є датою.', - 'date_equals' => 'Поле :attribute має бути датою рівною :date.', - 'date_format' => 'Поле :attribute не відповідає формату :format.', - 'different' => 'Поля :attribute та :other повинні бути різними.', - 'digits' => 'Довжина цифрового поля :attribute повинна дорівнювати :digits.', + 'boolean' => 'Поле :attribute повинне містити логічний тип.', + 'confirmed' => 'Поле :attribute не збігається з підтвердженням.', + 'date' => 'Поле :attribute не є датою.', + 'date_equals' => 'Поле :attribute має бути датою рівною :date.', + 'date_format' => 'Поле :attribute не відповідає формату :format.', + 'different' => 'Поля :attribute та :other повинні бути різними.', + 'digits' => 'Довжина цифрового поля :attribute повинна дорівнювати :digits.', 'digits_between' => 'Довжина цифрового поля :attribute повинна бути від :min до :max.', - 'dimensions' => 'Поле :attribute містіть неприпустимі розміри зображення.', - 'distinct' => 'Поле :attribute містить значення, яке дублюється.', - 'email' => 'Поле :attribute повинне містити коректну електронну адресу.', - 'file' => 'Поле :attribute має містити файл.', - 'filled' => "Поле :attribute є обов'язковим для заповнення.", - 'exists' => 'Вибране для :attribute значення не коректне.', - 'gt' => [ + 'dimensions' => 'Поле :attribute містить недопустимі розміри зображення.', + 'distinct' => 'Поле :attribute містить значення, яке дублюється.', + 'email' => 'Поле :attribute повинне містити коректну електронну адресу.', + 'file' => 'Поле :attribute має містити файл.', + 'filled' => "Поле :attribute є обов'язковим для заповнення.", + 'exists' => 'Вибране для :attribute значення не коректне.', + 'gt' => [ 'numeric' => 'Поле :attribute має бути більше ніж :value.', - 'file' => 'Поле :attribute має бути більше ніж :value кілобайт.', - 'string' => 'Поле :attribute має бути більше ніж :value символів.', - 'array' => 'Поле :attribute має містити більше ніж :value елементів.', + 'file' => 'Поле :attribute має бути більше ніж :value кілобайт.', + 'string' => 'Поле :attribute має бути більше ніж :value символів.', + 'array' => 'Поле :attribute має містити більше ніж :value елементів.', ], 'gte' => [ - 'numeric' => 'Поле :attribute має доріванювати чи бути більше ніж :value.', - 'file' => 'Поле :attribute має доріванювати чи бути більше ніж :value кілобайт.', - 'string' => 'Поле :attribute має доріванювати чи бути більше ніж :value символів.', - 'array' => 'Поле :attribute має містити :value чи більше елементів.', + 'numeric' => 'Поле :attribute має дорівнювати чи бути більше ніж :value.', + 'file' => 'Поле :attribute має дорівнювати чи бути більше ніж :value кілобайт.', + 'string' => 'Поле :attribute має дорівнювати чи бути більше ніж :value символів.', + 'array' => 'Поле :attribute має містити :value чи більше елементів.', ], - 'image' => 'Поле :attribute має містити зображення.', - 'in' => 'Вибране для :attribute значення не коректне.', + 'image' => 'Поле :attribute має містити зображення.', + 'in' => 'Вибране для :attribute значення не коректне.', 'in_array' => 'Значення поля :attribute не міститься в :other.', - 'integer' => 'Поле :attribute має містити ціле число.', - 'ip' => 'Поле :attribute має містити IP адресу.', - 'ipv4' => 'Поле :attribute має містити IPv4 адресу.', - 'ipv6' => 'Поле :attribute має містити IPv6 адресу.', - 'json' => 'Дані поля :attribute мають бути в форматі JSON.', - 'lt' => [ + 'integer' => 'Поле :attribute має містити ціле число.', + 'ip' => 'Поле :attribute має містити IP адресу.', + 'ipv4' => 'Поле :attribute має містити IPv4 адресу.', + 'ipv6' => 'Поле :attribute має містити IPv6 адресу.', + 'json' => 'Дані поля :attribute мають бути в форматі JSON.', + 'lt' => [ 'numeric' => 'Поле :attribute має бути менше ніж :value.', - 'file' => 'Поле :attribute має бути менше ніж :value кілобайт.', - 'string' => 'Поле :attribute має бути менше ніж :value символів.', - 'array' => 'Поле :attribute має містити менше ніж :value items.', + 'file' => 'Поле :attribute має бути менше ніж :value кілобайт.', + 'string' => 'Поле :attribute має бути менше ніж :value символів.', + 'array' => 'Поле :attribute має містити менше ніж :value items.', ], 'lte' => [ 'numeric' => 'Поле :attribute має дорівнювати чи бути менше ніж :value.', - 'file' => 'Поле :attribute має дорівнювати чи бути менше ніж :value кілобайт.', - 'string' => 'Поле :attribute має дорівнювати чи бути менше ніж :value символів.', - 'array' => 'Поле :attribute має містити не більше ніж :value елементів.', + 'file' => 'Поле :attribute має дорівнювати чи бути менше ніж :value кілобайт.', + 'string' => 'Поле :attribute має дорівнювати чи бути менше ніж :value символів.', + 'array' => 'Поле :attribute має містити не більше ніж :value елементів.', ], 'max' => [ 'numeric' => 'Поле :attribute має бути не більше :max.', - 'file' => 'Файл в полі :attribute має бути не більше :max кілобайт.', - 'string' => 'Текст в полі :attribute повинен мати довжину не більшу за :max.', - 'array' => 'Поле :attribute повинне містити не більше :max елементів.', + 'file' => 'Файл в полі :attribute має бути не більше :max кілобайт.', + 'string' => 'Текст в полі :attribute повинен мати довжину не більшу за :max.', + 'array' => 'Поле :attribute повинне містити не більше :max елементів.', ], - 'mimes' => 'Поле :attribute повинне містити файл одного з типів: :values.', - 'mimetypes' => 'Поле :attribute повинне містити файл одного з типів: :values.', - 'min' => [ + 'mimes' => 'Для поля :attribute прийнятні лише файли типу: :values.', + 'mimetypes' => 'Для поля :attribute прийнятні лише файли типу: :values.', + 'min' => [ 'numeric' => 'Поле :attribute повинне бути не менше :min.', - 'file' => 'Розмір файлу в полі :attribute має бути не меншим :min кілобайт.', - 'string' => 'Текст в полі :attribute повинен містити не менше :min символів.', - 'array' => 'Поле :attribute повинне містити не менше :min елементів.', + 'file' => 'Розмір файлу в полі :attribute має бути не меншим :min кілобайт.', + 'string' => 'Текст в полі :attribute повинен містити не менше :min символів.', + 'array' => 'Поле :attribute повинне містити не менше :min елементів.', ], - 'not_in' => 'Вибране для :attribute значення не коректне.', - 'not_regex' => 'Формат поля :attribute не вірний.', - 'numeric' => 'Поле :attribute повинно містити число.', - 'present' => 'Поле :attribute повинне бути присутнє.', - 'regex' => 'Поле :attribute має хибний формат.', - 'required' => "Поле :attribute є обов'язковим для заповнення.", - 'required_if' => "Поле :attribute є обов'язковим для заповнення, коли :other є рівним :value.", - 'required_unless' => "Поле :attribute є обов'язковим для заповнення, коли :other відрізняється від :values", - 'required_with' => "Поле :attribute є обов'язковим для заповнення, коли :values вказано.", - 'required_with_all' => "Поле :attribute є обов'язковим для заповнення, коли :values вказано.", - 'required_without' => "Поле :attribute є обов'язковим для заповнення, коли :values не вказано.", + 'not_in' => 'Вибране для :attribute значення не коректне.', + 'not_regex' => 'Формат поля :attribute не вірний.', + 'numeric' => 'Поле :attribute повинно містити число.', + 'present' => 'Поле :attribute є обов’язковим для заповнення.', + 'regex' => 'Поле :attribute має хибний формат.', + 'required' => "Поле :attribute є обов'язковим для заповнення.", + 'required_if' => "Поле :attribute є обов'язковим для заповнення, коли :other є рівним :value.", + 'required_unless' => "Поле :attribute є обов’язковим, якщо лише :other не належить до :values.", + 'required_with' => "Поле :attribute є обов'язковим для заповнення, коли :values вказано.", + 'required_with_all' => "Поле :attribute є обов'язковим для заповнення, коли :values вказано.", + 'required_without' => "Поле :attribute є обов'язковим для заповнення, коли :values не вказано.", 'required_without_all' => "Поле :attribute є обов'язковим для заповнення, коли :values не вказано.", - 'same' => 'Поля :attribute та :other мають співпадати.', - 'size' => [ + 'same' => 'Поля :attribute та :other мають співпадати.', + 'size' => [ 'numeric' => 'Поле :attribute має бути довжини :size.', - 'file' => 'Файл в полі :attribute має бути розміром :size кілобайт.', - 'string' => 'Текст в полі :attribute повинен містити :size символів.', - 'array' => 'Поле :attribute повинне містити :size елементів.', + 'file' => 'Файл в полі :attribute має бути розміром :size кілобайт.', + 'string' => 'Текст в полі :attribute повинен містити :size символів.', + 'array' => 'Поле :attribute повинне містити :size елементів.', ], - 'starts_with' => 'Поле :attribute повинне розпочинатись з одного з наступного: :values', - 'string' => 'Поле :attribute повинне містити текст.', - 'timezone' => 'Поле :attribute повинне містити коректну часову зону.', - 'unique' => 'Таке значення поля :attribute вже існує.', - 'uploaded' => 'Завантаження поля :attribute не вдалося.', - 'url' => 'Формат поля :attribute неправильний.', - 'uuid' => 'Поле :attribute має бути коректним UUID ідентифікатором.', - - /* + 'starts_with' => 'Поле «:attribute» має починатися з будь-якого з наведених значень: :values.', + 'string' => 'Поле :attribute повинне містити текст.', + 'timezone' => 'Поле :attribute повинне містити коректну часову зону.', + 'unique' => 'Таке значення поля :attribute вже існує.', + 'uploaded' => 'Завантаження поля :attribute не вдалося.', + 'url' => 'Формат поля :attribute неправильний.', + 'uuid' => 'Поле :attribute має бути коректним UUID ідентифікатором.', + 'custom' => [ + 'attribute-name' => [ + /* |-------------------------------------------------------------------------- | Додаткові ресурси для перевірки введення |-------------------------------------------------------------------------- @@ -138,14 +135,11 @@ return [ | Так ви зможете легко додати текст повідомлення для заданого атрибуту. | */ - - 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', + 'rule-name' => 'користувацьке-повідомлення', ], ], - - /* + 'attributes' => [ + /* |-------------------------------------------------------------------------- | Власні назви атрибутів |-------------------------------------------------------------------------- @@ -161,36 +155,55 @@ return [ | ], | */ - - 'attributes' => [ - 'name' => 'Ім\'я', - 'username' => 'Нікнейм', - 'email' => 'E-Mail адреса', - 'first_name' => 'Ім\'я', - 'last_name' => 'Прізвище', - 'password' => 'Пароль', + 'name' => 'Ім\'я', + 'username' => 'Нікнейм', + 'email' => 'E-Mail адреса', + 'first_name' => 'Ім\'я', + 'last_name' => 'Прізвище', + 'password' => 'Пароль', 'password_confirmation' => 'Підтвердження паролю', - 'city' => 'Місто', - 'country' => 'Країна', - 'address' => 'Адреса', - 'phone' => 'Телефон', - 'mobile' => 'Моб. номер', - 'age' => 'Вік', - 'sex' => 'Стать', - 'gender' => 'Стать', - 'day' => 'День', - 'month' => 'Місяць', - 'year' => 'Рік', - 'hour' => 'Година', - 'minute' => 'Хвилина', - 'second' => 'Секунда', - 'title' => 'Назва', - 'content' => 'Контент', - 'description' => 'Опис', - 'excerpt' => 'Уривок', - 'date' => 'Дата', - 'time' => 'Час', - 'available' => 'Доступно', - 'size' => 'Розмір', + 'city' => 'Місто', + 'country' => 'Країна', + 'address' => 'Адреса', + 'phone' => 'Телефон', + 'mobile' => 'Моб. номер', + 'age' => 'Вік', + 'sex' => 'Стать', + 'gender' => 'Стать', + 'day' => 'День', + 'month' => 'Місяць', + 'year' => 'Рік', + 'hour' => 'Година', + 'minute' => 'Хвилина', + 'second' => 'Секунда', + 'title' => 'Назва', + 'content' => 'Контент', + 'description' => 'Опис', + 'excerpt' => 'Уривок', + 'date' => 'Дата', + 'time' => 'Час', + 'available' => 'Доступно', + 'size' => 'Розмір', ], + 'current_password' => 'Неправильний пароль.', + 'recaptcha' => 'Будь ласка, заповніть ReCaptcha.', + 'password' => [ + 'letters' => 'У полі :attribute має бути принаймні одна літера.', + 'mixed' => 'Поле :attribute має містити щонайменше одну велику та одну малу літеру.', + 'numbers' => 'Поле :attribute має містити принаймні одну цифру.', + 'symbols' => 'Поле :attribute має містити принаймні один символ.', + 'uncompromised' => ':attribute, який ви вказали, вже став публічним через витік даних. Будь ласка, підберіть новий.', + ], + 'multiple_of' => 'Значення :attribute повинно бути кратним числу :value.', + 'prohibited' => 'Заповнення поля :attribute є недопустимим.', + 'prohibited_if' => 'Заповнення поля :attribute не допускається, якщо :other дорівнює :value.', + 'prohibited_unless' => 'Заповнення поля :attribute заборонено, хіба що :other міститься серед :values.', + 'prohibits' => 'Поле «:attribute» не може містити «:other».', + 'email_list' => 'Цей домен електронної пошти не відповідає вимогам сайту. Будь ласка, перегляньте список дозволених доменів.', + 'accepted_if' => ':attribute буде схвалено, якщо :other = :value.', + 'declined' => ':attribute слід відхилити.', + 'declined_if' => ':attribute слід відхилити, коли :other дорівнює :value.', + 'ends_with' => ':attribute повинен закінчуватися значенням із цього списку: :values.', + 'enum' => 'Обраний :attribute є некоректним.', + 'mac_address' => ':attribute має бути дійсною MAC-адресою.', ]; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 46ed9e787..df8f96100 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -402,36 +402,6 @@ parameters: count: 1 path: app/Http/Controllers/Staff/DonationController.php - - - message: '#^Property App\\Models\\Donation\:\:\$ends_at \(Illuminate\\Support\\Carbon\) does not accept Carbon\\Carbon\.$#' - identifier: assign.propertyType - count: 1 - path: app/Http/Controllers/Staff/DonationController.php - - - - message: '#^Property App\\Models\\Donation\:\:\$ends_at \(Illuminate\\Support\\Carbon\) does not accept null\.$#' - identifier: assign.propertyType - count: 1 - path: app/Http/Controllers/Staff/DonationController.php - - - - message: '#^Property App\\Models\\Donation\:\:\$starts_at \(Illuminate\\Support\\Carbon\) does not accept Carbon\\Carbon\.$#' - identifier: assign.propertyType - count: 1 - path: app/Http/Controllers/Staff/DonationController.php - - - - message: '#^Method App\\Http\\Controllers\\Staff\\DonationGatewayController\:\:destroy\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: app/Http/Controllers/Staff/DonationGatewayController.php - - - - message: '#^Method App\\Http\\Controllers\\Staff\\DonationGatewayController\:\:store\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: app/Http/Controllers/Staff/DonationGatewayController.php - - message: '#^Access to an undefined property App\\Models\\Group\|Illuminate\\Database\\Eloquent\\Collection\\:\:\$level\.$#' identifier: property.notFound @@ -486,12 +456,6 @@ parameters: count: 1 path: app/Http/Livewire/AttachmentUpload.php - - - message: '#^Method App\\Http\\Livewire\\BackupPanel\:\:backups\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Livewire/BackupPanel.php - - message: '#^Property App\\Http\\Livewire\\BbcodeInput\:\:\$contentBbcode \(string\) does not accept array\|string\.$#' identifier: assign.propertyType @@ -540,36 +504,6 @@ parameters: count: 1 path: app/Http/Livewire/LaravelLogViewer.php - - - message: '#^Method App\\Http\\Livewire\\LaravelLogViewer\:\:entries\(\) return type with generic class Illuminate\\Pagination\\LengthAwarePaginator does not specify its types\: TKey, TValue$#' - identifier: missingType.generics - count: 1 - path: app/Http/Livewire/LaravelLogViewer.php - - - - message: '#^Method App\\Http\\Livewire\\LaravelLogViewer\:\:entries\(\) should return Illuminate\\Pagination\\LengthAwarePaginator&iterable\\> but returns Illuminate\\Pagination\\LengthAwarePaginator\\>\.$#' - identifier: return.type - count: 1 - path: app/Http/Livewire/LaravelLogViewer.php - - - - message: '#^Method App\\Http\\Livewire\\LaravelLogViewer\:\:logFiles\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: app/Http/Livewire/LaravelLogViewer.php - - - - message: '#^PHPDoc tag @property for property App\\Http\\Livewire\\LaravelLogViewer\:\:\$entries contains generic class Illuminate\\Pagination\\LengthAwarePaginator but does not specify its types\: TKey, TValue$#' - identifier: missingType.generics - count: 1 - path: app/Http/Livewire/LaravelLogViewer.php - - - - message: '#^PHPDoc tag @property for property App\\Http\\Livewire\\LaravelLogViewer\:\:\$logFiles contains generic class Illuminate\\Support\\Collection but does not specify its types\: TKey, TValue$#' - identifier: missingType.generics - count: 1 - path: app/Http/Livewire/LaravelLogViewer.php - - message: '#^Parameter \#1 \$array of function array_shift expects array, list\\|false given\.$#' identifier: argument.type @@ -660,90 +594,12 @@ parameters: count: 1 path: app/Http/Requests/StoreRequestFillRequest.php - - - message: '#^Method App\\Http\\Resources\\BotResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/BotResource.php - - - - message: '#^Method App\\Http\\Resources\\BotResource\:\:toArray\(\) return type with generic interface Illuminate\\Contracts\\Support\\Arrayable does not specify its types\: TKey, TValue$#' - identifier: missingType.generics - count: 1 - path: app/Http/Resources/BotResource.php - - - - message: '#^Method App\\Http\\Resources\\ChatMessageResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/ChatMessageResource.php - - - - message: '#^Method App\\Http\\Resources\\ChatRoomResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/ChatRoomResource.php - - - - message: '#^Method App\\Http\\Resources\\ChatUserResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/ChatUserResource.php - - - - message: '#^Method App\\Http\\Resources\\TorrentResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/TorrentResource.php - - message: '#^Strict comparison using \=\=\= between int\|null and true will always evaluate to false\.$#' identifier: identical.alwaysFalse count: 1 path: app/Http/Resources/TorrentResource.php - - - message: '#^Unable to resolve the template type TKey in call to function collect$#' - identifier: argument.templateType - count: 1 - path: app/Http/Resources/TorrentResource.php - - - - message: '#^Unable to resolve the template type TValue in call to function collect$#' - identifier: argument.templateType - count: 1 - path: app/Http/Resources/TorrentResource.php - - - - message: '#^Method App\\Http\\Resources\\TorrentsResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/TorrentsResource.php - - - - message: '#^Method App\\Http\\Resources\\TorrentsResource\:\:with\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/TorrentsResource.php - - - - message: '#^Method App\\Http\\Resources\\UserAudibleResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/UserAudibleResource.php - - - - message: '#^Method App\\Http\\Resources\\UserEchoResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/UserEchoResource.php - - - - message: '#^Method App\\Http\\Resources\\UserResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: app/Http/Resources/UserResource.php - - message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$name\.$#' identifier: property.notFound diff --git a/resources/js/app.js b/resources/js/app.js index 4b1239e8e..d3076f37b 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -41,6 +41,7 @@ import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.e // Custom AlpineJS Components import './components/alpine/chatbox'; import './components/alpine/checkboxGrid'; +import './components/alpine/clipboardButton'; import './components/alpine/dialog'; import './components/alpine/dislikeButton'; import './components/alpine/likeButton'; diff --git a/resources/js/components/alpine/chatbox.js b/resources/js/components/alpine/chatbox.js index 69ecc4e4c..3c69374e6 100644 --- a/resources/js/components/alpine/chatbox.js +++ b/resources/js/components/alpine/chatbox.js @@ -44,7 +44,7 @@ const messageHandler = { context.state.chat.activeTab.startsWith('bot') || context.state.chat.activeTab.startsWith('target') ) { - context.messages.push(response.data.data); + context.messages.set(response.data.data.id, response.data.data); } if (context.$refs && context.$refs.message) { context.$refs.message.value = ''; @@ -58,10 +58,7 @@ const messageHandler = { return axios .post(`/api/chat/message/${id}/delete`) .then(() => { - const index = context.messages.findIndex((msg) => msg.id === id); - if (index !== -1) { - context.messages.splice(index, 1); - } + context.messages.delete(id); }) .catch((error) => { console.error('Error deleting message:', error); @@ -97,15 +94,14 @@ const channelHandler = { .listen('.new.message', (e) => { if (!context.state.chat.activeTab.startsWith('room')) return; const message = context.processMessageCanMod(e.message); - context.messages.push(message); + context.messages.set(message.id, message); }) .listen('.new.ping', (e) => { context.handlePing('room', e.ping.id); }) .listen('.delete.message', (e) => { if (context.state.chat.target > 0 || context.state.chat.bot > 0) return; - let index = context.messages.findIndex((msg) => msg.id === e.message.id); - if (index !== -1) context.messages.splice(index, 1); + context.messages.delete(e.message.id); }) .listenForWhisper('typing', (e) => { if (context.state.chat.target > 0 || context.state.chat.bot > 0) return; @@ -158,10 +154,9 @@ document.addEventListener('alpine:init', () => { auth: user, statuses: [], - status: 0, echoes: [], chatrooms: [], - messages: [], + messages: new Map(), users: new Map(), pings: [], audibles: [], @@ -208,6 +203,11 @@ document.addEventListener('alpine:init', () => { this.state.ui.loading = false; }); + this.$watch('auth.chat_status_id', (status, oldStatus) => { + if (status === oldStatus) return; // Closing a chatbox tab triggers this (alpinejs bug) + this.syncStatus(); + }); + this.$cleanup = () => { if (this.channel) { window.Echo.leave(`chatroom.${this.state.chat.room}`); @@ -290,9 +290,11 @@ document.addEventListener('alpine:init', () => { try { const response = await axios.get(`/api/chat/bot/${id}`); // Process messages to add canMod property for each message and sanitize content - this.messages = response.data.data - .map((message) => this.processMessageCanMod(message)) - .reverse(); + this.messages = new Map( + response.data.data + .map((message) => [message.id, this.processMessageCanMod(message)]) + .reverse(), + ); } catch (error) { console.error('Error fetching bot messages:', error); throw error; @@ -305,9 +307,11 @@ document.addEventListener('alpine:init', () => { `/api/chat/private/messages/${this.state.chat.target}`, ); // Process messages to add canMod property for each message and sanitize content - this.messages = response.data.data - .map((message) => this.processMessageCanMod(message)) - .reverse(); + this.messages = new Map( + response.data.data + .map((message) => [message.id, this.processMessageCanMod(message)]) + .reverse(), + ); } catch (error) { console.error('Error fetching private messages:', error); throw error; @@ -318,9 +322,11 @@ document.addEventListener('alpine:init', () => { try { const response = await axios.get(`/api/chat/messages/${this.state.chat.room}`); // Process messages to add canMod property for each message and sanitize content - this.messages = response.data.data - .map((message) => this.processMessageCanMod(message)) - .reverse(); + this.messages = new Map( + response.data.data + .map((message) => [message.id, this.processMessageCanMod(message)]) + .reverse(), + ); } catch (error) { console.error('Error fetching messages:', error); throw error; @@ -595,11 +601,11 @@ document.addEventListener('alpine:init', () => { // Process and sanitize new message const message = this.processMessageCanMod(e.message); - this.messages.push(message); + this.messages.set(message.id, message); } else if (e.type == 'new.bot') { // Process and sanitize new bot message const message = this.processMessageCanMod(e.message); - this.messages.push(message); + this.messages.set(message.id, message); } else if (e.type == 'new.ping') { if (e.ping.type == 'bot') { this.handlePing('bot', e.ping.id); @@ -608,8 +614,7 @@ document.addEventListener('alpine:init', () => { } } else if (e.type == 'delete.message') { if (this.state.chat.target < 1 && this.state.chat.bot < 1) return; - let index = this.messages.findIndex((msg) => msg.id === e.message.id); - if (index !== -1) this.messages.splice(index, 1); + this.messages.delete(e.message.id); } else if (e.type == 'typing') { if (this.state.chat.target < 1) return; const username = e.username; @@ -676,18 +681,12 @@ document.addEventListener('alpine:init', () => { this.state.chat.showWhispers = !this.state.chat.showWhispers; }, - changeStatus(status_id) { - this.status = status_id; - if (this.auth.chat_status.id !== status_id) { - axios - .post(`/api/chat/user/status`, { status_id }) - .then((response) => { - this.auth = response.data; - }) - .catch((error) => { - console.error('Error changing status:', error); - }); - } + syncStatus() { + axios + .post(`/api/chat/user/status`, { status_id: this.auth.chat_status_id }) + .catch((error) => { + console.error('Error changing status:', error); + }); }, startBot() { diff --git a/resources/js/components/alpine/clipboardButton.js b/resources/js/components/alpine/clipboardButton.js new file mode 100644 index 000000000..c0def17b9 --- /dev/null +++ b/resources/js/components/alpine/clipboardButton.js @@ -0,0 +1,12 @@ +document.addEventListener('alpine:init', () => { + Alpine.data('clipboardButton', () => ({ + button: { + ['x-on:click']() { + let text = this.$root + .querySelector('pre > code') + .innerHTML.replace(/
    /g, '\r\n'); + navigator.clipboard.writeText(text); + }, + }, + })); +}); diff --git a/resources/sass/base/_reset.scss b/resources/sass/base/_reset.scss index 0d34b2ccf..909b4b6cd 100644 --- a/resources/sass/base/_reset.scss +++ b/resources/sass/base/_reset.scss @@ -25,7 +25,13 @@ a { code, pre { - font-family: 'Roboto Mono', Menlo, Monaco, Consolas, 'Courier New', + font-family: + ui-monospace, + SFMono-Regular, + SF Mono, + Menlo, + Consolas, + Liberation Mono, monospace; font-size: 12px; line-height: 1.46666667; diff --git a/resources/sass/components/_bbcode-rendered.scss b/resources/sass/components/_bbcode-rendered.scss index e600b1b73..f672f8b9d 100644 --- a/resources/sass/components/_bbcode-rendered.scss +++ b/resources/sass/components/_bbcode-rendered.scss @@ -195,7 +195,7 @@ border-left: 0.25em solid var(--bbcode-rendered-quote-border); font-size: 15px; background-color: var(--bbcode-rendered-quote-bg); - border-radius: 6px; + border-radius: 3px 6px 6px 3px / 8px 6px 6px 8px; > cite { font-size: 12px; @@ -229,12 +229,12 @@ ol, dl, table, - pre, .bbcode-rendered__center, .bbcode-rendered__left, .bbcode-rendered__right, .bbcode-rendered__alert, - .bbcode-rendered__note { + .bbcode-rendered__note, + .bbcode-rendered__clipboard { margin-top: 12px; margin-bottom: 12px; } @@ -383,17 +383,15 @@ } pre { - background-color: var(--bbcode-rendered-neutral-muted); - color: var(--bbcode-rendered-fg-default); border: revert; - border-radius: 6px; font-size: 12px; word-wrap: normal; - overflow: visible; + overflow: auto; line-height: inherit; word-break: break-word; overflow-wrap: anywhere; white-space: pre-wrap; + margin: 0; padding: 12px; } @@ -402,7 +400,7 @@ margin: 0; word-break: normal; overflow-wrap: anywhere; - white-space: normal; + white-space: break-spaces; font-size: 13px; background-color: var(--bbcode-rendered-neutral-muted); border-radius: 6px; @@ -421,7 +419,9 @@ } pre > code { - white-space: pre-wrap; + word-break: normal; + white-space: pre; + background-color: transparent; } pre code { @@ -429,11 +429,36 @@ padding: 0; overflow: visible; line-height: inherit; + word-wrap: normal; overflow-wrap: anywhere; background-color: transparent; border: 0; } + .bbcode-rendered__clipboard { + display: flex; + justify-content: space-between; + background-color: var(--bbcode-rendered-neutral-muted); + color: var(--bbcode-rendered-fg-default); + border-radius: 6px; + position: relative; + overflow: auto; + } + + .bbcode-rendered__clipboard-button { + display: block; + background: transparent; + border: none; + margin: 6px; + color: var(--bbcode-rendered-fg-muted); + cursor: pointer; + } + + .bbcode-rendered__clipboard-button:hover, + .bbcode-rendered__clipboard-button:focus { + color: var(--bbcode-rendered-fg-default); + } + /* Markdown Extra footnotes */ sup { diff --git a/resources/sass/components/_chatbox.scss b/resources/sass/components/_chatbox.scss index 47631e7cd..a6ede4418 100644 --- a/resources/sass/components/_chatbox.scss +++ b/resources/sass/components/_chatbox.scss @@ -2,7 +2,7 @@ display: grid; grid-template-areas: 'messages users' 'whispers users' 'new-message users'; grid-template-columns: 1fr auto; - grid-template-rows: 1fr 18px auto; + grid-template-rows: 1fr auto auto; height: 700px; max-height: 90vh; background-color: inherit; @@ -19,7 +19,7 @@ flex-direction: column; list-style-type: none; gap: 8px; - padding: 0 10px; + padding: 0 10px 5px; margin: 0; align-items: flex-start; } @@ -28,12 +28,14 @@ grid-area: users; width: auto; overflow-y: auto; + background-color: var(--chatbox-users-bg); } .chatroom__whispers { grid-area: whispers; font-size: 12px; padding: 2px 4px; + height: 18px; } .chatroom__new-message { @@ -43,6 +45,7 @@ #chatbox__messages-create { max-height: 60vh; + resize: vertical; } .chatbox-message { @@ -145,37 +148,6 @@ border-style: solid; } -.chatbox-message__fallback-avatar { - width: 34px; - height: 34px; - border-radius: 17px; -} - -.chatbox-message__delete-button { - padding: 4px 12px; - margin: 0; - background-color: transparent; - text-align: center; - border: none; - color: transparent; - font-size: 14px; - cursor: pointer; -} - -.chatbox-message:hover .chatbox-message__delete-button { - color: var(--chatbox-button-fg); - width: auto; - - &:hover { - color: var(--chatbox-button-hover-fg); - width: auto; - } -} - -.chatroom__users { - background-color: var(--chatbox-users-bg); -} - .chatroom-users__heading { font-size: 18px; padding: 4px 8px; diff --git a/resources/sass/components/_mediainfo.scss b/resources/sass/components/_mediainfo.scss index 50218e19c..6e0cd4473 100644 --- a/resources/sass/components/_mediainfo.scss +++ b/resources/sass/components/_mediainfo.scss @@ -79,3 +79,15 @@ .mediainfo__encode-settings { flex-basis: 100%; } + +.mediainfo__encode-settings pre, +.torrent-mediainfo-dump pre { + padding: 12px; + background-color: var(--bbcode-rendered-neutral-muted); + color: var(--bbcode-rendered-fg-default); + border-radius: 6px; + font-size: 12px; + white-space: pre-wrap; + word-break: break-word; + overflow-wrap: anywhere; +} diff --git a/resources/sass/components/_meta.scss b/resources/sass/components/_meta.scss index ee27ad604..e2ca08f71 100644 --- a/resources/sass/components/_meta.scss +++ b/resources/sass/components/_meta.scss @@ -496,3 +496,157 @@ display: none; } } + +/* Meta Poster Popup +---------------------------------------------------------------------------- */ + +.meta__poster-popup { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 9999; + pointer-events: none; +} + +.meta__poster-popup-card { + width: 500px; + background: var(--meta-popup-bg); + border-radius: 20px; + box-shadow: 0 40px 100px rgba(0, 0, 0, 0.25); + overflow: hidden; + position: relative; + transition: all 0.3s ease; +} + +.meta__poster-popup-backdrop { + width: 100%; + height: 180px; + position: relative; + overflow: hidden; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.meta__poster-popup-backdrop-overlay { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 80px; + background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.6)); +} + +.meta__poster-popup-content { + padding: 25px; + background: var(--meta-popup-bg); + position: relative; +} + +.meta__poster-popup-header { + margin-bottom: 20px; +} + +.meta__poster-popup-title { + font-size: 22px; + font-weight: 700; + color: var(--meta-popup-fg); + margin: 0 0 15px 0; + line-height: 1.2; + + .meta__poster-popup-year { + color: var(--meta-popup-fg); + font-size: 22px; + font-weight: 700; + margin-left: 8px; + } +} + +.meta__poster-popup-meta-tags { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 20px; + flex-wrap: wrap; + + &:not(:empty)::after { + content: ''; + height: 1px; + background: var(--meta-popup-fg); + flex: 1 0 100%; + margin-top: 8px; + } +} + +.meta__poster-popup-rating, +.meta__poster-popup-genres, +.meta__poster-popup-runtime { + display: flex; + align-items: center; + gap: 8px; + color: var(--meta-popup-fg); + font-size: 13px; + font-weight: 500; +} + +.meta__poster-popup-stars { + display: flex; + gap: 2px; + + i { + font-size: 12px; + color: #ffd700; + + &:not(.active) { + color: var(--meta-popup-fg); + } + } +} + +.meta__poster-popup-overview { + color: var(--meta-popup-fg); + font-size: 14px; + line-height: 1.6; + margin: 0 0 25px 0; +} + +.meta__poster-popup-details { + display: flex; + flex-direction: column; + gap: 12px; +} + +.meta__poster-popup-detail { + display: flex; + justify-content: space-between; + align-items: flex-start; + padding: 10px 0; + border-bottom: 0.5px dashed var(--meta-popup-fg); + + &:last-child { + border-bottom: none; + } +} + +.detail-label { + color: var(--meta-popup-fg); + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + flex-shrink: 0; + width: 90px; +} + +.detail-value { + color: var(--meta-popup-fg); + font-size: 13px; + font-weight: 500; + text-align: right; + flex: 1; + line-height: 1.4; +} diff --git a/resources/sass/components/_user-card.scss b/resources/sass/components/_user-card.scss index 61d1236cc..4ef29b4db 100644 --- a/resources/sass/components/_user-card.scss +++ b/resources/sass/components/_user-card.scss @@ -45,9 +45,3 @@ margin: 0; padding: 0; } - -.user-card__group { - color: #fff; - margin: 0; - padding: 0; -} diff --git a/resources/sass/themes/_cosmic-void.scss b/resources/sass/themes/_cosmic-void.scss index 768e09626..28f9a4065 100644 --- a/resources/sass/themes/_cosmic-void.scss +++ b/resources/sass/themes/_cosmic-void.scss @@ -168,6 +168,8 @@ --meta-chip-value-hover-fg: #ccc; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #333; --meter-bg: #505050; diff --git a/resources/sass/themes/_galactic.scss b/resources/sass/themes/_galactic.scss index f54b909af..0ffea7844 100644 --- a/resources/sass/themes/_galactic.scss +++ b/resources/sass/themes/_galactic.scss @@ -208,6 +208,8 @@ --meta-chip-value-hover-fg: #ccc; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #333; --meter-bg: #505050; diff --git a/resources/sass/themes/_light.scss b/resources/sass/themes/_light.scss index 204a891a4..033cc5b8e 100644 --- a/resources/sass/themes/_light.scss +++ b/resources/sass/themes/_light.scss @@ -178,6 +178,8 @@ --meta-chip-name-fg: #111; --meta-chip-value-fg: #333; --meta-chip-value-hover-fg: #000; + --meta-popup-bg: #d6d6d6; + --meta-popup-fg: #1a1a1a; --meter-fg: #d6d6d6; --meter-bg: #bbb; diff --git a/resources/sass/themes/_material-design-v3-amoled.scss b/resources/sass/themes/_material-design-v3-amoled.scss index a67552911..b12d157d3 100644 --- a/resources/sass/themes/_material-design-v3-amoled.scss +++ b/resources/sass/themes/_material-design-v3-amoled.scss @@ -176,6 +176,8 @@ --meta-chip-value-hover-fg: #ccc; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #2a292e; --meter-bg: #444; diff --git a/resources/sass/themes/_material-design-v3-dark.scss b/resources/sass/themes/_material-design-v3-dark.scss index 67244685d..4d3e957ef 100644 --- a/resources/sass/themes/_material-design-v3-dark.scss +++ b/resources/sass/themes/_material-design-v3-dark.scss @@ -179,6 +179,8 @@ --meta-chip-value-hover-fg: #ccc; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #2a292e; --meter-bg: #444; diff --git a/resources/sass/themes/_material-design-v3-light.scss b/resources/sass/themes/_material-design-v3-light.scss index ce6f66acb..050be5c43 100644 --- a/resources/sass/themes/_material-design-v3-light.scss +++ b/resources/sass/themes/_material-design-v3-light.scss @@ -178,6 +178,8 @@ --meta-chip-name-fg: #111; --meta-chip-value-fg: #333; --meta-chip-value-hover-fg: #000; + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #fff; --meter-bg: #e8e8e8; diff --git a/resources/sass/themes/_material-design-v3-navy.scss b/resources/sass/themes/_material-design-v3-navy.scss index 65244caf1..5699e50f3 100644 --- a/resources/sass/themes/_material-design-v3-navy.scss +++ b/resources/sass/themes/_material-design-v3-navy.scss @@ -180,6 +180,8 @@ --meta-chip-value-hover-fg: #fff; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #2260be; --meter-bg: #0f111a; diff --git a/resources/sass/themes/_nord.scss b/resources/sass/themes/_nord.scss index e04d80537..f3ebb1b7c 100644 --- a/resources/sass/themes/_nord.scss +++ b/resources/sass/themes/_nord.scss @@ -195,6 +195,8 @@ --meta-chip-value-hover-fg: #d8dee9; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #8fbcbb; --meter-bg: #5e81ac; diff --git a/resources/sass/themes/_revel.scss b/resources/sass/themes/_revel.scss index 927c7c364..d34ed101d 100644 --- a/resources/sass/themes/_revel.scss +++ b/resources/sass/themes/_revel.scss @@ -201,6 +201,8 @@ --meta-chip-value-hover-fg: #ccc; --meta-chip-backdrop-filter-hover: brightness(2) blur(10px); --meta-chip-hover-bg: rgba(255, 255, 255, 0.1); + --meta-popup-bg: #1a1a1a; + --meta-popup-fg: #7f8c8d; --meter-fg: #333; --meter-bg: #505050; diff --git a/resources/views/blocks/chat.blade.php b/resources/views/blocks/chat.blade.php index 9b8d271ea..f40a7b880 100644 --- a/resources/views/blocks/chat.blade.php +++ b/resources/views/blocks/chat.blade.php @@ -1,5 +1,5 @@ @php - $user = App\Models\User::with(['chatStatus', 'chatroom', 'group'])->find(auth()->id()); + $user = App\Models\User::with(['chatroom', 'group'])->find(auth()->id()); @endphp