mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 23:01:29 +00:00
Make imdbid string everywhere
This commit is contained in:
@@ -76,7 +76,7 @@ class CreateManticoreIndexes extends Command
|
||||
'filename' => ['type' => 'text'],
|
||||
'categories_id' => ['type' => 'integer'],
|
||||
// External media IDs for efficient searching
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'string'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'tvdb' => ['type' => 'integer'],
|
||||
@@ -103,7 +103,7 @@ class CreateManticoreIndexes extends Command
|
||||
'min_infix_len' => 2,
|
||||
],
|
||||
'columns' => [
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'string'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'title' => ['type' => 'text'],
|
||||
@@ -126,7 +126,7 @@ class CreateManticoreIndexes extends Command
|
||||
'trakt' => ['type' => 'integer'],
|
||||
'tvmaze' => ['type' => 'integer'],
|
||||
'tvrage' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'string'],
|
||||
'tmdb' => ['type' => 'integer'],
|
||||
'started' => ['type' => 'text'],
|
||||
'type' => ['type' => 'integer'],
|
||||
|
||||
@@ -81,7 +81,7 @@ class CreateMediaIndexes extends Command
|
||||
'min_infix_len' => 2,
|
||||
],
|
||||
'columns' => [
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'string'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'title' => ['type' => 'text'],
|
||||
@@ -104,7 +104,7 @@ class CreateMediaIndexes extends Command
|
||||
'trakt' => ['type' => 'integer'],
|
||||
'tvmaze' => ['type' => 'integer'],
|
||||
'tvrage' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'string'],
|
||||
'tmdb' => ['type' => 'integer'],
|
||||
'started' => ['type' => 'text'],
|
||||
'type' => ['type' => 'integer'],
|
||||
@@ -228,7 +228,7 @@ class CreateMediaIndexes extends Command
|
||||
$moviesMapping = [
|
||||
'mappings' => [
|
||||
'properties' => [
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'keyword'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'title' => ['type' => 'text', 'analyzer' => 'standard'],
|
||||
@@ -255,7 +255,7 @@ class CreateMediaIndexes extends Command
|
||||
'trakt' => ['type' => 'integer'],
|
||||
'tvmaze' => ['type' => 'integer'],
|
||||
'tvrage' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'keyword'],
|
||||
'tmdb' => ['type' => 'integer'],
|
||||
'started' => ['type' => 'keyword'],
|
||||
'type' => ['type' => 'integer'],
|
||||
|
||||
@@ -202,7 +202,7 @@ class NntmuxPopulateSearchIndexes extends Command
|
||||
'filename' => '',
|
||||
'videos_id' => (int) ($item->videos_id ?? 0),
|
||||
'movieinfo_id' => (int) ($item->movieinfo_id ?? 0),
|
||||
'imdbid' => (int) ($item->imdbid ?? 0),
|
||||
'imdbid' => (string) ($item->imdbid ?? ''),
|
||||
'tmdbid' => 0,
|
||||
'traktid' => 0,
|
||||
'tvdb' => 0,
|
||||
@@ -287,7 +287,7 @@ class NntmuxPopulateSearchIndexes extends Command
|
||||
function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'imdbid' => (int) ($item->imdbid ?? 0),
|
||||
'imdbid' => (string) ($item->imdbid ?? ''),
|
||||
'tmdbid' => (int) ($item->tmdbid ?? 0),
|
||||
'traktid' => (int) ($item->traktid ?? 0),
|
||||
'title' => (string) ($item->title ?? ''),
|
||||
@@ -345,7 +345,7 @@ class NntmuxPopulateSearchIndexes extends Command
|
||||
'trakt' => (int) ($item->trakt ?? 0),
|
||||
'tvmaze' => (int) ($item->tvmaze ?? 0),
|
||||
'tvrage' => (int) ($item->tvrage ?? 0),
|
||||
'imdb' => (int) ($item->imdb ?? 0),
|
||||
'imdb' => (string) ($item->imdb ?? ''),
|
||||
'tmdb' => (int) ($item->tmdb ?? 0),
|
||||
'started' => (string) ($item->started ?? ''),
|
||||
'type' => (int) ($item->type ?? 0),
|
||||
|
||||
@@ -194,7 +194,7 @@ class NntmuxResetDb extends Command
|
||||
'type' => 'long',
|
||||
'index' => false,
|
||||
],
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'keyword'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'title' => [
|
||||
@@ -247,7 +247,7 @@ class NntmuxResetDb extends Command
|
||||
'trakt' => ['type' => 'integer'],
|
||||
'tvmaze' => ['type' => 'integer'],
|
||||
'tvrage' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'keyword'],
|
||||
'tmdb' => ['type' => 'integer'],
|
||||
'started' => ['type' => 'text'],
|
||||
'type' => ['type' => 'integer'],
|
||||
|
||||
@@ -427,7 +427,7 @@ class UpdateReleasesIndexSchema extends Command
|
||||
private function prepareMediaData(mixed $release): array
|
||||
{
|
||||
return [
|
||||
'imdbid' => (int) ($release->imdbid ?: 0),
|
||||
'imdbid' => (string) ($release->imdbid ?: ''),
|
||||
'tmdbid' => (int) ($release->tmdbid ?: ($release->video_tmdb ?: 0)),
|
||||
'traktid' => (int) ($release->traktid ?: ($release->video_trakt ?: 0)),
|
||||
'tvdb' => (int) ($release->tvdb ?: 0),
|
||||
|
||||
@@ -42,7 +42,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private array $mediaFields = [
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'keyword'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'tvdb' => ['type' => 'integer'],
|
||||
@@ -384,7 +384,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
'format' => 'yyyy-MM-dd HH:mm:ss',
|
||||
],
|
||||
// New media-related fields
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'keyword'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'tvdb' => ['type' => 'integer'],
|
||||
@@ -597,7 +597,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
private function prepareMediaData(mixed $release): array
|
||||
{
|
||||
return [
|
||||
'imdbid' => (int) ($release->imdbid ?: 0),
|
||||
'imdbid' => (string) ($release->imdbid ?: ''),
|
||||
'tmdbid' => (int) ($release->tmdbid ?: ($release->video_tmdb ?: 0)),
|
||||
'traktid' => (int) ($release->traktid ?: ($release->video_trakt ?: 0)),
|
||||
'tvdb' => (int) ($release->tvdb ?: 0),
|
||||
|
||||
@@ -217,10 +217,27 @@ if (! function_exists('runCmd')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('imdb_id_is_valid')) {
|
||||
/**
|
||||
* Check whether an IMDB ID string is a valid, non-zero numeric identifier.
|
||||
* IMDB IDs are stored as plain digit strings (e.g. "0137523", "1375666", "14688458")
|
||||
* exactly as provided by upstream sources — no padding, no trimming.
|
||||
*/
|
||||
function imdb_id_is_valid(int|string|null $id): bool
|
||||
{
|
||||
if ($id === null || $id === '' || $id === 0) {
|
||||
return false;
|
||||
}
|
||||
$s = preg_replace('/\D/', '', trim((string) $id));
|
||||
|
||||
return $s !== '' && $s !== '0' && ((int) $s) !== 0;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
* @deprecated Use imdb_id_is_valid() instead. This function exists only for backward
|
||||
* compatibility during the transition period and will be removed.
|
||||
*/
|
||||
function imdb_id_pad(int|string|null $id): string
|
||||
{
|
||||
@@ -467,7 +484,7 @@ if (! function_exists('getReleaseCover')) {
|
||||
$gamesinfo_id = $getValue($release, 'gamesinfo_id');
|
||||
$anidbid = $getValue($release, 'anidbid');
|
||||
|
||||
if (! empty($imdbid) && $imdbid > 0) {
|
||||
if (! empty($imdbid) && imdb_id_is_valid($imdbid)) {
|
||||
$coverType = 'movies';
|
||||
$coverId = (string) $imdbid;
|
||||
} elseif (! empty($videos_id) && $videos_id > 0) {
|
||||
|
||||
@@ -260,7 +260,9 @@ class ApiController extends BasePageController
|
||||
$maxAge = $this->maxAge($request);
|
||||
UserRequest::addApiRequest($uid, $request->getRequestUri());
|
||||
|
||||
$imdbId = $request->has('imdbid') && $request->filled('imdbid') ? (int) $request->input('imdbid') : -1;
|
||||
$imdbId = $request->has('imdbid') && $request->filled('imdbid')
|
||||
? (string) Str::replace('tt', '', (string) $request->input('imdbid'))
|
||||
: '';
|
||||
$tmdbId = $request->has('tmdbid') && $request->filled('tmdbid') ? (int) $request->input('tmdbid') : -1;
|
||||
$traktId = $request->has('traktid') && $request->filled('traktid') ? (int) $request->input('traktid') : -1;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ApiV2Controller extends BasePageController
|
||||
{
|
||||
@@ -133,7 +134,7 @@ class ApiV2Controller extends BasePageController
|
||||
event(new UserAccessedApi($user, $request->ip()));
|
||||
|
||||
// Get request parameters efficiently
|
||||
$imdbId = (int) $request->input('imdbid', -1);
|
||||
$imdbId = (string) Str::replace('tt', '', (string) $request->input('imdbid', ''));
|
||||
$tmdbId = (int) $request->input('tmdbid', -1);
|
||||
$traktId = (int) $request->input('traktid', -1);
|
||||
$minSize = max(0, (int) $request->input('minsize', 0));
|
||||
|
||||
@@ -173,7 +173,8 @@ class RSS extends ApiController
|
||||
DB::raw('COUNT(DISTINCT ud.id) as total_downloads'),
|
||||
])
|
||||
->where('m.title', '!=', '')
|
||||
->where('m.imdbid', '!=', '0000000')
|
||||
->whereNotNull('m.imdbid')
|
||||
->where('m.imdbid', '!=', '')
|
||||
->where('ud.timestamp', '>=', $fortyEightHoursAgo)
|
||||
->groupBy('m.imdbid')
|
||||
->havingRaw('COUNT(DISTINCT ud.id) > 0')
|
||||
|
||||
@@ -240,7 +240,7 @@ class XML_Response
|
||||
$attrs = array_merge($attrs, $this->buildTvAttrArray());
|
||||
}
|
||||
|
||||
if (isset($this->release->imdbid) && $this->release->imdbid > 0) {
|
||||
if (isset($this->release->imdbid) && imdb_id_is_valid($this->release->imdbid)) {
|
||||
$attrs['imdb'] = $this->release->imdbid;
|
||||
}
|
||||
if (isset($this->release->anidbid) && $this->release->anidbid > 0) {
|
||||
@@ -302,7 +302,7 @@ class XML_Response
|
||||
if (isset($this->release->tvmaze) && $this->release->tvmaze > 0) {
|
||||
$attrs['tvmazeid'] = $this->release->tvmaze;
|
||||
}
|
||||
if (isset($this->release->imdb) && $this->release->imdb > 0) {
|
||||
if (isset($this->release->imdb) && imdb_id_is_valid($this->release->imdb)) {
|
||||
$attrs['imdbid'] = $this->release->imdb;
|
||||
}
|
||||
if (isset($this->release->tmdb) && $this->release->tmdb > 0) {
|
||||
@@ -645,7 +645,7 @@ class XML_Response
|
||||
$this->setTvAttr();
|
||||
}
|
||||
|
||||
if (isset($this->release->imdbid) && $this->release->imdbid > 0) {
|
||||
if (isset($this->release->imdbid) && imdb_id_is_valid($this->release->imdbid)) {
|
||||
$this->writeZedAttr('imdb', $this->release->imdbid);
|
||||
}
|
||||
if (isset($this->release->anidbid) && $this->release->anidbid > 0) {
|
||||
@@ -706,7 +706,7 @@ class XML_Response
|
||||
if (isset($this->release->tvmaze) && $this->release->tvmaze > 0) {
|
||||
$this->writeZedAttr('tvmazeid', $this->release->tvmaze);
|
||||
}
|
||||
if (isset($this->release->imdb) && $this->release->imdb > 0) {
|
||||
if (isset($this->release->imdb) && imdb_id_is_valid($this->release->imdb)) {
|
||||
$this->writeZedAttr('imdbid', $this->release->imdb);
|
||||
}
|
||||
if (isset($this->release->tmdb) && $this->release->tmdb > 0) {
|
||||
|
||||
@@ -85,7 +85,7 @@ class DetailsController extends BasePageController
|
||||
}
|
||||
|
||||
$mov = '';
|
||||
if (imdb_id_pad($data['imdbid']) !== '00000000') {
|
||||
if (imdb_id_is_valid($data['imdbid'])) {
|
||||
$mov = $this->movieService->getMovieInfo($data['imdbid']);
|
||||
if (! empty($mov['title'])) {
|
||||
$mov['title'] = str_replace(['/', '\\'], '', $mov['title']);
|
||||
|
||||
@@ -305,7 +305,7 @@ class GetNzbController extends BasePageController
|
||||
];
|
||||
|
||||
// Add optional metadata headers
|
||||
if (! empty($releaseData->imdbid) && $releaseData->imdbid > 0) {
|
||||
if (! empty($releaseData->imdbid) && imdb_id_is_valid($releaseData->imdbid)) {
|
||||
$headers['X-DNZB-MoreInfo'] = "http://www.imdb.com/title/tt{$releaseData->imdbid}";
|
||||
} elseif (! empty($releaseData->tvdb) && $releaseData->tvdb > 0) {
|
||||
$headers['X-DNZB-MoreInfo'] = "http://www.thetvdb.com/?tab=series&id={$releaseData->tvdb}";
|
||||
|
||||
@@ -229,7 +229,8 @@ class MovieController extends BasePageController
|
||||
DB::raw('COUNT(DISTINCT r.id) as release_count'),
|
||||
])
|
||||
->where('m.title', '!=', '')
|
||||
->where('m.imdbid', '!=', '0000000')
|
||||
->whereNotNull('m.imdbid')
|
||||
->where('m.imdbid', '!=', '')
|
||||
->where('ud.timestamp', '>=', $fortyEightHoursAgo)
|
||||
->groupBy('m.imdbid', 'm.title', 'm.year', 'm.rating', 'm.plot', 'm.genre', 'm.cover', 'm.tmdbid', 'm.traktid')
|
||||
->havingRaw('COUNT(DISTINCT ud.id) > 0')
|
||||
|
||||
@@ -13,7 +13,7 @@ use Illuminate\Support\Facades\Cache;
|
||||
* App\Models\MovieInfo.
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $imdbid
|
||||
* @property string $imdbid
|
||||
* @property int $tmdbid
|
||||
* @property string $title
|
||||
* @property string $tagline
|
||||
|
||||
@@ -13,7 +13,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $users_id
|
||||
* @property int|null $imdbid
|
||||
* @property string|null $imdbid
|
||||
* @property string|null $categories List of categories for user movies
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
|
||||
@@ -20,7 +20,7 @@ use Illuminate\Support\Facades\DB;
|
||||
* @property string $countries_id Two character country code (FK to countries table).
|
||||
* @property string $started Date (UTC) of production's first airing.
|
||||
* @property int $anidb ID number for anidb site
|
||||
* @property int $imdb ID number for IMDB site (without the 'tt' prefix).
|
||||
* @property string $imdb ID number for IMDB site (without the 'tt' prefix).
|
||||
* @property int $tmdb ID number for TMDB site.
|
||||
* @property int $trakt ID number for TraktTV site.
|
||||
* @property int $tvdb ID number for TVDB site
|
||||
|
||||
@@ -49,7 +49,7 @@ class MovieInfoObserver
|
||||
try {
|
||||
Search::insertMovie([
|
||||
'id' => $movie->id,
|
||||
'imdbid' => $movie->imdbid ?? 0,
|
||||
'imdbid' => $movie->imdbid ?? '',
|
||||
'tmdbid' => $movie->tmdbid ?? 0,
|
||||
'traktid' => $movie->traktid ?? 0,
|
||||
'title' => $movie->title ?? '',
|
||||
|
||||
@@ -63,7 +63,7 @@ class MovieBrowseService
|
||||
$whereAge = $maxAge > 0 ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.' DAY ' : '';
|
||||
$browseBy = $this->getBrowseBy();
|
||||
|
||||
$baseWhere = "m.title != '' AND m.imdbid NOT IN ('0000000', '00000000') "
|
||||
$baseWhere = "m.title != '' AND m.imdbid IS NOT NULL AND m.imdbid != '' "
|
||||
."AND r.passwordstatus {$this->showPasswords} "
|
||||
.$browseBy.' '
|
||||
.$catFilter
|
||||
@@ -85,11 +85,9 @@ class MovieBrowseService
|
||||
$totalCount = Cache::get($countCacheKey);
|
||||
|
||||
if ($totalCount === null) {
|
||||
// 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 r.imdbid = LPAD(TRIM(m.imdbid), 8, \'0\') '
|
||||
.'INNER JOIN releases r ON r.imdbid = m.imdbid '
|
||||
.'WHERE '.$baseWhere;
|
||||
|
||||
$totalResult = DB::select($countSql);
|
||||
@@ -125,7 +123,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 r.imdbid = LPAD(TRIM(m.imdbid), 8, \'0\') '
|
||||
.'INNER JOIN releases r ON r.imdbid = m.imdbid '
|
||||
.'WHERE '.$baseWhere.' '
|
||||
.'GROUP BY m.imdbid'.$innerExtraGroupBy.' '
|
||||
."ORDER BY {$innerOrderBy} {$order[1]} "
|
||||
@@ -144,11 +142,9 @@ class MovieBrowseService
|
||||
$movieImdbIds = $movies->pluck('imdbid')->toArray();
|
||||
|
||||
// Step 3: Get top 2 releases per movie using UNION ALL with LIMIT 2 per imdbid.
|
||||
// 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);
|
||||
$quotedId = "'".$paddedId."'";
|
||||
$quotedId = escapeString((string) $id);
|
||||
$unionParts[] = '(SELECT r.id, r.imdbid, r.guid, r.searchname, '
|
||||
.'r.size, r.postdate, r.adddate, r.haspreview '
|
||||
.'FROM releases r '
|
||||
@@ -163,16 +159,15 @@ class MovieBrowseService
|
||||
$releasesSql = implode(' UNION ALL ', $unionParts);
|
||||
$releases = DB::select($releasesSql);
|
||||
|
||||
// Group by imdbid (already 8-char in DB)
|
||||
// Group by imdbid
|
||||
$releasesByMovie = [];
|
||||
foreach ($releases as $release) {
|
||||
$releasesByMovie[$release->imdbid][] = $release;
|
||||
}
|
||||
|
||||
// Attach releases to each movie (movie imdbid may be 7/8 digit; normalize for lookup)
|
||||
// Attach releases to each movie
|
||||
foreach ($movies as $movie) {
|
||||
$normMovieId = str_pad((string) (int) $movie->imdbid, 8, '0', STR_PAD_LEFT);
|
||||
$movie->releases = $releasesByMovie[$normMovieId] ?? []; // @phpstan-ignore assign.propertyReadOnly
|
||||
$movie->releases = $releasesByMovie[$movie->imdbid] ?? []; // @phpstan-ignore assign.propertyReadOnly
|
||||
}
|
||||
|
||||
// Set total count on first item (matches existing pattern used by controllers)
|
||||
@@ -194,11 +189,11 @@ class MovieBrowseService
|
||||
public function getMovieReleases(string $imdbid, array $excludedCats = []): array
|
||||
{
|
||||
$whereExcluded = count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : '';
|
||||
$paddedId = "'".str_pad((string) (int) $imdbid, 8, '0', STR_PAD_LEFT)."'";
|
||||
$quotedId = escapeString($imdbid);
|
||||
|
||||
$sql = 'SELECT r.id, r.guid, r.searchname, r.size, r.postdate, r.adddate, r.haspreview '
|
||||
.'FROM releases r '
|
||||
.'WHERE r.imdbid = '.$paddedId.' '
|
||||
.'WHERE r.imdbid = '.$quotedId.' '
|
||||
."AND r.passwordstatus {$this->showPasswords} "
|
||||
.$whereExcluded.' '
|
||||
.'ORDER BY r.postdate DESC';
|
||||
@@ -256,7 +251,7 @@ class MovieBrowseService
|
||||
$bbv .= '.';
|
||||
}
|
||||
if ($bb === 'imdb') {
|
||||
$browseBy .= sprintf(' AND m.imdbid = %d', $bbv);
|
||||
$browseBy .= ' AND m.imdbid = '.escapeString($bbv);
|
||||
} else {
|
||||
$browseBy .= ' AND m.'.$bb.' '.'LIKE '.escapeString('%'.$bbv.'%');
|
||||
}
|
||||
|
||||
@@ -108,19 +108,12 @@ class MovieService
|
||||
*/
|
||||
public function getMovieInfo(int|string|null $imdbId): ?MovieInfo
|
||||
{
|
||||
$lookupIds = $this->movieInfoLookupIds($imdbId);
|
||||
if ($lookupIds === []) {
|
||||
$sanitized = $this->sanitizeImdbId($imdbId);
|
||||
if ($sanitized === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($lookupIds as $lookupId) {
|
||||
$movie = MovieInfo::query()->where('imdbid', $lookupId)->first();
|
||||
if ($movie !== null) {
|
||||
return $movie;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return MovieInfo::query()->where('imdbid', $sanitized)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,33 +124,26 @@ class MovieService
|
||||
*/
|
||||
public function getTrailer(int|string|null $imdbId): string|false
|
||||
{
|
||||
$lookupIds = $this->movieInfoLookupIds($imdbId);
|
||||
if ($lookupIds === []) {
|
||||
$sanitized = $this->sanitizeImdbId($imdbId);
|
||||
if ($sanitized === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($lookupIds as $lookupId) {
|
||||
$trailer = MovieInfo::query()->where('imdbid', $lookupId)->where('trailer', '<>', '')->first(['trailer']);
|
||||
if ($trailer !== null) {
|
||||
return $trailer['trailer'];
|
||||
}
|
||||
}
|
||||
|
||||
$canonicalImdbId = $this->canonicalImdbId($imdbId);
|
||||
if ($canonicalImdbId === null) {
|
||||
return false;
|
||||
$trailer = MovieInfo::query()->where('imdbid', $sanitized)->where('trailer', '<>', '')->first(['trailer']);
|
||||
if ($trailer !== null) {
|
||||
return $trailer['trailer'];
|
||||
}
|
||||
|
||||
if ($this->traktcheck !== null) {
|
||||
$data = $this->traktTv->client->getMovieSummary('tt'.$canonicalImdbId, 'full');
|
||||
$data = $this->traktTv->client->getMovieSummary('tt'.$sanitized, 'full');
|
||||
if (($data !== false) && ! empty($data['trailer'])) {
|
||||
return $data['trailer'];
|
||||
}
|
||||
}
|
||||
|
||||
$trailer = imdb_trailers($canonicalImdbId);
|
||||
$trailer = imdb_trailers($sanitized);
|
||||
if ($trailer) {
|
||||
MovieInfo::query()->whereIn('imdbid', $lookupIds)->update(['trailer' => $trailer]);
|
||||
MovieInfo::query()->where('imdbid', $sanitized)->update(['trailer' => $trailer]);
|
||||
|
||||
return $trailer;
|
||||
}
|
||||
@@ -165,41 +151,10 @@ class MovieService
|
||||
return false;
|
||||
}
|
||||
|
||||
private function movieInfoLookupIds(int|string|null $imdbId): array
|
||||
{
|
||||
$canonicalImdbId = $this->canonicalImdbId($imdbId);
|
||||
if ($canonicalImdbId === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$lookupIds = [$canonicalImdbId];
|
||||
$rawImdbId = $this->sanitizeImdbId($imdbId);
|
||||
if ($rawImdbId !== null && ! in_array($rawImdbId, $lookupIds, true)) {
|
||||
$lookupIds[] = $rawImdbId;
|
||||
}
|
||||
|
||||
$paddedImdbId = imdb_id_pad($canonicalImdbId);
|
||||
if ($paddedImdbId !== '00000000' && ! in_array($paddedImdbId, $lookupIds, true)) {
|
||||
$lookupIds[] = $paddedImdbId;
|
||||
}
|
||||
|
||||
return $lookupIds;
|
||||
}
|
||||
|
||||
private function canonicalImdbId(int|string|null $imdbId): ?string
|
||||
{
|
||||
$sanitizedImdbId = $this->sanitizeImdbId($imdbId);
|
||||
if ($sanitizedImdbId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strlen($sanitizedImdbId) === 8 && str_starts_with($sanitizedImdbId, '0')) {
|
||||
return substr($sanitizedImdbId, 1);
|
||||
}
|
||||
|
||||
return $sanitizedImdbId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize an IMDB ID to its raw numeric string, preserving leading zeros.
|
||||
* Returns null if the ID is empty or all zeros.
|
||||
*/
|
||||
private function sanitizeImdbId(int|string|null $imdbId): ?string
|
||||
{
|
||||
if ($imdbId === null || $imdbId === '') {
|
||||
@@ -207,7 +162,7 @@ class MovieService
|
||||
}
|
||||
|
||||
$sanitizedImdbId = preg_replace('/\D/', '', trim((string) $imdbId));
|
||||
if ($sanitizedImdbId === null || $sanitizedImdbId === '' || imdb_id_pad($sanitizedImdbId) === '00000000') {
|
||||
if ($sanitizedImdbId === null || $sanitizedImdbId === '' || ! imdb_id_is_valid($sanitizedImdbId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1013,12 +968,12 @@ 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' && $existingImdbId !== '00000000') {
|
||||
if ($existingImdbId !== null && imdb_id_is_valid($existingImdbId)) {
|
||||
return $existingImdbId;
|
||||
}
|
||||
|
||||
$imdbId = false;
|
||||
if (preg_match('/(?:imdb.*?)?(?:tt|Title\?)(?P<imdbid>\d{5,8})/i', $buffer, $hits)) {
|
||||
if (preg_match('/(?:imdb.*?)?(?:tt|Title\?)(?P<imdbid>\d{5,})/i', $buffer, $hits)) {
|
||||
$imdbId = $hits['imdbid'];
|
||||
}
|
||||
|
||||
@@ -1032,7 +987,7 @@ class MovieService
|
||||
$movieInfoId = MovieInfo::query()->where('imdbid', $imdbId)->first(['id']);
|
||||
|
||||
Release::query()->where('id', $id)->update([
|
||||
'imdbid' => imdb_id_pad($imdbId),
|
||||
'imdbid' => $imdbId,
|
||||
'movieinfo_id' => $movieInfoId !== null ? $movieInfoId['id'] : null,
|
||||
]);
|
||||
|
||||
@@ -1047,7 +1002,7 @@ class MovieService
|
||||
$info = $this->updateMovieInfo($imdbId);
|
||||
|
||||
if ($info === false) {
|
||||
Release::query()->where('id', $id)->update(['imdbid' => imdb_id_pad('0000000')]);
|
||||
Release::query()->where('id', $id)->update(['imdbid' => '']);
|
||||
} elseif ($info === true) {
|
||||
$freshMovieInfo = MovieInfo::query()->where('imdbid', $imdbId)->first(['id']);
|
||||
|
||||
@@ -1084,7 +1039,10 @@ class MovieService
|
||||
$query = Release::query()
|
||||
->select(['searchname', 'id'])
|
||||
->whereBetween('categories_id', [Category::MOVIE_ROOT, Category::MOVIE_OTHER])
|
||||
->whereNull('imdbid');
|
||||
->where(function ($query): void {
|
||||
$query->whereNull('imdbid')
|
||||
->orWhereIn('imdbid', ['', '0', '0000000', '00000000']);
|
||||
});
|
||||
|
||||
if ($groupID !== '') {
|
||||
$query->where('groups_id', $groupID);
|
||||
@@ -1135,7 +1093,13 @@ class MovieService
|
||||
|
||||
continue;
|
||||
} else {
|
||||
$releaseCheck = Release::query()->where('id', $arr['id'])->whereNotNull('imdbid')->exists();
|
||||
$releaseCheck = Release::query()
|
||||
->where('id', $arr['id'])
|
||||
->where(function ($query): void {
|
||||
$query->whereNotNull('imdbid')
|
||||
->whereNotIn('imdbid', ['', '0', '0000000', '00000000']);
|
||||
})
|
||||
->exists();
|
||||
if ($releaseCheck) {
|
||||
if ($this->echooutput) {
|
||||
cli()->info('Release already has IMDB ID, skipping');
|
||||
@@ -1162,7 +1126,7 @@ class MovieService
|
||||
}
|
||||
|
||||
foreach (array_chunk($failedIDs, 100) as $chunk) {
|
||||
Release::query()->whereIn('id', $chunk)->update(['imdbid' => imdb_id_pad('0000000')]);
|
||||
Release::query()->whereIn('id', $chunk)->update(['imdbid' => '']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ class NfoService
|
||||
}
|
||||
|
||||
// IMDB (movies and TV shows)
|
||||
if (preg_match('/imdb\.com\/title\/(tt\d{7,8})/i', $str, $hits)) {
|
||||
if (preg_match('/imdb\.com\/title\/(tt\d{7,})/i', $str, $hits)) {
|
||||
return ['showid' => trim($hits[1]), 'site' => 'imdb'];
|
||||
}
|
||||
|
||||
@@ -1174,7 +1174,7 @@ class NfoService
|
||||
$ids = [];
|
||||
|
||||
// IMDB
|
||||
if (preg_match_all('/imdb\.com\/title\/(tt\d{7,8})/i', $nfoContent, $matches)) {
|
||||
if (preg_match_all('/imdb\.com\/title\/(tt\d{7,})/i', $nfoContent, $matches)) {
|
||||
foreach ($matches[1] as $id) {
|
||||
$ids[] = ['id' => $id, 'source' => 'imdb'];
|
||||
}
|
||||
|
||||
@@ -841,7 +841,7 @@ class ReleaseRemoverService
|
||||
FROM releases r
|
||||
LEFT JOIN release_files rf ON r.id = rf.releases_id
|
||||
WHERE r.categories_id IN ({$categories})
|
||||
AND (r.imdbid NOT IN ('0000000', 0) OR r.categories_id BETWEEN ".Category::XXX_ROOT.' AND '.Category::XXX_OTHER.")
|
||||
AND ((r.imdbid IS NOT NULL AND r.imdbid NOT IN ('', '0')) OR r.categories_id BETWEEN ".Category::XXX_ROOT.' AND '.Category::XXX_OTHER.")
|
||||
AND r.nfostatus = 1
|
||||
AND r.haspreview = 0
|
||||
AND r.jpgstatus = 0
|
||||
|
||||
@@ -297,7 +297,11 @@ class ReleaseSearchService
|
||||
$externalIds = [];
|
||||
if (! empty($siteIdArr)) {
|
||||
foreach ($siteIdArr as $column => $id) {
|
||||
if ($id > 0 && $column !== 'id') {
|
||||
$hasValue = $column === 'imdb'
|
||||
? ($id !== null && $id !== '' && imdb_id_is_valid((string) $id))
|
||||
: ($id > 0);
|
||||
|
||||
if ($hasValue && $column !== 'id') {
|
||||
// Map column names to search index field names
|
||||
$fieldName = match ($column) {
|
||||
'tvdb' => 'tvdb',
|
||||
@@ -309,7 +313,7 @@ class ReleaseSearchService
|
||||
default => null,
|
||||
};
|
||||
if ($fieldName) {
|
||||
$externalIds[$fieldName] = (int) $id;
|
||||
$externalIds[$fieldName] = $column === 'imdb' ? (string) $id : (int) $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,7 +552,11 @@ class ReleaseSearchService
|
||||
// OPTIMIZATION: Try to find releases using search index external IDs first
|
||||
$externalIds = [];
|
||||
foreach ($siteIdArr as $column => $Id) {
|
||||
if ($Id > 0 && $column !== 'id') {
|
||||
$hasValue = $column === 'imdb'
|
||||
? ($Id !== null && $Id !== '' && imdb_id_is_valid((string) $Id))
|
||||
: ($Id > 0);
|
||||
|
||||
if ($hasValue && $column !== 'id') {
|
||||
$fieldName = match ($column) {
|
||||
'tvdb' => 'tvdb',
|
||||
'trakt' => 'traktid',
|
||||
@@ -559,7 +567,7 @@ class ReleaseSearchService
|
||||
default => null,
|
||||
};
|
||||
if ($fieldName) {
|
||||
$externalIds[$fieldName] = (int) $Id;
|
||||
$externalIds[$fieldName] = $column === 'imdb' ? (string) $Id : (int) $Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,7 +767,7 @@ class ReleaseSearchService
|
||||
* @param array<string, mixed> $excludedCategories
|
||||
* @return Collection|mixed
|
||||
*/
|
||||
public function moviesSearch(int $imDbId = -1, int $tmDbId = -1, int $traktId = -1, int $offset = 0, int $limit = 100, string $name = '', array $cat = [-1], int $maxAge = -1, int $minSize = 0, array $excludedCategories = []): mixed
|
||||
public function moviesSearch(string $imDbId = '', int $tmDbId = -1, int $traktId = -1, int $offset = 0, int $limit = 100, string $name = '', array $cat = [-1], int $maxAge = -1, int $minSize = 0, array $excludedCategories = []): mixed
|
||||
{
|
||||
$searchLimit = $this->determineSearchCandidateLimit($offset, $limit);
|
||||
$searchResult = [];
|
||||
@@ -767,7 +775,7 @@ class ReleaseSearchService
|
||||
// OPTIMIZATION: If we have external IDs, use the search index to find releases directly
|
||||
// This avoids expensive database JOINs by using indexed external ID fields in releases_rt
|
||||
$externalIds = [];
|
||||
if ($imDbId !== -1 && $imDbId > 0) {
|
||||
if ($imDbId !== '' && imdb_id_is_valid($imDbId)) {
|
||||
$externalIds['imdbid'] = $imDbId;
|
||||
}
|
||||
if ($tmDbId !== -1 && $tmDbId > 0) {
|
||||
@@ -822,8 +830,8 @@ class ReleaseSearchService
|
||||
$needsMovieJoin = false;
|
||||
if (empty($searchResult) && ! empty($externalIds)) {
|
||||
$needsMovieJoin = true;
|
||||
if ($imDbId !== -1 && $imDbId > 0) {
|
||||
$conditions[] = sprintf('r.imdbid = %d', $imDbId);
|
||||
if ($imDbId !== '' && imdb_id_is_valid($imDbId)) {
|
||||
$conditions[] = sprintf('r.imdbid = %s', escapeString($imDbId));
|
||||
}
|
||||
if ($tmDbId !== -1 && $tmDbId > 0) {
|
||||
$conditions[] = sprintf('m.tmdbid = %d', $tmDbId);
|
||||
|
||||
@@ -131,7 +131,7 @@ class PostProcessRunner extends BaseRunner
|
||||
SELECT id
|
||||
FROM releases
|
||||
WHERE categories_id BETWEEN 2000 AND 2999
|
||||
AND imdbid IS NULL
|
||||
AND (imdbid IS NULL OR imdbid IN (\'\', \'0\', \'0000000\', \'00000000\'))
|
||||
'.$condLookup.' '.$condRenamedOnly.'
|
||||
LIMIT 1';
|
||||
if (count(DB::select($checkSql)) === 0) {
|
||||
@@ -145,7 +145,7 @@ class PostProcessRunner extends BaseRunner
|
||||
SELECT DISTINCT LEFT(leftguid, 1) AS id, '.$renamedFlag.' AS renamed
|
||||
FROM releases
|
||||
WHERE categories_id BETWEEN 2000 AND 2999
|
||||
AND imdbid IS NULL
|
||||
AND (imdbid IS NULL OR imdbid IN (\'\', \'0\', \'0000000\', \'00000000\'))
|
||||
'.$condLookup.' '.$condRenamedOnly.'
|
||||
LIMIT 16';
|
||||
$queue = DB::select($sql);
|
||||
|
||||
@@ -1059,6 +1059,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'releases.searchname',
|
||||
'releases.fromname',
|
||||
'releases.categories_id',
|
||||
'releases.imdbid',
|
||||
DB::raw('IFNULL(GROUP_CONCAT(rf.name SEPARATOR " "),"") filename'),
|
||||
])
|
||||
->groupBy('releases.id')
|
||||
@@ -1080,6 +1081,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'plainsearchname' => $searchNameDotless,
|
||||
'fromname' => $release->fromname,
|
||||
'categories_id' => $release->categories_id,
|
||||
'imdbid' => (string) ($release->imdbid ?? ''),
|
||||
'filename' => $release->filename, // @phpstan-ignore property.notFound
|
||||
],
|
||||
'doc_as_upsert' => true,
|
||||
@@ -1681,6 +1683,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'plainsearchname' => $searchNameDotless,
|
||||
'fromname' => $parameters['fromname'] ?? '',
|
||||
'categories_id' => $parameters['categories_id'] ?? 0,
|
||||
'imdbid' => (string) ($parameters['imdbid'] ?? ''),
|
||||
'filename' => $parameters['filename'] ?? '',
|
||||
'add_date' => now()->format('Y-m-d H:i:s'),
|
||||
'post_date' => $parameters['postdate'] ?? now()->format('Y-m-d H:i:s'),
|
||||
@@ -1849,7 +1852,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
|
||||
$document = [
|
||||
'id' => $parameters['id'],
|
||||
'imdbid' => (int) ($parameters['imdbid'] ?? 0),
|
||||
'imdbid' => (string) ($parameters['imdbid'] ?? ''),
|
||||
'tmdbid' => (int) ($parameters['tmdbid'] ?? 0),
|
||||
'traktid' => (int) ($parameters['traktid'] ?? 0),
|
||||
'title' => (string) ($parameters['title'] ?? ''),
|
||||
@@ -1971,7 +1974,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
|
||||
$params['body'][] = [
|
||||
'id' => $movie['id'],
|
||||
'imdbid' => (int) ($movie['imdbid'] ?? 0),
|
||||
'imdbid' => (string) ($movie['imdbid'] ?? ''),
|
||||
'tmdbid' => (int) ($movie['tmdbid'] ?? 0),
|
||||
'traktid' => (int) ($movie['traktid'] ?? 0),
|
||||
'title' => (string) ($movie['title'] ?? ''),
|
||||
@@ -2091,7 +2094,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'body' => [
|
||||
'query' => [
|
||||
'term' => [
|
||||
$field => (int) $value,
|
||||
$field => $field === 'imdbid' ? (string) $value : (int) $value,
|
||||
],
|
||||
],
|
||||
'size' => 1,
|
||||
@@ -2141,7 +2144,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'trakt' => (int) ($parameters['trakt'] ?? 0),
|
||||
'tvmaze' => (int) ($parameters['tvmaze'] ?? 0),
|
||||
'tvrage' => (int) ($parameters['tvrage'] ?? 0),
|
||||
'imdb' => (int) ($parameters['imdb'] ?? 0),
|
||||
'imdb' => (string) ($parameters['imdb'] ?? ''),
|
||||
'tmdb' => (int) ($parameters['tmdb'] ?? 0),
|
||||
'started' => (string) ($parameters['started'] ?? ''),
|
||||
'type' => (int) ($parameters['type'] ?? 0),
|
||||
@@ -2262,7 +2265,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'trakt' => (int) ($tvShow['trakt'] ?? 0),
|
||||
'tvmaze' => (int) ($tvShow['tvmaze'] ?? 0),
|
||||
'tvrage' => (int) ($tvShow['tvrage'] ?? 0),
|
||||
'imdb' => (int) ($tvShow['imdb'] ?? 0),
|
||||
'imdb' => (string) ($tvShow['imdb'] ?? ''),
|
||||
'tmdb' => (int) ($tvShow['tmdb'] ?? 0),
|
||||
'started' => (string) ($tvShow['started'] ?? ''),
|
||||
'type' => (int) ($tvShow['type'] ?? 0),
|
||||
@@ -2429,7 +2432,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
$shouldClauses = [];
|
||||
foreach ($externalIds as $field => $value) {
|
||||
if (! empty($value) && in_array($field, ['imdbid', 'tmdbid', 'traktid', 'tvdb', 'tvmaze', 'tvrage'])) {
|
||||
$shouldClauses[] = ['term' => [$field => (int) $value]];
|
||||
$shouldClauses[] = ['term' => [$field => $field === 'imdbid' ? (string) $value : (int) $value]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'categories_id' => (int) ($parameters['categories_id'] ?? 0),
|
||||
'filename' => $parameters['filename'] ?? '',
|
||||
// External media IDs for efficient searching
|
||||
'imdbid' => (int) ($parameters['imdbid'] ?? 0),
|
||||
'imdbid' => (string) ($parameters['imdbid'] ?? ''),
|
||||
'tmdbid' => (int) ($parameters['tmdbid'] ?? 0),
|
||||
'traktid' => (int) ($parameters['traktid'] ?? 0),
|
||||
'tvdb' => (int) ($parameters['tvdb'] ?? 0),
|
||||
@@ -304,7 +304,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'fromname' => (string) ($release['fromname'] ?? ''),
|
||||
'categories_id' => (int) ($release['categories_id'] ?? 0),
|
||||
'filename' => (string) ($release['filename'] ?? ''),
|
||||
'imdbid' => (int) ($release['imdbid'] ?? 0),
|
||||
'imdbid' => (string) ($release['imdbid'] ?? ''),
|
||||
'tmdbid' => (int) ($release['tmdbid'] ?? 0),
|
||||
'traktid' => (int) ($release['traktid'] ?? 0),
|
||||
'tvdb' => (int) ($release['tvdb'] ?? 0),
|
||||
@@ -714,7 +714,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'filename' => ['type' => 'text'],
|
||||
'categories_id' => ['type' => 'integer'],
|
||||
// External media IDs for efficient searching
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'string'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'tvdb' => ['type' => 'integer'],
|
||||
@@ -751,7 +751,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'min_infix_len' => 2,
|
||||
],
|
||||
'columns' => [
|
||||
'imdbid' => ['type' => 'integer'],
|
||||
'imdbid' => ['type' => 'string'],
|
||||
'tmdbid' => ['type' => 'integer'],
|
||||
'traktid' => ['type' => 'integer'],
|
||||
'title' => ['type' => 'text'],
|
||||
@@ -779,7 +779,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'trakt' => ['type' => 'integer'],
|
||||
'tvmaze' => ['type' => 'integer'],
|
||||
'tvrage' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'integer'],
|
||||
'imdb' => ['type' => 'string'],
|
||||
'tmdb' => ['type' => 'integer'],
|
||||
'started' => ['type' => 'text'],
|
||||
'type' => ['type' => 'integer'],
|
||||
@@ -1611,7 +1611,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
|
||||
try {
|
||||
$document = [
|
||||
'imdbid' => (int) ($parameters['imdbid'] ?? 0),
|
||||
'imdbid' => (string) ($parameters['imdbid'] ?? ''),
|
||||
'tmdbid' => (int) ($parameters['tmdbid'] ?? 0),
|
||||
'traktid' => (int) ($parameters['traktid'] ?? 0),
|
||||
'title' => (string) ($parameters['title'] ?? ''),
|
||||
@@ -1713,7 +1713,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
|
||||
$documents[] = [
|
||||
'id' => $movie['id'],
|
||||
'imdbid' => (int) ($movie['imdbid'] ?? 0),
|
||||
'imdbid' => (string) ($movie['imdbid'] ?? ''),
|
||||
'tmdbid' => (int) ($movie['tmdbid'] ?? 0),
|
||||
'traktid' => (int) ($movie['traktid'] ?? 0),
|
||||
'title' => (string) ($movie['title'] ?? ''),
|
||||
@@ -1818,7 +1818,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'trakt' => (int) ($parameters['trakt'] ?? 0),
|
||||
'tvmaze' => (int) ($parameters['tvmaze'] ?? 0),
|
||||
'tvrage' => (int) ($parameters['tvrage'] ?? 0),
|
||||
'imdb' => (int) ($parameters['imdb'] ?? 0),
|
||||
'imdb' => (string) ($parameters['imdb'] ?? ''),
|
||||
'tmdb' => (int) ($parameters['tmdb'] ?? 0),
|
||||
'started' => (string) ($parameters['started'] ?? ''),
|
||||
'type' => (int) ($parameters['type'] ?? 0),
|
||||
@@ -1919,7 +1919,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
'trakt' => (int) ($tvShow['trakt'] ?? 0),
|
||||
'tvmaze' => (int) ($tvShow['tvmaze'] ?? 0),
|
||||
'tvrage' => (int) ($tvShow['tvrage'] ?? 0),
|
||||
'imdb' => (int) ($tvShow['imdb'] ?? 0),
|
||||
'imdb' => (string) ($tvShow['imdb'] ?? ''),
|
||||
'tmdb' => (int) ($tvShow['tmdb'] ?? 0),
|
||||
'started' => (string) ($tvShow['started'] ?? ''),
|
||||
'type' => (int) ($tvShow['type'] ?? 0),
|
||||
@@ -2026,7 +2026,7 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
// Add filters for each external ID provided
|
||||
foreach ($externalIds as $field => $value) {
|
||||
if (! empty($value) && in_array($field, ['imdbid', 'tmdbid', 'traktid', 'tvdb', 'tvmaze', 'tvrage'])) {
|
||||
$query->filter($field, '=', (int) $value);
|
||||
$query->filter($field, '=', $field === 'imdbid' ? (string) $value : (int) $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-12
@@ -409,12 +409,11 @@ class TmdbClient
|
||||
}
|
||||
|
||||
// Try to find the show by IMDB ID
|
||||
$imdbId = $ids['imdb'] ?? 0;
|
||||
$imdbId = $ids['imdb'] ?? '';
|
||||
if (! empty($imdbId)) {
|
||||
// Format IMDB ID with tt prefix if it's numeric
|
||||
$imdbFormatted = is_numeric($imdbId)
|
||||
? 'tt'.str_pad((string) $imdbId, 8, '0', STR_PAD_LEFT)
|
||||
: (string) $imdbId;
|
||||
$imdbFormatted = str_starts_with((string) $imdbId, 'tt')
|
||||
? (string) $imdbId
|
||||
: 'tt'.(string) $imdbId;
|
||||
|
||||
$show = $this->findTvByExternalId($imdbFormatted, 'imdb_id');
|
||||
if ($show !== null && isset($show['id'])) {
|
||||
@@ -452,9 +451,9 @@ class TmdbClient
|
||||
} elseif ($source === 'tvdb' && is_numeric($id) && (int) $id > 0) {
|
||||
$show = $this->findTvByExternalId((string) $id, 'tvdb_id');
|
||||
} elseif ($source === 'imdb') {
|
||||
$imdbFormatted = is_numeric($id)
|
||||
? 'tt'.str_pad((string) $id, 8, '0', STR_PAD_LEFT)
|
||||
: (string) $id;
|
||||
$imdbFormatted = str_starts_with((string) $id, 'tt')
|
||||
? (string) $id
|
||||
: 'tt'.(string) $id;
|
||||
$show = $this->findTvByExternalId($imdbFormatted, 'imdb_id');
|
||||
}
|
||||
|
||||
@@ -471,11 +470,11 @@ class TmdbClient
|
||||
|
||||
$externalIds = self::getArray($show, 'external_ids');
|
||||
|
||||
// Parse IMDB ID to numeric
|
||||
$imdbId = 0;
|
||||
// Parse IMDB ID to raw numeric string
|
||||
$imdbId = '';
|
||||
if (! empty($externalIds['imdb_id'])) {
|
||||
preg_match('/tt(?P<imdbid>\d{6,8})$/i', $externalIds['imdb_id'], $imdb);
|
||||
$imdbId = (int) ($imdb['imdbid'] ?? 0);
|
||||
preg_match('/tt(?P<imdbid>\d{6,})$/i', (string) $externalIds['imdb_id'], $imdb);
|
||||
$imdbId = (string) ($imdb['imdbid'] ?? '');
|
||||
}
|
||||
|
||||
return [
|
||||
|
||||
@@ -307,7 +307,7 @@ class Tmux
|
||||
SELECT
|
||||
SUM(IF(categories_id BETWEEN %d AND %d AND categories_id != %d AND videos_id = 0 AND tv_episodes_id BETWEEN -3 AND 0 AND size > 1048576,1,0)) AS processtv,
|
||||
SUM(IF(categories_id = %d AND anidbid IS NULL,1,0)) AS processanime,
|
||||
SUM(IF(categories_id BETWEEN %d AND %d AND imdbid IS NULL,1,0)) AS processmovies,
|
||||
SUM(IF(categories_id BETWEEN %d AND %d AND (imdbid IS NULL OR imdbid IN (\'\', \'0\', \'0000000\', \'00000000\')),1,0)) AS processmovies,
|
||||
SUM(IF(categories_id IN (%d, %d, %d) AND musicinfo_id IS NULL,1,0)) AS processmusic,
|
||||
SUM(IF(categories_id BETWEEN %d AND %d AND consoleinfo_id IS NULL,1,0)) AS processconsole,
|
||||
SUM(IF(categories_id IN (%s) AND bookinfo_id IS NULL,1,0)) AS processbooks,
|
||||
|
||||
@@ -384,13 +384,13 @@ class TmdbProvider extends AbstractTvProvider
|
||||
->first(['tmdb', 'tvdb', 'imdb']);
|
||||
|
||||
if ($result === null) {
|
||||
return ['tmdb' => 0, 'tvdb' => 0, 'imdb' => 0];
|
||||
return ['tmdb' => 0, 'tvdb' => 0, 'imdb' => ''];
|
||||
}
|
||||
|
||||
return [
|
||||
'tmdb' => (int) ($result->tmdb ?? 0),
|
||||
'tvdb' => (int) ($result->tvdb ?? 0),
|
||||
'imdb' => (int) ($result->imdb ?? 0),
|
||||
'imdb' => (string) ($result->imdb ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -495,11 +495,11 @@ class TmdbProvider extends AbstractTvProvider
|
||||
? 'https://image.tmdb.org/t/p/w500'.$posterPath
|
||||
: '';
|
||||
|
||||
$imdbId = 0;
|
||||
$imdbId = '';
|
||||
$externalIds = TmdbClient::getArray($show, 'external_ids');
|
||||
if (! empty($externalIds['imdb_id'])) {
|
||||
preg_match('/tt(?P<imdbid>\d{6,8})$/i', (string) $externalIds['imdb_id'], $imdb);
|
||||
$imdbId = $imdb['imdbid'] ?? 0;
|
||||
preg_match('/tt(?P<imdbid>\d{6,})$/i', (string) $externalIds['imdb_id'], $imdb);
|
||||
$imdbId = (string) ($imdb['imdbid'] ?? '');
|
||||
}
|
||||
|
||||
$originCountry = TmdbClient::getArray($show, 'origin_country');
|
||||
@@ -558,7 +558,7 @@ class TmdbProvider extends AbstractTvProvider
|
||||
}
|
||||
|
||||
// Try IMDB ID
|
||||
if (! empty($imdbId) && $imdbId > 0) {
|
||||
if (! empty($imdbId) && imdb_id_is_valid($imdbId)) {
|
||||
$ids = $traktService->lookupShowIds($imdbId, 'imdb');
|
||||
if ($ids !== null && ! empty($ids['trakt'])) {
|
||||
return (int) $ids['trakt'];
|
||||
|
||||
@@ -254,14 +254,14 @@ class TraktProvider extends AbstractTvProvider
|
||||
->first(['trakt', 'tmdb', 'tvdb', 'imdb']);
|
||||
|
||||
if ($result === null) {
|
||||
return ['trakt' => 0, 'tmdb' => 0, 'tvdb' => 0, 'imdb' => 0];
|
||||
return ['trakt' => 0, 'tmdb' => 0, 'tvdb' => 0, 'imdb' => ''];
|
||||
}
|
||||
|
||||
return [
|
||||
'trakt' => (int) ($result->trakt ?? 0),
|
||||
'tmdb' => (int) ($result->tmdb ?? 0),
|
||||
'tvdb' => (int) ($result->tvdb ?? 0),
|
||||
'imdb' => (int) ($result->imdb ?? 0),
|
||||
'imdb' => (string) ($result->imdb ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -387,12 +387,12 @@ class TraktProvider extends AbstractTvProvider
|
||||
*/
|
||||
public function formatShowInfo(mixed $show): array
|
||||
{
|
||||
preg_match('/tt(?P<imdbid>\d{6,8})$/i', (string) ($show['ids']['imdb'] ?? ''), $imdb);
|
||||
preg_match('/tt(?P<imdbid>\d{6,})$/i', (string) ($show['ids']['imdb'] ?? ''), $imdb);
|
||||
$this->posterUrl = $show['images']['poster']['thumb'] ?? '';
|
||||
$this->fanartUrl = $show['images']['fanart']['thumb'] ?? '';
|
||||
$this->localizedTZ = $show['airs']['timezone'] ?? '';
|
||||
|
||||
$imdbId = $imdb['imdbid'] ?? 0;
|
||||
$imdbId = (string) ($imdb['imdbid'] ?? '');
|
||||
$tvdbId = $show['ids']['tvdb'] ?? 0;
|
||||
|
||||
// Look up TVMaze ID using TVDB or IMDB
|
||||
@@ -438,8 +438,8 @@ class TraktProvider extends AbstractTvProvider
|
||||
}
|
||||
|
||||
// Try IMDB ID as fallback
|
||||
if (! empty($imdbId) && $imdbId > 0) {
|
||||
$imdbFormatted = 'tt'.str_pad((string) $imdbId, 8, '0', STR_PAD_LEFT);
|
||||
if (! empty($imdbId) && imdb_id_is_valid($imdbId)) {
|
||||
$imdbFormatted = 'tt'.(string) $imdbId;
|
||||
$result = $tvmazeClient->getShowBySiteID('imdb', $imdbFormatted);
|
||||
if ($result !== null && isset($result->id)) {
|
||||
return (int) $result->id;
|
||||
|
||||
@@ -444,12 +444,12 @@ class TvMazeProvider extends AbstractTvProvider
|
||||
$this->posterUrl = (string) ($show->mediumImage ?? '');
|
||||
|
||||
$tvdbId = (int) ($show->externalIDs['thetvdb'] ?? 0);
|
||||
$imdbId = 0;
|
||||
$imdbId = '';
|
||||
|
||||
// Extract IMDB ID if available
|
||||
if (! empty($show->externalIDs['imdb'])) {
|
||||
preg_match('/tt(?P<imdbid>\d{6,9})$/i', (string) $show->externalIDs['imdb'], $imdb);
|
||||
$imdbId = (int) ($imdb['imdbid'] ?? 0);
|
||||
preg_match('/tt(?P<imdbid>\d{6,})$/i', (string) $show->externalIDs['imdb'], $imdb);
|
||||
$imdbId = (string) ($imdb['imdbid'] ?? '');
|
||||
}
|
||||
|
||||
// Look up TMDB and Trakt IDs using available external IDs
|
||||
@@ -497,7 +497,7 @@ class TvMazeProvider extends AbstractTvProvider
|
||||
}
|
||||
}
|
||||
// Try IMDB ID if TMDB not found
|
||||
if ($result['tmdb'] === 0 && ! empty($imdbId) && $imdbId > 0) {
|
||||
if ($result['tmdb'] === 0 && ! empty($imdbId) && imdb_id_is_valid($imdbId)) {
|
||||
$tmdbIds = $tmdbClient->lookupTvShowIds($imdbId, 'imdb');
|
||||
if ($tmdbIds !== null) {
|
||||
$result['tmdb'] = $tmdbIds['tmdb'] ?? 0;
|
||||
|
||||
@@ -403,12 +403,12 @@ class TvdbProvider extends AbstractTvProvider
|
||||
}
|
||||
}
|
||||
|
||||
$imdbId = 0;
|
||||
$imdbId = '';
|
||||
$imdbIdObj = null;
|
||||
try {
|
||||
$imdbIdObj = $this->client->series()->extended((int) $show->tvdb_id);
|
||||
preg_match('/tt(?P<imdbid>\d{6,9})$/i', (string) ($imdbIdObj->getIMDBId() ?? ''), $imdb);
|
||||
$imdbId = $imdb['imdbid'] ?? 0;
|
||||
preg_match('/tt(?P<imdbid>\d{6,})$/i', (string) ($imdbIdObj->getIMDBId() ?? ''), $imdb);
|
||||
$imdbId = (string) ($imdb['imdbid'] ?? '');
|
||||
} catch (ResourceNotFoundException $e) {
|
||||
cli()->error('Show ImdbId not found on TVDB');
|
||||
} catch (\Exception) {
|
||||
@@ -476,7 +476,7 @@ class TvdbProvider extends AbstractTvProvider
|
||||
}
|
||||
|
||||
// Try IMDB ID as fallback
|
||||
if (! empty($imdbId) && $imdbId > 0) {
|
||||
if (! empty($imdbId) && imdb_id_is_valid($imdbId)) {
|
||||
$traktIds = $traktService->lookupShowIds($imdbId, 'imdb');
|
||||
if ($traktIds !== null && ! empty($traktIds['trakt'])) {
|
||||
$result['trakt'] = (int) $traktIds['trakt'];
|
||||
|
||||
@@ -141,6 +141,6 @@ class ApiTransformer extends TransformerAbstract
|
||||
*/
|
||||
protected function nullIfZero($value)
|
||||
{
|
||||
return ($value !== null && $value !== 0) ? $value : $this->null();
|
||||
return ($value !== null && $value !== 0 && $value !== '' && $value !== '0') ? $value : $this->null();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Normalize legacy zero-padded IMDb IDs while preserving legitimate leading-zero IDs.
|
||||
*
|
||||
* Historically some paths stored IMDb IDs with imdb_id_pad(), which converted 7-digit
|
||||
* IDs like 0137523 into 8-digit padded values. Real 8+ digit IMDb IDs are never expected
|
||||
* to start with 0, so values matching /^0\d{7}$/ can safely drop a single leading zero.
|
||||
*
|
||||
* Sentinel values like 0000000 / 00000000 become empty strings to preserve the existing
|
||||
* "attempted but unresolved" behavior in string-based code paths.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->normalizeImdbColumn('releases', 'imdbid');
|
||||
$this->normalizeImdbColumn('movieinfo', 'imdbid');
|
||||
$this->normalizeImdbColumn('user_movies', 'imdbid');
|
||||
$this->normalizeImdbColumn('videos', 'imdb');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// No-op: this migration removes lossy zero-padding and cannot be safely reversed.
|
||||
}
|
||||
|
||||
private function normalizeImdbColumn(string $table, string $column): void
|
||||
{
|
||||
DB::table($table)
|
||||
->whereIn($column, ['0000000', '00000000', '0'])
|
||||
->update([$column => '']);
|
||||
|
||||
DB::table($table)
|
||||
->whereRaw(sprintf("`%s` REGEXP '^0[0-9]{7}$'", $column))
|
||||
->update([$column => DB::raw(sprintf('SUBSTRING(`%s`, 2)', $column))]);
|
||||
}
|
||||
};
|
||||
@@ -248,7 +248,7 @@
|
||||
<a href="#" class="add-to-cart px-2 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-500 transition text-sm" data-guid="{{ $result->guid }}" title="Add to Cart">
|
||||
<i class="icon_cart fa fa-shopping-basket"></i>
|
||||
</a>
|
||||
@if(!empty($result->imdbid) && $result->imdbid != '0' && $result->imdbid != 0 && $result->imdbid != '0000000')
|
||||
@if(!empty($result->imdbid) && imdb_id_is_valid($result->imdbid))
|
||||
<a href="{{ url('/mymovies?id=add&imdb=' . $result->imdbid) }}"
|
||||
class="px-2 py-1 bg-purple-600 dark:bg-purple-700 text-white rounded-lg hover:bg-purple-700 dark:hover:bg-purple-800 transition text-sm"
|
||||
title="Add to My Movies">
|
||||
|
||||
@@ -325,7 +325,7 @@
|
||||
<a href="#" class="add-to-cart px-2 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition text-sm" data-guid="{{ $result->guid }}" title="Add to Cart">
|
||||
<i class="icon_cart fa fa-shopping-basket"></i>
|
||||
</a>
|
||||
@if(!empty($result->imdbid) && $result->imdbid != '0' && $result->imdbid != 0 && $result->imdbid != '0000000')
|
||||
@if(!empty($result->imdbid) && imdb_id_is_valid($result->imdbid))
|
||||
<a href="{{ url('/mymovies?id=add&imdb=' . $result->imdbid) }}"
|
||||
class="px-2 py-1 bg-purple-600 dark:bg-purple-700 text-white rounded-lg hover:bg-purple-700 dark:hover:bg-purple-800 transition text-sm"
|
||||
title="Add to My Movies">
|
||||
@@ -371,7 +371,7 @@
|
||||
<a href="#" class="add-to-cart px-2 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition text-sm" data-guid="{{ $result->guid }}" title="Add to Cart">
|
||||
<i class="icon_cart fa fa-shopping-basket"></i>
|
||||
</a>
|
||||
@if(!empty($result->imdbid) && $result->imdbid != '0' && $result->imdbid != 0 && $result->imdbid != '0000000')
|
||||
@if(!empty($result->imdbid) && imdb_id_is_valid($result->imdbid))
|
||||
<a href="{{ url('/mymovies?id=add&imdb=' . $result->imdbid) }}"
|
||||
class="px-2 py-1 bg-purple-600 dark:bg-purple-700 text-white rounded-lg hover:bg-purple-700 dark:hover:bg-purple-800 transition text-sm"
|
||||
title="Add to My Movies">
|
||||
|
||||
@@ -90,7 +90,7 @@ class MovieServiceTest extends ImdbScraperTestCase
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_finds_movie_info_for_padded_release_imdb_ids(): void
|
||||
public function it_finds_movie_info_for_imdb_ids_with_meaningful_leading_zeroes(): void
|
||||
{
|
||||
Cache::flush();
|
||||
|
||||
@@ -98,20 +98,20 @@ class MovieServiceTest extends ImdbScraperTestCase
|
||||
$service->echooutput = false;
|
||||
|
||||
$service->update([
|
||||
'imdbid' => '8169446',
|
||||
'imdbid' => '0137523',
|
||||
'title' => 'Example Movie',
|
||||
'year' => '2024',
|
||||
]);
|
||||
|
||||
$movie = $service->getMovieInfo('08169446');
|
||||
$movie = $service->getMovieInfo('0137523');
|
||||
|
||||
$this->assertNotNull($movie);
|
||||
$this->assertSame('8169446', $movie->imdbid);
|
||||
$this->assertSame('0137523', $movie->imdbid);
|
||||
$this->assertSame('Example Movie', $movie->title);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_returns_existing_trailer_for_padded_release_imdb_ids(): void
|
||||
public function it_returns_existing_trailer_for_imdb_ids_with_meaningful_leading_zeroes(): void
|
||||
{
|
||||
Cache::flush();
|
||||
|
||||
@@ -119,13 +119,13 @@ class MovieServiceTest extends ImdbScraperTestCase
|
||||
$service->echooutput = false;
|
||||
|
||||
$service->update([
|
||||
'imdbid' => '8169446',
|
||||
'imdbid' => '0137523',
|
||||
'title' => 'Example Movie',
|
||||
'year' => '2024',
|
||||
'trailer' => 'https://example.test/embed/trailer',
|
||||
]);
|
||||
|
||||
$this->assertSame('https://example.test/embed/trailer', $service->getTrailer('08169446'));
|
||||
$this->assertSame('https://example.test/embed/trailer', $service->getTrailer('0137523'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user