diff --git a/app/Console/Commands/FindSizeMismatchedReleases.php b/app/Console/Commands/FindSizeMismatchedReleases.php index 7deeee01d..016829721 100644 --- a/app/Console/Commands/FindSizeMismatchedReleases.php +++ b/app/Console/Commands/FindSizeMismatchedReleases.php @@ -54,7 +54,7 @@ class FindSizeMismatchedReleases extends Command $query->orderBy($shouldRename ? 'releases.id' : 'diff_percent', $shouldRename ? 'asc' : 'desc'); if ($limit > 0) { - $query->limit($limit); + $query->limit((int) $limit); } $mismatches = $query->get(); @@ -107,20 +107,18 @@ class FindSizeMismatchedReleases extends Command { if (preg_match(ReleaseUpdateService::PREDB_REGEX, $this->stripDomainFromString($release->name), $matches)) { $newName = $matches[1]; - if ($newName) { - $nameFixingService->getUpdateService()->updateRelease( - release: $release, - name: $newName, - method: 'size-mismatch / season pack', - echo: true, - type: '', - nameStatus: true, - show: true, - preId: 0 - ); + $nameFixingService->getUpdateService()->updateRelease( + release: $release, + name: $newName, + method: 'size-mismatch / season pack', + echo: true, + type: '', + nameStatus: true, + show: true, + preId: 0 + ); - return $newName; - } + return $newName; } return null; diff --git a/app/Console/Commands/InstallNntmux.php b/app/Console/Commands/InstallNntmux.php index d11e4f40d..9a2f425b5 100644 --- a/app/Console/Commands/InstallNntmux.php +++ b/app/Console/Commands/InstallNntmux.php @@ -181,7 +181,7 @@ class InstallNntmux extends Command } /** - * @return array|bool + * @return bool * * @throws \Exception * @throws \RuntimeException diff --git a/app/Console/Commands/ManageRoleStacking.php b/app/Console/Commands/ManageRoleStacking.php index 973f46173..495ae9722 100644 --- a/app/Console/Commands/ManageRoleStacking.php +++ b/app/Console/Commands/ManageRoleStacking.php @@ -75,6 +75,7 @@ class ManageRoleStacking extends Command $rows = []; foreach ($users as $user) { + /** @var Role|null $currentRole */ $currentRole = $user->roles->first(); $pendingRole = $user->getPendingRole(); $activationDate = Carbon::parse($user->pending_role_start_date); @@ -252,6 +253,7 @@ class ManageRoleStacking extends Command foreach ($users as $user) { $pendingRole = $user->getPendingRole(); + /** @var Role|null $oldRole */ $oldRole = $user->roles->first(); try { diff --git a/app/Console/Commands/NntmuxOffsetPopulate.php b/app/Console/Commands/NntmuxOffsetPopulate.php index 70e063900..45fef61e4 100644 --- a/app/Console/Commands/NntmuxOffsetPopulate.php +++ b/app/Console/Commands/NntmuxOffsetPopulate.php @@ -2,6 +2,7 @@ namespace App\Console\Commands; +use App\Facades\Elasticsearch; use App\Facades\Search; use App\Models\Predb; use App\Models\Release; @@ -76,7 +77,7 @@ class NntmuxOffsetPopulate extends Command return Command::SUCCESS; } - $parallelProcesses = $this->option('parallel'); + $parallelProcesses = (int) $this->option('parallel'); $recordsPerProcess = ceil($total / $parallelProcesses); $this->info(sprintf( diff --git a/app/Console/Commands/NntmuxOffsetWorker.php b/app/Console/Commands/NntmuxOffsetWorker.php index cc27241ea..cfb743e5f 100644 --- a/app/Console/Commands/NntmuxOffsetWorker.php +++ b/app/Console/Commands/NntmuxOffsetWorker.php @@ -2,6 +2,7 @@ namespace App\Console\Commands; +use App\Facades\Elasticsearch; use App\Facades\Search; use App\Models\Predb; use App\Models\Release; @@ -42,7 +43,7 @@ class NntmuxOffsetWorker extends Command */ public function handle(): int { - $workerId = $this->option('worker-id'); + $workerId = (int) $this->option('worker-id'); $offset = (int) $this->option('offset'); $limit = (int) $this->option('limit'); diff --git a/app/Console/Commands/NntmuxPopulateSearchIndexes.php b/app/Console/Commands/NntmuxPopulateSearchIndexes.php index ba70ae53b..e16892e61 100644 --- a/app/Console/Commands/NntmuxPopulateSearchIndexes.php +++ b/app/Console/Commands/NntmuxPopulateSearchIndexes.php @@ -47,6 +47,7 @@ class NntmuxPopulateSearchIndexes extends Command private const DEFAULT_CHUNK_SIZE = 50000; + /** @phpstan-ignore classConstant.unused */ private const DEFAULT_PARALLEL_PROCESSES = 4; private const DEFAULT_BATCH_SIZE = 5000; diff --git a/app/Console/Commands/NntmuxResetPostProcessing.php b/app/Console/Commands/NntmuxResetPostProcessing.php index b0037faf5..84eee74bc 100644 --- a/app/Console/Commands/NntmuxResetPostProcessing.php +++ b/app/Console/Commands/NntmuxResetPostProcessing.php @@ -116,7 +116,7 @@ class NntmuxResetPostProcessing extends Command foreach ($normalized as $adjusted) { // skip 'all' since handled above - if ($adjusted === 'all') { + if ($adjusted === 'all') { // @phpstan-ignore identical.alwaysFalse continue; } $this->info('Resetting postprocessing for '.$adjusted.' category'); diff --git a/app/Console/Commands/RecategorizeReleases.php b/app/Console/Commands/RecategorizeReleases.php index 6f5345026..2a4136705 100644 --- a/app/Console/Commands/RecategorizeReleases.php +++ b/app/Console/Commands/RecategorizeReleases.php @@ -39,7 +39,7 @@ class RecategorizeReleases extends Command if ($this->option('misc')) { $countQuery->whereIn('categories_id', Category::OTHERS_GROUP); } elseif ($this->option('all')) { - if ($this->confirm('This will reset categorization on all releases and re-categorize them all from scratch. Are you sure? (y/n)', 'n')) { + if ($this->confirm('This will reset categorization on all releases and re-categorize them all from scratch. Are you sure? (y/n)', false)) { Release::query()->where('iscategorized', 1)->update([ 'iscategorized' => 0, ]); @@ -91,14 +91,15 @@ class RecategorizeReleases extends Command 'categories_id' => $catId['categories_id'], ]); + /** @var Category|null $newCatName */ $newCatName = Category::query()->where('id', $catId['categories_id'])->first(); $this->line(''); $this->output->writeln('ID : '.$result->id); $this->output->writeln('Release : '.$result->searchname); - $this->output->writeln('Group : '.$result->group->name); - $oldCategoryTitle = $result->category?->parent ? ($result->category->parent->title.' -> '.$result->category->title) : ($result->category?->title ?? 'N/A'); - $newCategoryTitle = $newCatName?->parent ? ($newCatName->parent->title.' -> '.$newCatName->title) : ($newCatName?->title ?? 'N/A'); + $this->output->writeln('Group : '.$result->group->name); // @phpstan-ignore property.notFound + $oldCategoryTitle = $result->category?->parent ? ($result->category->parent->title.' -> '.$result->category->title) : ($result->category?->title ?? 'N/A'); // @phpstan-ignore property.notFound, property.notFound, property.notFound, nullsafe.neverNull + $newCategoryTitle = $newCatName?->parent ? ($newCatName->parent->title.' -> '.$newCatName->title) : ($newCatName?->title ?? 'N/A'); // @phpstan-ignore nullsafe.neverNull $this->output->writeln('Category : '.$oldCategoryTitle.' '.$newCategoryTitle.''); $this->line(''); } diff --git a/app/Console/Commands/RefreshAnimeData.php b/app/Console/Commands/RefreshAnimeData.php index 2733fdd3d..3acc078da 100644 --- a/app/Console/Commands/RefreshAnimeData.php +++ b/app/Console/Commands/RefreshAnimeData.php @@ -172,7 +172,7 @@ class RefreshAnimeData extends Command $this->enforceRateLimit(); $searchResults = $populateAniList->searchAnime($cleanTitle, 1); - if (! $searchResults || empty($searchResults)) { + if (! $searchResults) { // Try with spaces replaced for broader matching $altTitle = preg_replace('/\s+/', ' ', $cleanTitle); if ($altTitle !== $cleanTitle) { @@ -181,7 +181,7 @@ class RefreshAnimeData extends Command } } - if (! $searchResults || empty($searchResults)) { + if (! $searchResults) { $notFound++; $failedSearchnames[] = [ 'searchname' => $searchname, diff --git a/app/Console/Commands/ReleasesFixNamesGroup.php b/app/Console/Commands/ReleasesFixNamesGroup.php index 16a80c669..80a9dd105 100644 --- a/app/Console/Commands/ReleasesFixNamesGroup.php +++ b/app/Console/Commands/ReleasesFixNamesGroup.php @@ -187,13 +187,11 @@ class ReleasesFixNamesGroup extends Command $this->nameFixingService->reset(); $fileNames = explode('|', $release->filestring); - if (is_array($fileNames)) { - $releaseFile = $release; - foreach ($fileNames as $fileName) { - if (! $this->nameFixingService->getUpdateService()->matched) { - $releaseFile->textstring = $fileName; - $this->nameFixingService->checkName($releaseFile, true, 'Filenames, ', true, true); - } + $releaseFile = $release; + foreach ($fileNames as $fileName) { + if (! $this->nameFixingService->getUpdateService()->matched) { + $releaseFile->textstring = $fileName; + $this->nameFixingService->checkName($releaseFile, true, 'Filenames, ', true, true); } } } diff --git a/app/Console/Commands/UpdateNNTmuxDB.php b/app/Console/Commands/UpdateNNTmuxDB.php index 73b6326d6..a966335c7 100644 --- a/app/Console/Commands/UpdateNNTmuxDB.php +++ b/app/Console/Commands/UpdateNNTmuxDB.php @@ -192,6 +192,8 @@ class UpdateNNTmuxDB extends Command /** * Optimize database tables with proper driver detection + * + * @phpstan-ignore method.unused */ private function optimizeDatabase(string $dbType): void { diff --git a/app/Console/Commands/UpdatePostProcess.php b/app/Console/Commands/UpdatePostProcess.php index 3190e7a7f..764dd22ed 100644 --- a/app/Console/Commands/UpdatePostProcess.php +++ b/app/Console/Commands/UpdatePostProcess.php @@ -70,9 +70,9 @@ class UpdatePostProcess extends Command $nntp = self::VALID_TYPES[$type] ? $this->getNntp() : null; match ($type) { - 'all' => $this->postProcessService->processAll($nntp), + 'all' => $this->postProcessService->processAll($nntp ?? $this->getNntp()), 'amazon' => $this->processAmazon(), - 'nfo' => $this->postProcessService->processNfos($nntp), + 'nfo' => $this->postProcessService->processNfos($nntp ?? $this->getNntp()), 'movies' => $this->postProcessService->processMovies(), 'music' => $this->postProcessService->processMusic(), 'console' => $this->postProcessService->processConsoles(), @@ -82,7 +82,6 @@ class UpdatePostProcess extends Command 'tv' => $this->postProcessService->processTv(), 'xxx' => $this->postProcessService->processXXX(), 'additional' => $this->postProcessService->processAdditional(), - default => throw new \Exception("Unhandled type: {$type}"), }; return self::SUCCESS; diff --git a/app/Console/Commands/UpdateReleasesIndexSchema.php b/app/Console/Commands/UpdateReleasesIndexSchema.php index 5763feb97..cde6ecc5c 100644 --- a/app/Console/Commands/UpdateReleasesIndexSchema.php +++ b/app/Console/Commands/UpdateReleasesIndexSchema.php @@ -510,7 +510,7 @@ class UpdateReleasesIndexSchema extends Command $this->client->table($indexName)->replaceDocument($document, $id); } else { // Document doesn't exist in index, we need full data from database - $release = Release::with(['movieinfo', 'video'])->find($id); + $release = Release::with(['video'])->find($id); if ($release) { Search::insertRelease([ 'id' => $release->id, diff --git a/app/Console/Commands/UpdateReleasesIndexSchemaES.php b/app/Console/Commands/UpdateReleasesIndexSchemaES.php index d56653157..be0fd2e57 100644 --- a/app/Console/Commands/UpdateReleasesIndexSchemaES.php +++ b/app/Console/Commands/UpdateReleasesIndexSchemaES.php @@ -4,7 +4,6 @@ namespace App\Console\Commands; use App\Facades\Elasticsearch; use App\Models\Release; -use Elasticsearch\Common\Exceptions\Missing404Exception; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -608,9 +607,6 @@ class UpdateReleasesIndexSchemaES extends Command || ($source['tvmaze'] ?? 0) > 0 || ($source['tvrage'] ?? 0) > 0; - } catch (Missing404Exception $e) { - // Document doesn't exist - return false; } catch (\Throwable $e) { // Other error, assume no media IDs return false; diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 13f48c331..d7eea48b4 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -10,7 +10,7 @@ class Handler extends ExceptionHandler /** * A list of the exception types that are not reported. * - * @var array + * @var array> */ protected $dontReport = [ // @@ -19,7 +19,7 @@ class Handler extends ExceptionHandler /** * A list of the inputs that are never flashed for validation exceptions. * - * @var array + * @var array */ protected $dontFlash = [ 'password', diff --git a/app/Extensions/helper/helpers.php b/app/Extensions/helper/helpers.php index ce72fb470..01432a0ce 100644 --- a/app/Extensions/helper/helpers.php +++ b/app/Extensions/helper/helpers.php @@ -81,7 +81,7 @@ if (! function_exists('getRawHtml')) { $cookieJar = new CookieJar; $client = new Client(['headers' => ['User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246']]); if ($cookie !== false && $cookie !== null && $cookie !== '') { - $cookie = $cookieJar->setCookie(SetCookie::fromString($cookie)); + $cookie = $cookieJar->setCookie(SetCookie::fromString((string) $cookie)); $client = new Client(['cookies' => $cookie, 'headers' => ['User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246']]); } try { @@ -209,9 +209,9 @@ if (! function_exists('human_filesize')) { function human_filesize($bytes, $decimals = 0): string { $size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - $factor = floor((\strlen($bytes) - 1) / 3); + $factor = (int) floor((\strlen((string) $bytes) - 1) / 3); - return round(sprintf("%.{$decimals}f", $bytes / (1024 ** $factor)), $decimals).@$size[$factor]; + return round((float) sprintf("%.{$decimals}f", $bytes / (1024 ** $factor)), $decimals).@$size[$factor]; } } @@ -223,9 +223,9 @@ if (! function_exists('bcdechex')) { { $hex = ''; do { - $last = bcmod($dec, 16); - $hex = dechex($last).$hex; - $dec = bcdiv(bcsub($dec, $last), 16); + $last = bcmod($dec, '16'); + $hex = dechex((int) $last).$hex; + $dec = bcdiv(bcsub($dec, $last), '16'); } while ($dec > 0); return $hex; @@ -712,7 +712,7 @@ if (! function_exists('unzipGzipFile')) { function unzipGzipFile(string $filePath) { $string = ''; - $gzFile = @gzopen($filePath, 'rb', 0); + $gzFile = @gzopen($filePath, 'rb', false); if ($gzFile) { while (! gzeof($gzFile)) { $temp = gzread($gzFile, 1024); @@ -937,7 +937,7 @@ if (! function_exists('showApiError')) { "\n". '\n"; - return response($response)->header('Content-type', 'text/xml')->header('Content-Length', strlen($response))->header('X-NNTmux', 'API ERROR ['.$errorCode.'] '.$errorText)->header('HTTP/1.1', $errorHeader); + return response($response)->header('Content-type', 'text/xml')->header('Content-Length', (string) strlen($response))->header('X-NNTmux', 'API ERROR ['.$errorCode.'] '.$errorText)->header('HTTP/1.1', $errorHeader); } } @@ -1219,7 +1219,7 @@ if (! function_exists('cli')) { public function percentString(int $cur, int $total): string { $percent = 100 * $cur / $total; - $formatString = '% '.\strlen($total).'d/%d (% 2d%%)'; + $formatString = '% '.\strlen((string) $total).'d/%d (% 2d%%)'; return sprintf($formatString, $cur, $total, $percent); } @@ -1228,7 +1228,7 @@ if (! function_exists('cli')) { { $percent1 = 100 * ($first - 1) / $total; $percent2 = 100 * $last / $total; - $formatString = '% '.\strlen($total).'d-% '.\strlen($total).'d/%d (% 2d%%-% 3d%%)'; + $formatString = '% '.\strlen((string) $total).'d-% '.\strlen((string) $total).'d/%d (% 2d%%-% 3d%%)'; return sprintf($formatString, $first, $last, $total, $percent1, $percent2); } diff --git a/app/Facades/Elasticsearch.php b/app/Facades/Elasticsearch.php index 260a87f13..be8d2bac9 100644 --- a/app/Facades/Elasticsearch.php +++ b/app/Facades/Elasticsearch.php @@ -7,12 +7,12 @@ use Illuminate\Support\Facades\Facade; /** * Elasticsearch Facade - provides static access to Elasticsearch client. * - * @method static array indices() + * @method static \Elasticsearch\Namespaces\IndicesNamespace indices() + * @method static \Elasticsearch\Namespaces\ClusterNamespace cluster() * @method static array search(array $params) * @method static array bulk(array $params) * @method static array get(array $params) * @method static array deleteByQuery(array $params) - * @method static array cluster() * * @see \Mailerlite\LaravelElasticsearch\Manager */ diff --git a/app/Http/Controllers/Admin/AdminBlacklistController.php b/app/Http/Controllers/Admin/AdminBlacklistController.php index 7c0332d31..3dfd70cdc 100644 --- a/app/Http/Controllers/Admin/AdminBlacklistController.php +++ b/app/Http/Controllers/Admin/AdminBlacklistController.php @@ -32,7 +32,7 @@ class AdminBlacklistController extends BasePageController } /** - * @return \Illuminate\Http\RedirectResponse|void + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\View|void * * @throws \Exception */ @@ -63,7 +63,6 @@ class AdminBlacklistController extends BasePageController } return redirect()->to('admin/binaryblacklist-list'); - break; case 'addtest': if ($request->has('regex') && $request->has('groupname')) { diff --git a/app/Http/Controllers/Admin/AdminCategoryController.php b/app/Http/Controllers/Admin/AdminCategoryController.php index b33c62ff8..78eb212b9 100644 --- a/app/Http/Controllers/Admin/AdminCategoryController.php +++ b/app/Http/Controllers/Admin/AdminCategoryController.php @@ -59,7 +59,7 @@ class AdminCategoryController extends BasePageController $category->root_categories_id = $request->input('root_categories_id') ?: null; $category->status = Category::STATUS_ACTIVE; // Always active $category->description = $request->input('description'); - $category->disablepreview = 0; // Always enabled + $category->disablepreview = false; // Always enabled $category->minsizetoformrelease = 0; $category->maxsizetoformrelease = 0; $category->save(); @@ -104,7 +104,7 @@ class AdminCategoryController extends BasePageController $category->root_categories_id = $request->input('root_categories_id') ?: null; $category->status = Category::STATUS_ACTIVE; // Always active $category->description = $request->input('description'); - $category->disablepreview = 0; // Always enabled + $category->disablepreview = false; // Always enabled $category->minsizetoformrelease = 0; $category->maxsizetoformrelease = 0; $category->save(); diff --git a/app/Http/Controllers/Admin/AdminCategoryRegexesController.php b/app/Http/Controllers/Admin/AdminCategoryRegexesController.php index 8047b5b62..8701a673a 100644 --- a/app/Http/Controllers/Admin/AdminCategoryRegexesController.php +++ b/app/Http/Controllers/Admin/AdminCategoryRegexesController.php @@ -107,6 +107,7 @@ class AdminCategoryRegexesController extends BasePageController $category_names = []; foreach ($categories_db as $category_db) { $category_ids[] = $category_db->id; + /** @phpstan-ignore property.notFound */ $category_names[] = $category_db->parent_title.' '.$category_db->title.': '.$category_db->id; } diff --git a/app/Http/Controllers/Admin/AdminGroupController.php b/app/Http/Controllers/Admin/AdminGroupController.php index 09c2a4406..b8390a4e2 100644 --- a/app/Http/Controllers/Admin/AdminGroupController.php +++ b/app/Http/Controllers/Admin/AdminGroupController.php @@ -77,7 +77,6 @@ class AdminGroupController extends BasePageController } return redirect()->to('admin/group-list'); - break; case 'view': default: diff --git a/app/Http/Controllers/Admin/AdminInvitationController.php b/app/Http/Controllers/Admin/AdminInvitationController.php index a1e92ddff..5c74910aa 100644 --- a/app/Http/Controllers/Admin/AdminInvitationController.php +++ b/app/Http/Controllers/Admin/AdminInvitationController.php @@ -172,7 +172,7 @@ class AdminInvitationController extends BasePageController public function cancel(Request $request): RedirectResponse { try { - $id = $request->route('id'); + $id = (int) $request->route('id'); $this->invitationService->cancelInvitation($id); return redirect()->back()->with('success', 'Invitation cancelled successfully'); @@ -187,7 +187,7 @@ class AdminInvitationController extends BasePageController public function resend(Request $request): RedirectResponse { try { - $id = $request->route('id'); + $id = (int) $request->route('id'); $this->invitationService->resendInvitation($id); return redirect()->back()->with('success', 'Invitation resent successfully'); diff --git a/app/Http/Controllers/Admin/AdminMusicController.php b/app/Http/Controllers/Admin/AdminMusicController.php index 340bb955e..bd376980c 100644 --- a/app/Http/Controllers/Admin/AdminMusicController.php +++ b/app/Http/Controllers/Admin/AdminMusicController.php @@ -21,7 +21,7 @@ class AdminMusicController extends BasePageController $search = $request->input('musicsearch', ''); if (! empty($search)) { - $musicList = getRange('musicinfo', $search); + $musicList = getRange('musicinfo'); $lastSearch = $search; } else { $musicList = getRange('musicinfo'); diff --git a/app/Http/Controllers/Admin/AdminReleaseReportController.php b/app/Http/Controllers/Admin/AdminReleaseReportController.php index 50d8f7914..0190c6835 100644 --- a/app/Http/Controllers/Admin/AdminReleaseReportController.php +++ b/app/Http/Controllers/Admin/AdminReleaseReportController.php @@ -61,7 +61,9 @@ class AdminReleaseReportController extends BasePageController $report = ReleaseReport::with('release')->findOrFail($id); if ($report->release) { - $releaseName = $report->release->searchname; + /** @var \App\Models\Release $release */ + $release = $report->release; + $releaseName = $release->searchname; $releaseId = $report->releases_id; // Delete the release diff --git a/app/Http/Controllers/Admin/AdminReleasesController.php b/app/Http/Controllers/Admin/AdminReleasesController.php index c70b6d1da..55717af86 100644 --- a/app/Http/Controllers/Admin/AdminReleasesController.php +++ b/app/Http/Controllers/Admin/AdminReleasesController.php @@ -69,7 +69,6 @@ class AdminReleasesController extends BasePageController $release = Release::getByGuid($request->input('guid')); return redirect('details/'.$release['guid'])->with('success', 'Release updated successfully'); - break; case 'view': default: diff --git a/app/Http/Controllers/Admin/AdminUserController.php b/app/Http/Controllers/Admin/AdminUserController.php index 4b1a115ab..f0b0952e5 100644 --- a/app/Http/Controllers/Admin/AdminUserController.php +++ b/app/Http/Controllers/Admin/AdminUserController.php @@ -57,7 +57,7 @@ class AdminUserController extends BasePageController $variables['created_to'] ); - $results = $this->paginate($result ?? [], User::getCount($variables['role'], $variables['username'], $variables['host'], $variables['email'], $variables['created_from'], $variables['created_to']) ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); + $results = $this->paginate($result, User::getCount($variables['role'], $variables['username'], $variables['host'], $variables['email'], $variables['created_from'], $variables['created_to']), config('nntmux.items_per_page'), $page, $request->url(), $request->query()); // Note: API request counts are already included via the getRange query when $apiRequests = true // Country lookups and additional counts removed to improve performance on large datasets diff --git a/app/Http/Controllers/AdultController.php b/app/Http/Controllers/AdultController.php index c219c348e..2be007d7f 100644 --- a/app/Http/Controllers/AdultController.php +++ b/app/Http/Controllers/AdultController.php @@ -49,7 +49,7 @@ class AdultController extends BasePageController $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; $offset = ($page - 1) * config('nntmux.items_per_page'); $rslt = $this->xxxBrowseService->getXXXRange($page, $catarray, $offset, config('nntmux.items_per_page'), $orderby, -1, $this->userdata['categoryexclusions']); - $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); + $results = $this->paginate($rslt, $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); $title = ($request->has('title') && ! empty($request->input('title'))) ? stripslashes($request->input('title')) : ''; diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index 29690e5da..3457e916a 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -17,6 +17,7 @@ use App\Services\Releases\ReleaseSearchService; use Illuminate\Contracts\Foundation\Application; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\Http\Response; use Illuminate\Routing\Redirector; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\File; @@ -42,7 +43,7 @@ class ApiController extends BasePageController } /** - * @return Application|\Illuminate\Foundation\Application|RedirectResponse|Redirector|StreamedResponse|void + * @return Application|\Illuminate\Foundation\Application|RedirectResponse|Redirector|Response|StreamedResponse|void * * @throws \Throwable */ @@ -97,7 +98,7 @@ class ApiController extends BasePageController // Page is accessible only by the apikey - if ($function !== 'c' && $function !== 'r') { + if ($function !== 'c' && $function !== 'r') { // @phpstan-ignore notIdentical.alwaysTrue if ($request->missing('apikey') || ($request->has('apikey') && empty($request->input('apikey')))) { return showApiError(200, 'Missing parameter (apikey)'); } @@ -314,7 +315,7 @@ class ApiController extends BasePageController UserRequest::addApiRequest($apiKey, $request->getRequestUri()); $rel = Release::query()->where('guid', $request->input('id'))->first(['id', 'searchname']); - if ($rel && $rel->isNotEmpty()) { + if ($rel) { $data = ReleaseNfo::getReleaseNfo($rel->id); if (! empty($data)) { if ($request->has('o') && $request->input('o') === 'file') { @@ -392,6 +393,8 @@ class ApiController extends BasePageController } /** + * @return Response|void + * * @throws \Exception */ public function output($data, array $params, bool $xml, int $offset, string $type = '') @@ -464,7 +467,7 @@ class ApiController extends BasePageController } /** - * @return Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Foundation\Application|\Illuminate\Http\Response|int + * @return Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Foundation\Application|Response|int */ public function maxAge(Request $request) { @@ -547,6 +550,8 @@ class ApiController extends BasePageController /** * Check if a parameter is empty. + * + * @return Response|void */ public function verifyEmptyParameter(Request $request, string $parameter) { diff --git a/app/Http/Controllers/Api/XML_Response.php b/app/Http/Controllers/Api/XML_Response.php index 61b7b7365..5d701695a 100644 --- a/app/Http/Controllers/Api/XML_Response.php +++ b/app/Http/Controllers/Api/XML_Response.php @@ -101,25 +101,19 @@ class XML_Response public function returnXML(): bool|string { - if ($this->xml) { - switch ($this->type) { - case 'caps': - return $this->returnCaps(); - break; - case 'api': - $this->namespace = 'newznab'; + switch ($this->type) { + case 'caps': + return $this->returnCaps(); + case 'api': + $this->namespace = 'newznab'; - return $this->returnApiXml(); - break; - case 'rss': - $this->namespace = 'nntmux'; + return $this->returnApiXml(); + case 'rss': + $this->namespace = 'nntmux'; - return $this->returnApiRssXml(); - break; - case 'reg': - return $this->returnReg(); - break; - } + return $this->returnApiRssXml(); + case 'reg': + return $this->returnReg(); } return false; @@ -451,7 +445,7 @@ class XML_Response $this->writeZedAttr('anidbid', $this->release->anidbid); } if (isset($this->release->predb_id) && $this->release->predb_id > 0) { - $this->writeZedAttr('prematch', 1); + $this->writeZedAttr('prematch', '1'); } if (isset($this->release->nfostatus) && (int) $this->release->nfostatus === 1) { $this->writeZedAttr( diff --git a/app/Http/Controllers/ApiHelpController.php b/app/Http/Controllers/ApiHelpController.php index 90a8cddfd..e5ff97324 100644 --- a/app/Http/Controllers/ApiHelpController.php +++ b/app/Http/Controllers/ApiHelpController.php @@ -3,14 +3,13 @@ namespace App\Http\Controllers; use App\Models\Category; -use Illuminate\Http\Request; use Illuminate\View\View; class ApiHelpController extends BasePageController { - public function __construct(Request $request) + public function __construct() { - parent::__construct($request); + parent::__construct(); } /** diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 90866a824..a5ea40cc4 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -12,8 +12,8 @@ use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; -use Illuminate\Support\Facades\Password as PasswordFacade; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; use Illuminate\Validation\Rules\Password; use Illuminate\Validation\ValidationException; use Jrean\UserVerification\Traits\VerifiesUsers; @@ -62,7 +62,7 @@ class RegisterController extends Controller 'roles_id' => $data['roles_id'], 'notes' => $data['notes'], 'invites' => $data['defaultinvites'], - 'api_token' => md5(PasswordFacade::getRepository()->createNewToken()), + 'api_token' => md5(Str::random(40)), ]); $role = Role::query()->where('id', '=', $data['roles_id'])->first(); @@ -165,10 +165,6 @@ class RegisterController extends Controller // Get the default user role. $userDefault = Role::query()->where('isdefault', '=', 1)->first(); - if (! empty($error)) { - return $this->showRegistrationForm($request, $error); - } - // Check invitation validity using custom system $invitationValid = $this->isInvitationValid($inviteCode, $email); $registrationOpen = Settings::settingValue('registerstatus') === Settings::REGISTER_STATUS_OPEN; diff --git a/app/Http/Controllers/BasePageController.php b/app/Http/Controllers/BasePageController.php index 89c6ee07a..ffbd6d5d9 100644 --- a/app/Http/Controllers/BasePageController.php +++ b/app/Http/Controllers/BasePageController.php @@ -101,7 +101,7 @@ class BasePageController extends Controller /** * Show 404 page. * - * @param null $message + * @param string|null $message */ public function show404($message = null): View { diff --git a/app/Http/Controllers/BooksController.php b/app/Http/Controllers/BooksController.php index f1443c12f..83a97ff75 100644 --- a/app/Http/Controllers/BooksController.php +++ b/app/Http/Controllers/BooksController.php @@ -44,8 +44,8 @@ class BooksController extends BasePageController $books = []; $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; $offset = ($page - 1) * config('nntmux.items_per_cover_page'); - $rslt = $bookService->getBookRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, $this->userdata->categoryexclusions); - $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); + $rslt = $bookService->getBookRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, (array) $this->userdata->categoryexclusions); + $results = $this->paginate($rslt, $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); $maxwords = 50; foreach ($results as $result) { if (! empty($result->overview)) { diff --git a/app/Http/Controllers/BrowseController.php b/app/Http/Controllers/BrowseController.php index 532d1fdea..88161d31d 100644 --- a/app/Http/Controllers/BrowseController.php +++ b/app/Http/Controllers/BrowseController.php @@ -27,7 +27,7 @@ class BrowseController extends BasePageController $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; $offset = ($page - 1) * config('nntmux.items_per_page'); - $rslt = $this->releaseBrowseService->getBrowseRange($page, [-1], $offset, config('nntmux.items_per_page'), $orderBy, -1, $this->userdata->categoryexclusions, -1); + $rslt = $this->releaseBrowseService->getBrowseRange($page, [-1], $offset, config('nntmux.items_per_page'), $orderBy, -1, (array) $this->userdata->categoryexclusions, -1); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); // Build order by URLs @@ -75,14 +75,14 @@ class BrowseController extends BasePageController $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; $offset = ($page - 1) * config('nntmux.items_per_page'); - $rslt = $this->releaseBrowseService->getBrowseRange($page, $catarray, $offset, config('nntmux.items_per_page'), $orderBy, -1, $this->userdata->categoryexclusions, $grp); + $rslt = $this->releaseBrowseService->getBrowseRange($page, $catarray, $offset, config('nntmux.items_per_page'), $orderBy, -1, (array) $this->userdata->categoryexclusions, $grp); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); $covgroup = ''; $shows = false; - if ($category === -1 && $grp === -1) { + if ($category === -1) { $catname = 'All'; - } elseif ($category !== -1 && $grp === -1) { + } else { $catname = $id; // Determine the root category ID - either from the category's root_categories_id @@ -118,8 +118,6 @@ class BrowseController extends BasePageController } elseif ($rootCategoryId === Category::TV_ROOT) { $shows = true; } - } else { - $catname = $grp; } // Build order by URLs @@ -166,7 +164,7 @@ class BrowseController extends BasePageController $group = $request->input('g'); $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; $offset = ($page - 1) * config('nntmux.items_per_page'); - $rslt = $this->releaseBrowseService->getBrowseRange($page, [-1], $offset, config('nntmux.items_per_page'), '', -1, $this->userdata->categoryexclusions, $group); + $rslt = $this->releaseBrowseService->getBrowseRange($page, [-1], $offset, config('nntmux.items_per_page'), '', -1, (array) $this->userdata->categoryexclusions, $group); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); $this->viewData = array_merge($this->viewData, [ diff --git a/app/Http/Controllers/CartController.php b/app/Http/Controllers/CartController.php index 3a257a2bf..b9a606b06 100644 --- a/app/Http/Controllers/CartController.php +++ b/app/Http/Controllers/CartController.php @@ -16,6 +16,7 @@ class CartController extends BasePageController public function index() { $results = UsersRelease::getCart(Auth::id()) + /** @phpstan-ignore property.notFound */ ->filter(fn ($item) => $item->release !== null); $this->viewData = array_merge($this->viewData, [ diff --git a/app/Http/Controllers/ConsoleController.php b/app/Http/Controllers/ConsoleController.php index 95e050100..690f933e3 100644 --- a/app/Http/Controllers/ConsoleController.php +++ b/app/Http/Controllers/ConsoleController.php @@ -55,8 +55,8 @@ class ConsoleController extends BasePageController $offset = ($page - 1) * config('nntmux.items_per_cover_page'); $consoles = []; - $rslt = $this->consoleService->getConsoleRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, $this->userdata->categoryexclusions); - $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); + $rslt = $this->consoleService->getConsoleRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, (array) $this->userdata->categoryexclusions); + $results = $this->paginate($rslt, $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); $maxwords = 50; foreach ($results as $result) { @@ -76,6 +76,7 @@ class ConsoleController extends BasePageController $genres = $gen->getGenres((string) GenreService::CONSOLE_TYPE, true); $tmpgnr = []; foreach ($genres as $gn) { + /** @var \App\Models\Genre $gn */ $tmpgnr[$gn->id] = $gn->title; } $genre = ($request->has('genre') && array_key_exists($request->input('genre'), $tmpgnr)) ? $request->input('genre') : ''; diff --git a/app/Http/Controllers/ContentController.php b/app/Http/Controllers/ContentController.php index 7d7f9996d..a72e5c079 100644 --- a/app/Http/Controllers/ContentController.php +++ b/app/Http/Controllers/ContentController.php @@ -56,9 +56,9 @@ class ContentController extends BasePageController $content = $this->getFrontPageContent()->all(); $index = $this->getIndexContent(); $isFront = true; - $meta_title = $index?->title ?? 'Contents page'; - $meta_keywords = $index?->metakeywords ?? 'contents'; - $meta_description = $index?->metadescription ?? 'This is the contents page.'; + $meta_title = $index->title ?? 'Contents page'; + $meta_keywords = $index->metakeywords ?? 'contents'; + $meta_description = $index->metadescription ?? 'This is the contents page.'; } if (empty($content)) { diff --git a/app/Http/Controllers/DetailsController.php b/app/Http/Controllers/DetailsController.php index 506095b12..e4533645c 100644 --- a/app/Http/Controllers/DetailsController.php +++ b/app/Http/Controllers/DetailsController.php @@ -50,157 +50,154 @@ class DetailsController extends BasePageController public function show(Request $request, string $guid) { - if ($guid !== null) { - $data = Release::getByGuid($guid); - $releaseRegex = ''; - if (! empty($data)) { - $releaseRegex = ReleaseRegex::query()->where('releases_id', '=', $data['id'])->first(); - } - - if (! $data) { - return redirect()->back(); - } - - if ($this->isPostBack($request)) { - ReleaseComment::addComment($data['id'], $data['gid'], $request->input('txtAddComment'), $this->userdata->id, $request->ip()); - - return redirect()->route('details', ['guid' => $guid])->with('success', 'Comment posted successfully!'); - } - - $nfoData = ReleaseNfo::getReleaseNfo($data['id']); - $nfo = $nfoData ? $nfoData->nfo : null; - $reVideo = $this->releaseExtraService->getVideo($data['id']); - $reAudio = $this->releaseExtraService->getAudio($data['id']); - $reSubs = $this->releaseExtraService->getSubs($data['id']); - $comments = ReleaseComment::getComments($data['id']); - $similars = $this->releaseSearchService->searchSimilar($data['id'], $data['searchname'], $this->userdata->categoryexclusions); - $failed = DnzbFailure::getFailedCount($data['id']); - $reportData = ReleaseReport::where('releases_id', $data['id']) - ->whereIn('status', ['pending', 'reviewed', 'resolved']) - ->get(); - $reportCount = $reportData->count(); - $reportReasons = ReleaseReport::reasonKeysToLabels($reportData->pluck('reason')->unique()->implode(', ')); - $downloadedBy = UserDownload::query()->with('user')->where('releases_id', $data['id'])->get(['users_id']); - - $showInfo = ''; - if ($data['videos_id'] > 0) { - $showInfo = Video::getByVideoID($data['videos_id']); - } - - $mov = ''; - if ($data['imdbid'] !== '' && $data['imdbid'] !== 0000000) { - $mov = $this->movieService->getMovieInfo($data['imdbid']); - if (! empty($mov['title'])) { - $mov['title'] = str_replace(['/', '\\'], '', $mov['title']); - $mov['actors'] = makeFieldLinks($mov, 'actors', 'movies'); - $mov['genre'] = makeFieldLinks($mov, 'genre', 'movies'); - $mov['director'] = makeFieldLinks($mov, 'director', 'movies'); - if (Settings::settingValue('trailers_display')) { - $trailer = empty($mov['trailer']) || $mov['trailer'] === '' ? $this->movieService->getTrailer($data['imdbid']) : $mov['trailer']; - if ($trailer) { - $mov['trailer'] = sprintf('', Settings::settingValue('trailers_size_x'), Settings::settingValue('trailers_size_y'), $trailer); - } - } - } - } - - $xxx = ''; - if ($data['xxxinfo_id'] !== '' && $data['xxxinfo_id'] !== 0) { - $xxx = XxxInfo::getXXXInfo($data['xxxinfo_id']); - - if (isset($xxx['trailers'])) { - $xxx['trailers'] = $this->xxxBrowseService->insertSwf($xxx['classused'], $xxx['trailers']); - } - - if ($xxx && isset($xxx['title'])) { - $xxx['title'] = str_replace(['/', '\\'], '', $xxx['title']); - $xxx['actors'] = makeFieldLinks($xxx, 'actors', 'xxx'); - $xxx['genre'] = makeFieldLinks($xxx, 'genre', 'xxx'); - $xxx['director'] = makeFieldLinks($xxx, 'director', 'xxx'); - } else { - $xxx = false; - } - } - - $game = ''; - if (! empty($data['gamesinfo_id'])) { - $game = (new GamesService)->getGamesInfoById($data['gamesinfo_id']); - } - - $mus = ''; - if (! empty($data['musicinfo_id'])) { - $mus = (new MusicService)->getMusicInfo($data['musicinfo_id']); - } - - $book = ''; - if (! empty($data['bookinfo_id'])) { - $book = (new BookService)->getBookInfo($data['bookinfo_id']); - } - - $con = ''; - if (! empty($data['consoleinfo_id'])) { - $con = (new ConsoleService)->getConsoleInfo($data['consoleinfo_id']); - } - - $AniDBAPIArray = ''; - if ($data['anidbid'] > 0) { - $AniDBAPIArray = (new AnidbService)->getAnimeInfo($data['anidbid']); - - // If we have anilist_id but missing details, fetch from AniList - if ($AniDBAPIArray && ! empty($AniDBAPIArray->anilist_id)) { - $anilistId = is_object($AniDBAPIArray) ? $AniDBAPIArray->anilist_id : ($AniDBAPIArray['anilist_id'] ?? null); - if ($anilistId && (empty($AniDBAPIArray->country) && empty($AniDBAPIArray->media_type))) { - // Fetch fresh data from AniList if country/media_type is missing - try { - $palist = new \App\Services\PopulateAniListService; - $palist->populateTable('info', $anilistId); - // Refresh the data - $AniDBAPIArray = (new AnidbService)->getAnimeInfo($data['anidbid']); - } catch (\Exception $e) { - // Silently fail, use existing data - } - } - } - } - - $pre = Predb::getForRelease($data['predb_id']); - - $releasefiles = ReleaseFile::getReleaseFiles($data['id']); - - $this->viewData = array_merge($this->viewData, [ - 'releasefiles' => $releasefiles, - 'release' => $data, - 'reVideo' => $reVideo, - 'reAudio' => $reAudio, - 'reSubs' => $reSubs, - 'nfo' => $nfo, - 'show' => $showInfo, - 'movie' => $mov, - 'xxx' => $xxx, - 'anidb' => $AniDBAPIArray, - 'music' => $mus, - 'con' => $con, - 'game' => $game, - 'book' => $book, - 'predb' => $pre, - 'comments' => $comments, - 'files' => $releasefiles, - 'searchname' => getSimilarName($data['searchname']), - 'similars' => $similars !== false ? $similars : [], - 'privateprofiles' => config('nntmux_settings.private_profiles'), - 'failed' => $failed, - 'reportCount' => $reportCount, - 'reportReasons' => $reportReasons, - 'regex' => $releaseRegex, - 'downloadedby' => $downloadedBy, - 'meta_title' => 'View NZB', - 'meta_keywords' => 'view,nzb,description,details', - 'meta_description' => 'View NZB for '.$data['searchname'], - ]); - - return view('details.index', $this->viewData); + $data = Release::getByGuid($guid); + $releaseRegex = ''; + if (! empty($data)) { + $releaseRegex = ReleaseRegex::query()->where('releases_id', '=', $data['id'])->first(); } - return redirect()->back()->with('error', 'Release not found'); + if (! $data) { + return redirect()->back(); + } + + if ($this->isPostBack($request)) { + ReleaseComment::addComment($data['id'], $data['gid'], $request->input('txtAddComment'), $this->userdata->id, $request->ip()); + + return redirect()->route('details', ['guid' => $guid])->with('success', 'Comment posted successfully!'); + } + + $nfoData = ReleaseNfo::getReleaseNfo($data['id']); + /** @var \App\Models\ReleaseNfo|null $nfoData */ + $nfo = $nfoData ? $nfoData->nfo : null; + $reVideo = $this->releaseExtraService->getVideo($data['id']); + $reAudio = $this->releaseExtraService->getAudio($data['id']); + $reSubs = $this->releaseExtraService->getSubs($data['id']); + $comments = ReleaseComment::getComments($data['id']); + $similars = $this->releaseSearchService->searchSimilar($data['id'], $data['searchname'], (array) $this->userdata->categoryexclusions); + $failed = DnzbFailure::getFailedCount($data['id']); + $reportData = ReleaseReport::where('releases_id', $data['id']) + ->whereIn('status', ['pending', 'reviewed', 'resolved']) + ->get(); + $reportCount = $reportData->count(); + $reportReasons = ReleaseReport::reasonKeysToLabels($reportData->pluck('reason')->unique()->implode(', ')); + $downloadedBy = UserDownload::query()->with('user')->where('releases_id', $data['id'])->get(['users_id']); + + $showInfo = ''; + if ($data['videos_id'] > 0) { + $showInfo = Video::getByVideoID($data['videos_id']); + } + + $mov = ''; + if ($data['imdbid'] !== '' && $data['imdbid'] !== 0000000) { + $mov = $this->movieService->getMovieInfo($data['imdbid']); + if (! empty($mov['title'])) { + $mov['title'] = str_replace(['/', '\\'], '', $mov['title']); + $mov['actors'] = makeFieldLinks($mov, 'actors', 'movies'); + $mov['genre'] = makeFieldLinks($mov, 'genre', 'movies'); + $mov['director'] = makeFieldLinks($mov, 'director', 'movies'); + if (Settings::settingValue('trailers_display')) { + $trailer = empty($mov['trailer']) ? $this->movieService->getTrailer($data['imdbid']) : $mov['trailer']; + if ($trailer) { + $mov['trailer'] = sprintf('', Settings::settingValue('trailers_size_x'), Settings::settingValue('trailers_size_y'), $trailer); + } + } + } + } + + $xxx = ''; + if ($data['xxxinfo_id'] !== '' && $data['xxxinfo_id'] !== 0) { + $xxx = XxxInfo::getXXXInfo($data['xxxinfo_id']); + + if (isset($xxx['trailers'])) { + $xxx['trailers'] = $this->xxxBrowseService->insertSwf($xxx['classused'], $xxx['trailers']); + } + + if ($xxx && isset($xxx['title'])) { + $xxx['title'] = str_replace(['/', '\\'], '', $xxx['title']); + $xxx['actors'] = makeFieldLinks($xxx, 'actors', 'xxx'); + $xxx['genre'] = makeFieldLinks($xxx, 'genre', 'xxx'); + $xxx['director'] = makeFieldLinks($xxx, 'director', 'xxx'); + } else { + $xxx = false; + } + } + + $game = ''; + if (! empty($data['gamesinfo_id'])) { + $game = (new GamesService)->getGamesInfoById($data['gamesinfo_id']); + } + + $mus = ''; + if (! empty($data['musicinfo_id'])) { + $mus = (new MusicService)->getMusicInfo($data['musicinfo_id']); + } + + $book = ''; + if (! empty($data['bookinfo_id'])) { + $book = (new BookService)->getBookInfo($data['bookinfo_id']); + } + + $con = ''; + if (! empty($data['consoleinfo_id'])) { + $con = (new ConsoleService)->getConsoleInfo($data['consoleinfo_id']); + } + + $AniDBAPIArray = ''; + if ($data['anidbid'] > 0) { + $AniDBAPIArray = (new AnidbService)->getAnimeInfo($data['anidbid']); + + // If we have anilist_id but missing details, fetch from AniList + if ($AniDBAPIArray && ! empty($AniDBAPIArray->anilist_id)) { + $anilistId = $AniDBAPIArray->anilist_id; + if (empty($AniDBAPIArray->country) && empty($AniDBAPIArray->media_type)) { + // Fetch fresh data from AniList if country/media_type is missing + try { + $palist = new \App\Services\PopulateAniListService; + $palist->populateTable('info', $anilistId); + // Refresh the data + $AniDBAPIArray = (new AnidbService)->getAnimeInfo($data['anidbid']); + } catch (\Exception $e) { + // Silently fail, use existing data + } + } + } + } + + $pre = Predb::getForRelease($data['predb_id']); + + $releasefiles = ReleaseFile::getReleaseFiles($data['id']); + + $this->viewData = array_merge($this->viewData, [ + 'releasefiles' => $releasefiles, + 'release' => $data, + 'reVideo' => $reVideo, + 'reAudio' => $reAudio, + 'reSubs' => $reSubs, + 'nfo' => $nfo, + 'show' => $showInfo, + 'movie' => $mov, + 'xxx' => $xxx, + 'anidb' => $AniDBAPIArray, + 'music' => $mus, + 'con' => $con, + 'game' => $game, + 'book' => $book, + 'predb' => $pre, + 'comments' => $comments, + 'files' => $releasefiles, + 'searchname' => getSimilarName($data['searchname']), + 'similars' => $similars !== false ? $similars : [], + 'privateprofiles' => config('nntmux_settings.private_profiles'), + 'failed' => $failed, + 'reportCount' => $reportCount, + 'reportReasons' => $reportReasons, + 'regex' => $releaseRegex, + 'downloadedby' => $downloadedBy, + 'meta_title' => 'View NZB', + 'meta_keywords' => 'view,nzb,description,details', + 'meta_description' => 'View NZB for '.$data['searchname'], + ]); + + return view('details.index', $this->viewData); } } diff --git a/app/Http/Controllers/GamesController.php b/app/Http/Controllers/GamesController.php index 8cb1be091..76c2f1234 100644 --- a/app/Http/Controllers/GamesController.php +++ b/app/Http/Controllers/GamesController.php @@ -34,14 +34,15 @@ class GamesController extends BasePageController $ordering = $games->getGamesOrdering(); $orderby = $request->has('ob') && \in_array($request->input('ob'), $ordering, false) ? $request->input('ob') : ''; $offset = ($page - 1) * config('nntmux.items_per_cover_page'); - $rslt = $games->getGamesRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, '', $this->userdata->categoryexclusions); - $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); + $rslt = $games->getGamesRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, '', (array) $this->userdata->categoryexclusions); + $results = $this->paginate($rslt, $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); $title = ($request->has('title') && ! empty($request->input('title'))) ? stripslashes($request->input('title')) : ''; $genres = $gen->getGenres((string) GenreService::GAME_TYPE, true); $tmpgnr = []; foreach ($genres as $gn) { + /** @var \App\Models\Genre $gn */ $tmpgnr[$gn->id] = $gn->title; } diff --git a/app/Http/Controllers/GetNzbController.php b/app/Http/Controllers/GetNzbController.php index 0b3d10ec3..152d860c7 100644 --- a/app/Http/Controllers/GetNzbController.php +++ b/app/Http/Controllers/GetNzbController.php @@ -186,7 +186,7 @@ class GetNzbController extends BasePageController /** * Handle zip download of multiple releases * - * @return JsonResponse|ZipStream|StreamedResponse + * @return JsonResponse|ZipStream|StreamedResponse|\STS\ZipStream\Builder * * @throws Exception */ @@ -207,7 +207,7 @@ class GetNzbController extends BasePageController } $zip = getStreamingZip($guids); - if ($zip === '') { + if ($zip === '') { // @phpstan-ignore identical.alwaysFalse return response()->json(['message' => 'Unable to create .zip file'], 404); } @@ -358,12 +358,12 @@ class GetNzbController extends BasePageController $buffer .= $chunk; // Check if this is the last chunk - if (gzeof($fileHandle)) { + if (gzeof($fileHandle)) { // @phpstan-ignore if.alwaysFalse $lastChunk = true; } // Process buffer - if ($lastChunk) { + if ($lastChunk) { // @phpstan-ignore if.alwaysFalse // On last chunk, modify poster attributes $buffer = preg_replace('/file poster="/', 'file poster="'.$uid.'-', $buffer); echo $buffer; diff --git a/app/Http/Controllers/MovieController.php b/app/Http/Controllers/MovieController.php index 07f2fcbb2..6ecca17a7 100644 --- a/app/Http/Controllers/MovieController.php +++ b/app/Http/Controllers/MovieController.php @@ -46,7 +46,7 @@ class MovieController extends BasePageController $orderby = ''; } - $rslt = $this->movieBrowseService->getMovieRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, -1, $this->userdata->categoryexclusions); + $rslt = $this->movieBrowseService->getMovieRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, -1, (array) $this->userdata->categoryexclusions); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); $movies = $results->map(function ($result) { @@ -112,7 +112,7 @@ class MovieController extends BasePageController } // Get all releases for this movie - $rslt = $this->movieBrowseService->getMovieRange(1, [], 0, 1000, '', -1, $this->userdata->categoryexclusions); + $rslt = $this->movieBrowseService->getMovieRange(1, [], 0, 1000, '', -1, (array) $this->userdata->categoryexclusions); // Filter to only this movie's IMDB ID $movieData = collect($rslt)->firstWhere('imdbid', $imdbid); @@ -121,17 +121,8 @@ class MovieController extends BasePageController return redirect()->route('Movies')->with('error', 'No releases found for this movie'); } - // Process movie data - ensure we handle both objects and arrays - if (is_object($movieInfo)) { - // If it's an Eloquent model, use toArray() - if (method_exists($movieInfo, 'toArray')) { - $movieArray = $movieInfo->toArray(); - } else { - $movieArray = get_object_vars($movieInfo); - } - } else { - $movieArray = $movieInfo; - } + // Convert Eloquent model to array + $movieArray = $movieInfo->toArray(); // Ensure we have at least the basic fields if (empty($movieArray['title'])) { diff --git a/app/Http/Controllers/MusicController.php b/app/Http/Controllers/MusicController.php index e1a4c083c..24c50f556 100644 --- a/app/Http/Controllers/MusicController.php +++ b/app/Http/Controllers/MusicController.php @@ -46,7 +46,7 @@ class MusicController extends BasePageController $orderby = $request->has('ob') && \in_array($request->input('ob'), $ordering, false) ? $request->input('ob') : ''; $musics = []; - $rslt = $music->getMusicRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, $this->userdata->categoryexclusions); + $rslt = $music->getMusicRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, (array) $this->userdata->categoryexclusions); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query()); $artist = ($request->has('artist') && ! empty($request->input('artist'))) ? stripslashes($request->input('artist')) : ''; @@ -56,6 +56,7 @@ class MusicController extends BasePageController $genres = $gen->getGenres((string) GenreService::MUSIC_TYPE, true); $tmpgnr = []; foreach ($genres as $gn) { + /** @var \App\Models\Genre $gn */ $tmpgnr[$gn->id] = $gn->title; } diff --git a/app/Http/Controllers/MyMoviesController.php b/app/Http/Controllers/MyMoviesController.php index c38afcf01..0816b6bf7 100644 --- a/app/Http/Controllers/MyMoviesController.php +++ b/app/Http/Controllers/MyMoviesController.php @@ -7,24 +7,19 @@ use App\Models\Settings; use App\Models\UserMovie; use App\Services\MovieBrowseService; use App\Services\MovieService; -use App\Services\Releases\ReleaseBrowseService; use Illuminate\Http\Request; class MyMoviesController extends BasePageController { - private ReleaseBrowseService $releaseBrowseService; - private MovieService $movieService; private MovieBrowseService $movieBrowseService; public function __construct( - ReleaseBrowseService $releaseBrowseService, MovieService $movieService, MovieBrowseService $movieBrowseService ) { parent::__construct(); - $this->releaseBrowseService = $releaseBrowseService; $this->movieService = $movieService; $this->movieBrowseService = $movieBrowseService; } @@ -141,10 +136,11 @@ class MyMoviesController extends BasePageController $offset = ($page - 1) * config('nntmux.items_per_cover_page'); $movies = UserMovie::getMovies($this->userdata->id); + /** @var array $categories */ $categories = $movie = []; foreach ($movies as $moviek => $movie) { $showcats = explode('|', $movie['categories']); - if (\is_array($showcats) && \count($showcats) > 0) { + if (\count($showcats) > 0) { $catarr = []; foreach ($showcats as $scat) { if (! empty($scat)) { @@ -161,7 +157,7 @@ class MyMoviesController extends BasePageController $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; - $results = $this->movieBrowseService->getMovieRange($page, [], $offset, config('nntmux.items_per_cover_page'), $ordering, -1, $this->userdata->categoryexclusions); + $results = $this->movieBrowseService->getMovieRange($page, [], $offset, config('nntmux.items_per_cover_page'), $ordering, -1, (array) $this->userdata->categoryexclusions); $this->viewData['covgroup'] = ''; @@ -172,7 +168,9 @@ class MyMoviesController extends BasePageController $this->viewData['lastvisit'] = $this->userdata->lastlogin; $this->viewData['results'] = $results; $this->viewData['movies'] = true; - $this->viewData['content'] = view('browse', $this->viewData)->render(); + /** @var view-string $browseView */ + $browseView = 'browse'; + $this->viewData['content'] = view($browseView, $this->viewData)->render(); $this->viewData = array_merge($this->viewData, compact('title', 'meta_title', 'meta_keywords', 'meta_description')); return $this->pagerender(); @@ -194,7 +192,7 @@ class MyMoviesController extends BasePageController $results = []; foreach ($movies as $moviek => $movie) { $showcats = explode('|', $movie['categories'] ?? ''); - if (\is_array($showcats) && \count($showcats) > 0) { + if (\count($showcats) > 0) { $catarr = []; foreach ($showcats as $scat) { if (! empty($scat) && isset($categories[$scat])) { diff --git a/app/Http/Controllers/MyShowsController.php b/app/Http/Controllers/MyShowsController.php index 7cca82f5d..ec978fb2b 100644 --- a/app/Http/Controllers/MyShowsController.php +++ b/app/Http/Controllers/MyShowsController.php @@ -139,7 +139,7 @@ class MyShowsController extends BasePageController foreach ($shows as $showk => $show) { $catArr = []; $showcats = explode('|', $show['categories'] ?? ''); - if (\is_array($showcats) && ! empty($showcats)) { + if (! empty($showcats)) { foreach ($showcats as $scat) { if (! empty($scat) && isset($categories[$scat])) { $catArr[] = $categories[$scat]; @@ -182,7 +182,7 @@ class MyShowsController extends BasePageController $orderby = $request->has('ob') && \in_array($request->input('ob'), $ordering, false) ? $request->input('ob') : ''; $browseCount = $shows ? $shows->count() : 0; - $rslt = $this->releaseBrowseService->getShowsRange($shows ?? [], $offset, config('nntmux.items_per_page'), $orderby, -1, $this->userdata->categoryexclusions); + $rslt = $this->releaseBrowseService->getShowsRange($shows ?? [], $offset, config('nntmux.items_per_page'), $orderby, -1, (array) $this->userdata->categoryexclusions); $results = $this->paginate($rslt ?? [], $browseCount, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); $this->viewData['covgroup'] = ''; diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 5ed075257..7bc281f78 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -55,7 +55,7 @@ class ProfileController extends BasePageController } } - if ($this->userdata === null) { + if ($this->userdata === null) { // @phpstan-ignore identical.alwaysFalse return $this->show404('No such user!'); } @@ -77,7 +77,7 @@ class ProfileController extends BasePageController 'downloadlist' => UserDownload::getDownloadRequestsForUser($userID), 'apirequests' => UserRequest::getApiRequests($userID), 'grabstoday' => UserDownload::getDownloadRequests($userID), - 'userinvitedby' => ($this->userdata->invitedby && $this->userdata->invitedby !== '') ? User::find($this->userdata->invitedby) : null, + 'userinvitedby' => $this->userdata->invitedby ? User::find($this->userdata->invitedby) : null, 'user' => $this->userdata, 'privateprofiles' => $privateProfiles, 'publicview' => $publicView, @@ -97,7 +97,7 @@ class ProfileController extends BasePageController } /** - * @return Factory|\Illuminate\View\View|View + * @return Factory|\Illuminate\View\View|View|RedirectResponse * * @throws \Exception */ @@ -107,9 +107,6 @@ class ProfileController extends BasePageController $action = $request->input('action') ?? 'view'; $userid = $this->userdata->id; - if (! $this->userdata) { - $this->show404('No such user!'); - } $errorStr = ''; $success_2fa = $request->session()->get('success'); @@ -313,7 +310,7 @@ class ProfileController extends BasePageController 'yesno_names' => ['Yes', 'No'], 'publicview' => false, 'privileged' => $this->userdata->hasRole('Admin') || $this->userdata->hasRole('Moderator'), - 'userinvitedby' => ($this->userdata->invitedby && $this->userdata->invitedby !== '') ? User::find($this->userdata->invitedby) : null, + 'userinvitedby' => $this->userdata->invitedby ? User::find($this->userdata->invitedby) : null, 'categoriesWithSubs' => RootCategory::with(['categories' => function ($query) { $query->where('status', 1)->orderBy('title'); }])->where('status', 1)->orderBy('title')->get(), diff --git a/app/Http/Controllers/RssController.php b/app/Http/Controllers/RssController.php index 994828fa0..2b67ddc71 100644 --- a/app/Http/Controllers/RssController.php +++ b/app/Http/Controllers/RssController.php @@ -151,7 +151,7 @@ class RssController extends BasePageController $rss = app(RSS::class); $offset = 0; if ($request->missing('id')) { - return response()->json(['error' => 'Category ID is missing'], '403'); + return response()->json(['error' => 'Category ID is missing'], 403); } $user = $this->userCheck($request); diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index f97e3e04f..710df2355 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -56,15 +56,15 @@ class SearchController extends BasePageController $searchString = []; switch (true) { case $request->filled('subject'): - $searchString['searchname'] = (string) $request->input('subject') ?? []; + $searchString['searchname'] = (string) $request->input('subject'); $subject = $searchString['searchname']; break; case $request->filled('id'): - $searchString['searchname'] = (string) $request->input('id') ?? []; + $searchString['searchname'] = (string) $request->input('id'); $id = $searchString['searchname']; break; case $request->filled('search'): - $searchString['searchname'] = (string) $request->input('search') ?? []; + $searchString['searchname'] = (string) $request->input('search'); $search = $searchString['searchname']; break; default: @@ -153,7 +153,7 @@ class SearchController extends BasePageController // Get spell correction suggestions if we have a search query but few/no results $spellSuggestion = null; - $searchQuery = $search ?: ($searchVars['searchadvr'] ?? ''); + $searchQuery = $search ?: $searchVars['searchadvr']; if (! empty($searchQuery) && $this->searchService->isSuggestEnabled()) { // Get suggestions from search service $suggestions = $this->searchService->suggest($searchQuery); diff --git a/app/Http/Controllers/SeriesController.php b/app/Http/Controllers/SeriesController.php index 6758d9ad1..d87d00aa3 100644 --- a/app/Http/Controllers/SeriesController.php +++ b/app/Http/Controllers/SeriesController.php @@ -94,7 +94,7 @@ class SeriesController extends BasePageController if ((empty($r->series) || (int) $r->series === 0 || empty($r->episode) || (int) $r->episode === 0) && ! empty($r->searchname)) { $matched = false; - if (! $matched && preg_match('/\bS(\d{1,2})E(\d{1,3})\b/i', $r->searchname, $m)) { + if (preg_match('/\bS(\d{1,2})E(\d{1,3})\b/i', $r->searchname, $m)) { if (empty($r->series) || (int) $r->series === 0) { $r->series = (int) $m[1]; } diff --git a/app/Http/Middleware/CheckForMaintenanceMode.php b/app/Http/Middleware/CheckForMaintenanceMode.php index 35b9824ba..03d2ea19e 100644 --- a/app/Http/Middleware/CheckForMaintenanceMode.php +++ b/app/Http/Middleware/CheckForMaintenanceMode.php @@ -9,7 +9,7 @@ class CheckForMaintenanceMode extends Middleware /** * The URIs that should be reachable while maintenance mode is enabled. * - * @var array + * @var array */ protected $except = [ // diff --git a/app/Http/Middleware/Google2FAMiddleware.php b/app/Http/Middleware/Google2FAMiddleware.php index 869a08861..d871505a2 100644 --- a/app/Http/Middleware/Google2FAMiddleware.php +++ b/app/Http/Middleware/Google2FAMiddleware.php @@ -44,6 +44,7 @@ class Google2FAMiddleware } // Continue with normal 2FA flow if we reach this point + /** @var Google2FAAuthenticator $authenticator */ $authenticator = app(Google2FAAuthenticator::class)->boot($request); if ($authenticator->isAuthenticated()) { diff --git a/app/Http/Resources/AnidbResource.php b/app/Http/Resources/AnidbResource.php index 0ff03cd6a..48b3d3d7f 100644 --- a/app/Http/Resources/AnidbResource.php +++ b/app/Http/Resources/AnidbResource.php @@ -7,6 +7,8 @@ use Illuminate\Http\Resources\Json\JsonResource; /** * AniDB API Resource for transforming anime data. + * + * @mixin \App\Models\AnidbInfo */ class AnidbResource extends JsonResource { diff --git a/app/Http/Resources/BookResource.php b/app/Http/Resources/BookResource.php index 7df0e52e2..efc22f3e3 100644 --- a/app/Http/Resources/BookResource.php +++ b/app/Http/Resources/BookResource.php @@ -7,6 +7,8 @@ use Illuminate\Http\Resources\Json\JsonResource; /** * Book API Resource for transforming book data. + * + * @mixin \App\Models\BookInfo */ class BookResource extends JsonResource { diff --git a/app/Http/Resources/MovieResource.php b/app/Http/Resources/MovieResource.php index 8724c77ad..e45df2273 100644 --- a/app/Http/Resources/MovieResource.php +++ b/app/Http/Resources/MovieResource.php @@ -7,6 +7,8 @@ use Illuminate\Http\Resources\Json\JsonResource; /** * Movie API Resource for transforming movie data. + * + * @mixin \App\Models\MovieInfo */ class MovieResource extends JsonResource { diff --git a/app/Jobs/SendInviteEmail.php b/app/Jobs/SendInviteEmail.php index a72914f39..92539635c 100644 --- a/app/Jobs/SendInviteEmail.php +++ b/app/Jobs/SendInviteEmail.php @@ -16,8 +16,6 @@ class SendInviteEmail implements ShouldQueue private $email; - private $userId; - private $url; /** diff --git a/app/Models/AnidbEpisode.php b/app/Models/AnidbEpisode.php index ed5ace56c..e128e9765 100644 --- a/app/Models/AnidbEpisode.php +++ b/app/Models/AnidbEpisode.php @@ -31,9 +31,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; */ class AnidbEpisode extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** @@ -52,7 +49,7 @@ class AnidbEpisode extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/AnidbInfo.php b/app/Models/AnidbInfo.php index d579f4e1a..4702cb9bf 100644 --- a/app/Models/AnidbInfo.php +++ b/app/Models/AnidbInfo.php @@ -60,9 +60,6 @@ class AnidbInfo extends Model */ protected $primaryKey = 'anidbid'; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -76,7 +73,7 @@ class AnidbInfo extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/AnidbTitle.php b/app/Models/AnidbTitle.php index 00285b6cd..386df3207 100644 --- a/app/Models/AnidbTitle.php +++ b/app/Models/AnidbTitle.php @@ -32,9 +32,6 @@ class AnidbTitle extends Model */ protected $primaryKey = 'anidbid'; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -48,7 +45,7 @@ class AnidbTitle extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/AudioData.php b/app/Models/AudioData.php index af55465c9..eca26706c 100644 --- a/app/Models/AudioData.php +++ b/app/Models/AudioData.php @@ -51,13 +51,10 @@ class AudioData extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/BinaryBlacklist.php b/app/Models/BinaryBlacklist.php index 4806e2a89..c809a088b 100644 --- a/app/Models/BinaryBlacklist.php +++ b/app/Models/BinaryBlacklist.php @@ -43,13 +43,10 @@ class BinaryBlacklist extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/BookInfo.php b/app/Models/BookInfo.php index c54338ecd..8df920765 100644 --- a/app/Models/BookInfo.php +++ b/app/Models/BookInfo.php @@ -58,13 +58,10 @@ class BookInfo extends Model */ protected $table = 'bookinfo'; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/Category.php b/app/Models/Category.php index e31479902..4db963d6f 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -19,6 +19,7 @@ use Illuminate\Support\Facades\DB; * @property bool $disablepreview * @property int $minsizetoformrelease * @property int $maxsizetoformrelease + * @property int|null $count Computed count from aggregate queries * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Category[] $children * @property-read Category|null $parent * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Release[] $releases @@ -261,13 +262,10 @@ class Category extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -282,7 +280,7 @@ class Category extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getRecentlyAdded() { @@ -419,7 +417,7 @@ class Category extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getFlat() { @@ -449,7 +447,7 @@ class Category extends Model /** * Get names of enabled parent categories. * - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getEnabledParentNames() { @@ -460,7 +458,7 @@ class Category extends Model * Returns category ID's for site disabled categories. * * - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getDisabledIDs() { @@ -472,7 +470,7 @@ class Category extends Model /** * Get multiple categories. * - * @return bool|\Illuminate\Database\Eloquent\Collection|static[] + * @return bool|\Illuminate\Database\Eloquent\Collection */ public static function getByIds($ids) { @@ -577,16 +575,14 @@ class Category extends Model $temp_array[-1] = '--Please Select--'; } foreach ($categories as $category) { + /** @var Category $category */ $temp_array[$category->id] = $category->parent->title.' > '.$category->title; } return $temp_array; } - /** - * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection - */ - public static function getCategories(bool $activeOnly = false, array $excludedCats = []): \Illuminate\Database\Eloquent\Collection|array + public static function getCategories(bool $activeOnly = false, array $excludedCats = []): \Illuminate\Database\Eloquent\Collection { $sql = self::query() ->with('parent') diff --git a/app/Models/Collection.php b/app/Models/Collection.php index e0ae9ef18..3785c6034 100644 --- a/app/Models/Collection.php +++ b/app/Models/Collection.php @@ -22,6 +22,8 @@ use Illuminate\Database\Eloquent\Model; * @property int $filesize * @property int|null $releases_id * @property string $noise + * @property string|null $udate Computed Unix timestamp from raw query + * @property string|null $gname Computed group name from join * * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Collection whereAdded($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Collection whereCollectionRegexesId($value) diff --git a/app/Models/ConsoleInfo.php b/app/Models/ConsoleInfo.php index c04abe639..7df6de12f 100644 --- a/app/Models/ConsoleInfo.php +++ b/app/Models/ConsoleInfo.php @@ -55,13 +55,10 @@ class ConsoleInfo extends Model */ protected $table = 'consoleinfo'; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/Content.php b/app/Models/Content.php index 934d4120b..3e8ad7f61 100644 --- a/app/Models/Content.php +++ b/app/Models/Content.php @@ -69,18 +69,15 @@ class Content extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; /** - * @var array + * @var array */ protected $casts = [ 'contenttype' => 'integer', @@ -127,7 +124,7 @@ class Content extends Model */ public function scopeFrontPage(Builder $query): Builder { - return $query->active() + return $query->active() // @phpstan-ignore method.notFound ->ofType(self::TYPE_INDEX) ->orderByRaw('ordinal ASC, COALESCE(ordinal, 1000000), id'); } diff --git a/app/Models/Country.php b/app/Models/Country.php index 871c794e4..89ca87a42 100644 --- a/app/Models/Country.php +++ b/app/Models/Country.php @@ -58,9 +58,6 @@ class Country extends Model */ public $incrementing = false; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -69,7 +66,7 @@ class Country extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/DnzbFailure.php b/app/Models/DnzbFailure.php index 52b771a87..e9e58165e 100644 --- a/app/Models/DnzbFailure.php +++ b/app/Models/DnzbFailure.php @@ -29,10 +29,6 @@ class DnzbFailure extends Model /** * @var string */ - - /** - * @var bool - */ protected $dateFormat = false; /** @@ -46,7 +42,7 @@ class DnzbFailure extends Model public $incrementing = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/Forumpost.php b/app/Models/Forumpost.php index 2f43331d0..989143deb 100644 --- a/app/Models/Forumpost.php +++ b/app/Models/Forumpost.php @@ -45,13 +45,10 @@ class Forumpost extends Model */ protected $table = 'forumpost'; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -103,7 +100,7 @@ class Forumpost extends Model * Get forum posts for a parent category. * * - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getPosts($parent) { @@ -188,7 +185,7 @@ class Forumpost extends Model * Get range of posts for user. * * - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getForUserRange($uid, $start, $num) { diff --git a/app/Models/GamesInfo.php b/app/Models/GamesInfo.php index a30b76902..8225b1991 100644 --- a/app/Models/GamesInfo.php +++ b/app/Models/GamesInfo.php @@ -59,18 +59,15 @@ class GamesInfo extends Model */ protected $table = 'gamesinfo'; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; /** - * @var array + * @var array */ protected $casts = [ 'cover' => 'boolean', diff --git a/app/Models/Genre.php b/app/Models/Genre.php index 1a9ff505e..bba7d2a76 100644 --- a/app/Models/Genre.php +++ b/app/Models/Genre.php @@ -33,9 +33,6 @@ use Illuminate\Support\Facades\DB; */ class Genre extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** @@ -44,7 +41,7 @@ class Genre extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index 7e938c718..5257b5df4 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -40,7 +40,7 @@ class Invitation extends Model public const DEFAULT_INVITE_EXPIRY_DAYS = 7; /** - * @var array + * @var list */ protected $fillable = [ 'token', @@ -54,7 +54,7 @@ class Invitation extends Model ]; /** - * @var array + * @var array */ protected $casts = [ 'expires_at' => 'datetime', @@ -102,7 +102,7 @@ class Invitation extends Model */ public function scopeValid(Builder $query): Builder { - return $query->active() + return $query->active() // @phpstan-ignore method.notFound ->where('expires_at', '>', now()) ->whereNull('used_at'); } diff --git a/app/Models/MissedPart.php b/app/Models/MissedPart.php index ab2316d1a..f0270e6a8 100644 --- a/app/Models/MissedPart.php +++ b/app/Models/MissedPart.php @@ -25,13 +25,10 @@ use Illuminate\Database\Eloquent\Model; */ class MissedPart extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/MovieInfo.php b/app/Models/MovieInfo.php index fc32af282..10af76092 100644 --- a/app/Models/MovieInfo.php +++ b/app/Models/MovieInfo.php @@ -64,13 +64,10 @@ class MovieInfo extends Model */ protected $table = 'movieinfo'; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = ['id']; diff --git a/app/Models/MusicInfo.php b/app/Models/MusicInfo.php index 4258612e0..b80efe656 100644 --- a/app/Models/MusicInfo.php +++ b/app/Models/MusicInfo.php @@ -24,6 +24,7 @@ use Laravel\Scout\Searchable; * @property bool $cover * @property \Carbon\Carbon|null $created_at * @property \Carbon\Carbon|null $updated_at + * @property int|null $_totalcount Computed total count from aggregate queries * @property-read Genre|null $genre * * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\MusicInfo whereArtist($value) @@ -57,9 +58,6 @@ class MusicInfo extends Model */ protected $table = 'musicinfo'; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -68,7 +66,7 @@ class MusicInfo extends Model public $timestamps = true; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/ParHash.php b/app/Models/ParHash.php index 739313f31..45fd6eb0a 100644 --- a/app/Models/ParHash.php +++ b/app/Models/ParHash.php @@ -31,13 +31,10 @@ class ParHash extends Model */ public $incrementing = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/PasswordSecurity.php b/app/Models/PasswordSecurity.php index d8e11d419..2769ad9ff 100644 --- a/app/Models/PasswordSecurity.php +++ b/app/Models/PasswordSecurity.php @@ -11,7 +11,7 @@ class PasswordSecurity extends Model use HasFactory; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/Predb.php b/app/Models/Predb.php index 70f93590a..0738f6f35 100644 --- a/app/Models/Predb.php +++ b/app/Models/Predb.php @@ -76,13 +76,10 @@ class Predb extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -210,7 +207,7 @@ class Predb extends Model * Get all PRE's for a release. * * - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getForRelease($preID) { diff --git a/app/Models/PredbHash.php b/app/Models/PredbHash.php index 6e4d99970..34a4551ae 100644 --- a/app/Models/PredbHash.php +++ b/app/Models/PredbHash.php @@ -28,9 +28,6 @@ class PredbHash extends Model */ public $incrementing = false; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -39,7 +36,7 @@ class PredbHash extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/Release.php b/app/Models/Release.php index 9698f3c56..ebae58a61 100644 --- a/app/Models/Release.php +++ b/app/Models/Release.php @@ -12,13 +12,42 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; +/** + * Properties from computed columns, joins, and subqueries. + * + * @property int|null $relsize From join/computed column + * @property int|null $_totalrows From subquery count + * @property string|null $textstring From join + * @property string|null $episodes From join + * @property string|null $category_name From join + * @property int|null $tvrage From join + * @property int|null $tvmaze From join + * @property int|null $tvdb From join + * @property int|null $trakt From join + * @property int|null $tmdb From join + * @property int|null $preid From join + * @property string|null $firstaired From join + * @property string|null $title From join + * @property string|null $summary From join + * @property string|null $sub_category From join + * @property float|null $size_diff Computed column + * @property string|null $showtitle From join + * @property string|null $se_complete From join + * @property int|null $files_total_size Computed column + * @property string|null $group_name From join (group relationship) + * @property string|null $image From join (video.tvInfo relationship) + * @property string|null $parent_category From join (category.parent relationship) + * @property string|null $category_ids Computed from category relationship + * @property string|null $group_names Computed from releaseGroup relationship + * @property float|null $release_size Computed column (size in GiB) + * @property float|null $diff_percent Computed column (difference percentage) + * @property int|null $releases_id From raw query alias + * @property int|null $_totalcount From subquery count + */ class Release extends Model { use HasFactory; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -27,7 +56,7 @@ class Release extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -204,7 +233,7 @@ class Release extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getTopDownloads() { @@ -229,7 +258,7 @@ class Release extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getTopComments() { @@ -352,9 +381,9 @@ class Release extends Model $release->parent_category = $release->category->parent->title ?? null; $release->sub_category = $release->category->title ?? null; $release->category_name = $release->parent_category.' > '.$release->sub_category; - $release->category_ids = $release->category ? ($release->category->parentid.','.$release->category->id) : ''; + $release->category_ids = $release->category ? ($release->category->parentid.','.$release->category->id) : ''; // @phpstan-ignore property.notFound, property.notFound $release->group_names = $release->releaseGroup->map(function ($relGroup) { - return $relGroup->group ? $relGroup->group->name : null; + return $relGroup->group ? $relGroup->group->name : null; // @phpstan-ignore property.notFound })->implode(','); }); diff --git a/app/Models/ReleaseComment.php b/app/Models/ReleaseComment.php index e9ed228af..588a403a0 100644 --- a/app/Models/ReleaseComment.php +++ b/app/Models/ReleaseComment.php @@ -58,13 +58,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; class ReleaseComment extends Model { /** - * @var array + * @var array */ protected $guarded = []; - /** - * @var bool - */ protected $dateFormat = false; public function release(): BelongsTo @@ -95,7 +92,7 @@ class ReleaseComment extends Model public static function getCommentCount(): int { - return self::query()->count(['id']); + return self::query()->count('id'); } /** @@ -162,7 +159,7 @@ class ReleaseComment extends Model */ public static function updateReleaseCommentCount($gid): void { - $commentCount = self::query()->where('gid', '=', 'releases.gid')->where('isvisible', '=', 1)->count(['id']); + $commentCount = self::query()->where('gid', '=', 'releases.gid')->where('isvisible', '=', 1)->count('id'); Release::query()->where('gid', $gid)->update(['comments' => $commentCount]); } @@ -171,7 +168,7 @@ class ReleaseComment extends Model */ public static function getCommentCountForUser($uid): int { - $res = self::query()->where(['users_id' => $uid, 'isvisible' => 1])->count(['id']); + $res = self::query()->where(['users_id' => $uid, 'isvisible' => 1])->count('id'); return $res; } diff --git a/app/Models/ReleaseFile.php b/app/Models/ReleaseFile.php index 43c0efe6e..6ce5d6e3a 100644 --- a/app/Models/ReleaseFile.php +++ b/app/Models/ReleaseFile.php @@ -38,13 +38,10 @@ use Illuminate\Support\Facades\Log; */ class ReleaseFile extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -62,7 +59,7 @@ class ReleaseFile extends Model * Get releasefiles row by id. * * - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getReleaseFiles($id) { @@ -70,7 +67,7 @@ class ReleaseFile extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getByGuid($guid) { diff --git a/app/Models/ReleaseNfo.php b/app/Models/ReleaseNfo.php index 9f098b519..22309db40 100644 --- a/app/Models/ReleaseNfo.php +++ b/app/Models/ReleaseNfo.php @@ -28,15 +28,12 @@ class ReleaseNfo extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; protected $primaryKey = 'releases_id'; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/ReleaseRegex.php b/app/Models/ReleaseRegex.php index 5aa508be9..dbbebe2f7 100644 --- a/app/Models/ReleaseRegex.php +++ b/app/Models/ReleaseRegex.php @@ -23,9 +23,6 @@ use Illuminate\Database\Eloquent\Model; */ class ReleaseRegex extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** @@ -39,7 +36,7 @@ class ReleaseRegex extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/ReleaseSubtitle.php b/app/Models/ReleaseSubtitle.php index 03eb81c1b..c0c7c5139 100644 --- a/app/Models/ReleaseSubtitle.php +++ b/app/Models/ReleaseSubtitle.php @@ -34,13 +34,10 @@ class ReleaseSubtitle extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var list */ protected $fillable = [ 'id', diff --git a/app/Models/ReleaseUnique.php b/app/Models/ReleaseUnique.php index c32c1025a..bac91e151 100644 --- a/app/Models/ReleaseUnique.php +++ b/app/Models/ReleaseUnique.php @@ -31,9 +31,6 @@ class ReleaseUnique extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -42,7 +39,7 @@ class ReleaseUnique extends Model public $incrementing = false; /** - * @var array + * @var list */ protected $fillable = [ 'releases_id', diff --git a/app/Models/ReleasesGroups.php b/app/Models/ReleasesGroups.php index 0e2cd32b0..bcff99aa6 100644 --- a/app/Models/ReleasesGroups.php +++ b/app/Models/ReleasesGroups.php @@ -56,18 +56,14 @@ class ReleasesGroups extends Model */ public $timestamps = false; - /** - * @var bool - */ + /** @phpstan-ignore property.defaultValue */ public $dateFormat = false; - /** - * @var array - */ + /** @phpstan-ignore property.defaultValue */ protected $primaryKey = ['releases_id', 'groups_id']; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/RolePromotion.php b/app/Models/RolePromotion.php index ec3bcee76..7cf9e4731 100644 --- a/app/Models/RolePromotion.php +++ b/app/Models/RolePromotion.php @@ -15,8 +15,8 @@ use Spatie\Permission\Models\Role; * @property string|null $description * @property array $applicable_roles * @property int $additional_days - * @property string|null $start_date - * @property string|null $end_date + * @property \Carbon\Carbon|null $start_date + * @property \Carbon\Carbon|null $end_date * @property bool $is_active * @property \Carbon\Carbon|null $created_at * @property \Carbon\Carbon|null $updated_at @@ -212,9 +212,12 @@ class RolePromotion extends Model ->get() ->groupBy('role_id') ->map(function ($stats, $roleId) { + /** @var \App\Models\RolePromotionStat|null $firstStat */ + $firstStat = $stats->first(); + return [ 'role_id' => $roleId, - 'role_name' => $stats->first()->role?->name, + 'role_name' => $firstStat?->role?->name, 'total_upgrades' => $stats->count(), 'total_days_added' => $stats->sum('days_added'), 'unique_users' => $stats->unique('user_id')->count(), @@ -229,6 +232,7 @@ class RolePromotion extends Model */ public function getStatisticsForPeriod(Carbon $startDate, Carbon $endDate): array { + /** @phpstan-ignore method.notFound */ $stats = $this->statistics() ->appliedBetween($startDate, $endDate) ->get(); diff --git a/app/Models/RolePromotionStat.php b/app/Models/RolePromotionStat.php index d7e368b78..41469ab83 100644 --- a/app/Models/RolePromotionStat.php +++ b/app/Models/RolePromotionStat.php @@ -127,7 +127,7 @@ class RolePromotionStat extends Model 'promotions' => $stats->groupBy('role_promotion_id')->map(function ($group) { return [ 'promotion_id' => $group->first()->role_promotion_id, - 'promotion_name' => $group->first()->promotion?->name, + 'promotion_name' => $group->first()->promotion->name, 'times_applied' => $group->count(), 'total_days' => $group->sum('days_added'), ]; diff --git a/app/Models/Settings.php b/app/Models/Settings.php index 4df00ebe4..ea94cffd6 100644 --- a/app/Models/Settings.php +++ b/app/Models/Settings.php @@ -73,9 +73,6 @@ class Settings extends Model */ protected $keyType = 'string'; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -89,7 +86,7 @@ class Settings extends Model public $incrementing = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/SteamApp.php b/app/Models/SteamApp.php index 1b1e87d79..e80d11998 100644 --- a/app/Models/SteamApp.php +++ b/app/Models/SteamApp.php @@ -29,9 +29,6 @@ class SteamApp extends Model */ public $incrementing = false; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -40,7 +37,7 @@ class SteamApp extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/TvEpisode.php b/app/Models/TvEpisode.php index 825af6a63..713e0251c 100644 --- a/app/Models/TvEpisode.php +++ b/app/Models/TvEpisode.php @@ -37,13 +37,10 @@ use Illuminate\Database\Eloquent\Relations\HasMany; */ class TvEpisode extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/TvInfo.php b/app/Models/TvInfo.php index 156b0c466..6e44b9f60 100644 --- a/app/Models/TvInfo.php +++ b/app/Models/TvInfo.php @@ -38,7 +38,7 @@ class TvInfo extends Model public $incrementing = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -47,9 +47,6 @@ class TvInfo extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** diff --git a/app/Models/UsenetGroup.php b/app/Models/UsenetGroup.php index 381dec5bb..af62dd954 100644 --- a/app/Models/UsenetGroup.php +++ b/app/Models/UsenetGroup.php @@ -50,9 +50,6 @@ use Illuminate\Support\Facades\DB; */ class UsenetGroup extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** @@ -61,7 +58,7 @@ class UsenetGroup extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -124,7 +121,7 @@ class UsenetGroup extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getActive() { @@ -135,7 +132,7 @@ class UsenetGroup extends Model * Get active backfill groups ordered by name ascending. * * - * @return array|\Illuminate\Database\Eloquent\Collection|static[] + * @return array|\Illuminate\Database\Eloquent\Collection */ public static function getActiveBackfill($order) { @@ -143,10 +140,8 @@ class UsenetGroup extends Model case '': case 'normal': return self::query()->where('backfill', '=', 1)->where('last_record', '<>', 0)->orderBy('name')->get(); - break; case 'date': return self::query()->where('backfill', '=', 1)->where('last_record', '<>', 0)->orderByDesc('first_record_postdate')->get(); - break; default: return []; } @@ -156,7 +151,7 @@ class UsenetGroup extends Model * Get all active group IDs. * * - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getActiveIDs() { @@ -219,7 +214,7 @@ class UsenetGroup extends Model $res->where('active', $active); } - return $res === null ? 0 : $res->count(['id']); + return $res === null ? 0 : $res->count('id'); } public static function getGroupsRange(string $groupname = '', $active = null): LengthAwarePaginator @@ -322,7 +317,7 @@ class UsenetGroup extends Model * * @throws \Exception */ - public static function reset($id): bool + public static function reset($id): int { // Remove rows from part repair. MissedPart::query()->where('groups_id', $id)->delete(); @@ -344,7 +339,7 @@ class UsenetGroup extends Model /** * Reset all groups. */ - public static function resetall(): bool + public static function resetall(): int { // Disable foreign key checks to allow truncating tables with foreign key constraints DB::statement('SET FOREIGN_KEY_CHECKS=0'); diff --git a/app/Models/User.php b/app/Models/User.php index b1c98901e..53d85e712 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -83,6 +83,16 @@ use Spatie\Permission\Traits\HasRoles; * @property string|null $verification_token * @property string|null $timezone * @property bool $can_post + * @property array|string|null $categoryexclusions Computed from join/subquery for category exclusion lists + * @property string|null $sort_date Computed column for date sorting + * @property string|null $role_name Computed from join with roles table + * @property int|null $num Computed count value + * @property string|null $mth Computed month value + * @property bool|null $is_role_expired Computed via Attribute accessor + * @property int|null $days_until_expiry Computed via Attribute accessor + * @property int|null $count Computed count from aggregate queries + * @property int|null $daily_api_count Computed daily API request count + * @property int|null $daily_download_count Computed daily download count * @property-read Collection $comments * @property-read Collection $downloads * @property-read Collection $failedReleases @@ -557,8 +567,8 @@ final class User extends Authenticatable * @return \Illuminate\Support\Collection */ @@ -571,12 +581,12 @@ final class User extends Authenticatable ->orderBy('effective_date', 'asc') ->get(); - return $stackedHistory->map(function ($history) { + return $stackedHistory->map(function ($history) { // @phpstan-ignore return.type $role = Role::find($history->new_role_id); return [ 'role' => $role, - 'role_name' => $role?->name ?? 'Unknown Role', + 'role_name' => $role?->name ?? 'Unknown Role', // @phpstan-ignore nullsafe.neverNull 'start_date' => $history->effective_date, 'end_date' => $history->new_expiry_date, 'is_current_pending' => $this->pending_roles_id === $history->new_role_id @@ -751,7 +761,7 @@ final class User extends Authenticatable 'consoleview' => $consoleview, 'bookview' => $bookview, 'style' => $style, - 'rate_limit' => $roleModel?->rate_limit ?? 60, + 'rate_limit' => $roleModel?->rate_limit ?? 60, // @phpstan-ignore nullsafe.neverNull ...($email ? ['email' => trim($email)] : []), ]); @@ -1324,7 +1334,7 @@ final class User extends Authenticatable public static function updateRssKey(int $uid): int { static::find($uid)?->update([ - 'api_token' => md5(Password::getRepository()->createNewToken()), + 'api_token' => md5(Password::getRepository()->createNewToken()), // @phpstan-ignore method.notFound ]); return SignupError::SUCCESS->value; @@ -1399,7 +1409,7 @@ final class User extends Authenticatable bool $forceInviteMode = false, int $role = UserRole::USER->value, bool $validate = true, - ): bool|int|string { + ): int|string { $userData = [ 'username' => trim($userName), 'password' => trim($password), @@ -1476,7 +1486,7 @@ final class User extends Authenticatable string $host = '', int $invites = Invitation::DEFAULT_INVITES, int $invitedBy = 0, - ): int|false { + ): int { $hashedPassword = Hash::make($password); $storeIps = config('nntmux:settings.store_user_ip') === true ? $host : ''; diff --git a/app/Models/UserDownload.php b/app/Models/UserDownload.php index 1faa37d16..90a5fd26a 100644 --- a/app/Models/UserDownload.php +++ b/app/Models/UserDownload.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; * @property string $hosthash * @property string $timestamp * @property int $releases_id FK to releases.id + * @property int|null $count Computed count from aggregate queries * @property-read Release $release * @property-read User $user * @@ -30,9 +31,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; */ class UserDownload extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** @@ -41,7 +39,7 @@ class UserDownload extends Model public $timestamps = false; /** - * @var array + * @var array */ protected $guarded = []; @@ -104,7 +102,7 @@ class UserDownload extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getDownloadRequestsForUser($userID) { diff --git a/app/Models/UserMovie.php b/app/Models/UserMovie.php index 4d1425453..e5903589a 100644 --- a/app/Models/UserMovie.php +++ b/app/Models/UserMovie.php @@ -30,13 +30,10 @@ use Illuminate\Database\Eloquent\Model; class UserMovie extends Model { /** - * @var array + * @var array */ protected $guarded = []; - /** - * @var bool - */ protected $dateFormat = false; /** diff --git a/app/Models/UserRequest.php b/app/Models/UserRequest.php index 973ba901b..30d82434d 100644 --- a/app/Models/UserRequest.php +++ b/app/Models/UserRequest.php @@ -14,6 +14,7 @@ use Illuminate\Support\Facades\DB; * @property string $hosthash * @property string $request * @property string $timestamp + * @property int|null $count Computed count from aggregate queries * @property-read User $user * * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UserRequest whereHosthash($value) @@ -33,10 +34,6 @@ class UserRequest extends Model /** * @var string */ - - /** - * @var bool - */ protected $dateFormat = false; /** @@ -45,7 +42,7 @@ class UserRequest extends Model public $timestamps = false; /** - * @var array + * @var list */ protected $fillable = ['id', 'users_id', 'request', 'hosthash', 'timestamp']; diff --git a/app/Models/UserSerie.php b/app/Models/UserSerie.php index 2d3a0b7d1..906fee983 100644 --- a/app/Models/UserSerie.php +++ b/app/Models/UserSerie.php @@ -32,13 +32,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; class UserSerie extends Model { /** - * @var array + * @var array */ protected $guarded = []; - /** - * @var bool - */ protected $dateFormat = false; public function user(): BelongsTo @@ -70,7 +67,7 @@ class UserSerie extends Model * Get all the user's "my shows". * * - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getShows($userId) { diff --git a/app/Models/UsersRelease.php b/app/Models/UsersRelease.php index a08c5edf6..794f022bb 100644 --- a/app/Models/UsersRelease.php +++ b/app/Models/UsersRelease.php @@ -30,13 +30,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; */ class UsersRelease extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = ['id']; @@ -71,7 +68,7 @@ class UsersRelease extends Model } /** - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function getCart($uid) { diff --git a/app/Models/Video.php b/app/Models/Video.php index b856f8fff..e3d71e331 100644 --- a/app/Models/Video.php +++ b/app/Models/Video.php @@ -49,13 +49,10 @@ use Illuminate\Database\Eloquent\Relations\HasOne; */ class Video extends Model { - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/VideoAlias.php b/app/Models/VideoAlias.php index a2c61c21c..f9a5d2d35 100644 --- a/app/Models/VideoAlias.php +++ b/app/Models/VideoAlias.php @@ -31,7 +31,7 @@ class VideoAlias extends Model public $incrementing = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Models/VideoData.php b/app/Models/VideoData.php index 930ca845f..25fd8538b 100644 --- a/app/Models/VideoData.php +++ b/app/Models/VideoData.php @@ -49,9 +49,6 @@ class VideoData extends Model */ public $timestamps = false; - /** - * @var bool - */ protected $dateFormat = false; /** @@ -65,7 +62,7 @@ class VideoData extends Model protected $primaryKey = 'releases_id'; /** - * @var array + * @var array */ protected $guarded = []; } diff --git a/app/Models/XxxInfo.php b/app/Models/XxxInfo.php index bb2db37c6..4bec8a594 100644 --- a/app/Models/XxxInfo.php +++ b/app/Models/XxxInfo.php @@ -55,13 +55,10 @@ class XxxInfo extends Model */ protected $table = 'xxxinfo'; - /** - * @var bool - */ protected $dateFormat = false; /** - * @var array + * @var array */ protected $guarded = []; diff --git a/app/Observers/ReleaseObserver.php b/app/Observers/ReleaseObserver.php index 9fdfb45d9..70b31c2c7 100644 --- a/app/Observers/ReleaseObserver.php +++ b/app/Observers/ReleaseObserver.php @@ -137,13 +137,13 @@ class ReleaseObserver 'categories_id' => $release->categories_id ?? 0, 'filename' => '', // Not available from model // Movie external IDs - 'imdbid' => $release->imdbid ?? ($movieInfo?->imdbid ?? 0), - 'tmdbid' => $movieInfo?->tmdbid ?? 0, - 'traktid' => $movieInfo?->traktid ?? 0, + 'imdbid' => $release->imdbid ?? ($movieInfo?->imdbid ?? 0), // @phpstan-ignore nullsafe.neverNull + 'tmdbid' => $movieInfo?->tmdbid ?? 0, // @phpstan-ignore nullsafe.neverNull + 'traktid' => $movieInfo?->traktid ?? 0, // @phpstan-ignore nullsafe.neverNull // TV show external IDs - 'tvdb' => $video?->tvdb ?? 0, - 'tvmaze' => $video?->tvmaze ?? 0, - 'tvrage' => $video?->tvrage ?? 0, + 'tvdb' => $video?->tvdb ?? 0, // @phpstan-ignore nullsafe.neverNull + 'tvmaze' => $video?->tvmaze ?? 0, // @phpstan-ignore nullsafe.neverNull + 'tvrage' => $video?->tvrage ?? 0, // @phpstan-ignore nullsafe.neverNull 'videos_id' => $release->videos_id ?? 0, 'movieinfo_id' => $release->movieinfo_id ?? 0, ]; diff --git a/app/Observers/UserActivityObserver.php b/app/Observers/UserActivityObserver.php index 68411ff49..1c21f038a 100644 --- a/app/Observers/UserActivityObserver.php +++ b/app/Observers/UserActivityObserver.php @@ -49,7 +49,7 @@ class UserActivityObserver 'new_role_id' => $newRoleId, 'old_role_name' => $oldRoleName, 'new_role_name' => $newRoleName, - 'updated_by' => auth()->user()?->username ?? 'System', + 'updated_by' => auth()->user()?->username ?? 'System', // @phpstan-ignore nullsafe.neverNull ], ]); @@ -64,7 +64,7 @@ class UserActivityObserver */ public function deleting(User $user): void { - $deletedBy = auth()->user()?->username ?? 'System'; + $deletedBy = auth()->user()?->username ?? 'System'; // @phpstan-ignore nullsafe.neverNull // Check if user is deleting their own account if (auth()->check() && auth()->id() === $user->id) { @@ -119,7 +119,7 @@ class UserActivityObserver 'activity_type' => 'registered', 'description' => "User restored: {$user->username}", 'metadata' => [ - 'restored_by' => auth()->user()?->username ?? 'System', + 'restored_by' => auth()->user()?->username ?? 'System', // @phpstan-ignore nullsafe.neverNull ], ]); } @@ -129,7 +129,7 @@ class UserActivityObserver */ public function forceDeleted(User $user): void { - $deletedBy = auth()->user()?->username ?? 'System'; + $deletedBy = auth()->user()?->username ?? 'System'; // @phpstan-ignore nullsafe.neverNull // Check if user is deleting their own account if (auth()->check() && auth()->id() === $user->id) { diff --git a/app/Observers/UserServiceObserver.php b/app/Observers/UserServiceObserver.php index abf72b582..56b95e72f 100644 --- a/app/Observers/UserServiceObserver.php +++ b/app/Observers/UserServiceObserver.php @@ -6,7 +6,7 @@ use App\Jobs\SendNewRegisteredAccountMail; use App\Jobs\SendWelcomeEmail; use App\Models\User; use Illuminate\Support\Facades\File; -use Illuminate\Support\Facades\Password; +use Illuminate\Support\Str; use Jrean\UserVerification\Facades\UserVerification; use Spatie\Permission\Models\Role; @@ -26,7 +26,7 @@ class UserServiceObserver $user->syncRoles([$roleName]); $user->update( [ - 'api_token' => md5(Password::getRepository()->createNewToken()), + 'api_token' => md5(Str::random(40)), 'rate_limit' => $rateLimit, ] ); diff --git a/app/Policies/CategoryPolicy.php b/app/Policies/CategoryPolicy.php index 481d07c3c..5d2354395 100644 --- a/app/Policies/CategoryPolicy.php +++ b/app/Policies/CategoryPolicy.php @@ -67,6 +67,7 @@ class CategoryPolicy extends \TeamTeaTime\Forum\Policies\CategoryPolicy public function edit(User $user, Category $category): bool { + /** @var \App\Models\User $user */ return $user->hasRole('Admin'); } } diff --git a/app/Policies/PostPolicy.php b/app/Policies/PostPolicy.php index e626e1843..006047d78 100644 --- a/app/Policies/PostPolicy.php +++ b/app/Policies/PostPolicy.php @@ -9,18 +9,18 @@ class PostPolicy extends \TeamTeaTime\Forum\Policies\PostPolicy public function edit($user, Post $post): bool { // Admins can edit any post; users can edit their own - return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); // @phpstan-ignore property.notFound } public function delete($user, Post $post): bool { // Admins can delete any post; users can delete their own - return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); // @phpstan-ignore property.notFound } public function restore($user, Post $post): bool { // Admins can restore any post; users can restore their own - return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $post->author_id); // @phpstan-ignore property.notFound } } diff --git a/app/Policies/ThreadPolicy.php b/app/Policies/ThreadPolicy.php index 848dabbd3..f0c6c1943 100644 --- a/app/Policies/ThreadPolicy.php +++ b/app/Policies/ThreadPolicy.php @@ -15,7 +15,7 @@ class ThreadPolicy extends \TeamTeaTime\Forum\Policies\ThreadPolicy public function rename($user, Thread $thread): bool { // Admins can rename any thread; users can rename their own - return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound } public function reply($user, Thread $thread): bool @@ -27,19 +27,19 @@ class ThreadPolicy extends \TeamTeaTime\Forum\Policies\ThreadPolicy public function replyWithoutApproval($user, Thread $thread): bool { // Admins can reply to unapproved threads; otherwise only thread author - return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound } public function delete($user, Thread $thread): bool { // Admins can delete any thread; users can delete their own - return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound } public function restore($user, Thread $thread): bool { // Admins can restore any thread; users can restore their own - return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); + return $user->hasRole('Admin') || ($user->getKey() === $thread->author_id); // @phpstan-ignore property.notFound } public function deletePosts($user, Thread $thread): bool diff --git a/app/Providers/AdditionalProcessingServiceProvider.php b/app/Providers/AdditionalProcessingServiceProvider.php index b76f32b02..163b5766c 100644 --- a/app/Providers/AdditionalProcessingServiceProvider.php +++ b/app/Providers/AdditionalProcessingServiceProvider.php @@ -78,7 +78,6 @@ class AdditionalProcessingServiceProvider extends ServiceProvider $this->app->singleton(ReleaseFileManager::class, function ($app) { return new ReleaseFileManager( $app->make(ProcessingConfiguration::class), - $app->make(ReleaseExtraService::class), new ReleaseImageService, new NfoService, $app->make(NzbService::class), diff --git a/app/Rules/ValidEmailDomain.php b/app/Rules/ValidEmailDomain.php index 1a3f20809..e4e971ccd 100644 --- a/app/Rules/ValidEmailDomain.php +++ b/app/Rules/ValidEmailDomain.php @@ -198,6 +198,8 @@ class ValidEmailDomain implements ValidationRule /** * Check for suspicious plus addressing patterns * Some users abuse plus addressing to create multiple accounts + * + * @phpstan-ignore method.unused */ private function hasSuspiciousPlusAddressing(string $email): bool { diff --git a/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php b/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php index a9afdf78a..b255b4ae5 100644 --- a/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php +++ b/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php @@ -426,7 +426,7 @@ class AdditionalProcessingOrchestrator if ($failed >= $this->config->maximumRarPasswordChecks) { break; } - if ($context->releaseHasPassword || $context->groupUnavailable) { + if ($context->releaseHasPassword || $context->groupUnavailable) { // @phpstan-ignore booleanOr.rightAlwaysFalse break; } @@ -479,7 +479,7 @@ class AdditionalProcessingOrchestrator $downloaded++; $processed = $this->processCompressedData($result['data'], $context, $reverse); - if ($processed || $context->releaseHasPassword) { + if ($processed || $context->releaseHasPassword) { // @phpstan-ignore booleanOr.rightAlwaysFalse break; } } else { @@ -703,10 +703,6 @@ class AdditionalProcessingOrchestrator // Try to extract each image file from the archive foreach ($imageFiles as $imageFile) { - if ($context->foundJPGSample) { - break; - } - $imageData = $this->archiveService->extractSpecificFile( $result['data'], $imageFile->name, diff --git a/app/Services/AdditionalProcessing/ArchiveExtractionService.php b/app/Services/AdditionalProcessing/ArchiveExtractionService.php index a5b60ecc7..5a015eae7 100644 --- a/app/Services/AdditionalProcessing/ArchiveExtractionService.php +++ b/app/Services/AdditionalProcessing/ArchiveExtractionService.php @@ -35,7 +35,7 @@ class ArchiveExtractionService /** * Process compressed data and extract file information. * - * @return array{success: bool, files: array, hasPassword: bool, passwordStatus: int} + * @return array{success: bool, files: array, hasPassword: bool, passwordStatus: int, archiveMarker?: string, dataSummary?: array, standaloneVideoType?: string, standaloneVideoData?: string} */ public function processCompressedData( string $compressedData, @@ -757,7 +757,7 @@ class ArchiveExtractionService } } // MP4/MOV - if ($len >= 12 && substr($data, 4, 4) === 'ftyp') { + if (substr($data, 4, 4) === 'ftyp') { $brands = ['isom', 'iso2', 'avc1', 'mp41', 'mp42', 'dash', 'MSNV', 'qt ', 'M4V ', 'M4P ', 'M4B ', 'M4A ']; if (in_array(substr($data, 8, 4), $brands, true)) { return 'mp4'; @@ -987,6 +987,10 @@ class ArchiveExtractionService /** * Execute a command with output capture. + * + * @param-out int $exitCode + * @param-out string|null $stdout + * @param-out string|null $stderr */ private function execCommand(array $cmd, ?int &$exitCode, ?string &$stdout, ?string &$stderr): bool { @@ -1002,9 +1006,9 @@ class ArchiveExtractionService return false; } - $stdout = stream_get_contents($pipes[1]); + $stdout = stream_get_contents($pipes[1]) ?: null; fclose($pipes[1]); - $stderr = stream_get_contents($pipes[2]); + $stderr = stream_get_contents($pipes[2]) ?: null; fclose($pipes[2]); $exitCode = proc_close($process); diff --git a/app/Services/AdditionalProcessing/MediaExtractionService.php b/app/Services/AdditionalProcessing/MediaExtractionService.php index 9a3721b17..09b3782d6 100644 --- a/app/Services/AdditionalProcessing/MediaExtractionService.php +++ b/app/Services/AdditionalProcessing/MediaExtractionService.php @@ -87,8 +87,9 @@ class MediaExtractionService try { if ($this->ffprobe()->isValid($fileLocation)) { - $this->ffmpeg()->open($fileLocation) - ->frame(TimeCode::fromString($time === '' ? '00:00:03:00' : $time)) + /** @var \FFMpeg\Media\Video $video */ + $video = $this->ffmpeg()->open($fileLocation); + $video->frame(TimeCode::fromString($time === '' ? '00:00:03:00' : $time)) ->save($fileName); } } catch (\Throwable $e) { @@ -138,7 +139,7 @@ class MediaExtractionService } else { $lowestLength = ($numbers[1] - $this->config->ffmpegDuration); $end = '.'.$numbers[2]; - $lowestLength = match (strlen($lowestLength)) { + $lowestLength = match (strlen((string) $lowestLength)) { 1 => '00:00:0'.$lowestLength.$end, 2 => '00:00:'.$lowestLength.$end, default => '00:00:60.00', @@ -147,6 +148,7 @@ class MediaExtractionService try { if ($this->ffprobe()->isValid($fileLocation)) { + /** @var \FFMpeg\Media\Video $video */ $video = $this->ffmpeg()->open($fileLocation); $clip = $video->clip( TimeCode::fromString($lowestLength), @@ -169,6 +171,7 @@ class MediaExtractionService if (! $newMethod) { try { if ($this->ffprobe()->isValid($fileLocation)) { + /** @var \FFMpeg\Media\Video $video */ $video = $this->ffmpeg()->open($fileLocation); $clip = $video->clip( TimeCode::fromSeconds(0), @@ -285,7 +288,7 @@ class MediaExtractionService Category::MOVIE_OTHER, Category::TV_OTHER ), - $rQuery->categories_id + (string) $rQuery->categories_id )) { return $result; } @@ -298,55 +301,53 @@ class MediaExtractionService if (! $result['audioInfo']) { try { $xmlArray = $this->mediaInfo()->getInfo($fileLocation, false); - if ($xmlArray !== null) { - foreach ($xmlArray->getAudios() as $track) { - if ($track->get('album') !== null && $track->get('performer') !== null) { - if ((int) $context->release->predb_id === 0 && $this->config->renameMusicMediaInfo) { - $ext = strtoupper($fileExtension); + foreach ($xmlArray->getAudios() as $track) { + if ($track->get('album') !== null && $track->get('performer') !== null) { + if ((int) $context->release->predb_id === 0 && $this->config->renameMusicMediaInfo) { + $ext = strtoupper($fileExtension); - $newName = $track->get('performer')->getFullName().' - '.$track->get('album')->getFullName(); - if (! empty($track->get('recorded_date')) - && preg_match('/(?:19|20)\d\d/', $track->get('recorded_date')->getFullname, $Year) - ) { - $newName .= ' ('.$Year[0].') '.$ext; - } else { - $newName .= ' '.$ext; - } - - $newCat = match ($ext) { - 'MP3' => Category::MUSIC_MP3, - 'FLAC' => Category::MUSIC_LOSSLESS, - default => $this->categorize->determineCategory($rQuery->groups_id, $newName, $rQuery->fromname), - }; - - $newTitle = escapeString(substr($newName, 0, 255)); - Release::whereId($context->release->id)->update([ - 'searchname' => $newTitle, - 'categories_id' => is_array($newCat) ? $newCat['categories_id'] : $newCat, - 'iscategorized' => 1, - 'isrenamed' => 1, - 'proc_pp' => 1, - ]); - - Search::updateRelease($context->release->id); - - if ($this->config->echoCLI) { - $releaseInfo = (object) [ - 'groups_id' => $rQuery->groups_id, 'categories_id' => $rQuery->categories_id, - 'searchname' => $rQuery->searchname, 'name' => $rQuery->searchname, - 'releases_id' => $context->release->id, 'filename' => '', - ]; - (new ReleaseUpdateService)->echoReleaseInfo($releaseInfo, $newTitle, - is_array($newCat) ? $newCat : ['categories_id' => $newCat], '', - 'MediaExtractionService->getAudioInfo'); - } + $newName = $track->get('performer')->getFullName().' - '.$track->get('album')->getFullName(); + if (! empty($track->get('recorded_date')) + && preg_match('/(?:19|20)\d\d/', $track->get('recorded_date')->getFullname, $Year) + ) { + $newName .= ' ('.$Year[0].') '.$ext; + } else { + $newName .= ' '.$ext; } - $this->releaseExtra->addFromXml($context->release->id, $xmlArray); - $result['audioInfo'] = true; - $context->foundAudioInfo = true; - break; + $newCat = match ($ext) { + 'MP3' => Category::MUSIC_MP3, + 'FLAC' => Category::MUSIC_LOSSLESS, + default => $this->categorize->determineCategory($rQuery->groups_id, $newName, $rQuery->fromname), + }; + + $newTitle = escapeString(substr($newName, 0, 255)); + Release::whereId($context->release->id)->update([ + 'searchname' => $newTitle, + 'categories_id' => is_array($newCat) ? $newCat['categories_id'] : $newCat, + 'iscategorized' => 1, + 'isrenamed' => 1, + 'proc_pp' => 1, + ]); + + Search::updateRelease($context->release->id); + + if ($this->config->echoCLI) { + $releaseInfo = (object) [ + 'groups_id' => $rQuery->groups_id, 'categories_id' => $rQuery->categories_id, + 'searchname' => $rQuery->searchname, 'name' => $rQuery->searchname, + 'releases_id' => $context->release->id, 'filename' => '', + ]; + (new ReleaseUpdateService)->echoReleaseInfo($releaseInfo, $newTitle, + is_array($newCat) ? $newCat : ['categories_id' => $newCat], '', + 'MediaExtractionService->getAudioInfo'); + } } + + $this->releaseExtra->addFromXml($context->release->id, $xmlArray); + $result['audioInfo'] = true; + $context->foundAudioInfo = true; + break; } } } catch (\Throwable $e) { @@ -362,7 +363,7 @@ class MediaExtractionService if ($this->ffprobe()->isValid($fileLocation)) { $audioSample = $this->ffmpeg()->open($fileLocation); $format = new Vorbis; - $audioSample->clip(TimeCode::fromSeconds(30), TimeCode::fromSeconds(30)); + $audioSample->clip(TimeCode::fromSeconds(30), TimeCode::fromSeconds(30)); // @phpstan-ignore method.notFound $audioSample->save($format, $tmpPath.$audioFileName); } } catch (\Throwable $e) { diff --git a/app/Services/AdditionalProcessing/ReleaseFileManager.php b/app/Services/AdditionalProcessing/ReleaseFileManager.php index f7d6aa0be..4cdd6d152 100644 --- a/app/Services/AdditionalProcessing/ReleaseFileManager.php +++ b/app/Services/AdditionalProcessing/ReleaseFileManager.php @@ -13,7 +13,6 @@ use App\Services\NameFixing\ReleaseUpdateService; use App\Services\NfoService; use App\Services\NNTP\NNTPService; use App\Services\Nzb\NzbService; -use App\Services\ReleaseExtraService; use App\Services\ReleaseImageService; use App\Services\Releases\ReleaseBrowseService; use Illuminate\Contracts\Filesystem\FileNotFoundException; @@ -29,7 +28,6 @@ class ReleaseFileManager { public function __construct( private readonly ProcessingConfiguration $config, - private readonly ReleaseExtraService $releaseExtra, private readonly ReleaseImageService $releaseImage, private readonly NfoService $nfo, private readonly NzbService $nzb, @@ -218,7 +216,7 @@ class ReleaseFileManager $this->releaseImage->vidSavePath.$guid.'.ogv', ]; foreach ($files as $file) { - if ($file && File::exists($file)) { + if (File::exists($file)) { File::delete($file); } } @@ -249,7 +247,7 @@ class ReleaseFileManager Release::where('id', $id)->delete(); } catch (\Throwable) { } - } catch (\Throwable) { + } catch (\Throwable) { // @phpstan-ignore catch.neverThrown // Last resort: swallow any exception } } diff --git a/app/Services/AdultProcessing/AdultProcessingPipeline.php b/app/Services/AdultProcessing/AdultProcessingPipeline.php index 62e2c7fa7..fd7f8e9fb 100644 --- a/app/Services/AdultProcessing/AdultProcessingPipeline.php +++ b/app/Services/AdultProcessing/AdultProcessingPipeline.php @@ -676,15 +676,11 @@ class AdultProcessingPipeline */ protected function insertGenre(string $genre): int|string { - if ($genre !== null) { - return Genre::query()->insertGetId([ - 'title' => $genre, - 'type' => Category::XXX_ROOT, - 'disabled' => 0, - ]); - } - - return ''; + return Genre::query()->insertGetId([ + 'title' => $genre, + 'type' => Category::XXX_ROOT, + 'disabled' => 0, + ]); } /** diff --git a/app/Services/AdultProcessing/Pipes/AbstractAdultProviderPipe.php b/app/Services/AdultProcessing/Pipes/AbstractAdultProviderPipe.php index 6c79b126b..c4430a646 100644 --- a/app/Services/AdultProcessing/Pipes/AbstractAdultProviderPipe.php +++ b/app/Services/AdultProcessing/Pipes/AbstractAdultProviderPipe.php @@ -868,7 +868,7 @@ abstract class AbstractAdultProviderPipe foreach ($metaTags as $property => $key) { $meta = $this->getHtmlParser()->findOne('meta[property="'.$property.'"]'); - if ($meta && isset($meta->content)) { + if ($meta && isset($meta->content)) { // @phpstan-ignore booleanAnd.leftAlwaysTrue $og[$key] = trim($meta->content); } } diff --git a/app/Services/AdultProcessing/Pipes/AdePipe.php b/app/Services/AdultProcessing/Pipes/AdePipe.php index a92b74306..20a86db8a 100644 --- a/app/Services/AdultProcessing/Pipes/AdePipe.php +++ b/app/Services/AdultProcessing/Pipes/AdePipe.php @@ -57,7 +57,7 @@ class AdePipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -154,35 +154,12 @@ class AdePipe extends AbstractAdultProviderPipe } // Get all the movie data - $synopsis = $this->extractSynopsis(); - if (is_array($synopsis)) { - $results = array_merge($results, $synopsis); - } - - $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo)) { - $results = array_merge($results, $productInfo); - } - - $cast = $this->extractCast(); - if (is_array($cast)) { - $results = array_merge($results, $cast); - } - - $genres = $this->extractGenres(); - if (is_array($genres)) { - $results = array_merge($results, $genres); - } - - $covers = $this->extractCovers(); - if (is_array($covers)) { - $results = array_merge($results, $covers); - } - - $trailers = $this->extractTrailers(); - if (is_array($trailers)) { - $results = array_merge($results, $trailers); - } + $results = array_merge($results, $this->extractSynopsis()); + $results = array_merge($results, $this->extractProductInfo(true)); + $results = array_merge($results, $this->extractCast()); + $results = array_merge($results, $this->extractGenres()); + $results = array_merge($results, $this->extractCovers()); + $results = array_merge($results, $this->extractTrailers()); if (empty($results)) { return false; @@ -229,7 +206,7 @@ class AdePipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret && isset($ret->src)) { + if ($ret && isset($ret->src)) { // @phpstan-ignore booleanAnd.leftAlwaysTrue // Get high-resolution covers $res['boxcover'] = preg_replace('/[ms]\.jpg$/', 'h.jpg', $ret->src); $res['backcover'] = preg_replace('/[ms]\.jpg$/', 'bh.jpg', $ret->src); @@ -255,7 +232,7 @@ class AdePipe extends AbstractAdultProviderPipe foreach ($selectors as $selector => $property) { $meta = $this->getHtmlParser()->findOne($selector); - if ($meta && isset($meta->$property) && $meta->$property !== false && ! empty(trim($meta->$property))) { + if ($meta && isset($meta->$property) && $meta->$property !== false && ! empty(trim($meta->$property))) { // @phpstan-ignore booleanAnd.leftAlwaysTrue $res['synopsis'] = trim($meta->$property); return $res; @@ -339,7 +316,7 @@ class AdePipe extends AbstractAdultProviderPipe $tmpHtml = new \voku\helper\HtmlDomParser; $tmpHtml->loadHtml($tmpResponse); - if ($ret = $tmpHtml->findOne('div[class=spdinfo]')) { + if ($ret = $tmpHtml->findOne('div[class=spdinfo]')) { // @phpstan-ignore if.alwaysTrue $productinfo = []; $extrasData = []; diff --git a/app/Services/AdultProcessing/Pipes/AdmPipe.php b/app/Services/AdultProcessing/Pipes/AdmPipe.php index abb00f1c5..4fcddc405 100644 --- a/app/Services/AdultProcessing/Pipes/AdmPipe.php +++ b/app/Services/AdultProcessing/Pipes/AdmPipe.php @@ -57,7 +57,7 @@ class AdmPipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -142,30 +142,11 @@ class AdmPipe extends AbstractAdultProviderPipe } // Get all the movie data - $synopsis = $this->extractSynopsis(); - if (is_array($synopsis)) { - $results = array_merge($results, $synopsis); - } - - $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo)) { - $results = array_merge($results, $productInfo); - } - - $cast = $this->extractCast(); - if (is_array($cast)) { - $results = array_merge($results, $cast); - } - - $genres = $this->extractGenres(); - if (is_array($genres)) { - $results = array_merge($results, $genres); - } - - $covers = $this->extractCovers(); - if (is_array($covers)) { - $results = array_merge($results, $covers); - } + $results = array_merge($results, $this->extractSynopsis()); + $results = array_merge($results, $this->extractProductInfo(true)); + $results = array_merge($results, $this->extractCast()); + $results = array_merge($results, $this->extractGenres()); + $results = array_merge($results, $this->extractCovers()); if (empty($results)) { return false; @@ -180,7 +161,7 @@ class AdmPipe extends AbstractAdultProviderPipe $baseUrl = 'https://www.adultdvdmarketplace.com/'; // Try fancybox link first - if ($ret = $this->getHtmlParser()->findOne('a[rel=fancybox-button]')) { + if ($ret = $this->getHtmlParser()->findOne('a[rel=fancybox-button]')) { // @phpstan-ignore if.alwaysTrue if (isset($ret->href) && preg_match('/images\/.*[\d]+\.jpg$/i', $ret->href, $hits)) { $res['boxcover'] = str_starts_with($hits[0], 'http') ? $hits[0] @@ -192,7 +173,7 @@ class AdmPipe extends AbstractAdultProviderPipe } // Try license image - if ($ret = $this->getHtmlParser()->findOne('img[rel=license]')) { + if ($ret = $this->getHtmlParser()->findOne('img[rel=license]')) { // @phpstan-ignore if.alwaysTrue if (isset($ret->src) && preg_match('/images\/.*[\d]+\.jpg$/i', $ret->src, $hits)) { $res['boxcover'] = str_starts_with($hits[0], 'http') ? $hits[0] @@ -224,7 +205,7 @@ class AdmPipe extends AbstractAdultProviderPipe // Fallback: Try meta description $meta = $this->getHtmlParser()->findOne('meta[name="description"]'); - if ($meta && isset($meta->content) && ! empty(trim($meta->content))) { + if ($meta && isset($meta->content) && ! empty(trim($meta->content))) { // @phpstan-ignore booleanAnd.leftAlwaysTrue $res['synopsis'] = trim($meta->content); } @@ -261,7 +242,7 @@ class AdmPipe extends AbstractAdultProviderPipe if (trim($heading->plaintext) === 'Cast') { $next = $heading->nextSibling(); while ($next) { - if ($next->nodeName === 'h3') { + if ($next->nodeName === 'h3') { // @phpstan-ignore property.notFound break; } if (isset($next->href) && preg_match('/search_performerid/', $next->href)) { diff --git a/app/Services/AdultProcessing/Pipes/AebnPipe.php b/app/Services/AdultProcessing/Pipes/AebnPipe.php index ef8f4e409..4f382ac6b 100644 --- a/app/Services/AdultProcessing/Pipes/AebnPipe.php +++ b/app/Services/AdultProcessing/Pipes/AebnPipe.php @@ -79,7 +79,7 @@ class AebnPipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -138,7 +138,7 @@ class AebnPipe extends AbstractAdultProviderPipe $movies = []; foreach ($containerSelectors as $containerSelector) { $movies = $this->getHtmlParser()->find($containerSelector); - if (! empty($movies) && count($movies) > 0) { + if (! empty($movies) && (is_countable($movies) ? count($movies) > 0 : true)) { break; } } @@ -205,32 +205,32 @@ class AebnPipe extends AbstractAdultProviderPipe // Get all the movie data (HTML fallback) $synopsis = $this->extractSynopsis(); - if (is_array($synopsis) && ! empty($synopsis)) { + if (! empty($synopsis)) { $results = array_merge($results, $synopsis); } $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo) && ! empty($productInfo)) { + if (! empty($productInfo)) { $results = array_merge($results, $productInfo); } $cast = $this->extractCast(); - if (is_array($cast) && ! empty($cast)) { + if (! empty($cast)) { $results = array_merge($results, $cast); } $genres = $this->extractGenres(); - if (is_array($genres) && ! empty($genres)) { + if (! empty($genres)) { $results = array_merge($results, $genres); } $covers = $this->extractCovers(); - if (is_array($covers) && ! empty($covers)) { + if (! empty($covers)) { $results = array_merge($results, $covers); } $trailers = $this->extractTrailers(); - if (is_array($trailers) && ! empty($trailers)) { + if (! empty($trailers)) { $results = array_merge($results, $trailers); } @@ -358,7 +358,7 @@ class AebnPipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $coverUrl = $ret->src ?? $ret->content ?? null; if (! empty($coverUrl)) { @@ -447,7 +447,7 @@ class AebnPipe extends AbstractAdultProviderPipe // Fallback: try detailsLink div if (empty($cast)) { $ret = $this->getHtmlParser()->findOne('div.detailsLink'); - if ($ret && ! ($ret instanceof \voku\helper\SimpleHtmlDomNodeBlank)) { + if ($ret && ! ($ret instanceof \voku\helper\SimpleHtmlDomNodeBlank)) { // @phpstan-ignore booleanAnd.leftAlwaysTrue foreach ($ret->find('span') as $star) { $text = $star->plaintext ?? ''; if (str_contains($text, '/More/') && str_contains($text, '/Stars/')) { @@ -527,7 +527,7 @@ class AebnPipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $text = $ret->plaintext ?? $ret->content ?? ''; if (! empty(trim($text))) { $text = trim($text); diff --git a/app/Services/AdultProcessing/Pipes/Data18Pipe.php b/app/Services/AdultProcessing/Pipes/Data18Pipe.php index f57c4e4d8..1dfb60d98 100644 --- a/app/Services/AdultProcessing/Pipes/Data18Pipe.php +++ b/app/Services/AdultProcessing/Pipes/Data18Pipe.php @@ -75,7 +75,7 @@ class Data18Pipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -199,27 +199,27 @@ class Data18Pipe extends AbstractAdultProviderPipe // Get all the movie data (HTML fallback) $synopsis = $this->extractSynopsis(); - if (is_array($synopsis) && ! empty($synopsis)) { + if (! empty($synopsis)) { $results = array_merge($results, $synopsis); } $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo) && ! empty($productInfo)) { + if (! empty($productInfo)) { $results = array_merge($results, $productInfo); } $cast = $this->extractCast(); - if (is_array($cast) && ! empty($cast)) { + if (! empty($cast)) { $results = array_merge($results, $cast); } $genres = $this->extractGenres(); - if (is_array($genres) && ! empty($genres)) { + if (! empty($genres)) { $results = array_merge($results, $genres); } $covers = $this->extractCovers(); - if (is_array($covers) && ! empty($covers)) { + if (! empty($covers)) { $results = array_merge($results, $covers); } @@ -321,7 +321,7 @@ class Data18Pipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $coverUrl = $ret->src ?? $ret->content ?? null; if (! empty($coverUrl)) { @@ -363,7 +363,7 @@ class Data18Pipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $text = $ret->plaintext ?? $ret->content ?? ''; if (! empty(trim($text))) { $res['synopsis'] = trim($text); @@ -459,7 +459,7 @@ class Data18Pipe extends AbstractAdultProviderPipe foreach ($studioSelectors as $selector) { $studio = $this->getHtmlParser()->findOne($selector); - if ($studio) { + if ($studio) { // @phpstan-ignore if.alwaysTrue $res['studio'] = trim($studio->plaintext ?? ''); break; } @@ -474,7 +474,7 @@ class Data18Pipe extends AbstractAdultProviderPipe foreach ($dateSelectors as $selector) { $date = $this->getHtmlParser()->findOne($selector); - if ($date) { + if ($date) { // @phpstan-ignore if.alwaysTrue $res['releasedate'] = $date->datetime ?? trim($date->plaintext ?? ''); break; } @@ -488,7 +488,7 @@ class Data18Pipe extends AbstractAdultProviderPipe foreach ($directorSelectors as $selector) { $director = $this->getHtmlParser()->findOne($selector); - if ($director) { + if ($director) { // @phpstan-ignore if.alwaysTrue $res['director'] = trim($director->plaintext ?? ''); break; } diff --git a/app/Services/AdultProcessing/Pipes/HotmoviesPipe.php b/app/Services/AdultProcessing/Pipes/HotmoviesPipe.php index 0bd35821e..5161f3006 100644 --- a/app/Services/AdultProcessing/Pipes/HotmoviesPipe.php +++ b/app/Services/AdultProcessing/Pipes/HotmoviesPipe.php @@ -59,7 +59,7 @@ class HotmoviesPipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -156,30 +156,11 @@ class HotmoviesPipe extends AbstractAdultProviderPipe } // Get all the movie data - $synopsis = $this->extractSynopsis(); - if (is_array($synopsis)) { - $results = array_merge($results, $synopsis); - } - - $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo)) { - $results = array_merge($results, $productInfo); - } - - $cast = $this->extractCast(); - if (is_array($cast)) { - $results = array_merge($results, $cast); - } - - $genres = $this->extractGenres(); - if (is_array($genres)) { - $results = array_merge($results, $genres); - } - - $covers = $this->extractCovers(); - if (is_array($covers)) { - $results = array_merge($results, $covers); - } + $results = array_merge($results, $this->extractSynopsis()); + $results = array_merge($results, $this->extractProductInfo(true)); + $results = array_merge($results, $this->extractCast()); + $results = array_merge($results, $this->extractGenres()); + $results = array_merge($results, $this->extractCovers()); if (empty($results)) { return false; @@ -203,7 +184,7 @@ class HotmoviesPipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $text = $ret->innerText ?? $ret->plaintext ?? $ret->content ?? ''; if (! empty(trim($text))) { $res['synopsis'] = trim($text); @@ -255,9 +236,7 @@ class HotmoviesPipe extends AbstractAdultProviderPipe } } - if (is_array($productinfo)) { - $res['productinfo'] = array_chunk($productinfo, 2, false); - } + $res['productinfo'] = array_chunk($productinfo, 2, false); } return $res; @@ -269,9 +248,9 @@ class HotmoviesPipe extends AbstractAdultProviderPipe $cast = []; // Prefer scoped search within stars container to avoid unrelated links - if ($container = $this->getHtmlParser()->findOne('.stars')) { + if ($container = $this->getHtmlParser()->findOne('.stars')) { // @phpstan-ignore if.alwaysTrue foreach ($container->find('a[title]') as $e) { - $name = trim($e->title); + $name = trim($e->title); // @phpstan-ignore property.notFound $name = preg_replace('/\((.*)\)/', '', $name); $name = trim($name); if ($name !== '') { @@ -302,9 +281,9 @@ class HotmoviesPipe extends AbstractAdultProviderPipe $res = []; $genres = []; - if ($ret = $this->getHtmlParser()->findOne('div.categories')) { + if ($ret = $this->getHtmlParser()->findOne('div.categories')) { // @phpstan-ignore if.alwaysTrue foreach ($ret->find('a') as $e) { - if (str_contains($e->title, ' -> ')) { + if (str_contains($e->title, ' -> ')) { // @phpstan-ignore property.notFound $e = explode(' -> ', $e->plaintext); $genres[] = trim($e[1]); } @@ -329,7 +308,7 @@ class HotmoviesPipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret && isset($ret->src)) { + if ($ret && isset($ret->src)) { // @phpstan-ignore booleanAnd.leftAlwaysTrue $res['boxcover'] = trim($ret->src); $res['backcover'] = str_ireplace(['.cover', 'front'], ['.back', 'back'], trim($ret->src)); diff --git a/app/Services/AdultProcessing/Pipes/IafdPipe.php b/app/Services/AdultProcessing/Pipes/IafdPipe.php index b9a066395..34e4511ff 100644 --- a/app/Services/AdultProcessing/Pipes/IafdPipe.php +++ b/app/Services/AdultProcessing/Pipes/IafdPipe.php @@ -75,7 +75,7 @@ class IafdPipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -189,27 +189,27 @@ class IafdPipe extends AbstractAdultProviderPipe // Get all the movie data (HTML fallback) $synopsis = $this->extractSynopsis(); - if (is_array($synopsis) && ! empty($synopsis)) { + if (! empty($synopsis)) { $results = array_merge($results, $synopsis); } $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo) && ! empty($productInfo)) { + if (! empty($productInfo)) { $results = array_merge($results, $productInfo); } $cast = $this->extractCast(); - if (is_array($cast) && ! empty($cast)) { + if (! empty($cast)) { $results = array_merge($results, $cast); } $genres = $this->extractGenres(); - if (is_array($genres) && ! empty($genres)) { + if (! empty($genres)) { $results = array_merge($results, $genres); } $covers = $this->extractCovers(); - if (is_array($covers) && ! empty($covers)) { + if (! empty($covers)) { $results = array_merge($results, $covers); } @@ -300,7 +300,7 @@ class IafdPipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $coverUrl = $ret->src ?? $ret->content ?? null; if (! empty($coverUrl)) { @@ -334,7 +334,7 @@ class IafdPipe extends AbstractAdultProviderPipe foreach ($selectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret) { + if ($ret) { // @phpstan-ignore if.alwaysTrue $text = $ret->plaintext ?? $ret->content ?? ''; if (! empty(trim($text))) { $res['synopsis'] = trim($text); @@ -355,7 +355,7 @@ class IafdPipe extends AbstractAdultProviderPipe // IAFD has a specific cast table structure $castTable = $this->getHtmlParser()->findOne('table#perfcast, div#perfcast'); - if ($castTable) { + if ($castTable) { // @phpstan-ignore if.alwaysTrue $performers = $castTable->find('a[href*="/person.rme"]'); foreach ($performers as $performer) { $name = trim($performer->plaintext ?? ''); @@ -434,13 +434,13 @@ class IafdPipe extends AbstractAdultProviderPipe // Look for studio $studio = $this->getHtmlParser()->findOne('a[href*="/studio.rme"]'); - if ($studio) { + if ($studio) { // @phpstan-ignore if.alwaysTrue $res['studio'] = trim($studio->plaintext ?? ''); } // Look for distributor $distributor = $this->getHtmlParser()->findOne('a[href*="/distrib.rme"]'); - if ($distributor) { + if ($distributor) { // @phpstan-ignore if.alwaysTrue $res['distributor'] = trim($distributor->plaintext ?? ''); } @@ -457,7 +457,7 @@ class IafdPipe extends AbstractAdultProviderPipe foreach ($directorSelectors as $selector) { $director = $this->getHtmlParser()->findOne($selector); - if ($director) { + if ($director) { // @phpstan-ignore if.alwaysTrue $res['director'] = trim($director->plaintext ?? ''); break; } @@ -475,7 +475,7 @@ class IafdPipe extends AbstractAdultProviderPipe } if (stripos($text, 'Studio:') !== false) { $parts = explode(':', $text, 2); - if (count($parts) === 2 && empty($res['studio'] ?? '')) { + if (count($parts) === 2 && empty($res['studio'])) { $res['studio'] = trim($parts[1]); } } diff --git a/app/Services/AdultProcessing/Pipes/PoppornPipe.php b/app/Services/AdultProcessing/Pipes/PoppornPipe.php index 82c506dc2..f860d1b25 100644 --- a/app/Services/AdultProcessing/Pipes/PoppornPipe.php +++ b/app/Services/AdultProcessing/Pipes/PoppornPipe.php @@ -57,7 +57,7 @@ class PoppornPipe extends AbstractAdultProviderPipe // Fetch the movie details page $this->response = $this->fetchHtml($this->directUrl, $this->cookie); - if ($this->response === false) { + if ($this->response === false) { // @phpstan-ignore identical.alwaysFalse return AdultProcessingResult::failed('Failed to fetch movie details page', $this->getName()); } @@ -112,7 +112,7 @@ class PoppornPipe extends AbstractAdultProviderPipe if (! empty($results)) { foreach ($results as $result) { $title = $result->title ?? $result->plaintext; - $url = $result->href; + $url = $result->href; // @phpstan-ignore property.notFound if (! empty($title)) { $similarity = $this->calculateSimilarity($movie, $title); @@ -150,35 +150,12 @@ class PoppornPipe extends AbstractAdultProviderPipe } // Get all the movie data - $synopsis = $this->extractSynopsis(); - if (is_array($synopsis)) { - $results = array_merge($results, $synopsis); - } - - $productInfo = $this->extractProductInfo(true); - if (is_array($productInfo)) { - $results = array_merge($results, $productInfo); - } - - $cast = $this->extractCast(); - if (is_array($cast)) { - $results = array_merge($results, $cast); - } - - $genres = $this->extractGenres(); - if (is_array($genres)) { - $results = array_merge($results, $genres); - } - - $covers = $this->extractCovers(); - if (is_array($covers)) { - $results = array_merge($results, $covers); - } - - $trailers = $this->extractTrailers(); - if (is_array($trailers)) { - $results = array_merge($results, $trailers); - } + $results = array_merge($results, $this->extractSynopsis()); + $results = array_merge($results, $this->extractProductInfo(true)); + $results = array_merge($results, $this->extractCast()); + $results = array_merge($results, $this->extractGenres()); + $results = array_merge($results, $this->extractCovers()); + $results = array_merge($results, $this->extractTrailers()); if (empty($results)) { return false; @@ -213,8 +190,8 @@ class PoppornPipe extends AbstractAdultProviderPipe ]; foreach ($selectors as $selector) { - if ($ret = $this->getHtmlParser()->findOne($selector)) { - $res['boxcover'] = $ret->href ?? $ret->src; + if ($ret = $this->getHtmlParser()->findOne($selector)) { // @phpstan-ignore if.alwaysTrue + $res['boxcover'] = $ret->href ?? $ret->src; // @phpstan-ignore property.notFound // Try to determine backcover if (stripos($res['boxcover'], '_aa') !== false) { @@ -227,7 +204,7 @@ class PoppornPipe extends AbstractAdultProviderPipe } } - return $res; + return $res; // @phpstan-ignore deadCode.unreachable } protected function extractSynopsis(): array @@ -250,8 +227,8 @@ class PoppornPipe extends AbstractAdultProviderPipe ]; foreach ($selectors as $selector) { - if ($ret = $this->getHtmlParser()->findOne($selector)) { - $text = $ret->plaintext ?? $ret->content; + if ($ret = $this->getHtmlParser()->findOne($selector)) { // @phpstan-ignore if.alwaysTrue + $text = $ret->plaintext ?? $ret->content; // @phpstan-ignore property.notFound // Filter out "POPPORN EXCLUSIVE" text if (stripos(trim($text), 'POPPORN EXCLUSIVE') !== false) { @@ -294,7 +271,7 @@ class PoppornPipe extends AbstractAdultProviderPipe foreach ($videoSelectors as $selector) { $ret = $this->getHtmlParser()->findOne($selector); - if ($ret && isset($ret->src) && ! empty(trim($ret->src))) { + if ($ret && isset($ret->src) && ! empty(trim($ret->src))) { // @phpstan-ignore booleanAnd.leftAlwaysTrue $res['trailers']['url'] = trim($ret->src); return $res; @@ -323,7 +300,7 @@ class PoppornPipe extends AbstractAdultProviderPipe ]; foreach ($selectors as $selector) { - if ($ret = $this->getHtmlParser()->findOne($selector)) { + if ($ret = $this->getHtmlParser()->findOne($selector)) { // @phpstan-ignore if.alwaysTrue // Extract country information $country = false; $rawInfo = []; @@ -369,7 +346,7 @@ class PoppornPipe extends AbstractAdultProviderPipe ]; foreach ($featureSelectors as $selector) { - if ($ret = $this->getHtmlParser()->findOne($selector)) { + if ($ret = $this->getHtmlParser()->findOne($selector)) { // @phpstan-ignore if.alwaysTrue foreach ($ret->find('li') as $e) { $text = trim($e->plaintext); if ($text === 'Features:') { diff --git a/app/Services/AnimeProcessor.php b/app/Services/AnimeProcessor.php index 503aecf5e..b39bc69a0 100644 --- a/app/Services/AnimeProcessor.php +++ b/app/Services/AnimeProcessor.php @@ -39,6 +39,8 @@ class AnimeProcessor * Simple cache of looked up titles -> anilist_id to reduce repeat queries within one run. * * @var array + * + * @phpstan-ignore property.onlyWritten */ private array $anilistIdCache = []; @@ -314,7 +316,7 @@ class AnimeProcessor // Not found locally, search AniList API try { $searchResults = $this->palist->searchAnime($searchName, 1); - if ($searchResults && ! empty($searchResults)) { + if ($searchResults) { $anilistData = $searchResults[0]; $anilistId = $anilistData['id'] ?? null; @@ -395,7 +397,7 @@ class AnimeProcessor // Search AniList for this title try { $searchResults = $this->palist->searchAnime($title, 1); - if ($searchResults && ! empty($searchResults)) { + if ($searchResults) { $anilistId = $searchResults[0]['id'] ?? null; } } catch (\Exception $e) { diff --git a/app/Services/Archives/SevenZipPartialParser.php b/app/Services/Archives/SevenZipPartialParser.php index 66d5f63a0..5aaa05839 100644 --- a/app/Services/Archives/SevenZipPartialParser.php +++ b/app/Services/Archives/SevenZipPartialParser.php @@ -103,12 +103,15 @@ class SevenZipPartialParser private const K_WIN_ATTRIBUTES = 0x15; + /** @phpstan-ignore classConstant.unused */ private const K_COMMENT = 0x16; private const K_ENCODED_HEADER = 0x17; + /** @phpstan-ignore classConstant.unused */ private const K_START_POS = 0x18; + /** @phpstan-ignore classConstant.unused */ private const K_DUMMY = 0x19; // Compression method IDs @@ -120,8 +123,10 @@ class SevenZipPartialParser private const METHOD_PPMD = "\x03\x04\x01"; + /** @phpstan-ignore classConstant.unused */ private const METHOD_BCJ = "\x03\x03\x01\x03"; + /** @phpstan-ignore classConstant.unused */ private const METHOD_BCJ2 = "\x03\x03\x01\x1B"; private const METHOD_DEFLATE = "\x04\x01\x08"; @@ -131,14 +136,18 @@ class SevenZipPartialParser private const METHOD_AES = "\x06\xF1\x07\x01"; // Windows file attributes + /** @phpstan-ignore classConstant.unused */ private const FILE_ATTRIBUTE_READONLY = 0x01; + /** @phpstan-ignore classConstant.unused */ private const FILE_ATTRIBUTE_HIDDEN = 0x02; + /** @phpstan-ignore classConstant.unused */ private const FILE_ATTRIBUTE_SYSTEM = 0x04; private const FILE_ATTRIBUTE_DIRECTORY = 0x10; + /** @phpstan-ignore classConstant.unused */ private const FILE_ATTRIBUTE_ARCHIVE = 0x20; public function __construct(string $data) @@ -1562,6 +1571,8 @@ class SevenZipPartialParser /** * Reads a 7z variable-length integer at offset, returns value via reference. + * + * @param-out int $value */ private function readVIntAt(int $offset, ?int &$value, ?int &$newOffset, int $limit): bool { diff --git a/app/Services/Backfill/BackfillService.php b/app/Services/Backfill/BackfillService.php index 053a10db5..cf32c9b6e 100644 --- a/app/Services/Backfill/BackfillService.php +++ b/app/Services/Backfill/BackfillService.php @@ -122,7 +122,7 @@ final class BackfillService public function safeBackfill(int|string $articles = ''): void { $group = UsenetGroup::query() - ->whereBetween('first_record_postdate', [Carbon::createFromDate($this->config->safeBackFillDate), now()]) + ->whereBetween('first_record_postdate', [Carbon::createFromDate((int) $this->config->safeBackFillDate), now()]) ->where('backfill', '=', 1) ->select(['name']) ->orderBy('name') diff --git a/app/Services/Binaries/BinariesService.php b/app/Services/Binaries/BinariesService.php index cd4eab7d3..67e5e3f2c 100644 --- a/app/Services/Binaries/BinariesService.php +++ b/app/Services/Binaries/BinariesService.php @@ -165,7 +165,7 @@ class BinariesService $endTime = now()->diffInSeconds($allTime, true); $this->log( - 'Updating completed in '.$endTime.Str::plural(' second', $endTime), + 'Updating completed in '.$endTime.Str::plural(' second', (int) $endTime), __FUNCTION__, 'primary' ); @@ -238,7 +238,7 @@ class BinariesService if ($this->config->echoCli) { $endGroup = now()->diffInSeconds($startGroup, true); cli()->primary( - PHP_EOL.'Group '.$groupMySQL['name'].' processed in '.$endGroup.Str::plural(' second', $endGroup) + PHP_EOL.'Group '.$groupMySQL['name'].' processed in '.$endGroup.Str::plural(' second', (int) $endGroup) ); } } diff --git a/app/Services/Binaries/PartHandler.php b/app/Services/Binaries/PartHandler.php index 2019f9172..b56c6ddcc 100644 --- a/app/Services/Binaries/PartHandler.php +++ b/app/Services/Binaries/PartHandler.php @@ -23,6 +23,7 @@ final class PartHandler private int $chunkSize; + /** @phpstan-ignore property.onlyWritten */ private bool $addToPartRepair; public function __construct(int $chunkSize = 5000, bool $addToPartRepair = true) diff --git a/app/Services/BookService.php b/app/Services/BookService.php index 6387d4ac5..97931e396 100644 --- a/app/Services/BookService.php +++ b/app/Services/BookService.php @@ -49,7 +49,7 @@ class BookService $this->sleeptime = Settings::settingValue('amazonsleep') !== '' ? (int) Settings::settingValue('amazonsleep') : 1000; $this->imgSavePath = storage_path('covers/book/'); - $this->bookreqids = Category::BOOKS_EBOOK; + $this->bookreqids = (string) Category::BOOKS_EBOOK; $this->renamed = (int) Settings::settingValue('lookupbooks') === 2 ? 'AND isrenamed = 1' : ''; $this->failCache = []; @@ -159,8 +159,8 @@ class BookService %s GROUP BY boo.id ORDER BY %s %s', - \is_array($bookIDs) && ! empty($bookIDs) ? implode(',', $bookIDs) : -1, - \is_array($releaseIDs) && ! empty($releaseIDs) ? implode(',', $releaseIDs) : -1, + ! empty($bookIDs) ? implode(',', $bookIDs) : -1, + ! empty($releaseIDs) ? implode(',', $releaseIDs) : -1, $catsrch, $order[0], $order[1] @@ -368,7 +368,7 @@ class BookService // Sleep to not flood amazon. $diff = floor((now()->timestamp - $startTime) * 1000000); if ($this->sleeptime * 1000 - $diff > 0 && $usedAmazon === true) { - usleep($this->sleeptime * 1000 - $diff); + usleep((int) ($this->sleeptime * 1000 - $diff)); } } } elseif ($this->echooutput) { @@ -445,12 +445,8 @@ class BookService $book = false; if ($bookInfo !== '') { - if (! $book) { - cli()->info('Fetching data from iTunes for '.$bookInfo); - $book = $this->fetchItunesBookProperties($bookInfo); - } elseif ($amazdata !== null) { - $book = $amazdata; - } + cli()->info('Fetching data from iTunes for '.$bookInfo); + $book = $this->fetchItunesBookProperties($bookInfo); } if (empty($book)) { @@ -479,9 +475,7 @@ class BookService ] ); } else { - if ($check !== null) { - $bookId = $check['id']; - } + $bookId = $check['id']; BookInfo::query()->where('id', $bookId)->update( [ 'title' => $book['title'], diff --git a/app/Services/BooksProcessor.php b/app/Services/BooksProcessor.php index 4a3d64094..879a4caad 100644 --- a/app/Services/BooksProcessor.php +++ b/app/Services/BooksProcessor.php @@ -6,6 +6,7 @@ use App\Models\Settings; class BooksProcessor { + /** @phpstan-ignore property.onlyWritten */ private bool $echooutput; public function __construct(bool $echooutput) diff --git a/app/Services/Categorization/CategorizationService.php b/app/Services/Categorization/CategorizationService.php index 1863ecd0c..9b39ab8b3 100644 --- a/app/Services/Categorization/CategorizationService.php +++ b/app/Services/Categorization/CategorizationService.php @@ -2,6 +2,7 @@ namespace App\Services\Categorization; +use App\Models\Category; use App\Services\Categorization\Pipes\AbstractCategorizationPipe; /** @@ -79,6 +80,55 @@ class CategorizationService return $this; } + /** + * Compare pipeline categorization against the legacy Blacklight\Categorize class. + * + * Returns an array with 'pipeline', 'legacy', and 'match' keys so callers + * can verify the new pipeline produces the same results as the old categorizer. + * + * @param int|string $groupId The usenet group ID + * @param string $releaseName The name of the release + * @return array{pipeline: array{category_id: int, category_name: string}, legacy: array{category_id: int, category_name: string}, match: bool} + */ + public function compare(int|string $groupId, string $releaseName): array + { + // Run the new pipeline categorization + $pipelineResult = $this->determineCategory($groupId, $releaseName); + $pipelineCategoryId = $pipelineResult['categories_id']; + $pipelineCategory = Category::find($pipelineCategoryId); + $pipelineCategoryName = $pipelineCategory ? $pipelineCategory->title : 'Unknown'; + + // Attempt legacy categorization if the class still exists + $legacyCategoryId = Category::OTHER_MISC; + $legacyCategoryName = 'Unknown'; + + if (class_exists(\Blacklight\Categorize::class)) { + try { + $legacy = new \Blacklight\Categorize; + /** @var int $legacyCategoryId */ + $legacyCategoryId = (int) $legacy->determineCategory($groupId, $releaseName); + $legacyCategory = Category::find($legacyCategoryId); + $legacyCategoryName = $legacyCategory ? $legacyCategory->title : 'Unknown'; + } catch (\Throwable) { + $legacyCategoryName = 'Legacy error'; + } + } else { + $legacyCategoryName = 'Legacy unavailable'; + } + + return [ + 'pipeline' => [ + 'category_id' => $pipelineCategoryId, + 'category_name' => $pipelineCategoryName, + ], + 'legacy' => [ + 'category_id' => $legacyCategoryId, + 'category_name' => $legacyCategoryName, + ], + 'match' => $pipelineCategoryId === $legacyCategoryId, + ]; + } + /** * Get statistics about categorizer usage. */ diff --git a/app/Services/CollectionCleanupService.php b/app/Services/CollectionCleanupService.php index ea2aae910..a17aeaa52 100644 --- a/app/Services/CollectionCleanupService.php +++ b/app/Services/CollectionCleanupService.php @@ -76,7 +76,7 @@ class CollectionCleanupService $elapsed = now()->diffInSeconds($startTime, true); cli()->primary( 'Finished deleting '.$batchDeleted.' old collections/binaries/parts in '. - $elapsed.Str::plural(' second', $elapsed), + $elapsed.Str::plural(' second', (int) $elapsed), true ); } @@ -105,7 +105,7 @@ class CollectionCleanupService $totalTime = now()->diffInSeconds($startTime); if ($echoCLI) { - cli()->primary('Finished deleting '.$deleted.' orphaned collections in '.$totalTime.Str::plural(' second', $totalTime), true); + cli()->primary('Finished deleting '.$deleted.' orphaned collections in '.$totalTime.Str::plural(' second', (int) $totalTime), true); } } @@ -130,8 +130,8 @@ class CollectionCleanupService if ($echoCLI) { cli()->primary( - 'Finished deleting '.$deleted.' collections missed after NZB creation in '.($totalTime).Str::plural(' second', $totalTime). - PHP_EOL.'Removed '.number_format($deletedCount).' parts/binaries/collection rows in '.$totalTime.Str::plural(' second', $totalTime), + 'Finished deleting '.$deleted.' collections missed after NZB creation in '.($totalTime).Str::plural(' second', (int) $totalTime). + PHP_EOL.'Removed '.number_format($deletedCount).' parts/binaries/collection rows in '.$totalTime.Str::plural(' second', (int) $totalTime), true ); } diff --git a/app/Services/ConsoleService.php b/app/Services/ConsoleService.php index bedd2759b..c4f0a9362 100644 --- a/app/Services/ConsoleService.php +++ b/app/Services/ConsoleService.php @@ -350,7 +350,6 @@ class ConsoleService /** * Update console info from IGDB. * - * @return int|mixed * * @throws \Exception */ @@ -460,7 +459,7 @@ class ConsoleService 'publisher' => ! empty($publishers) ? implode(',', $publishers) : 'Unknown', 'platform' => $platform ?? '', 'consolegenre' => ! empty($genres) ? implode(',', $genres) : 'Unknown', - 'consolegenreid' => $genreKey ?? '', + 'consolegenreid' => $genreKey, 'salesrank' => '', ]; } @@ -538,8 +537,7 @@ class ConsoleService } elseif ($gameCheck === false) { $gameId = $this->updateConsoleInfo($gameInfo); $usedAmazon = true; - if ($gameId === null) { - $gameId = -2; + if ($gameId === self::CONS_NTFND) { $this->failCache[] = $gameInfo['title'].$gameInfo['platform']; } } else { @@ -728,8 +726,6 @@ class ConsoleService /** * Update or create console info in the database. - * - * @return int|mixed */ protected function updateConsoleTable(array $con = []): int { diff --git a/app/Services/ConsolesProcessor.php b/app/Services/ConsolesProcessor.php index e4e1b99b2..4c8a353b2 100644 --- a/app/Services/ConsolesProcessor.php +++ b/app/Services/ConsolesProcessor.php @@ -6,6 +6,7 @@ use App\Models\Settings; class ConsolesProcessor { + /** @phpstan-ignore property.onlyWritten */ private bool $echooutput; public function __construct(bool $echooutput) diff --git a/app/Services/GamesProcessor.php b/app/Services/GamesProcessor.php index 8370503f4..fa7fa49ef 100644 --- a/app/Services/GamesProcessor.php +++ b/app/Services/GamesProcessor.php @@ -6,6 +6,7 @@ use App\Models\Settings; class GamesProcessor { + /** @phpstan-ignore property.onlyWritten */ private bool $echooutput; private GamesService $gamesService; diff --git a/app/Services/GamesService.php b/app/Services/GamesService.php index a70ddfac9..cb3806438 100644 --- a/app/Services/GamesService.php +++ b/app/Services/GamesService.php @@ -170,7 +170,7 @@ class GamesService */ public function getCount(): int { - return GamesInfo::query()->count(['id']) ?? 0; + return GamesInfo::query()->count('id') ?? 0; } /** @@ -470,7 +470,7 @@ class GamesService if (! empty($steamResults['releasedate'])) { $dateReleased = strtotime($steamResults['releasedate']) === false ? '' : $steamResults['releasedate']; - $game['releasedate'] = ($steamResults['releasedate'] === '' || strtotime($steamResults['releasedate']) === false) + $game['releasedate'] = (strtotime($steamResults['releasedate']) === false) ? null : Carbon::createFromFormat('M j, Y', Carbon::parse($dateReleased)->toFormattedDateString())->format('Y-m-d'); } @@ -703,10 +703,6 @@ class GamesService if ($gameId === false) { $gameId = -2; $this->failedCount++; - - if ($this->maxHitRequest === true) { - $gameId = 0; - } } } else { $gameId = $gameCheck['id']; diff --git a/app/Services/GenreService.php b/app/Services/GenreService.php index 19178e8cb..98f84792b 100644 --- a/app/Services/GenreService.php +++ b/app/Services/GenreService.php @@ -39,6 +39,7 @@ class GenreService $genres = $this->getGenres($type); $genresArray = []; foreach ($genres as $genre) { + /** @var \App\Models\Genre $genre */ $genresArray[$genre->id] = strtolower($genre->title); } diff --git a/app/Services/IGDBService.php b/app/Services/IGDBService.php index 2d6e0286f..e1dca5426 100644 --- a/app/Services/IGDBService.php +++ b/app/Services/IGDBService.php @@ -14,6 +14,9 @@ use MarcReichel\IGDBLaravel\Models\Game; /** * IGDBService - IGDB (Internet Game Database) API integration. * + * Note: MarcReichel\IGDBLaravel\Models\Game and Company use dynamic properties + * (name, id, etc.) that PHPStan cannot resolve. + * * Features: * - Rate limiting and caching * - Multiple search strategies for better matching @@ -79,7 +82,7 @@ class IGDBService if ($game !== null) { Cache::put($cacheKey, $game, self::GAME_CACHE_TTL); - Log::info('IGDBService: Found match', ['title' => $title, 'matched' => $game->name]); + Log::info('IGDBService: Found match', ['title' => $title, 'matched' => $game->name]); // @phpstan-ignore property.notFound } else { Cache::put("igdb_search_failed:{$cacheKey}", true, self::FAILED_LOOKUP_CACHE_TTL); Log::debug('IGDBService: No match found', ['title' => $title]); @@ -125,7 +128,7 @@ class IGDBService // Strategy 1: Exact name search with PC platform filter $game = $this->searchExact($title); if ($game !== null) { - Log::debug('IGDBService: Exact match found', ['title' => $title, 'matched' => $game->name]); + Log::debug('IGDBService: Exact match found', ['title' => $title, 'matched' => $game->name]); // @phpstan-ignore property.notFound return $game; } @@ -133,7 +136,7 @@ class IGDBService // Strategy 2: Fuzzy search using IGDB's search endpoint $game = $this->searchFuzzy($title); if ($game !== null) { - Log::debug('IGDBService: Fuzzy match found', ['title' => $title, 'matched' => $game->name]); + Log::debug('IGDBService: Fuzzy match found', ['title' => $title, 'matched' => $game->name]); // @phpstan-ignore property.notFound return $game; } @@ -143,7 +146,7 @@ class IGDBService if ($cleanTitle !== $title && $cleanTitle !== '') { $game = $this->searchFuzzy($cleanTitle); if ($game !== null) { - Log::debug('IGDBService: Clean title match found', ['title' => $title, 'matched' => $game->name]); + Log::debug('IGDBService: Clean title match found', ['title' => $title, 'matched' => $game->name]); // @phpstan-ignore property.notFound return $game; } @@ -154,7 +157,7 @@ class IGDBService if ($baseTitle !== $title && $baseTitle !== $cleanTitle && $baseTitle !== '') { $game = $this->searchFuzzy($baseTitle); if ($game !== null) { - Log::debug('IGDBService: Base title match found', ['title' => $title, 'matched' => $game->name]); + Log::debug('IGDBService: Base title match found', ['title' => $title, 'matched' => $game->name]); // @phpstan-ignore property.notFound return $game; } @@ -316,13 +319,13 @@ class IGDBService if ($isPublisher === true && $companyId) { $companyData = Company::find($companyId); if ($companyData) { - $publishers[] = $companyData->name; + $publishers[] = $companyData->name; // @phpstan-ignore property.notFound } } if ($isDeveloper === true && $companyId) { $companyData = Company::find($companyId); if ($companyData) { - $developers[] = $companyData->name; + $developers[] = $companyData->name; // @phpstan-ignore property.notFound } } } @@ -346,22 +349,22 @@ class IGDBService $releaseDate = $this->getReleaseDate($game); // Get game URL - $gameUrl = $game->url ?? ('https://www.igdb.com/games/'.($game->slug ?? $game->id)); + $gameUrl = $game->url ?? ('https://www.igdb.com/games/'.($game->slug ?? $game->id)); // @phpstan-ignore property.notFound // Build review text $review = $this->buildReview($game, $developers); Log::info('IGDBService: Game data built', [ - 'title' => $game->name, - 'id' => $game->id, + 'title' => $game->name, // @phpstan-ignore property.notFound + 'id' => $game->id, // @phpstan-ignore property.notFound 'has_cover' => ! empty($coverUrl), 'has_backdrop' => ! empty($backdropUrl), 'genres' => $genres, ]); return [ - 'title' => $game->name, - 'asin' => 'igdb-'.$game->id, + 'title' => $game->name, // @phpstan-ignore property.notFound + 'asin' => 'igdb-'.$game->id, // @phpstan-ignore property.notFound 'review' => $review, 'coverurl' => $coverUrl, 'releasedate' => $releaseDate, @@ -658,19 +661,15 @@ class IGDBService $genreName = ''; $a = str_replace('-', ' ', $genre); $tmpGenre = explode(',', $a); - if (is_array($tmpGenre)) { - foreach ($tmpGenre as $tg) { - $genreMatch = $this->isKnownGenre(ucwords(trim($tg))); - if ($genreMatch !== false) { - $genreName = (string) $genreMatch; - break; - } + foreach ($tmpGenre as $tg) { + $genreMatch = $this->isKnownGenre(ucwords(trim($tg))); + if ($genreMatch !== false) { + $genreName = (string) $genreMatch; + break; } if (empty($genreName) && ! empty($tmpGenre[0])) { $genreName = trim($tmpGenre[0]); } - } else { - $genreName = $genre; } return $genreName; diff --git a/app/Services/IRCClient.php b/app/Services/IRCClient.php index 183445c8e..cc3282154 100644 --- a/app/Services/IRCClient.php +++ b/app/Services/IRCClient.php @@ -63,7 +63,7 @@ class IRCClient /** * Stream socket client. * - * @var resource + * @var resource|null */ protected $_socket = null; @@ -326,7 +326,7 @@ class IRCClient */ public function readIncoming(): void { - while (true) { + while (true) { // @phpstan-ignore while.alwaysTrue $this->_readSocket(); // If the server pings us, return it a pong. diff --git a/app/Services/ImdbScraper.php b/app/Services/ImdbScraper.php index 6b80296d6..a5e394678 100644 --- a/app/Services/ImdbScraper.php +++ b/app/Services/ImdbScraper.php @@ -3,7 +3,6 @@ namespace App\Services; use GuzzleHttp\Client; -use GuzzleHttp\Exception\GuzzleException; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; use voku\helper\HtmlDomParser; @@ -49,7 +48,7 @@ class ImdbScraper } $titleNode = $dom->findOne('h1'); - $title = trim($titleNode?->text() ?? ''); + $title = trim($titleNode->text() ?? ''); if ($title === '') { Cache::put($cacheKey, false, now()->addHours(6)); @@ -164,7 +163,7 @@ class ImdbScraper Cache::put($cacheKey, $data, now()->addDays(7)); return $data; - } catch (GuzzleException|\Throwable $e) { + } catch (\Throwable $e) { Log::debug('IMDb fetch error tt'.$id.': '.$e->getMessage()); Cache::put($cacheKey, false, now()->addHours(6)); @@ -215,7 +214,7 @@ class ImdbScraper Cache::put($cacheKey, $results, now()->addHours(12)); return $results; - } catch (GuzzleException|\Throwable $e) { + } catch (\Throwable $e) { Log::debug('IMDb search error '.$query.': '.$e->getMessage()); Cache::put($cacheKey, [], now()->addHours(6)); diff --git a/app/Services/MediaProcessingService.php b/app/Services/MediaProcessingService.php index 976474133..986d37c18 100644 --- a/app/Services/MediaProcessingService.php +++ b/app/Services/MediaProcessingService.php @@ -121,8 +121,9 @@ class MediaProcessingService $time = $this->getVideoTime($fileLocation); if ($this->ffprobe->isValid($fileLocation)) { try { - $this->ffmpeg->open($fileLocation) - ->frame(TimeCode::fromString($time === '' ? '00:00:03:00' : $time)) + /** @var \FFMpeg\Media\Video $video */ + $video = $this->ffmpeg->open($fileLocation); + $video->frame(TimeCode::fromString($time === '' ? '00:00:03:00' : $time)) ->save($fileName); } catch (\Throwable $e) { if (config('app.debug') === true) { @@ -175,6 +176,7 @@ class MediaProcessingService } if ($this->ffprobe->isValid($fileLocation)) { try { + /** @var \FFMpeg\Media\Video $video */ $video = $this->ffmpeg->open($fileLocation); $videoSample = $video->clip(TimeCode::fromString($lowestLength), TimeCode::fromSeconds($durationSeconds)); $format = new Ogg; @@ -191,6 +193,7 @@ class MediaProcessingService } if (! $newMethod && $this->ffprobe->isValid($fileLocation)) { try { + /** @var \FFMpeg\Media\Video $video */ $video = $this->ffmpeg->open($fileLocation); $videoSample = $video->clip(TimeCode::fromSeconds(0), TimeCode::fromSeconds($durationSeconds)); $format = new Ogg; @@ -255,37 +258,35 @@ class MediaProcessingService if ($processAudioInfo) { try { $xmlArray = $this->mediaInfo->getInfo($fileLocation, false); - if ($xmlArray !== null) { - foreach ($xmlArray->getAudios() as $track) { - if ($track->get('album') !== null && $track->get('performer') !== null) { - if ((int) $release->predb_id === 0 && config('nntmux.rename_music_mediainfo')) { - $ext = strtoupper($fileExtension); - if (! empty($track->get('recorded_date')) && preg_match('/(?:19|20)\d\d/', $track->get('recorded_date')->getFullname(), $Year)) { - $newName = $track->get('performer')->getFullName().' - '.$track->get('album')->getFullName().' ('.$Year[0].') '.$ext; - } else { - $newName = $track->get('performer')->getFullName().' - '.$track->get('album')->getFullName().' '.$ext; - } - if ($ext === 'MP3') { - $newCat = Category::MUSIC_MP3; - } elseif ($ext === 'FLAC') { - $newCat = Category::MUSIC_LOSSLESS; - } else { - $newCat = $this->categorize->determineCategory($release->groups_id, $newName, $release->fromname); - } - $newTitle = escapeString(substr($newName, 0, 255)); - Release::whereId($release->id)->update([ - 'searchname' => $newTitle, - 'categories_id' => $newCat['categories_id'] ?? $release->categories_id, - 'iscategorized' => 1, - 'isrenamed' => 1, - 'proc_pp' => 1, - ]); - Search::updateRelease($release->id); + foreach ($xmlArray->getAudios() as $track) { + if ($track->get('album') !== null && $track->get('performer') !== null) { + if ((int) $release->predb_id === 0 && config('nntmux.rename_music_mediainfo')) { + $ext = strtoupper($fileExtension); + if (! empty($track->get('recorded_date')) && preg_match('/(?:19|20)\d\d/', $track->get('recorded_date')->getFullname(), $Year)) { + $newName = $track->get('performer')->getFullName().' - '.$track->get('album')->getFullName().' ('.$Year[0].') '.$ext; + } else { + $newName = $track->get('performer')->getFullName().' - '.$track->get('album')->getFullName().' '.$ext; } - $this->releaseExtra->addFromXml($release->id, $xmlArray); - $retVal = true; - break; + if ($ext === 'MP3') { + $newCat = Category::MUSIC_MP3; + } elseif ($ext === 'FLAC') { + $newCat = Category::MUSIC_LOSSLESS; + } else { + $newCat = $this->categorize->determineCategory($release->groups_id, $newName, $release->fromname); + } + $newTitle = escapeString(substr($newName, 0, 255)); + Release::whereId($release->id)->update([ + 'searchname' => $newTitle, + 'categories_id' => $newCat['categories_id'] ?? $release->categories_id, + 'iscategorized' => 1, + 'isrenamed' => 1, + 'proc_pp' => 1, + ]); + Search::updateRelease($release->id); } + $this->releaseExtra->addFromXml($release->id, $xmlArray); + $retVal = true; + break; } } } catch (\Throwable $e) { @@ -299,7 +300,7 @@ class MediaProcessingService try { $audioSample = $this->ffmpeg->open($fileLocation); $format = new Vorbis; - $audioSample->clip(TimeCode::fromSeconds(30), TimeCode::fromSeconds(30)); + $audioSample->clip(TimeCode::fromSeconds(30), TimeCode::fromSeconds(30)); // @phpstan-ignore method.notFound $audioSample->save($format, $audioSavePath.$audioFileName); } catch (\Throwable $e) { if (config('app.debug') === true) { diff --git a/app/Services/MovieBrowseService.php b/app/Services/MovieBrowseService.php index efcabf1cf..499f6c931 100644 --- a/app/Services/MovieBrowseService.php +++ b/app/Services/MovieBrowseService.php @@ -59,8 +59,8 @@ class MovieBrowseService $releaseIDs[] = $id->grp_release_id; } } - $inMovieIds = (is_array($movieIDs) && ! empty($movieIDs)) ? implode(',', $movieIDs) : -1; - $inReleaseIds = (is_array($releaseIDs) && ! empty($releaseIDs)) ? implode(',', $releaseIDs) : -1; + $inMovieIds = ! empty($movieIDs) ? implode(',', $movieIDs) : -1; + $inReleaseIds = ! empty($releaseIDs) ? implode(',', $releaseIDs) : -1; $sql = 'SELECT ' ."GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',' ) AS grp_release_id, " ."GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',' ) AS grp_rarinnerfilecount, " diff --git a/app/Services/MoviesProcessor.php b/app/Services/MoviesProcessor.php index e9ecc1f2c..9ba7d0420 100644 --- a/app/Services/MoviesProcessor.php +++ b/app/Services/MoviesProcessor.php @@ -7,6 +7,7 @@ use GuzzleHttp\Exception\GuzzleException; class MoviesProcessor { + /** @phpstan-ignore property.onlyWritten */ private bool $echooutput; public function __construct(bool $echooutput) diff --git a/app/Services/MusicProcessor.php b/app/Services/MusicProcessor.php index 249a9d7a3..dd17fa6ac 100644 --- a/app/Services/MusicProcessor.php +++ b/app/Services/MusicProcessor.php @@ -6,6 +6,7 @@ use App\Models\Settings; class MusicProcessor { + /** @phpstan-ignore property.onlyWritten */ private bool $echooutput; public function __construct(bool $echooutput) diff --git a/app/Services/MusicService.php b/app/Services/MusicService.php index 95d240556..2d17c3302 100644 --- a/app/Services/MusicService.php +++ b/app/Services/MusicService.php @@ -356,11 +356,11 @@ class MusicService 'created_at' => now(), 'updated_at' => now(), ]); - $mus['cover'] = $ri->saveImage($musicId, $mus['coverurl'], $this->imgSavePath, 250, 250); + $mus['cover'] = $ri->saveImage((string) $musicId, $mus['coverurl'], $this->imgSavePath, 250, 250); MusicInfo::query()->where('id', $musicId)->update(['cover' => $mus['cover']]); } else { $musicId = $check['id']; - $mus['cover'] = $ri->saveImage($musicId, $mus['coverurl'], $this->imgSavePath, 250, 250); + $mus['cover'] = $ri->saveImage((string) $musicId, $mus['coverurl'], $this->imgSavePath, 250, 250); MusicInfo::query()->where('id', $musicId)->update([ 'title' => $mus['title'], 'asin' => $mus['asin'], @@ -470,7 +470,7 @@ class MusicService $sleeptime = $this->sleeptime / 1000; $diff = now()->diffInSeconds($startTime, true); if ($sleeptime - $diff > 0 && $usedAmazon === true) { - sleep($sleeptime - $diff); + sleep((int) ($sleeptime - $diff)); } } diff --git a/app/Services/NNTP/NNTPService.php b/app/Services/NNTP/NNTPService.php index 95bc0fd2d..4551f8dff 100644 --- a/app/Services/NNTP/NNTPService.php +++ b/app/Services/NNTP/NNTPService.php @@ -41,7 +41,7 @@ class NNTPService extends \Net_NNTP_Client */ protected string $_currentGroup = ''; - protected string $_currentPort = 'NNTP_PORT'; + protected string|int $_currentPort = 'NNTP_PORT'; /** * Address of the current NNTP server. @@ -87,6 +87,8 @@ class NNTPService extends \Net_NNTP_Client /** * @var resource|null + * + * @phpstan-ignore property.phpDocType */ protected $_socket = null; @@ -259,7 +261,7 @@ class NNTPService extends \Net_NNTP_Client // If we are not connected, try to connect. if (! $connected) { - $ret = $this->connect($this->_currentServer, $sslEnabled, $this->_currentPort, 5, $socketTimeout); + $ret = $this->connect($this->_currentServer, $sslEnabled, (int) $this->_currentPort, 5, $socketTimeout); } // Check if we got an error while connecting. $cErr = self::isError($ret); @@ -526,7 +528,7 @@ class NNTPService extends \Net_NNTP_Client $parts = explode("\t", $header); // Make sure it's not empty. - if ($parts === false || empty($parts)) { + if (empty($parts)) { continue; } @@ -636,9 +638,7 @@ class NNTPService extends \Net_NNTP_Client $newBody = $nntp->_getMessage($groupName, $wanted); // Check if we got an error. if ($nntp->isError($newBody)) { - if ($aConnected) { - $nntp->doQuit(); - } + $nntp->doQuit(); // If we got some data, return it. if ($body !== '') { return $body; @@ -732,9 +732,7 @@ class NNTPService extends \Net_NNTP_Client if ($aConnected === true) { $altMsg = $alt->_getMessageByMessageID($id); if ($alt->isError($altMsg)) { - if ($aConnected) { - $alt->doQuit(); - } + $alt->doQuit(); return $body !== '' ? $body : $altMsg; // return what we have or error } diff --git a/app/Services/NameFixing/FilePrioritizer.php b/app/Services/NameFixing/FilePrioritizer.php index af9090c96..1ed0b4e75 100644 --- a/app/Services/NameFixing/FilePrioritizer.php +++ b/app/Services/NameFixing/FilePrioritizer.php @@ -19,6 +19,7 @@ class FilePrioritizer /** * Priority levels (lower = higher priority). */ + /** @phpstan-ignore classConstant.unused */ private const PRIORITY_SRR = 1; private const PRIORITY_MAIN_RAR = 2; diff --git a/app/Services/NameFixing/NameFixingService.php b/app/Services/NameFixing/NameFixingService.php index 20db24f71..a13e5a5f5 100644 --- a/app/Services/NameFixing/NameFixingService.php +++ b/app/Services/NameFixing/NameFixingService.php @@ -143,6 +143,7 @@ class NameFixingService cli()->info(number_format($total).' releases to process.'); foreach ($releases as $rel) { + /** @var Release $rel */ $releaseRow = Release::fromQuery( sprintf( 'SELECT nfo.releases_id AS nfoid, rel.groups_id, rel.fromname, rel.categories_id, rel.name, rel.searchname, @@ -237,6 +238,7 @@ class NameFixingService // Group files by release $releaseFiles = []; foreach ($releases as $release) { + /** @var Release $release */ $releaseId = $release->releases_id; if (! isset($releaseFiles[$releaseId])) { $releaseFiles[$releaseId] = [ @@ -255,6 +257,7 @@ class NameFixingService $prioritizedFiles = $this->filePrioritizer->prioritizeForMatching($data['files']); foreach ($prioritizedFiles as $filename) { + /** @var Release $release */ $release = clone $data['release']; $release->textstring = $filename; @@ -404,6 +407,7 @@ class NameFixingService // Group by release $releasesCrc = []; foreach ($releases as $release) { + /** @var Release $release */ $releaseId = $release->releases_id; if (! isset($releasesCrc[$releaseId])) { $releasesCrc[$releaseId] = [ @@ -424,6 +428,7 @@ class NameFixingService ksort($data['crcs']); foreach ($data['crcs'] as $crcs) { foreach ($crcs as $crc) { + /** @var Release $release */ $release = clone $data['release']; $release->textstring = $crc; @@ -661,6 +666,7 @@ class NameFixingService ); foreach ($result as $res) { + /** @var Release $res */ $floor = round(($res->relsize - $release->relsize) / $res->relsize * 100, 1); if ($floor >= -5 && $floor <= 5) { $this->updateService->updateRelease( @@ -708,6 +714,7 @@ class NameFixingService )); foreach ($result as $res) { + /** @var Release $res */ $floor = round(($res->relsize - $release->relsize) / $res->relsize * 100, 1); if ($floor >= -10 && $floor <= 10) { $this->updateService->updateRelease( @@ -747,6 +754,7 @@ class NameFixingService )); foreach ($result as $res) { + /** @var Release $res */ $floor = round(($res->relsize - $release->relsize) / $res->relsize * 100, 1); if ($floor >= -5 && $floor <= 5) { $this->updateService->updateRelease( @@ -986,6 +994,7 @@ class NameFixingService $nzbContentsService = app(\App\Services\Nzb\NzbContentsService::class); foreach ($releases as $release) { + /** @var Release $release */ if ($nzbContentsService->checkPar2($release->guid, $release->releases_id, $release->groups_id, (int) $nameStatus, (int) $show)) { $this->updateService->fixed++; } diff --git a/app/Services/NfoProcessor.php b/app/Services/NfoProcessor.php index f885f2bc9..7e061ef30 100644 --- a/app/Services/NfoProcessor.php +++ b/app/Services/NfoProcessor.php @@ -9,10 +9,9 @@ class NfoProcessor { private NfoService $nfo; - public function __construct(NfoService $nfo, bool $echooutput) + public function __construct(NfoService $nfo) { $this->nfo = $nfo; - // echooutput kept for signature parity } /** @@ -25,8 +24,8 @@ class NfoProcessor $nntp, $groupID, $guidChar, - (int) Settings::settingValue('lookupimdb'), - (int) Settings::settingValue('lookuptv') + (bool) Settings::settingValue('lookupimdb'), + (bool) Settings::settingValue('lookuptv') ); } } diff --git a/app/Services/NfoService.php b/app/Services/NfoService.php index 272f5e330..2170ecea1 100644 --- a/app/Services/NfoService.php +++ b/app/Services/NfoService.php @@ -453,13 +453,13 @@ class NfoService /** * Add an NFO from alternate sources. ex.: PreDB, rar, zip, etc... * - * @param string $nfo The nfo. + * @param bool|string $nfo The nfo. * @param NNTPService $nntp Instance of class NNTPService. * @return bool True on success, False on failure. * * @throws \Exception */ - public function addAlternateNfo(string &$nfo, $release, NNTPService $nntp): bool + public function addAlternateNfo(bool|string &$nfo, $release, NNTPService $nntp): bool { if ($release->id > 0 && $this->isNFO($nfo, $release->guid)) { $check = ReleaseNfo::whereReleasesId($release->id)->first(['releases_id']); diff --git a/app/Services/Nzb/NzbContentsService.php b/app/Services/Nzb/NzbContentsService.php index 125155394..c99eac073 100644 --- a/app/Services/Nzb/NzbContentsService.php +++ b/app/Services/Nzb/NzbContentsService.php @@ -190,7 +190,7 @@ class NzbContentsService Release::query()->where('id', $relID)->update(['completion' => $completion]); // If NFO check was requested, return the found message ID (prioritizing explicit) - if ($nfoCheck && $nfoMessageId !== null && isset($nfoMessageId['id']) && \strlen($nfoMessageId['id']) > 1) { + if ($nfoCheck && $nfoMessageId !== null && \strlen($nfoMessageId['id']) > 1) { return $nfoMessageId; } diff --git a/app/Services/Nzb/NzbImportService.php b/app/Services/Nzb/NzbImportService.php index b53155385..6d4f63021 100644 --- a/app/Services/Nzb/NzbImportService.php +++ b/app/Services/Nzb/NzbImportService.php @@ -221,7 +221,7 @@ class NzbImportService * * @throws \Exception */ - protected function scanNZBFile(&$nzbXML, $nzbFileName = ''): bool + protected function scanNZBFile(&$nzbXML, $nzbFileName = '', $source = ''): bool { $binary_names = []; $totalFiles = $totalSize = $groupID = 0; diff --git a/app/Services/Nzb/NzbParserService.php b/app/Services/Nzb/NzbParserService.php index ba4aa6e95..a047cf6bc 100644 --- a/app/Services/Nzb/NzbParserService.php +++ b/app/Services/Nzb/NzbParserService.php @@ -294,7 +294,7 @@ class NzbParserService { // Improve artificial parts calculation robustness (e.g., "[15/20]", "(15/20)") if (preg_match('/(?:[(\[])?(\d+)[\/)\\]](\d+)[)\]]?$/', $subject, $parts)) { - if (isset($parts[2]) && (int) $parts[2] > 0) { + if ((int) $parts[2] > 0) { return (int) $parts[2]; } } diff --git a/app/Services/Nzb/NzbService.php b/app/Services/Nzb/NzbService.php index 75913f871..1ecc687ff 100644 --- a/app/Services/Nzb/NzbService.php +++ b/app/Services/Nzb/NzbService.php @@ -52,7 +52,7 @@ class NzbService public function __construct() { $nzbSplitLevel = (int) Settings::settingValue('nzbsplitlevel'); - $this->nzbSplitLevel = $nzbSplitLevel ?? 1; + $this->nzbSplitLevel = $nzbSplitLevel; $this->siteNzbPath = config('nntmux_settings.path_to_nzbs'); if (! Str::endsWith($this->siteNzbPath, '/')) { $this->siteNzbPath .= '/'; @@ -100,7 +100,7 @@ class NzbService $XMLWriter->startElement('head'); $XMLWriter->startElement('meta'); $XMLWriter->writeAttribute('type', 'category'); - $XMLWriter->text(! empty($release->category->parent) ? $release->category->parent->title.' >'.$release->category->title : 'Other > Misc'); + $XMLWriter->text(! empty($release->category->parent) ? $release->category->parent->title.' >'.$release->category->title : 'Other > Misc'); // @phpstan-ignore property.notFound $XMLWriter->endElement(); $XMLWriter->startElement('meta'); $XMLWriter->writeAttribute('type', 'name'); @@ -214,7 +214,7 @@ class NzbService $nzbPath = $this->siteNzbPath.$nzbPath; - if ($createIfNotExist && ! File::isDirectory($nzbPath) && ! File::makeDirectory($nzbPath, 0777, true) && ! File::isDirectory($nzbPath)) { + if ($createIfNotExist && ! File::isDirectory($nzbPath) && ! File::makeDirectory($nzbPath, 0777, true) && ! File::isDirectory($nzbPath)) { // @phpstan-ignore booleanNot.alwaysTrue throw new \RuntimeException(sprintf('Directory "%s" was not created', $nzbPath)); } diff --git a/app/Services/Par2Processor.php b/app/Services/Par2Processor.php index 2819d9878..09cef10df 100644 --- a/app/Services/Par2Processor.php +++ b/app/Services/Par2Processor.php @@ -76,7 +76,7 @@ class Par2Processor // Get the file list from Par2Info. $files = $this->par2Info->getFileList(); - if ($files !== false && \count($files) > 0) { + if (\count($files) > 0) { $filesAdded = 0; // Loop through the files. @@ -112,7 +112,7 @@ class Par2Processor // Try to get a new name. if ($foundName === false) { $query['textstring'] = $file['name']; - if ($this->nameFixingService->checkName($query, true, 'PAR2, ', true, $show)) { + if ($this->nameFixingService->checkName($query, true, 'PAR2, ', true, (bool) $show)) { $foundName = true; } } diff --git a/app/Services/PopulateAniListService.php b/app/Services/PopulateAniListService.php index cd2a7fbd3..292e3f798 100644 --- a/app/Services/PopulateAniListService.php +++ b/app/Services/PopulateAniListService.php @@ -696,7 +696,7 @@ class PopulateAniListService if ($title) { $searchResults = $this->searchAnime($title, 1); - if ($searchResults && ! empty($searchResults)) { + if ($searchResults) { $anilistData = $searchResults[0]; $this->insertAniListInfo($anidb->anidbid, $anilistData); // Rate limiting is handled in makeGraphQLRequest diff --git a/app/Services/PostProcessService.php b/app/Services/PostProcessService.php index a0a18ecb9..3e85f0f9e 100644 --- a/app/Services/PostProcessService.php +++ b/app/Services/PostProcessService.php @@ -85,7 +85,7 @@ final class PostProcessService $this->alternateNNTP ); $this->tvProcessor = $tvProcessor ?? new TvProcessor($this->echoOutput); - $this->nfoProcessor = $nfoProcessor ?? new NfoProcessor($this->nfo, $this->echoOutput); + $this->nfoProcessor = $nfoProcessor ?? new NfoProcessor($this->nfo); $this->moviesProcessor = $moviesProcessor ?? new MoviesProcessor($this->echoOutput); $this->musicProcessor = $musicProcessor ?? new MusicProcessor($this->echoOutput); $this->booksProcessor = $booksProcessor ?? new BooksProcessor($this->echoOutput); @@ -100,7 +100,7 @@ final class PostProcessService * * @throws \Exception */ - public function processAll(NNTP $nntp): void + public function processAll(NNTPService $nntp): void { $this->processAdditional(); $this->processNfos($nntp); diff --git a/app/Services/RedisMonitorService.php b/app/Services/RedisMonitorService.php index 2a202a7a0..a5fd83442 100644 --- a/app/Services/RedisMonitorService.php +++ b/app/Services/RedisMonitorService.php @@ -19,6 +19,7 @@ class RedisMonitorService private const YELLOW = "\033[1;33m"; + /** @phpstan-ignore classConstant.unused */ private const BLUE = "\033[0;34m"; private const MAGENTA = "\033[0;35m"; diff --git a/app/Services/RegexService.php b/app/Services/RegexService.php index e11c937d3..00622a11c 100644 --- a/app/Services/RegexService.php +++ b/app/Services/RegexService.php @@ -235,12 +235,12 @@ class RegexService $rows->limit($queryLimit); } - $rows->get(); + $results = $rows->get(); $data = []; - if ($rows !== null) { + if ($results->isNotEmpty()) { $limit = 1; - foreach ($rows as $row) { + foreach ($results as $row) { $hit = $this->_matchRegex($regex, $row['name']); if ($hit) { $data[$row['id']] = [ diff --git a/app/Services/ReleaseCleaningService.php b/app/Services/ReleaseCleaningService.php index 08ddc39f6..997b44e0b 100644 --- a/app/Services/ReleaseCleaningService.php +++ b/app/Services/ReleaseCleaningService.php @@ -15,11 +15,13 @@ class ReleaseCleaningService /** * Used for matching endings in article subjects. */ + /** @phpstan-ignore classConstant.unused */ private const string REGEX_END = '[ -]{0,3}yEnc$/u'; /** * Used for matching file extension endings in article subjects. */ + /** @phpstan-ignore classConstant.unused */ private const string REGEX_FILE_EXTENSIONS = '([\-_](proof|sample|thumbs?))*(\.part\d*(\.rar)?|\.rar|\.7z)?(\d{1,3}\.rev"|\.vol.+?"|\.[A-Za-z0-9]{2,4}"|")'; /** @@ -27,6 +29,7 @@ class ReleaseCleaningService * * @example ' - 365.15 KB - ' */ + /** @phpstan-ignore classConstant.unused */ private const string REGEX_SUBJECT_SIZE = '[ -]{0,3}\d+([.,]\d+)? [kKmMgG][bB][ -]{0,3}'; public string $e0; diff --git a/app/Services/ReleaseCreationService.php b/app/Services/ReleaseCreationService.php index 80a9053e1..bd9be7a83 100644 --- a/app/Services/ReleaseCreationService.php +++ b/app/Services/ReleaseCreationService.php @@ -185,7 +185,7 @@ class ReleaseCreationService ' Releases added and '. number_format($duplicate). ' duplicate collections deleted in '. - $totalTime.\Illuminate\Support\Str::plural(' second', $totalTime), + $totalTime.\Illuminate\Support\Str::plural(' second', (int) $totalTime), true ); } diff --git a/app/Services/ReleaseImageService.php b/app/Services/ReleaseImageService.php index a14ecacd2..e8c2936ca 100644 --- a/app/Services/ReleaseImageService.php +++ b/app/Services/ReleaseImageService.php @@ -78,7 +78,7 @@ class ReleaseImageService $imageData = @file_get_contents($imgLoc, false, $context); // Check HTTP response headers if available - if (isset($http_response_header) && ! empty($http_response_header)) { + if (! empty($http_response_header)) { $statusLine = $http_response_header[0] ?? ''; if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $statusLine, $matches)) { $httpCode = (int) $matches[1]; @@ -93,7 +93,7 @@ class ReleaseImageService if ($imageData === false) { $error = error_get_last(); - $errorMsg = $error !== null && isset($error['message']) ? $error['message'] : 'Unknown error fetching image'; + $errorMsg = $error !== null ? $error['message'] : 'Unknown error fetching image'; Log::debug('Failed to fetch image from '.$imgLoc.': '.$errorMsg); cli()->notice('Failed to fetch image from '.$imgLoc.': '.$errorMsg); diff --git a/app/Services/ReleaseProcessingService.php b/app/Services/ReleaseProcessingService.php index a5f021019..71b3ce077 100644 --- a/app/Services/ReleaseProcessingService.php +++ b/app/Services/ReleaseProcessingService.php @@ -1050,11 +1050,11 @@ final class ReleaseProcessingService Release::query() ->select(['id', 'guid']) - ->where('passwordstatus', '=', Releases::PASSWD_RAR) + ->where('passwordstatus', '=', \App\Services\Releases\ReleaseBrowseService::PASSWD_RAR) ->orWhereIn('id', function ($query): void { $query->select('releases_id') ->from('release_files') - ->where('passworded', '=', Releases::PASSWD_RAR); + ->where('passworded', '=', \App\Services\Releases\ReleaseBrowseService::PASSWD_RAR); }) ->chunkById(self::BATCH_SIZE, function ($releases) use (&$stats): bool { foreach ($releases as $release) { @@ -1146,7 +1146,7 @@ final class ReleaseProcessingService foreach ($categories as $category) { Release::query() ->where('categories_id', (int) $category->id) - ->where('size', '<', (int) $category->minsize) + ->where('size', '<', (int) $category->minsize) // @phpstan-ignore property.notFound ->select(['id', 'guid']) ->limit(1000) ->chunkById(self::BATCH_SIZE, function ($releases) use (&$stats): bool { @@ -1167,13 +1167,13 @@ final class ReleaseProcessingService $genres = new GenreService; $genreList = $genres->getDisabledIDs(); - if ($genreList === null || $genreList->isEmpty()) { + if ($genreList->isEmpty()) { return $stats; } foreach ($genreList as $genre) { $musicInfoQuery = MusicInfo::query() - ->where('genre_id', (int) $genre->id) + ->where('genre_id', (int) $genre->id) // @phpstan-ignore property.notFound ->select(['id']); Release::query() @@ -1279,6 +1279,7 @@ final class ReleaseProcessingService cli()->notice(" {$title}"); } + /** @phpstan-ignore method.unused */ private function outputSuccess(string $message): void { if (! $this->echoCLI) { diff --git a/app/Services/ReleaseRemoverService.php b/app/Services/ReleaseRemoverService.php index dbd292094..7ce8b34ec 100644 --- a/app/Services/ReleaseRemoverService.php +++ b/app/Services/ReleaseRemoverService.php @@ -302,7 +302,7 @@ class ReleaseRemoverService * * @throws Exception */ - private function executeSimpleRemoval(string $method, string $query): bool|string + private function executeSimpleRemoval(string $method, string $query): bool { $this->method = $method; $this->query = $query; @@ -602,7 +602,7 @@ class ReleaseRemoverService /** * Perform search using configured search engine. */ - private function performSearch(string $regexMatch): array|string + private function performSearch(string $regexMatch): array { return \App\Facades\Search::searchReleases($regexMatch, 100); } diff --git a/app/Services/Releases/ReleaseBrowseService.php b/app/Services/Releases/ReleaseBrowseService.php index d57f5ecf4..259f09c0d 100644 --- a/app/Services/Releases/ReleaseBrowseService.php +++ b/app/Services/Releases/ReleaseBrowseService.php @@ -235,7 +235,7 @@ class ReleaseBrowseService public function showPasswords(): string { $show = (int) Settings::settingValue('showpasswordedrelease'); - $setting = $show ?? 0; + $setting = $show; return match ($setting) { 1 => '<= '.self::PASSWD_RAR, @@ -288,7 +288,7 @@ class ReleaseBrowseService } /** - * @return \Illuminate\Cache\|\Illuminate\Database\Eloquent\Collection|mixed + * @return \Illuminate\Database\Eloquent\Collection|mixed */ public function getShowsRange($userShows, $offset, $limit, $orderBy, int $maxAge = -1, array $excludedCats = []) { diff --git a/app/Services/Releases/ReleaseSearchService.php b/app/Services/Releases/ReleaseSearchService.php index 9b0b8977e..4cd2e4c2f 100644 --- a/app/Services/Releases/ReleaseSearchService.php +++ b/app/Services/Releases/ReleaseSearchService.php @@ -247,7 +247,7 @@ class ReleaseSearchService /** * Search for TV shows via API. * - * @return array|\Illuminate\Cache\|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|mixed + * @return array|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|mixed */ public function tvSearch(array $siteIdArr = [], string $series = '', string $episode = '', string $airDate = '', int $offset = 0, int $limit = 100, string $name = '', array $cat = [-1], int $maxAge = -1, int $minSize = 0, array $excludedCategories = []): mixed { @@ -577,7 +577,7 @@ class ReleaseSearchService } elseif (! empty($series) && empty($episode)) { $showSql .= ' AND r.tv_episodes_id IN ('.$show[0]->episodes.') AND tve.series = '.$series; } - if ($show[0]->video > 0) { + if ((int) ($show[0]->video ?? 0) > 0) { $showSql .= ' AND r.videos_id = '.$show[0]->video; } } else { @@ -1150,7 +1150,7 @@ class ReleaseSearchService public function showPasswords(): string { $show = (int) Settings::settingValue('showpasswordedrelease'); - $setting = $show ?? 0; + $setting = $show; return match ($setting) { 1 => '<= '.self::PASSWD_RAR, diff --git a/app/Services/Search/Drivers/ElasticSearchDriver.php b/app/Services/Search/Drivers/ElasticSearchDriver.php index 6c146151e..383dc3c74 100644 --- a/app/Services/Search/Drivers/ElasticSearchDriver.php +++ b/app/Services/Search/Drivers/ElasticSearchDriver.php @@ -635,7 +635,7 @@ class ElasticSearchDriver implements SearchDriverInterface // Normalize the input to a search string if (is_string($phrases)) { $searchString = $phrases; - } elseif (is_array($phrases)) { + } else { // Check if it's an associative array (has string keys like 'searchname') $isAssociative = count(array_filter(array_keys($phrases), 'is_string')) > 0; @@ -646,8 +646,6 @@ class ElasticSearchDriver implements SearchDriverInterface // Indexed array - combine values $searchString = implode(' ', $phrases); } - } else { - return []; } $result = $this->indexSearch($searchString, $limit); @@ -714,15 +712,13 @@ class ElasticSearchDriver implements SearchDriverInterface // Normalize the input to a search string if (is_string($phrases)) { $searchString = $phrases; - } elseif (is_array($phrases)) { + } else { $isAssociative = count(array_filter(array_keys($phrases), 'is_string')) > 0; if ($isAssociative) { $searchString = implode(' ', array_values($phrases)); } else { $searchString = implode(' ', $phrases); } - } else { - return []; } $keywords = $this->sanitizeSearchTerms($searchString); @@ -1127,7 +1123,7 @@ class ElasticSearchDriver implements SearchDriverInterface 'plainsearchname' => $searchNameDotless, 'fromname' => $release->fromname, 'categories_id' => $release->categories_id, - 'filename' => $release->filename, + 'filename' => $release->filename, // @phpstan-ignore property.notFound ], 'doc_as_upsert' => true, ], diff --git a/app/Services/Search/Drivers/ManticoreSearchDriver.php b/app/Services/Search/Drivers/ManticoreSearchDriver.php index f683f1be9..e4c34be6a 100644 --- a/app/Services/Search/Drivers/ManticoreSearchDriver.php +++ b/app/Services/Search/Drivers/ManticoreSearchDriver.php @@ -442,7 +442,7 @@ class ManticoreSearchDriver implements SearchDriverInterface // Tokenize while preserving quoted phrases intact // Matches: optional negation prefix (! or -) + "quoted strings", OR non-whitespace sequences preg_match_all('/[-!]?"[^"]*"|\S+/', $query, $matches); - $tokens = $matches[0] ?? []; + $tokens = $matches[0]; if (empty($tokens)) { return ''; @@ -815,7 +815,7 @@ class ManticoreSearchDriver implements SearchDriverInterface if (is_string($phrases)) { // Simple string search - search in searchname field $searchArray = ['searchname' => $phrases]; - } elseif (is_array($phrases)) { + } else { // Check if it's an associative array (has string keys like 'searchname') $isAssociative = count(array_filter(array_keys($phrases), 'is_string')) > 0; @@ -826,8 +826,6 @@ class ManticoreSearchDriver implements SearchDriverInterface // Indexed array - combine values and search in searchname $searchArray = ['searchname' => implode(' ', $phrases)]; } - } else { - return []; } $result = $this->searchIndexes($this->getReleasesIndex(), '', [], $searchArray); @@ -909,15 +907,13 @@ class ManticoreSearchDriver implements SearchDriverInterface if (is_string($phrases)) { $searchArray = ['searchname' => $phrases]; - } elseif (is_array($phrases)) { + } else { $isAssociative = count(array_filter(array_keys($phrases), 'is_string')) > 0; if ($isAssociative) { $searchArray = $phrases; } else { $searchArray = ['searchname' => implode(' ', $phrases)]; } - } else { - return []; } $result = $this->fuzzySearchIndexes($this->getReleasesIndex(), $searchArray, $limit); diff --git a/app/Services/Search/SearchService.php b/app/Services/Search/SearchService.php index ba4ab433c..145d3f72c 100644 --- a/app/Services/Search/SearchService.php +++ b/app/Services/Search/SearchService.php @@ -50,7 +50,7 @@ class SearchService extends Manager implements SearchServiceInterface * * @param string|null $driver * - * @throws InvalidArgumentException + * @throws \InvalidArgumentException */ public function driver($driver = null): SearchDriverInterface { diff --git a/app/Services/TempWorkspaceService.php b/app/Services/TempWorkspaceService.php index 90b0a28f5..5ba00dd1c 100644 --- a/app/Services/TempWorkspaceService.php +++ b/app/Services/TempWorkspaceService.php @@ -25,7 +25,7 @@ class TempWorkspaceService } if (! File::isDirectory($basePath)) { - if (! File::makeDirectory($basePath, 0777, true, true) && ! File::isDirectory($basePath)) { + if (! File::makeDirectory($basePath, 0777, true, true) && ! File::isDirectory($basePath)) { // @phpstan-ignore booleanNot.alwaysTrue throw new \RuntimeException(sprintf('Directory "%s" was not created', $basePath)); } } @@ -40,9 +40,9 @@ class TempWorkspaceService { $tmpPath = rtrim($mainTmpPath, '/\\').'/'.$guid.'/'; if (! File::isDirectory($tmpPath)) { - if (! File::makeDirectory($tmpPath, 0777, true, false) && ! File::isDirectory($tmpPath)) { + if (! File::makeDirectory($tmpPath, 0777, true, false) && ! File::isDirectory($tmpPath)) { // @phpstan-ignore booleanNot.alwaysTrue // Try again once in case of transient FS issues - if (! File::makeDirectory($tmpPath, 0777, true, false) && ! File::isDirectory($tmpPath)) { + if (! File::makeDirectory($tmpPath, 0777, true, false) && ! File::isDirectory($tmpPath)) { // @phpstan-ignore booleanNot.alwaysTrue, booleanNot.alwaysTrue, booleanAnd.alwaysTrue throw new \RuntimeException('Unable to create directory: '.$tmpPath); } } diff --git a/app/Services/TmdbClient.php b/app/Services/TmdbClient.php index 721a8b1cb..ebc72aa1e 100644 --- a/app/Services/TmdbClient.php +++ b/app/Services/TmdbClient.php @@ -60,7 +60,7 @@ class TmdbClient try { $response = Http::timeout($this->timeout) - ->retry($this->retryTimes, $this->retryDelay, function (\Exception $exception, $request) { + ->retry($this->retryTimes, $this->retryDelay, function (\Throwable $exception, \Illuminate\Http\Client\PendingRequest $request, ?string $key = null) { // Don't retry on 404 errors - resource simply doesn't exist if ($exception instanceof \Illuminate\Http\Client\RequestException) { return $exception->response->status() !== 404; diff --git a/app/Services/Tmux/Scripts/groupfixrelnames.php b/app/Services/Tmux/Scripts/groupfixrelnames.php index 7225e982f..e182c55c9 100644 --- a/app/Services/Tmux/Scripts/groupfixrelnames.php +++ b/app/Services/Tmux/Scripts/groupfixrelnames.php @@ -23,7 +23,7 @@ $artisan = dirname(__DIR__, 4).'/artisan'; switch ($type) { case 'standard': - if ($guidChar === null || $maxPerRun === null || ! is_numeric($maxPerRun)) { + if ($guidChar === '' || $maxPerRun === '' || ! is_numeric($maxPerRun)) { fwrite(STDERR, "Invalid arguments for standard type\n"); exit(1); } @@ -32,7 +32,7 @@ switch ($type) { break; case 'predbft': - if (! isset($maxPerRun) || ! is_numeric($maxPerRun) || ! isset($thread) || ! is_numeric($thread)) { + if (! is_numeric($maxPerRun) || ! is_numeric($thread)) { fwrite(STDERR, "Invalid arguments for predbft type\n"); exit(1); } diff --git a/app/Services/Tmux/Scripts/monitor.php b/app/Services/Tmux/Scripts/monitor.php index ae20e0a37..02c2f2a11 100644 --- a/app/Services/Tmux/Scripts/monitor.php +++ b/app/Services/Tmux/Scripts/monitor.php @@ -12,7 +12,7 @@ $artisan = dirname(__DIR__, 4).'/artisan'; // Pass any arguments to the artisan command -$args = array_slice($argv, 1); +$args = array_slice($argv ?? [], 1); $argString = implode(' ', array_map('escapeshellarg', $args)); passthru("php {$artisan} tmux:monitor {$argString}", $exitCode); diff --git a/app/Services/Tmux/TmuxTaskRunner.php b/app/Services/Tmux/TmuxTaskRunner.php index 96e0f1518..a0a58d1f3 100644 --- a/app/Services/Tmux/TmuxTaskRunner.php +++ b/app/Services/Tmux/TmuxTaskRunner.php @@ -145,8 +145,8 @@ class TmuxTaskRunner */ protected function getRandomColor(): int { - $start = (int) Settings::settingValue('colors_start') ?? 0; - $end = (int) Settings::settingValue('colors_end') ?? 255; + $start = (int) Settings::settingValue('colors_start'); + $end = (int) Settings::settingValue('colors_end'); $exclude = Settings::settingValue('colors_exc') ?? ''; if (empty($exclude)) { @@ -430,7 +430,7 @@ class TmuxTaskRunner $selectedTypes = $runVar['settings']['fix_crap'] ?? ''; // Convert numeric 0 or empty values to empty string - if (empty($selectedTypes) || $selectedTypes === 0 || $selectedTypes === '0') { + if (empty($selectedTypes)) { return $this->disablePane($pane, 'Remove Crap', 'no crap types selected'); } @@ -438,7 +438,7 @@ class TmuxTaskRunner // Trim whitespace and filter out empty values and '0' $types = array_map('trim', $types); - $types = array_filter($types, fn ($type) => ! empty($type) && $type !== '0'); + $types = array_filter($types, fn ($type) => ! empty($type)); // Re-index array to ensure sequential keys $types = array_values($types); diff --git a/app/Services/TraktService.php b/app/Services/TraktService.php index ee03af1b1..04a9356a6 100644 --- a/app/Services/TraktService.php +++ b/app/Services/TraktService.php @@ -80,7 +80,7 @@ class TraktService try { $response = Http::timeout($this->timeout) - ->retry($this->retryTimes, $this->retryDelay, function (\Exception $exception, $request) { + ->retry($this->retryTimes, $this->retryDelay, function (\Throwable $exception, \Illuminate\Http\Client\PendingRequest $request, ?string $key = null) { // Don't retry on 404 errors - resource simply doesn't exist if ($exception instanceof \Illuminate\Http\Client\RequestException) { return $exception->response->status() !== 404; @@ -232,9 +232,7 @@ class TraktService return match ($idType) { 'imdb' => is_numeric($id) ? 'tt'.str_pad((string) $id, 7, '0', STR_PAD_LEFT) : (string) $id, - 'trakt' => (string) $id, - 'tmdb', 'tvdb' => (string) $id, - default => null, + 'trakt', 'tmdb', 'tvdb' => (string) $id, }; } @@ -277,7 +275,7 @@ class TraktService // Use the search endpoint to find the show by external ID $results = $this->searchById($id, $idType, 'show'); - if (empty($results) || ! is_array($results)) { + if (empty($results)) { return null; } diff --git a/app/Services/TvProcessing/Pipes/TmdbPipe.php b/app/Services/TvProcessing/Pipes/TmdbPipe.php index 0dd910ca1..550860432 100644 --- a/app/Services/TvProcessing/Pipes/TmdbPipe.php +++ b/app/Services/TvProcessing/Pipes/TmdbPipe.php @@ -75,7 +75,7 @@ class TmdbPipe extends AbstractTvProviderPipe if ($videoId !== 0) { $siteId = $tmdb->getSiteByID('tmdb', $videoId); // If show exists in local DB with a TMDB ID, use it directly - if ($siteId !== false && $siteId !== 0) { + if ($siteId !== false && $siteId !== 0) { // @phpstan-ignore notIdentical.alwaysTrue $this->outputFoundInDb($cleanName); } else { // Show exists in local DB but without TMDB ID (from another source) diff --git a/app/Services/TvProcessing/Pipes/TvMazePipe.php b/app/Services/TvProcessing/Pipes/TvMazePipe.php index 3282a9184..de052d099 100644 --- a/app/Services/TvProcessing/Pipes/TvMazePipe.php +++ b/app/Services/TvProcessing/Pipes/TvMazePipe.php @@ -76,7 +76,7 @@ class TvMazePipe extends AbstractTvProviderPipe $siteId = $tvmaze->getSiteByID('tvmaze', $videoId); // If show exists in local DB but doesn't have a TVMaze ID, use the existing video // and process episode matching without trying to search TVMaze API - if ($siteId === false || $siteId === 0) { + if ($siteId === false || $siteId === 0) { // @phpstan-ignore identical.alwaysFalse // Show exists in our DB (likely from another source like TMDB) // Skip TVMaze API search and proceed to episode matching $this->outputFoundInDb($cleanName); diff --git a/app/Services/TvProcessing/Pipes/TvdbPipe.php b/app/Services/TvProcessing/Pipes/TvdbPipe.php index e25914cf0..5bee12277 100644 --- a/app/Services/TvProcessing/Pipes/TvdbPipe.php +++ b/app/Services/TvProcessing/Pipes/TvdbPipe.php @@ -78,7 +78,7 @@ class TvdbPipe extends AbstractTvProviderPipe $siteId = $tvdb->getSiteByID('tvdb', $videoId); // If show exists in local DB but doesn't have a TVDB ID, use the existing video // and process episode matching without trying to search TVDB API - if ($siteId === false || $siteId === 0) { + if ($siteId === false || $siteId === 0) { // @phpstan-ignore identical.alwaysFalse // Show exists in our DB (likely from another source like TMDB) // Skip TVDB API search and proceed to episode matching $this->outputFoundInDb($cleanName); @@ -94,7 +94,7 @@ class TvdbPipe extends AbstractTvProviderPipe : '' ); - if ($siteId === false || $siteId === 0) { + if ($siteId === false || $siteId === 0) { // @phpstan-ignore identical.alwaysFalse // Not in local DB, search TVDB $this->outputSearching($cleanName); diff --git a/app/Services/TvProcessing/Providers/AbstractTvProvider.php b/app/Services/TvProcessing/Providers/AbstractTvProvider.php index ae47cdd03..4426de141 100644 --- a/app/Services/TvProcessing/Providers/AbstractTvProvider.php +++ b/app/Services/TvProcessing/Providers/AbstractTvProvider.php @@ -293,9 +293,9 @@ abstract class AbstractTvProvider extends BaseVideoProvider /** * @throws \Throwable */ - public function delete(int $id): mixed + public function delete(int $id): void { - return DB::transaction(function () use ($id) { + DB::transaction(function () use ($id) { DB::delete( sprintf( ' @@ -371,7 +371,7 @@ abstract class AbstractTvProvider extends BaseVideoProvider public function countEpsByVideoID(int $videoId): bool { $count = TvEpisode::query() - ->where('videos_id', $videoId)->count(['id']); + ->where('videos_id', $videoId)->count('id'); return $count !== null && $count > 0; } diff --git a/app/Services/TvProcessing/Providers/LocalDbProvider.php b/app/Services/TvProcessing/Providers/LocalDbProvider.php index fd89746c4..1c55862fc 100644 --- a/app/Services/TvProcessing/Providers/LocalDbProvider.php +++ b/app/Services/TvProcessing/Providers/LocalDbProvider.php @@ -159,7 +159,7 @@ class LocalDbProvider extends AbstractTvProvider public function getPoster(int $videoId): int { - return (new ReleaseImageService)->saveImage($videoId, '', $this->imgSavePath, '', '', parent::TYPE_TV); + return (new ReleaseImageService)->saveImage((string) $videoId, '', $this->imgSavePath, 0, 0, (bool) parent::TYPE_TV); } public function getShowInfo(string $name): bool|array diff --git a/app/Services/TvProcessing/Providers/TmdbProvider.php b/app/Services/TvProcessing/Providers/TmdbProvider.php index ec53b6062..58c1f1bf3 100644 --- a/app/Services/TvProcessing/Providers/TmdbProvider.php +++ b/app/Services/TvProcessing/Providers/TmdbProvider.php @@ -308,7 +308,7 @@ class TmdbProvider extends AbstractTvProvider } } - if ($highest !== null && is_array($highest)) { + if ($highest !== null) { $showId = TmdbClient::getInt($highest, 'id'); if ($showId === 0) { return false; @@ -355,7 +355,7 @@ class TmdbProvider extends AbstractTvProvider // Try to get the Poster if (! empty($this->posterUrl)) { - $hascover = $ri->saveImage($videoId, $this->posterUrl, $this->imgSavePath); + $hascover = $ri->saveImage((string) $videoId, $this->posterUrl, $this->imgSavePath); // Mark it retrieved if we saved an image if ($hascover === 1) { diff --git a/app/Services/TvProcessing/Providers/TraktProvider.php b/app/Services/TvProcessing/Providers/TraktProvider.php index 3b922bb16..1a2242338 100644 --- a/app/Services/TvProcessing/Providers/TraktProvider.php +++ b/app/Services/TvProcessing/Providers/TraktProvider.php @@ -312,12 +312,12 @@ class TraktProvider extends AbstractTvProvider if ($this->posterUrl !== '') { // Try to get the Poster - $hasCover = $ri->saveImage($videoId, $this->posterUrl, $this->imgSavePath); + $hasCover = $ri->saveImage((string) $videoId, $this->posterUrl, $this->imgSavePath); } // Couldn't get poster, try fan art instead if ($hasCover !== 1 && $this->fanartUrl !== '') { - $hasCover = $ri->saveImage($videoId, $this->fanartUrl, $this->imgSavePath); + $hasCover = $ri->saveImage((string) $videoId, $this->fanartUrl, $this->imgSavePath); } // Mark it retrieved if we saved an image @@ -347,30 +347,28 @@ class TraktProvider extends AbstractTvProvider sleep(1); - if (\is_array($response)) { - foreach ($response as $show) { - if (! is_bool($show)) { - // Check for exact title match first and then terminate if found - if ($show['show']['title'] === $name) { - $highest = $show; - break; - } + foreach ($response as $show) { + if (! is_bool($show)) { + // Check for exact title match first and then terminate if found + if ($show['show']['title'] === $name) { + $highest = $show; + break; + } - // Check each show title for similarity and then find the highest similar value - $matchPercent = $this->checkMatch($show['show']['title'], $name, self::MATCH_PROBABILITY); + // Check each show title for similarity and then find the highest similar value + $matchPercent = $this->checkMatch($show['show']['title'], $name, self::MATCH_PROBABILITY); - // If new match has a higher percentage, set as new matched title - if ($matchPercent > $highestMatch) { - $highestMatch = $matchPercent; - $highest = $show; - } + // If new match has a higher percentage, set as new matched title + if ($matchPercent > $highestMatch) { + $highestMatch = $matchPercent; + $highest = $show; } } - if ($highest !== null) { - $fullShow = $this->client->getShowSummary($highest['show']['ids']['trakt']); - if ($this->checkRequiredAttr($fullShow, 'traktS')) { - $return = $this->formatShowInfo($fullShow); - } + } + if ($highest !== null) { + $fullShow = $this->client->getShowSummary($highest['show']['ids']['trakt']); + if ($this->checkRequiredAttr($fullShow, 'traktS')) { + $return = $this->formatShowInfo($fullShow); } } diff --git a/app/Services/TvProcessing/Providers/TvMazeProvider.php b/app/Services/TvProcessing/Providers/TvMazeProvider.php index be45b55f5..1d6013b30 100644 --- a/app/Services/TvProcessing/Providers/TvMazeProvider.php +++ b/app/Services/TvProcessing/Providers/TvMazeProvider.php @@ -373,7 +373,7 @@ class TvMazeProvider extends AbstractTvProvider // Try to get the Poster if (! empty($this->posterUrl)) { - $hasCover = $ri->saveImage($videoId, $this->posterUrl, $this->imgSavePath); + $hasCover = $ri->saveImage((string) $videoId, $this->posterUrl, $this->imgSavePath); // Mark it retrieved if we saved an image if ($hasCover === 1) { diff --git a/app/Services/TvProcessing/Providers/TvdbProvider.php b/app/Services/TvProcessing/Providers/TvdbProvider.php index eeff4923a..8c422581e 100644 --- a/app/Services/TvProcessing/Providers/TvdbProvider.php +++ b/app/Services/TvProcessing/Providers/TvdbProvider.php @@ -312,7 +312,7 @@ class TvdbProvider extends AbstractTvProvider $hasCover = 0; if (! empty($this->posterUrl)) { - $hasCover = $ri->saveImage($videoId, $this->posterUrl, $this->imgSavePath); + $hasCover = $ri->saveImage((string) $videoId, $this->posterUrl, $this->imgSavePath); if ($hasCover === 1) { $this->setCoverFound($videoId); } diff --git a/app/Support/UpdatePerformanceHelper.php b/app/Support/UpdatePerformanceHelper.php index 76e71b31f..9ff01cef6 100644 --- a/app/Support/UpdatePerformanceHelper.php +++ b/app/Support/UpdatePerformanceHelper.php @@ -46,12 +46,12 @@ class UpdatePerformanceHelper // Wait for all processes to complete foreach ($processes as $key => $process) { - $process->wait(); + $result = $process->wait(); $results[$key] = [ - 'successful' => $process->successful(), - 'output' => $process->output(), - 'errorOutput' => $process->errorOutput(), - 'exitCode' => $process->exitCode(), + 'successful' => $result->successful(), + 'output' => $result->output(), + 'errorOutput' => $result->errorOutput(), + 'exitCode' => $result->exitCode(), ]; } diff --git a/app/Transformers/DetailsTransformer.php b/app/Transformers/DetailsTransformer.php index c53169445..7e4ac7538 100644 --- a/app/Transformers/DetailsTransformer.php +++ b/app/Transformers/DetailsTransformer.php @@ -52,7 +52,7 @@ class DetailsTransformer extends TransformerAbstract $data['traktid'] = $release->trakt; $data['tvrageid'] = $release->tvrage; $data['tvmazeid'] = $release->tvmaze; - $data['imdbid'] = $release->imdb; + $data['imdbid'] = $release->imdb; // @phpstan-ignore property.notFound $data['tmdbid'] = $release->tmdb; } diff --git a/routes/api.php b/routes/api.php index fd0294945..cbf2129de 100644 --- a/routes/api.php +++ b/routes/api.php @@ -23,7 +23,7 @@ Route::prefix('v2')->group(function () { Route::get('capabilities', [ApiV2Controller::class, 'capabilities']); }); -Route::prefix('v2')->middleware('auth:api', 'throttle:rate_limit,1')->group(function () { +Route::prefix('v2')->middleware(['auth:api', 'throttle:rate_limit,1'])->group(function () { Route::get('movies', [ApiV2Controller::class, 'movie']); Route::get('search', [ApiV2Controller::class, 'apiSearch']); Route::get('tv', [ApiV2Controller::class, 'tv']); @@ -46,7 +46,7 @@ Route::get('release/{id}/mediainfo', function ($id) { return response()->json([ 'video' => $video ?: null, 'audio' => $audio ?: null, - 'subs' => $subs ? $subs->subs : null, + 'subs' => $subs ? $subs->subs : null, // @phpstan-ignore property.notFound ]); }); diff --git a/routes/web.php b/routes/web.php index 94b30cbb7..71d9189a1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -182,7 +182,7 @@ Route::middleware('isVerified')->group(function () { Route::post('profile-security/disable-2fa', [ProfileSecurityController::class, 'disable2fa'])->name('profile.security.disable2fa'); }); -Route::middleware('role:Admin', '2fa')->prefix('admin')->group(function () { +Route::middleware(['role:Admin', '2fa'])->prefix('admin')->group(function () { Route::get('index', [AdminPageController::class, 'index'])->name('admin.index'); // System Metrics API endpoints @@ -303,7 +303,7 @@ Route::prefix('invitations')->name('invitations.')->group(function () { Route::get('/invitation/{token}', [InvitationController::class, 'show'])->name('invitation.show'); // Admin invitation management routes -Route::middleware('role:Admin', '2fa')->prefix('admin/invitations')->name('admin.invitations.')->group(function () { +Route::middleware(['role:Admin', '2fa'])->prefix('admin/invitations')->name('admin.invitations.')->group(function () { Route::get('/', [App\Http\Controllers\Admin\AdminInvitationController::class, 'index'])->name('index'); Route::get('/{id}', [App\Http\Controllers\Admin\AdminInvitationController::class, 'show'])->name('show'); Route::post('/{id}/resend', [App\Http\Controllers\Admin\AdminInvitationController::class, 'resend'])->name('resend');