Skip to content

Commit 95436c8

Browse files
committed
Fix movie and tv searches
1 parent e18d92f commit 95436c8

3 files changed

Lines changed: 164 additions & 0 deletions

File tree

app/Services/Releases/ReleaseSearchService.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,16 @@ private function performMySQLSearch(array $searchFields, int $limit): array
16361636
$query->where($field, 'LIKE', '%'.$term.'%');
16371637
}
16381638
}
1639+
1640+
if ($field === 'searchname' && count($terms) > 1) {
1641+
$normalizedPhrase = $this->normalizeMysqlFallbackPhrase($value);
1642+
if ($normalizedPhrase !== '') {
1643+
$query->whereRaw(
1644+
"LOWER(REPLACE(REPLACE(REPLACE($field, '.', ' '), '-', ' '), '_', ' ')) LIKE ?",
1645+
[$normalizedPhrase.'%']
1646+
);
1647+
}
1648+
}
16391649
}
16401650
}
16411651

@@ -1655,6 +1665,15 @@ private function performMySQLSearch(array $searchFields, int $limit): array
16551665
}
16561666
}
16571667

1668+
private function normalizeMysqlFallbackPhrase(string $value): string
1669+
{
1670+
$normalized = strtolower(trim($value));
1671+
$normalized = str_replace(['.', '-', '_'], ' ', $normalized);
1672+
$normalized = preg_replace('/\s+/', ' ', $normalized);
1673+
1674+
return trim((string) $normalized);
1675+
}
1676+
16581677
/**
16591678
* @param array<string, mixed> $siteIdArr
16601679
*/

tests/Feature/MovieSearchApiTest.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,39 @@ public function movies_search_name_queries_use_exact_search_without_fuzzy_fallba
102102
$this->assertSame('Resurrection.2025.1080p.WEB-DL.TEST', $results[0]->searchname);
103103
}
104104

105+
#[Test]
106+
public function movies_search_mysql_fallback_excludes_unrelated_2025_and_resurrection_releases(): void
107+
{
108+
config(['nntmux.mysql_search_fallback' => true]);
109+
110+
$mock = Mockery::mock(SearchService::class, [$this->app]);
111+
$mock->shouldReceive('searchReleasesByExternalId')->never();
112+
$mock->shouldReceive('searchReleases')->once()->with(['searchname' => 'Resurrection 2025'], 1000)->andReturn([]);
113+
$mock->shouldReceive('searchReleasesWithFuzzy')->never();
114+
$mock->shouldReceive('isAvailable')->andReturn(false);
115+
116+
$this->app->instance(SearchService::class, $mock);
117+
118+
$service = new ReleaseSearchService;
119+
$results = $service->moviesSearch(
120+
'',
121+
-1,
122+
-1,
123+
0,
124+
100,
125+
'Resurrection 2025',
126+
[2030],
127+
-1,
128+
0,
129+
[],
130+
'posted_desc'
131+
);
132+
133+
$this->assertCount(1, $results);
134+
$this->assertSame(['Resurrection.2025.1080p.WEB-DL.TEST'], $results->pluck('searchname')->all());
135+
$this->assertNotContains('Titanic.The.Digital.Resurrection.2025.720p.WEBRip-LAMA', $results->pluck('searchname')->all());
136+
}
137+
105138
private function registerSqliteConcatIfNeeded(): void
106139
{
107140
if (DB::getDriverName() !== 'sqlite') {
@@ -215,6 +248,20 @@ private function seedData(): void
215248
'traktid' => 2002,
216249
'title' => 'Resurrection Road',
217250
],
251+
[
252+
'id' => 3,
253+
'imdbid' => '2468135',
254+
'tmdbid' => 1003,
255+
'traktid' => 2003,
256+
'title' => 'Drop',
257+
],
258+
[
259+
'id' => 4,
260+
'imdbid' => '1123581',
261+
'tmdbid' => 1004,
262+
'traktid' => 2004,
263+
'title' => 'Titanic: The Digital Resurrection',
264+
],
218265
]);
219266

