mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 23:01:29 +00:00
Update search indexes and queries usage
This commit is contained in:
@@ -140,8 +140,8 @@ class NntmuxCheckIndex extends Command
|
||||
'anime' => 'anime_rt',
|
||||
default => 'releases_rt',
|
||||
};
|
||||
$host = config('nntmux.manticore.host', '127.0.0.1');
|
||||
$port = config('nntmux.manticore.port', 9308);
|
||||
$host = (string) config('search.drivers.manticore.host', '127.0.0.1');
|
||||
$port = (int) config('search.drivers.manticore.port', 9308);
|
||||
|
||||
// Use HTTP API endpoint
|
||||
$baseUrl = "http://{$host}:{$port}";
|
||||
|
||||
@@ -106,13 +106,14 @@ class RSS extends ApiController
|
||||
}
|
||||
}
|
||||
|
||||
$result = Cache::get(md5($sql));
|
||||
$cacheKey = $this->buildVersionedCacheKey($sql);
|
||||
$result = Cache::get($cacheKey);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = Release::fromQuery($sql);
|
||||
Cache::put(md5($sql), $result, $expiresAt);
|
||||
Cache::put($cacheKey, $result, $expiresAt);
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -209,13 +210,14 @@ class RSS extends ApiController
|
||||
);
|
||||
|
||||
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
|
||||
$result = Cache::get(md5($sql));
|
||||
$cacheKey = $this->buildVersionedCacheKey($sql);
|
||||
$result = Cache::get($cacheKey);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = Release::fromQuery($sql);
|
||||
Cache::put(md5($sql), $result, $expiresAt);
|
||||
Cache::put($cacheKey, $result, $expiresAt);
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -238,13 +240,14 @@ class RSS extends ApiController
|
||||
);
|
||||
|
||||
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
|
||||
$result = Cache::get(md5($sql));
|
||||
$cacheKey = $this->buildVersionedCacheKey($sql);
|
||||
$result = Cache::get($cacheKey);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
$result = Release::fromQuery($sql);
|
||||
|
||||
Cache::put(md5($sql), $result, $expiresAt);
|
||||
Cache::put($cacheKey, $result, $expiresAt);
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -381,6 +384,13 @@ class RSS extends ApiController
|
||||
});
|
||||
}
|
||||
|
||||
private function buildVersionedCacheKey(string $sql): string
|
||||
{
|
||||
$cacheVersion = (int) Cache::get('release_search_cache_version', 1);
|
||||
|
||||
return md5($cacheVersion.$sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first instance of a column from a table where the column is greater than 0, ordered by a specified column.
|
||||
*
|
||||
|
||||
@@ -97,10 +97,20 @@ class BookService
|
||||
$q = MetadataSearchLookup::normalizeBooleanSearchWords($searchWords);
|
||||
if ($q !== '') {
|
||||
$hits = Search::searchSecondary(SecondarySearchIndex::Books, $q, 25);
|
||||
foreach ($hits['id'] as $bid) {
|
||||
$found = BookInfo::query()->where('id', $bid)->first();
|
||||
if ($found !== null) {
|
||||
return $found;
|
||||
$bookIds = array_values(array_map('intval', $hits['id'] ?? []));
|
||||
if ($bookIds !== []) {
|
||||
$rowsById = BookInfo::query()
|
||||
->whereIn('id', $bookIds)
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
foreach ($bookIds as $bookId) {
|
||||
if ($rowsById->has($bookId)) {
|
||||
/** @var BookInfo $book */
|
||||
$book = $rowsById->get($bookId);
|
||||
|
||||
return $book;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,10 +106,20 @@ class ConsoleService
|
||||
$q = MetadataSearchLookup::normalizeBooleanSearchWords($searchWords);
|
||||
if ($q !== '') {
|
||||
$hits = Search::searchSecondary(SecondarySearchIndex::Console, $q, 25);
|
||||
foreach ($hits['id'] as $cid) {
|
||||
$found = ConsoleInfo::query()->where('id', $cid)->first();
|
||||
if ($found !== null) {
|
||||
return $found;
|
||||
$consoleIds = array_values(array_map('intval', $hits['id'] ?? []));
|
||||
if ($consoleIds !== []) {
|
||||
$rowsById = ConsoleInfo::query()
|
||||
->whereIn('id', $consoleIds)
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
foreach ($consoleIds as $consoleId) {
|
||||
if ($rowsById->has($consoleId)) {
|
||||
/** @var ConsoleInfo $console */
|
||||
$console = $rowsById->get($consoleId);
|
||||
|
||||
return $console;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,10 +93,21 @@ class MusicService
|
||||
$q = MetadataSearchLookup::normalizeBooleanSearchWords($searchwords);
|
||||
if ($q !== '') {
|
||||
$hits = Search::searchSecondary(SecondarySearchIndex::Music, $q, 25);
|
||||
foreach ($hits['id'] as $mid) {
|
||||
$found = MusicInfo::query()->with('genre')->where('id', $mid)->first();
|
||||
if ($found !== null) {
|
||||
return $found;
|
||||
$musicIds = array_values(array_map('intval', $hits['id'] ?? []));
|
||||
if ($musicIds !== []) {
|
||||
$rowsById = MusicInfo::query()
|
||||
->with('genre')
|
||||
->whereIn('id', $musicIds)
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
foreach ($musicIds as $musicId) {
|
||||
if ($rowsById->has($musicId)) {
|
||||
/** @var MusicInfo $music */
|
||||
$music = $rowsById->get($musicId);
|
||||
|
||||
return $music;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ class ReleaseSearchService
|
||||
$offset
|
||||
);
|
||||
|
||||
$cacheKey = md5($sql);
|
||||
$cacheKey = md5($this->getCacheVersion().$sql);
|
||||
$cachedReleases = Cache::get($cacheKey);
|
||||
if ($cachedReleases !== null) {
|
||||
return $cachedReleases;
|
||||
@@ -969,7 +969,8 @@ class ReleaseSearchService
|
||||
$whereSql
|
||||
);
|
||||
$sql = sprintf('%s ORDER BY postdate DESC LIMIT %d OFFSET %d', $baseSql, $limit, $offset);
|
||||
$releases = Cache::get(md5($sql));
|
||||
$cacheKey = md5($this->getCacheVersion().$sql);
|
||||
$releases = Cache::get($cacheKey);
|
||||
if ($releases !== null) {
|
||||
return $releases;
|
||||
}
|
||||
@@ -980,7 +981,7 @@ class ReleaseSearchService
|
||||
);
|
||||
}
|
||||
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
|
||||
Cache::put(md5($sql), $releases, $expiresAt);
|
||||
Cache::put($cacheKey, $releases, $expiresAt);
|
||||
|
||||
return $releases;
|
||||
}
|
||||
@@ -1060,7 +1061,8 @@ class ReleaseSearchService
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
$releases = Cache::get(md5($sql));
|
||||
$cacheKey = md5($this->getCacheVersion().$sql);
|
||||
$releases = Cache::get($cacheKey);
|
||||
if ($releases !== null) {
|
||||
return $releases;
|
||||
}
|
||||
@@ -1069,7 +1071,7 @@ class ReleaseSearchService
|
||||
$releases[0]->_totalrows = $this->getPagerCount($baseSql);
|
||||
}
|
||||
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
|
||||
Cache::put(md5($sql), $releases, $expiresAt);
|
||||
Cache::put($cacheKey, $releases, $expiresAt);
|
||||
|
||||
return $releases;
|
||||
}
|
||||
|
||||
@@ -231,6 +231,14 @@ interface SearchServiceInterface
|
||||
*/
|
||||
public function searchMovieByExternalId(string $field, int|string $value): ?array;
|
||||
|
||||
/**
|
||||
* Search movies by any provided external IDs in one call.
|
||||
*
|
||||
* @param array<string, mixed> $externalIds Keys: imdbid, tmdbid, traktid
|
||||
* @return array<string, mixed>|null Movie data or null if not found
|
||||
*/
|
||||
public function searchMovieByExternalIds(array $externalIds): ?array;
|
||||
|
||||
/**
|
||||
* Search movies index by field-specific terms (title, director, actors, genre).
|
||||
*
|
||||
@@ -286,6 +294,14 @@ interface SearchServiceInterface
|
||||
*/
|
||||
public function searchTvShowByExternalId(string $field, int|string $value): ?array;
|
||||
|
||||
/**
|
||||
* Search TV shows by any provided external IDs in one call.
|
||||
*
|
||||
* @param array<string, mixed> $externalIds Keys: tvdb, trakt, tvmaze, tvrage, imdb, tmdb
|
||||
* @return array<string, mixed>|null TV show data or null if not found
|
||||
*/
|
||||
public function searchTvShowByExternalIds(array $externalIds): ?array;
|
||||
|
||||
/**
|
||||
* Search releases by external media IDs.
|
||||
* Used to find releases associated with a specific movie or TV show.
|
||||
@@ -296,6 +312,14 @@ interface SearchServiceInterface
|
||||
*/
|
||||
public function searchReleasesByExternalId(array $externalIds, int $limit = 1000): array;
|
||||
|
||||
/**
|
||||
* Search releases by multiple external-ID sets in a single call.
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $externalIdSets
|
||||
* @return array<string, mixed> Array of release IDs
|
||||
*/
|
||||
public function searchReleasesByMultipleExternalIds(array $externalIdSets, int $limit = 1000): array;
|
||||
|
||||
/**
|
||||
* Search releases by category ID using the search index.
|
||||
* This provides a fast way to get release IDs for a specific category without hitting the database.
|
||||
|
||||
@@ -1663,7 +1663,8 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
array $fields,
|
||||
int $limit,
|
||||
array $options = [],
|
||||
bool $includeDateSort = true
|
||||
bool $includeDateSort = true,
|
||||
bool $useScroll = false
|
||||
): array {
|
||||
$queryString = array_merge([
|
||||
'query' => $keywords,
|
||||
@@ -1679,8 +1680,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
$sort[] = ['post_date' => ['order' => 'desc', 'unmapped_type' => 'date', 'missing' => '_last']];
|
||||
}
|
||||
|
||||
return [
|
||||
'scroll' => self::SCROLL_TIMEOUT,
|
||||
$search = [
|
||||
'index' => $index,
|
||||
'body' => [
|
||||
'query' => [
|
||||
@@ -1692,6 +1692,12 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'track_total_hits' => true,
|
||||
],
|
||||
];
|
||||
|
||||
if ($useScroll) {
|
||||
$search['scroll'] = self::SCROLL_TIMEOUT;
|
||||
}
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1746,6 +1752,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
}
|
||||
|
||||
$scrollId = null;
|
||||
$useScroll = isset($search['scroll']) && is_string($search['scroll']) && $search['scroll'] !== '';
|
||||
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
@@ -1771,14 +1778,19 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
|
||||
$searchResult = [];
|
||||
|
||||
while (isset($results['hits']['hits']) && count($results['hits']['hits']) > 0) {
|
||||
foreach ($results['hits']['hits'] as $result) {
|
||||
if ($fullResults) {
|
||||
$searchResult[] = $result['_source'];
|
||||
} else {
|
||||
$searchResult[] = $result['_source']['id'] ?? $result['_id'];
|
||||
}
|
||||
foreach ($results['hits']['hits'] ?? [] as $result) {
|
||||
if ($fullResults) {
|
||||
$searchResult[] = $result['_source'];
|
||||
} else {
|
||||
$searchResult[] = $result['_source']['id'] ?? $result['_id'];
|
||||
}
|
||||
}
|
||||
|
||||
if (! $useScroll) {
|
||||
return $searchResult;
|
||||
}
|
||||
|
||||
while (isset($results['hits']['hits']) && count($results['hits']['hits']) > 0) {
|
||||
|
||||
// Handle scrolling for large result sets
|
||||
if (! isset($results['_scroll_id'])) {
|
||||
@@ -1790,6 +1802,14 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'scroll_id' => $scrollId,
|
||||
'scroll' => self::SCROLL_TIMEOUT,
|
||||
]);
|
||||
|
||||
foreach ($results['hits']['hits'] ?? [] as $result) {
|
||||
if ($fullResults) {
|
||||
$searchResult[] = $result['_source'];
|
||||
} else {
|
||||
$searchResult[] = $result['_source']['id'] ?? $result['_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $searchResult; // @phpstan-ignore return.type
|
||||
@@ -2171,11 +2191,43 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
*/
|
||||
public function searchMovieByExternalId(string $field, int|string $value): ?array
|
||||
{
|
||||
if (empty($value) || ! in_array($field, ['imdbid', 'tmdbid', 'traktid'])) {
|
||||
if (empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'es:movie:'.$field.':'.$value;
|
||||
return $this->searchMovieByExternalIds([$field => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function searchMovieByExternalIds(array $externalIds): ?array
|
||||
{
|
||||
$allowedFields = ['imdbid', 'tmdbid', 'traktid'];
|
||||
$shouldClauses = [];
|
||||
$cacheableValues = [];
|
||||
|
||||
foreach ($allowedFields as $field) {
|
||||
$value = $externalIds[$field] ?? null;
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$typedValue = $field === 'imdbid' ? (string) $value : (int) $value;
|
||||
if ($typedValue === '' || $typedValue === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$shouldClauses[] = ['term' => [$field => $typedValue]];
|
||||
$cacheableValues[$field] = $typedValue;
|
||||
}
|
||||
|
||||
if ($shouldClauses === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'es:movie:any:'.md5(serialize($cacheableValues));
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
@@ -2188,8 +2240,9 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'index' => $this->getMoviesIndex(),
|
||||
'body' => [
|
||||
'query' => [
|
||||
'term' => [
|
||||
$field => $field === 'imdbid' ? (string) $value : (int) $value,
|
||||
'bool' => [
|
||||
'should' => $shouldClauses,
|
||||
'minimum_should_match' => 1,
|
||||
],
|
||||
],
|
||||
'size' => 1,
|
||||
@@ -2207,9 +2260,8 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch searchMovieByExternalId error: '.$e->getMessage(), [
|
||||
'field' => $field,
|
||||
'value' => $value,
|
||||
Log::error('ElasticSearch searchMovieByExternalIds error: '.$e->getMessage(), [
|
||||
'externalIds' => $externalIds,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -2456,11 +2508,43 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
*/
|
||||
public function searchTvShowByExternalId(string $field, int|string $value): ?array
|
||||
{
|
||||
if (empty($value) || ! in_array($field, ['tvdb', 'trakt', 'tvmaze', 'tvrage', 'imdb', 'tmdb'])) {
|
||||
if (empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'es:tvshow:'.$field.':'.$value;
|
||||
return $this->searchTvShowByExternalIds([$field => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function searchTvShowByExternalIds(array $externalIds): ?array
|
||||
{
|
||||
$allowedFields = ['tvdb', 'trakt', 'tvmaze', 'tvrage', 'imdb', 'tmdb'];
|
||||
$shouldClauses = [];
|
||||
$cacheableValues = [];
|
||||
|
||||
foreach ($allowedFields as $field) {
|
||||
$value = $externalIds[$field] ?? null;
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$typedValue = $field === 'imdb' ? (string) $value : (int) $value;
|
||||
if ($typedValue === '' || $typedValue === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$shouldClauses[] = ['term' => [$field => $typedValue]];
|
||||
$cacheableValues[$field] = $typedValue;
|
||||
}
|
||||
|
||||
if ($shouldClauses === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'es:tvshow:any:'.md5(serialize($cacheableValues));
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
@@ -2473,8 +2557,9 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'index' => $this->getTvShowsIndex(),
|
||||
'body' => [
|
||||
'query' => [
|
||||
'term' => [
|
||||
$field => (int) $value,
|
||||
'bool' => [
|
||||
'should' => $shouldClauses,
|
||||
'minimum_should_match' => 1,
|
||||
],
|
||||
],
|
||||
'size' => 1,
|
||||
@@ -2492,9 +2577,8 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch searchTvShowByExternalId error: '.$e->getMessage(), [
|
||||
'field' => $field,
|
||||
'value' => $value,
|
||||
Log::error('ElasticSearch searchTvShowByExternalIds error: '.$e->getMessage(), [
|
||||
'externalIds' => $externalIds,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -2511,11 +2595,42 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
*/
|
||||
public function searchReleasesByExternalId(array $externalIds, int $limit = 1000): array
|
||||
{
|
||||
if (empty($externalIds)) {
|
||||
return $this->searchReleasesByMultipleExternalIds([$externalIds], $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $externalIdSets
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function searchReleasesByMultipleExternalIds(array $externalIdSets, int $limit = 1000): array
|
||||
{
|
||||
if ($externalIdSets === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cacheKey = 'es:releases:extid:'.md5(serialize($externalIds));
|
||||
$shouldClauses = [];
|
||||
$cachePayload = [];
|
||||
|
||||
foreach ($externalIdSets as $externalIds) {
|
||||
$setClauses = $this->buildReleaseExternalIdShouldClauses($externalIds);
|
||||
if ($setClauses === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$shouldClauses[] = [
|
||||
'bool' => [
|
||||
'should' => $setClauses,
|
||||
'minimum_should_match' => 1,
|
||||
],
|
||||
];
|
||||
$cachePayload[] = $externalIds;
|
||||
}
|
||||
|
||||
if ($shouldClauses === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cacheKey = 'es:releases:extid_sets:'.md5(serialize([$cachePayload, $limit]));
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
@@ -2524,17 +2639,6 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
|
||||
$shouldClauses = [];
|
||||
foreach ($externalIds as $field => $value) {
|
||||
if (! empty($value) && in_array($field, ['imdbid', 'tmdbid', 'traktid', 'tvdb', 'tvmaze', 'tvrage'])) {
|
||||
$shouldClauses[] = ['term' => [$field => $field === 'imdbid' ? (string) $value : (int) $value]];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($shouldClauses)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$searchParams = [
|
||||
'index' => $this->getReleasesIndex(),
|
||||
'body' => [
|
||||
@@ -2552,27 +2656,42 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
$response = $client->search($searchParams);
|
||||
|
||||
$resultIds = [];
|
||||
if (isset($response['hits']['hits'])) {
|
||||
foreach ($response['hits']['hits'] as $hit) {
|
||||
$resultIds[] = $hit['_id'];
|
||||
}
|
||||
foreach ($response['hits']['hits'] ?? [] as $hit) {
|
||||
$resultIds[] = $hit['_id'];
|
||||
}
|
||||
|
||||
if (! empty($resultIds)) {
|
||||
if ($resultIds !== []) {
|
||||
Cache::put($cacheKey, $resultIds, now()->addMinutes(self::CACHE_TTL_MINUTES));
|
||||
}
|
||||
|
||||
return $resultIds; // @phpstan-ignore return.type
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch searchReleasesByExternalId error: '.$e->getMessage(), [
|
||||
'externalIds' => $externalIds,
|
||||
Log::error('ElasticSearch searchReleasesByMultipleExternalIds error: '.$e->getMessage(), [
|
||||
'externalIdSets' => $externalIdSets,
|
||||
]);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function buildReleaseExternalIdShouldClauses(array $externalIds): array
|
||||
{
|
||||
$clauses = [];
|
||||
foreach ($externalIds as $field => $value) {
|
||||
if (empty($value) || ! in_array($field, ['imdbid', 'tmdbid', 'traktid', 'tvdb', 'tvmaze', 'tvrage'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$clauses[] = ['term' => [$field => $field === 'imdbid' ? (string) $value : (int) $value]];
|
||||
}
|
||||
|
||||
return $clauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search releases by category ID using the search index.
|
||||
* This provides a fast way to get release IDs for a specific category without hitting the database.
|
||||
@@ -2647,7 +2766,6 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
* @param array<string, mixed> $categoryIds Array of category IDs to filter by (empty for all categories)
|
||||
* @param int $limit Maximum number of results
|
||||
* @return array<string, mixed>
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function searchReleasesWithCategoryFilter(string $searchTerm, array $categoryIds = [], int $limit = 1000): array
|
||||
{
|
||||
@@ -2975,7 +3093,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
return ['success' => 0, 'errors' => 0];
|
||||
}
|
||||
|
||||
$success = 0;
|
||||
$validDocs = [];
|
||||
$errors = 0;
|
||||
$indexName = $this->getSecondaryIndexName($index);
|
||||
|
||||
@@ -2986,18 +3104,33 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($doc['id']);
|
||||
try {
|
||||
$this->getClient()->index([
|
||||
'index' => $indexName,
|
||||
'id' => (string) $docId,
|
||||
'body' => $doc,
|
||||
]);
|
||||
$success++;
|
||||
} catch (\Throwable $e) {
|
||||
$errors++;
|
||||
Log::error('ElasticSearch bulkInsertSecondary row error: '.$e->getMessage());
|
||||
}
|
||||
$validDocs[] = ['id' => $docId, 'body' => $doc];
|
||||
}
|
||||
|
||||
if ($validDocs === []) {
|
||||
return ['success' => 0, 'errors' => $errors];
|
||||
}
|
||||
|
||||
$params = ['body' => []];
|
||||
foreach ($validDocs as $doc) {
|
||||
$params['body'][] = [
|
||||
'index' => [
|
||||
'_index' => $indexName,
|
||||
'_id' => (string) $doc['id'],
|
||||
],
|
||||
];
|
||||
$params['body'][] = $doc['body'];
|
||||
}
|
||||
|
||||
$success = count($validDocs);
|
||||
try {
|
||||
$this->executeBulk($params);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch bulkInsertSecondary error: '.$e->getMessage(), ['secondary' => $index->value]);
|
||||
$errors += $success;
|
||||
$success = 0;
|
||||
}
|
||||
|
||||
return ['success' => $success, 'errors' => $errors];
|
||||
|
||||
@@ -1865,35 +1865,61 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
*/
|
||||
public function searchMovieByExternalId(string $field, int|string $value): ?array
|
||||
{
|
||||
if (empty($value) || ! in_array($field, ['imdbid', 'tmdbid', 'traktid'])) {
|
||||
if (empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'manticore:movie:'.$field.':'.$value;
|
||||
return $this->searchMovieByExternalIds([$field => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function searchMovieByExternalIds(array $externalIds): ?array
|
||||
{
|
||||
$allowedFields = ['imdbid', 'tmdbid', 'traktid'];
|
||||
$normalized = [];
|
||||
|
||||
foreach ($allowedFields as $field) {
|
||||
$value = $externalIds[$field] ?? null;
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$normalized[$field] = $field === 'imdbid' ? (string) $value : (int) $value;
|
||||
}
|
||||
|
||||
if ($normalized === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'manticore:movie:any:'.md5(serialize($normalized));
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
try {
|
||||
$query = (new Search($this->manticoreSearch))
|
||||
->setTable($this->getMoviesIndex())
|
||||
->filter($field, '=', (int) $value)
|
||||
->limit(1);
|
||||
foreach ($normalized as $field => $value) {
|
||||
$query = (new Search($this->manticoreSearch))
|
||||
->setTable($this->getMoviesIndex())
|
||||
->filter($field, '=', $value)
|
||||
->limit(1);
|
||||
|
||||
$results = $query->get();
|
||||
$results = $query->get();
|
||||
|
||||
foreach ($results as $doc) {
|
||||
$data = $doc->getData();
|
||||
$data['id'] = $doc->getId();
|
||||
Cache::put($cacheKey, $data, now()->addMinutes($this->config['cache_minutes'] ?? 5));
|
||||
foreach ($results as $doc) {
|
||||
$data = $doc->getData();
|
||||
$data['id'] = $doc->getId();
|
||||
Cache::put($cacheKey, $data, now()->addMinutes($this->config['cache_minutes'] ?? 5));
|
||||
|
||||
return $data;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ManticoreSearch searchMovieByExternalId error: '.$e->getMessage(), [
|
||||
'field' => $field,
|
||||
'value' => $value,
|
||||
Log::error('ManticoreSearch searchMovieByExternalIds error: '.$e->getMessage(), [
|
||||
'externalIds' => $externalIds,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -2065,35 +2091,61 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
*/
|
||||
public function searchTvShowByExternalId(string $field, int|string $value): ?array
|
||||
{
|
||||
if (empty($value) || ! in_array($field, ['tvdb', 'trakt', 'tvmaze', 'tvrage', 'imdb', 'tmdb'])) {
|
||||
if (empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'manticore:tvshow:'.$field.':'.$value;
|
||||
return $this->searchTvShowByExternalIds([$field => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function searchTvShowByExternalIds(array $externalIds): ?array
|
||||
{
|
||||
$allowedFields = ['tvdb', 'trakt', 'tvmaze', 'tvrage', 'imdb', 'tmdb'];
|
||||
$normalized = [];
|
||||
|
||||
foreach ($allowedFields as $field) {
|
||||
$value = $externalIds[$field] ?? null;
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$normalized[$field] = $field === 'imdb' ? (string) $value : (int) $value;
|
||||
}
|
||||
|
||||
if ($normalized === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'manticore:tvshow:any:'.md5(serialize($normalized));
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
try {
|
||||
$query = (new Search($this->manticoreSearch))
|
||||
->setTable($this->getTvShowsIndex())
|
||||
->filter($field, '=', (int) $value)
|
||||
->limit(1);
|
||||
foreach ($normalized as $field => $value) {
|
||||
$query = (new Search($this->manticoreSearch))
|
||||
->setTable($this->getTvShowsIndex())
|
||||
->filter($field, '=', $value)
|
||||
->limit(1);
|
||||
|
||||
$results = $query->get();
|
||||
$results = $query->get();
|
||||
|
||||
foreach ($results as $doc) {
|
||||
$data = $doc->getData();
|
||||
$data['id'] = $doc->getId();
|
||||
Cache::put($cacheKey, $data, now()->addMinutes($this->config['cache_minutes'] ?? 5));
|
||||
foreach ($results as $doc) {
|
||||
$data = $doc->getData();
|
||||
$data['id'] = $doc->getId();
|
||||
Cache::put($cacheKey, $data, now()->addMinutes($this->config['cache_minutes'] ?? 5));
|
||||
|
||||
return $data;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ManticoreSearch searchTvShowByExternalId error: '.$e->getMessage(), [
|
||||
'field' => $field,
|
||||
'value' => $value,
|
||||
Log::error('ManticoreSearch searchTvShowByExternalIds error: '.$e->getMessage(), [
|
||||
'externalIds' => $externalIds,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -2110,47 +2162,83 @@ class ManticoreSearchDriver implements SearchDriverInterface
|
||||
*/
|
||||
public function searchReleasesByExternalId(array $externalIds, int $limit = 1000): array
|
||||
{
|
||||
if (empty($externalIds)) {
|
||||
return $this->searchReleasesByMultipleExternalIds([$externalIds], $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $externalIdSets
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function searchReleasesByMultipleExternalIds(array $externalIdSets, int $limit = 1000): array
|
||||
{
|
||||
if ($externalIdSets === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cacheKey = 'manticore:releases:extid:'.md5(serialize($externalIds));
|
||||
$normalizedLimit = min($limit, 10000);
|
||||
$cacheKey = 'manticore:releases:extid_sets:'.md5(serialize([$externalIdSets, $normalizedLimit]));
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
try {
|
||||
$query = (new Search($this->manticoreSearch))
|
||||
->setTable($this->getReleasesIndex())
|
||||
->limit(min($limit, 10000));
|
||||
|
||||
// Add filters for each external ID provided
|
||||
$queries = [];
|
||||
foreach ($externalIdSets as $externalIds) {
|
||||
foreach ($externalIds as $field => $value) {
|
||||
if (! empty($value) && in_array($field, ['imdbid', 'tmdbid', 'traktid', 'tvdb', 'tvmaze', 'tvrage'])) {
|
||||
$query->filter($field, '=', $field === 'imdbid' ? (string) $value : (int) $value);
|
||||
if (empty($value) || ! in_array($field, ['imdbid', 'tmdbid', 'traktid', 'tvdb', 'tvmaze', 'tvrage'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$typedValue = $field === 'imdbid' ? (string) $value : (int) $value;
|
||||
$key = $field.':'.$typedValue;
|
||||
$queries[$key] = [
|
||||
'field' => $field,
|
||||
'value' => $typedValue,
|
||||
];
|
||||
}
|
||||
|
||||
$results = $query->get();
|
||||
|
||||
$resultIds = [];
|
||||
foreach ($results as $doc) {
|
||||
$resultIds[] = $doc->getId();
|
||||
}
|
||||
|
||||
if (! empty($resultIds)) {
|
||||
Cache::put($cacheKey, $resultIds, now()->addMinutes($this->config['cache_minutes'] ?? 5));
|
||||
}
|
||||
|
||||
return $resultIds;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ManticoreSearch searchReleasesByExternalId error: '.$e->getMessage(), [
|
||||
'externalIds' => $externalIds,
|
||||
]);
|
||||
}
|
||||
|
||||
return [];
|
||||
if ($queries === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$resultIds = [];
|
||||
$seen = [];
|
||||
|
||||
try {
|
||||
foreach ($queries as $queryData) {
|
||||
$query = (new Search($this->manticoreSearch))
|
||||
->setTable($this->getReleasesIndex())
|
||||
->filter($queryData['field'], '=', $queryData['value'])
|
||||
->limit($normalizedLimit);
|
||||
|
||||
$results = $query->get();
|
||||
foreach ($results as $doc) {
|
||||
$docId = (int) $doc->getId();
|
||||
if (isset($seen[$docId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$seen[$docId] = true;
|
||||
$resultIds[] = $docId;
|
||||
if (count($resultIds) >= $normalizedLimit) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ManticoreSearch searchReleasesByMultipleExternalIds error: '.$e->getMessage(), [
|
||||
'externalIdSets' => $externalIdSets,
|
||||
]);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($resultIds !== []) {
|
||||
Cache::put($cacheKey, $resultIds, now()->addMinutes($this->config['cache_minutes'] ?? 5));
|
||||
}
|
||||
|
||||
return $resultIds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,16 +32,7 @@ class MediaSearchService
|
||||
*/
|
||||
public function findMovie(array $externalIds): ?array
|
||||
{
|
||||
foreach (['imdbid', 'tmdbid', 'traktid'] as $field) {
|
||||
if (! empty($externalIds[$field])) {
|
||||
$result = Search::searchMovieByExternalId($field, $externalIds[$field]);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return Search::searchMovieByExternalIds($externalIds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,16 +43,7 @@ class MediaSearchService
|
||||
*/
|
||||
public function findTvShow(array $externalIds): ?array
|
||||
{
|
||||
foreach (['tvdb', 'trakt', 'tvmaze', 'tvrage', 'imdb', 'tmdb'] as $field) {
|
||||
if (! empty($externalIds[$field])) {
|
||||
$result = Search::searchTvShowByExternalId($field, $externalIds[$field]);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return Search::searchTvShowByExternalIds($externalIds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +72,7 @@ class MediaSearchService
|
||||
}
|
||||
|
||||
// Collect all external IDs from matched movies
|
||||
$allReleaseIds = [];
|
||||
$externalIdSets = [];
|
||||
|
||||
foreach ($movieResults['data'] ?? [] as $movie) {
|
||||
$externalIds = [];
|
||||
@@ -106,11 +88,12 @@ class MediaSearchService
|
||||
}
|
||||
|
||||
if (! empty($externalIds)) {
|
||||
$releaseIds = Search::searchReleasesByExternalId($externalIds, $limit);
|
||||
$allReleaseIds = array_merge($allReleaseIds, $releaseIds);
|
||||
$externalIdSets[] = $externalIds;
|
||||
}
|
||||
}
|
||||
|
||||
$allReleaseIds = Search::searchReleasesByMultipleExternalIds($externalIdSets, $limit);
|
||||
|
||||
// Remove duplicates and limit results
|
||||
$allReleaseIds = array_unique($allReleaseIds);
|
||||
$allReleaseIds = array_slice($allReleaseIds, 0, $limit);
|
||||
@@ -148,7 +131,7 @@ class MediaSearchService
|
||||
}
|
||||
|
||||
// Collect all external IDs from matched TV shows
|
||||
$allReleaseIds = [];
|
||||
$externalIdSets = [];
|
||||
|
||||
foreach ($tvResults['data'] ?? [] as $tvShow) {
|
||||
$externalIds = [];
|
||||
@@ -167,11 +150,12 @@ class MediaSearchService
|
||||
}
|
||||
|
||||
if (! empty($externalIds)) {
|
||||
$releaseIds = Search::searchReleasesByExternalId($externalIds, $limit);
|
||||
$allReleaseIds = array_merge($allReleaseIds, $releaseIds);
|
||||
$externalIdSets[] = $externalIds;
|
||||
}
|
||||
}
|
||||
|
||||
$allReleaseIds = Search::searchReleasesByMultipleExternalIds($externalIdSets, $limit);
|
||||
|
||||
// Remove duplicates and limit results
|
||||
$allReleaseIds = array_unique($allReleaseIds);
|
||||
$allReleaseIds = array_slice($allReleaseIds, 0, $limit);
|
||||
|
||||
@@ -371,6 +371,15 @@ class SearchService extends Manager implements SearchServiceInterface
|
||||
return $this->driver()->searchMovieByExternalId($field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function searchMovieByExternalIds(array $externalIds): ?array
|
||||
{
|
||||
return $this->driver()->searchMovieByExternalIds($externalIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $fieldTerms
|
||||
* @return array{imdbids: list<string>, movieinfo_ids: list<int>, data: list<array<string, mixed>>}
|
||||
@@ -438,6 +447,15 @@ class SearchService extends Manager implements SearchServiceInterface
|
||||
return $this->driver()->searchTvShowByExternalId($field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $externalIds
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function searchTvShowByExternalIds(array $externalIds): ?array
|
||||
{
|
||||
return $this->driver()->searchTvShowByExternalIds($externalIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search releases by external media IDs.
|
||||
* Used to find releases associated with a specific movie or TV show.
|
||||
@@ -450,6 +468,15 @@ class SearchService extends Manager implements SearchServiceInterface
|
||||
return $this->driver()->searchReleasesByExternalId($externalIds, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $externalIdSets
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function searchReleasesByMultipleExternalIds(array $externalIdSets, int $limit = 1000): array
|
||||
{
|
||||
return $this->driver()->searchReleasesByMultipleExternalIds($externalIdSets, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search releases by category ID using the search index.
|
||||
* This provides a fast way to get release IDs for a specific category without hitting the database.
|
||||
|
||||
@@ -488,64 +488,75 @@ class SteamService
|
||||
protected function findMatches(string $title, int $limit = 25): array
|
||||
{
|
||||
$variants = $this->generateQueryVariants($title);
|
||||
$variants = array_values(array_unique(array_filter(array_map('trim', $variants), static fn (string $variant): bool => $variant !== '')));
|
||||
$matches = [];
|
||||
$seenAppIds = [];
|
||||
|
||||
foreach ($variants as $variant) {
|
||||
try {
|
||||
if (Search::isAvailable()) {
|
||||
$hits = Search::searchSecondary(SecondarySearchIndex::Steam, $variant, $limit);
|
||||
foreach ($hits['data'] as $row) {
|
||||
$appid = $row['appid'] ?? null;
|
||||
$name = $row['name'] ?? null;
|
||||
if ($appid === null || $name === null || $name === '' || isset($seenAppIds[$appid])) {
|
||||
continue;
|
||||
}
|
||||
$score = $this->scoreTitle((string) $name, $title);
|
||||
if ($score >= self::RELAXED_MATCH_THRESHOLD) {
|
||||
$seenAppIds[(int) $appid] = true;
|
||||
$matches[] = [
|
||||
'appid' => (int) $appid,
|
||||
'name' => (string) $name,
|
||||
'score' => $score,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('SteamService: search index lookup failed', ['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
// LIKE fallback
|
||||
$likeTerm = $this->buildLikePattern($variant);
|
||||
try {
|
||||
$fallbacks = SteamApp::query()
|
||||
->select(['appid', 'name'])
|
||||
->where('name', 'like', $likeTerm)
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
foreach ($fallbacks as $row) {
|
||||
$appid = $row->appid;
|
||||
$name = $row->name;
|
||||
|
||||
if (isset($seenAppIds[$appid])) {
|
||||
try {
|
||||
if (Search::isAvailable() && $variants !== []) {
|
||||
$orQuery = implode(' | ', $variants);
|
||||
$hits = Search::searchSecondary(SecondarySearchIndex::Steam, $orQuery, $limit);
|
||||
foreach ($hits['data'] as $row) {
|
||||
$appid = $row['appid'] ?? null;
|
||||
$name = $row['name'] ?? null;
|
||||
if ($appid === null || $name === null || $name === '' || isset($seenAppIds[$appid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$score = $this->scoreTitle($name, $title);
|
||||
$score = $this->scoreTitle((string) $name, $title);
|
||||
if ($score >= self::RELAXED_MATCH_THRESHOLD) {
|
||||
$seenAppIds[$appid] = true;
|
||||
$seenAppIds[(int) $appid] = true;
|
||||
$matches[] = [
|
||||
'appid' => (int) $appid,
|
||||
'name' => $name,
|
||||
'name' => (string) $name,
|
||||
'score' => $score,
|
||||
];
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('SteamService: LIKE search failed', ['error' => $e->getMessage()]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('SteamService: search index lookup failed', ['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
// LIKE fallback
|
||||
try {
|
||||
$fallbackQuery = SteamApp::query()->select(['appid', 'name']);
|
||||
if ($variants !== []) {
|
||||
$fallbackQuery->where(function ($query) use ($variants): void {
|
||||
foreach ($variants as $index => $variant) {
|
||||
$likeTerm = $this->buildLikePattern($variant);
|
||||
if ($index === 0) {
|
||||
$query->where('name', 'like', $likeTerm);
|
||||
} else {
|
||||
$query->orWhere('name', 'like', $likeTerm);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$fallbackQuery->where('name', 'like', $this->buildLikePattern($title));
|
||||
}
|
||||
|
||||
$fallbacks = $fallbackQuery->limit($limit)->get();
|
||||
|
||||
foreach ($fallbacks as $row) {
|
||||
$appid = $row->appid;
|
||||
$name = $row->name;
|
||||
|
||||
if (isset($seenAppIds[$appid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$score = $this->scoreTitle($name, $title);
|
||||
if ($score >= self::RELAXED_MATCH_THRESHOLD) {
|
||||
$seenAppIds[$appid] = true;
|
||||
$matches[] = [
|
||||
'appid' => (int) $appid,
|
||||
'name' => $name,
|
||||
'score' => $score,
|
||||
];
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('SteamService: LIKE search failed', ['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
// Sort by score descending
|
||||
|
||||
@@ -55,15 +55,6 @@ return [
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
'sphinx' => [
|
||||
'driver' => 'mysql',
|
||||
'host' => env('MANTICORESEARCH_HOST', '127.0.0.1'),
|
||||
'port' => env('MANTICORESEARCH_PORT', 9306),
|
||||
'database' => '',
|
||||
'unix_socket' => '',
|
||||
'charset' => 'utf8',
|
||||
],
|
||||
|
||||
'mariadb' => [
|
||||
'driver' => 'mariadb',
|
||||
'url' => env('DB_URL'),
|
||||
|
||||
Reference in New Issue
Block a user