SABnzbd path mapping + ASIN-based request deletion

Add bidirectional path mapping and complete_dir-aware category sync to the SABnzbd integration. Introduces PathMapper usage, complete_dir extraction, calculateCategoryPath(), and ensureCategory() logic to choose empty/relative/absolute category paths; ensureCategory is invoked before adding NZBs. Update singleton factory to load download_dir and path-mapping config from DownloadClientManager and recreate the service when config is not loaded. Make DownloadClientManager pass path-mapping config into the SABnzbd service. Change request deletion to remove plex_library records by ASIN (deleteMany) with a fallback to exact title/author matches so availability checks and deletions are consistent. Update documentation and tests to reflect the new behavior and APIs.
This commit is contained in:
kikootwo
2026-02-03 12:20:44 -05:00
parent 11376b36a2
commit c559f8ebe9
12 changed files with 805 additions and 131 deletions
+11 -4
View File
@@ -110,9 +110,8 @@ describe('deleteRequest', () => {
prismaMock.audibleCache.findUnique.mockResolvedValueOnce({
releaseDate: '2021-01-01T00:00:00.000Z',
});
prismaMock.plexLibrary.findMany.mockResolvedValue([
{ id: 'lib-1', title: 'Book', author: 'Author' },
]);
// Mock deleteMany for ASIN-based deletion
prismaMock.plexLibrary.deleteMany.mockResolvedValue({ count: 1 });
fsMock.access.mockResolvedValue(undefined);
fsMock.rm.mockResolvedValue(undefined);
prismaMock.request.update.mockResolvedValue({});
@@ -124,7 +123,15 @@ describe('deleteRequest', () => {
expect(result.success).toBe(true);
expect(result.torrentsRemoved).toBe(1);
expect(qbtMock.deleteTorrent).toHaveBeenCalledWith('hash-1', true);
expect(prismaMock.plexLibrary.delete).toHaveBeenCalledWith({ where: { id: 'lib-1' } });
// Code now uses deleteMany with ASIN-based matching
expect(prismaMock.plexLibrary.deleteMany).toHaveBeenCalledWith({
where: {
OR: [
{ asin: 'ASIN1' },
{ plexGuid: { contains: 'ASIN1' } },
],
},
});
const expectedPath = path.join('/media', 'Author', 'Book ASIN1');
expect(fsMock.rm).toHaveBeenCalledWith(expectedPath, { recursive: true, force: true });