diff --git a/app/Extensions/helper/helpers.php b/app/Extensions/helper/helpers.php index 13e8d4371..a9d0c0562 100644 --- a/app/Extensions/helper/helpers.php +++ b/app/Extensions/helper/helpers.php @@ -221,6 +221,26 @@ if (! function_exists('runCmd')) { } } +if (! function_exists('imdb_id_pad')) { + /** + * Normalize IMDB ID to 8 zero-padded digits for storage in releases / join consistency. + * Enables index use on releases.imdbid; call when writing to releases.imdbid. + */ + function imdb_id_pad(mixed $id): string + { + if ($id === null || $id === '') { + return '00000000'; + } + $s = (string) $id; + $s = trim($s); + if ($s === '' || $s === '0' || $s === '0000000' || $s === '00000000') { + return '00000000'; + } + + return str_pad((string) (int) $s, 8, '0', STR_PAD_LEFT); + } +} + if (! function_exists('escapeString')) { function escapeString(mixed $string): string diff --git a/app/Models/Release.php b/app/Models/Release.php index dac42c061..415e63e75 100644 --- a/app/Models/Release.php +++ b/app/Models/Release.php @@ -235,7 +235,7 @@ class Release extends Model 'adddate' => $addedDate, 'videos_id' => $videoId, 'tv_episodes_id' => $episodeId, - 'imdbid' => $imDbId, + 'imdbid' => imdb_id_pad($imDbId), 'anidbid' => $aniDbId, 'movieinfo_id' => $movieInfoId !== null ? $movieInfoId->id : $movieInfoId, ] diff --git a/app/Services/MovieBrowseService.php b/app/Services/MovieBrowseService.php index 40bf99fd9..c2ce697ba 100644 --- a/app/Services/MovieBrowseService.php +++ b/app/Services/MovieBrowseService.php @@ -60,7 +60,7 @@ class MovieBrowseService $whereAge = $maxAge > 0 ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.' DAY ' : ''; $browseBy = $this->getBrowseBy(); - $baseWhere = "m.title != '' AND m.imdbid != '0000000' " + $baseWhere = "m.title != '' AND m.imdbid NOT IN ('0000000', '00000000') " ."AND r.passwordstatus {$this->showPasswords} " .$browseBy.' ' .$catFilter @@ -82,11 +82,11 @@ class MovieBrowseService $totalCount = Cache::get($countCacheKey); if ($totalCount === null) { - // Normalize both sides so we match whether imdbid is stored with or without - // leading zeros (e.g. "0099348" vs "99348") in movieinfo or releases. + // releases.imdbid is stored 8-char normalized (imdb_id_pad); only pad movieinfo + // so the index on r.imdbid can be used. $countSql = 'SELECT COUNT(DISTINCT m.imdbid) AS total ' .'FROM movieinfo m ' - .'INNER JOIN releases r ON LPAD(TRIM(r.imdbid), 8, \'0\') = LPAD(TRIM(m.imdbid), 8, \'0\') ' + .'INNER JOIN releases r ON r.imdbid = LPAD(TRIM(m.imdbid), 8, \'0\') ' .'WHERE '.$baseWhere; $totalResult = DB::select($countSql); @@ -122,7 +122,7 @@ class MovieBrowseService .'FROM (' .'SELECT m.imdbid, MAX(r.postdate) AS latest_postdate, COUNT(r.id) AS total_releases ' .'FROM movieinfo m ' - .'INNER JOIN releases r ON LPAD(TRIM(r.imdbid), 8, \'0\') = LPAD(TRIM(m.imdbid), 8, \'0\') ' + .'INNER JOIN releases r ON r.imdbid = LPAD(TRIM(m.imdbid), 8, \'0\') ' .'WHERE '.$baseWhere.' ' .'GROUP BY m.imdbid'.$innerExtraGroupBy.' ' ."ORDER BY {$innerOrderBy} {$order[1]} " // @phpstan-ignore offsetAccess.notFound @@ -141,8 +141,7 @@ class MovieBrowseService $movieImdbIds = $movies->pluck('imdbid')->toArray(); // Step 3: Get top 2 releases per movie using UNION ALL with LIMIT 2 per imdbid. - // Match releases by normalized 8-char imdbid so we find them whether stored - // with or without leading zeros (IMDb IDs are 7–8 digits). + // r.imdbid is stored 8-char normalized so index can be used. $unionParts = []; foreach ($movieImdbIds as $id) { $paddedId = str_pad((string) (int) $id, 8, '0', STR_PAD_LEFT); @@ -150,7 +149,7 @@ class MovieBrowseService $unionParts[] = '(SELECT r.id, r.imdbid, r.guid, r.searchname, ' .'r.size, r.postdate, r.adddate, r.haspreview ' .'FROM releases r ' - .'WHERE LPAD(TRIM(r.imdbid), 8, \'0\') = '.$quotedId.' ' + .'WHERE r.imdbid = '.$quotedId.' ' ."AND r.passwordstatus {$this->showPasswords} " .$catFilter .$whereExcluded @@ -161,14 +160,13 @@ class MovieBrowseService $releasesSql = implode(' UNION ALL ', $unionParts); $releases = DB::select($releasesSql); - // Group releases by normalized imdbid so lookup works regardless of stored format + // Group by imdbid (already 8-char in DB) $releasesByMovie = []; foreach ($releases as $release) { - $normId = str_pad((string) (int) $release->imdbid, 8, '0', STR_PAD_LEFT); - $releasesByMovie[$normId][] = $release; + $releasesByMovie[$release->imdbid][] = $release; } - // Attach releases to each movie object + // Attach releases to each movie (movie imdbid may be 7/8 digit; normalize for lookup) foreach ($movies as $movie) { $normMovieId = str_pad((string) (int) $movie->imdbid, 8, '0', STR_PAD_LEFT); $movie->releases = $releasesByMovie[$normMovieId] ?? []; // @phpstan-ignore assign.propertyReadOnly @@ -197,7 +195,7 @@ class MovieBrowseService $sql = 'SELECT r.id, r.guid, r.searchname, r.size, r.postdate, r.adddate, r.haspreview ' .'FROM releases r ' - .'WHERE LPAD(TRIM(r.imdbid), 8, \'0\') = '.$paddedId.' ' + .'WHERE r.imdbid = '.$paddedId.' ' ."AND r.passwordstatus {$this->showPasswords} " .$whereExcluded.' ' .'ORDER BY r.postdate DESC'; diff --git a/app/Services/MovieService.php b/app/Services/MovieService.php index 53ae02115..533189de8 100644 --- a/app/Services/MovieService.php +++ b/app/Services/MovieService.php @@ -878,7 +878,7 @@ class MovieService public function doMovieUpdate(string $buffer, string $service, int $id, int $processImdb = 1): string|false { $existingImdbId = Release::query()->where('id', $id)->value('imdbid'); - if ($existingImdbId !== null && $existingImdbId !== '' && $existingImdbId !== '0000000') { + if ($existingImdbId !== null && $existingImdbId !== '' && $existingImdbId !== '0000000' && $existingImdbId !== '00000000') { return $existingImdbId; } @@ -897,7 +897,7 @@ class MovieService $movieInfoId = MovieInfo::query()->where('imdbid', $imdbId)->first(['id']); Release::query()->where('id', $id)->update([ - 'imdbid' => $imdbId, + 'imdbid' => imdb_id_pad($imdbId), 'movieinfo_id' => $movieInfoId !== null ? $movieInfoId['id'] : null, ]); @@ -912,7 +912,7 @@ class MovieService $info = $this->updateMovieInfo($imdbId); if ($info === false) { - Release::query()->where('id', $id)->update(['imdbid' => '0000000']); + Release::query()->where('id', $id)->update(['imdbid' => imdb_id_pad('0000000')]); } elseif ($info === true) { $freshMovieInfo = MovieInfo::query()->where('imdbid', $imdbId)->first(['id']); @@ -1027,7 +1027,7 @@ class MovieService } foreach (array_chunk($failedIDs, 100) as $chunk) { - Release::query()->whereIn('id', $chunk)->update(['imdbid' => '0000000']); + Release::query()->whereIn('id', $chunk)->update(['imdbid' => imdb_id_pad('0000000')]); } } }