Implement file hash-based library matching and remove fuzzy ASIN matching

Adds file hash-based matching for Audiobookshelf library items to ensure 100% accurate ASIN assignment for RMAB-organized content. Removes fuzzy matching from library availability checks, making all matching ASIN-only to eliminate false positives and race conditions. Updates database schema, processors, and matcher utilities; adds new tests and documentation for the new matching strategy. Removes obsolete scripts, Dockerfile, and related tests; updates docker-compose for test environments.
This commit is contained in:
kikootwo
2026-01-28 10:32:14 -05:00
parent 497849f427
commit a97979358f
111 changed files with 6571 additions and 1426 deletions
@@ -103,13 +103,13 @@ export async function processSearchIndexers(payload: SearchIndexersPayload): Pro
if (searchResults.length === 0) {
// No results found - queue for re-search instead of failing
logger.warn(`No torrents found for request ${requestId}, marking as awaiting_search`);
logger.warn(`No torrents/nzbs found for request ${requestId}, marking as awaiting_search`);
await prisma.request.update({
where: { id: requestId },
data: {
status: 'awaiting_search',
errorMessage: 'No torrents found. Will retry automatically.',
errorMessage: 'No torrents/nzbs found. Will retry automatically.',
lastSearchAt: new Date(),
updatedAt: new Date(),
},
@@ -117,7 +117,7 @@ export async function processSearchIndexers(payload: SearchIndexersPayload): Pro
return {
success: false,
message: 'No torrents found, queued for re-search',
message: 'No torrents/nzbs found, queued for re-search',
requestId,
};
}
@@ -149,11 +149,16 @@ export async function processSearchIndexers(payload: SearchIndexersPayload): Pro
// Rank results with indexer priorities and flag configs
// Note: rankTorrents now filters out results < 20 MB internally
// requireAuthor: true (default) - strict filtering for automatic selection
const rankedResults = ranker.rankTorrents(searchResults, {
title: audiobook.title,
author: audiobook.author,
durationMinutes,
}, indexerPriorities, flagConfigs);
}, {
indexerPriorities,
flagConfigs,
requireAuthor: true // Automatic mode - prevent wrong authors
});
// Log filter results
const postFilterCount = rankedResults.length;