220267
$now = now()->toDateTimeString();
@@ -252,6 +299,38 @@ private function seedData(): void
252299
'imdbid' => '7654321',
253300
'movieinfo_id' => 2,
254301
],
302+
[
303+
'id' => 3,
304+
'searchname' => 'Drop.2025.2160p.BluRay.TEST',
305+
'guid' => 'movie-guid-3',
306+
'postdate' => $now,
307+
'adddate' => $now,
308+
'categories_id' => 2030,
309+
'groups_id' => 1,
310+
'size' => 1000,
311+
'totalpart' => 1,
312+
'passwordstatus' => 0,
313+
'grabs' => 0,
314+
'comments' => 0,
315+
'imdbid' => '2468135',
316+
'movieinfo_id' => 3,
317+
],
318+
[
319+
'id' => 4,
320+
'searchname' => 'Titanic.The.Digital.Resurrection.2025.720p.WEBRip-LAMA',
321+
'guid' => 'movie-guid-4',
322+
'postdate' => $now,
323+
'adddate' => $now,
324+
'categories_id' => 2030,
325+
'groups_id' => 1,
326+
'size' => 1000,
327+
'totalpart' => 1,
328+
'passwordstatus' => 0,
329+
'grabs' => 0,
330+
'comments' => 0,
331+
'imdbid' => '1123581',
332+
'movieinfo_id' => 4,
333+
],
255334
]);
256335

257336
Release::clearBootedModels();

tests/Feature/TvSearchApiTest.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,40 @@ public function tv_search_name_queries_use_exact_search_without_fuzzy_fallback()
151151
$this->assertSame('Simpsons.S06E24.Test', $results[0]->searchname);
152152
}
153153

154+
#[Test]
155+
public function tv_search_mysql_fallback_excludes_mid_title_false_positives_for_multi_word_queries(): void
156+
{
157+
config(['nntmux.mysql_search_fallback' => true]);
158+
159+
$mock = Mockery::mock(SearchService::class, [$this->app]);
160+
$mock->shouldReceive('searchReleasesByExternalId')->never();
161+
$mock->shouldReceive('searchReleases')->once()->with(['searchname' => 'The Simpsons'], 1000)->andReturn([]);
162+
$mock->shouldReceive('searchReleasesWithFuzzy')->never();
163+
$mock->shouldReceive('isAvailable')->andReturn(false);
164+
165+
$this->app->instance(SearchService::class, $mock);
166+
167+
$service = new ReleaseSearchService;
168+
$results = $service->tvSearch(
169+
[],
170+
'',
171+
'',
172+
'',
173+
0,
174+
100,
175+
'The Simpsons',
176+
[5030],
177+
-1,
178+
0,
179+
[],
180+
'posted_desc'
181+
);
182+
183+
$this->assertCount(1, $results);
184+
$this->assertSame(['The.Simpsons.S06E24.Test'], $results->pluck('searchname')->all());
185+
$this->assertNotContains('Titanic.The.Digital.The.Simpsons.2025.Special', $results->pluck('searchname')->all());
186+
}
187+
154188
private function bindSearchIndexMockReturningBothReleases(): void
155189
{
156190
$mock = Mockery::mock(SearchService::class, [$this->app]);
@@ -462,6 +496,38 @@ private function seedData(): void
462496
'videos_id' => 1,
463497
'tv_episodes_id' => 2,
464498
],
499+
[
500+
'id' => 3,
501+
'searchname' => 'The.Simpsons.S06E24.Test',
502+
'guid' => 'guid-the-s06e24',
503+
'postdate' => $now,
504+
'adddate' => $now,
505+
'categories_id' => 5030,
506+
'groups_id' => 1,
507+
'size' => 1500,
508+
'totalpart' => 1,
509+
'passwordstatus' => 0,
510+
'grabs' => 0,
511+
'comments' => 0,
512+
'videos_id' => 1,
513+
'tv_episodes_id' => 1,
514+
],
515+
[
516+
'id' => 4,
517+
'searchname' => 'Titanic.The.Digital.The.Simpsons.2025.Special',
518+
'guid' => 'guid-titanic-simpsons-special',
519+
'postdate' => $now,
520+
'adddate' => $now,
521+
'categories_id' => 5030,
522+
'groups_id' => 1,
523+
'size' => 2500,
524+
'totalpart' => 1,
525+
'passwordstatus' => 0,
526+
'grabs' => 0,
527+
'comments' => 0,
528+
'videos_id' => 1,
529+
'tv_episodes_id' => 2,
530+
],
465531
]);
466532

467533
Release::clearBootedModels();

0 commit comments

Comments
 (0)