mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 21:00:09 +00:00
Fix critical bug: searches now respect enabled indexers
**Problem:** Prowlarr searches were querying ALL indexers instead of only the ones enabled in user settings, causing torrents to be selected from disabled/untrusted indexers. **Root Cause:** The prowlarr.search() method didn't filter by indexer IDs, and callers weren't passing enabled indexer IDs to the search. **Changes:** 1. Added indexerIds parameter to SearchFilters interface 2. Updated prowlarr.service.ts search() to filter by indexerIds 3. Updated search-indexers.processor.ts to fetch and pass enabled indexer IDs 4. Updated interactive-search route to fetch and pass enabled indexer IDs 5. Added validation: search fails if no indexers are configured/enabled 6. Updated documentation to reflect indexer filtering behavior **Impact:** - Manual search: Only searches enabled indexers - Interactive search: Only searches enabled indexers - RSS monitoring: Already correctly filtered (no changes needed) **Testing:** TypeScript type checking passed with no errors
This commit is contained in:
@@ -9,7 +9,7 @@ Indexer aggregator for searching multiple torrent/usenet indexers simultaneously
|
|||||||
**Base:** `http://prowlarr:9696/api/v1`
|
**Base:** `http://prowlarr:9696/api/v1`
|
||||||
**Auth:** `X-Api-Key` header
|
**Auth:** `X-Api-Key` header
|
||||||
|
|
||||||
**GET /search?query={q}&categories=3030** - Search all indexers (3030 = audiobooks)
|
**GET /search?query={q}&categories=3030&indexerIds={ids}** - Search indexers (3030 = audiobooks, ids = comma-separated indexer IDs)
|
||||||
**GET /indexer** - List configured indexers
|
**GET /indexer** - List configured indexers
|
||||||
**GET /indexerstats** - Indexer statistics
|
**GET /indexerstats** - Indexer statistics
|
||||||
**GET /feed/{indexerId}/api?t=search&cat=3030&limit=100** - RSS feed for specific indexer
|
**GET /feed/{indexerId}/api?t=search&cat=3030&limit=100** - RSS feed for specific indexer
|
||||||
@@ -49,13 +49,17 @@ interface TorrentResult {
|
|||||||
|
|
||||||
## Manual & Interactive Search
|
## Manual & Interactive Search
|
||||||
|
|
||||||
|
**Indexer Filtering:** All searches (manual and interactive) only query indexers enabled in settings (`prowlarr_indexers` config). If no indexers are enabled, search will fail with error.
|
||||||
|
|
||||||
**Manual Search** (`POST /api/requests/{id}/manual-search`)
|
**Manual Search** (`POST /api/requests/{id}/manual-search`)
|
||||||
- Triggers automatic search job for requests with status: pending, failed, awaiting_search
|
- Triggers automatic search job for requests with status: pending, failed, awaiting_search
|
||||||
|
- Searches only enabled indexers
|
||||||
- Uses ranking algorithm to select best torrent
|
- Uses ranking algorithm to select best torrent
|
||||||
- Updates request status to 'pending'
|
- Updates request status to 'pending'
|
||||||
|
|
||||||
**Interactive Search** (`POST /api/requests/{id}/interactive-search`)
|
**Interactive Search** (`POST /api/requests/{id}/interactive-search`)
|
||||||
- Returns ranked torrent results for user selection
|
- Returns ranked torrent results for user selection
|
||||||
|
- Searches only enabled indexers
|
||||||
- Shows table with: rank, title, size, quality score, seeders, indexer, publish date
|
- Shows table with: rank, title, size, quality score, seeders, indexer, publish date
|
||||||
- Available for same statuses as manual search
|
- Available for same statuses as manual search
|
||||||
- User clicks "Download" button to select specific torrent
|
- User clicks "Download" button to select specific torrent
|
||||||
|
|||||||
@@ -50,13 +50,37 @@ export async function POST(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search Prowlarr for torrents
|
// Get enabled indexers from configuration
|
||||||
|
const { getConfigService } = await import('@/lib/services/config.service');
|
||||||
|
const configService = getConfigService();
|
||||||
|
const indexersConfigStr = await configService.get('prowlarr_indexers');
|
||||||
|
|
||||||
|
if (!indexersConfigStr) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'ConfigError', message: 'No indexers configured. Please configure indexers in settings.' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexersConfig = JSON.parse(indexersConfigStr);
|
||||||
|
const enabledIndexerIds = indexersConfig.map((indexer: any) => indexer.id);
|
||||||
|
|
||||||
|
if (enabledIndexerIds.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'ConfigError', message: 'No indexers enabled. Please enable at least one indexer in settings.' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search Prowlarr for torrents - ONLY enabled indexers
|
||||||
const prowlarr = await getProwlarrService();
|
const prowlarr = await getProwlarrService();
|
||||||
const searchQuery = `${requestRecord.audiobook.title} ${requestRecord.audiobook.author}`;
|
const searchQuery = `${requestRecord.audiobook.title} ${requestRecord.audiobook.author}`;
|
||||||
|
|
||||||
console.log(`[InteractiveSearch] Searching for: ${searchQuery}`);
|
console.log(`[InteractiveSearch] Searching ${enabledIndexerIds.length} enabled indexers for: ${searchQuery}`);
|
||||||
|
|
||||||
const results = await prowlarr.search(searchQuery);
|
const results = await prowlarr.search(searchQuery, {
|
||||||
|
indexerIds: enabledIndexerIds,
|
||||||
|
});
|
||||||
|
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface SearchFilters {
|
|||||||
category?: number;
|
category?: number;
|
||||||
minSeeders?: number;
|
minSeeders?: number;
|
||||||
maxResults?: number;
|
maxResults?: number;
|
||||||
|
indexerIds?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Indexer {
|
export interface Indexer {
|
||||||
@@ -72,7 +73,8 @@ export class ProwlarrService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for audiobooks across all configured indexers
|
* Search for audiobooks across configured indexers
|
||||||
|
* If indexerIds is provided, only searches those indexers
|
||||||
*/
|
*/
|
||||||
async search(
|
async search(
|
||||||
query: string,
|
query: string,
|
||||||
@@ -86,6 +88,11 @@ export class ProwlarrService {
|
|||||||
extended: 1, // Enable searching in tags, labels, and metadata
|
extended: 1, // Enable searching in tags, labels, and metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Filter by specific indexers if provided
|
||||||
|
if (filters?.indexerIds && filters.indexerIds.length > 0) {
|
||||||
|
params.indexerIds = filters.indexerIds.join(',');
|
||||||
|
}
|
||||||
|
|
||||||
const response = await this.client.get('/search', { params });
|
const response = await this.client.get('/search', { params });
|
||||||
|
|
||||||
// Transform Prowlarr results to our format
|
// Transform Prowlarr results to our format
|
||||||
|
|||||||
@@ -31,6 +31,24 @@ export async function processSearchIndexers(payload: SearchIndexersPayload): Pro
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get enabled indexers from configuration
|
||||||
|
const { getConfigService } = await import('../services/config.service');
|
||||||
|
const configService = getConfigService();
|
||||||
|
const indexersConfigStr = await configService.get('prowlarr_indexers');
|
||||||
|
|
||||||
|
if (!indexersConfigStr) {
|
||||||
|
throw new Error('No indexers configured. Please configure indexers in settings.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexersConfig = JSON.parse(indexersConfigStr);
|
||||||
|
const enabledIndexerIds = indexersConfig.map((indexer: any) => indexer.id);
|
||||||
|
|
||||||
|
if (enabledIndexerIds.length === 0) {
|
||||||
|
throw new Error('No indexers enabled. Please enable at least one indexer in settings.');
|
||||||
|
}
|
||||||
|
|
||||||
|
await logger?.info(`Searching ${enabledIndexerIds.length} enabled indexers`);
|
||||||
|
|
||||||
// Get Prowlarr service
|
// Get Prowlarr service
|
||||||
const prowlarr = await getProwlarrService();
|
const prowlarr = await getProwlarrService();
|
||||||
|
|
||||||
@@ -39,11 +57,12 @@ export async function processSearchIndexers(payload: SearchIndexersPayload): Pro
|
|||||||
|
|
||||||
await logger?.info(`Searching for: "${searchQuery}"`);
|
await logger?.info(`Searching for: "${searchQuery}"`);
|
||||||
|
|
||||||
// Search indexers
|
// Search indexers - ONLY enabled ones
|
||||||
const searchResults = await prowlarr.search(searchQuery, {
|
const searchResults = await prowlarr.search(searchQuery, {
|
||||||
category: 3030, // Audiobooks
|
category: 3030, // Audiobooks
|
||||||
minSeeders: 1, // Only torrents with at least 1 seeder
|
minSeeders: 1, // Only torrents with at least 1 seeder
|
||||||
maxResults: 50, // Limit results
|
maxResults: 50, // Limit results
|
||||||
|
indexerIds: enabledIndexerIds, // Filter by enabled indexers
|
||||||
});
|
});
|
||||||
|
|
||||||
await logger?.info(`Found ${searchResults.length} results`);
|
await logger?.info(`Found ${searchResults.length} results`);
|
||||||
|
|||||||
Reference in New Issue
Block a user