mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
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:
@@ -256,7 +256,7 @@ describe('OIDCAuthProvider', () => {
|
||||
const result = await provider.handleCallback({ code: 'code', state: 'state-1' });
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.user?.isAdmin).toBe(true);
|
||||
expect(result.user?.role).toBe('admin');
|
||||
expect(schedulerMock.triggerJobNow).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -300,7 +300,7 @@ describe('OIDCAuthProvider', () => {
|
||||
|
||||
const { OIDCAuthProvider } = await import('@/lib/services/auth/OIDCAuthProvider');
|
||||
const provider = new OIDCAuthProvider();
|
||||
const result = await provider.validateAccess({ id: 'user-3', username: 'user', isAdmin: false, authProvider: 'oidc' });
|
||||
const result = await provider.validateAccess({ id: 'user-3', username: 'user', role: 'user', authProvider: 'oidc' });
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
@@ -314,7 +314,7 @@ describe('OIDCAuthProvider', () => {
|
||||
|
||||
const { OIDCAuthProvider } = await import('@/lib/services/auth/OIDCAuthProvider');
|
||||
const provider = new OIDCAuthProvider();
|
||||
const result = await provider.validateAccess({ id: 'user-4', username: 'user', isAdmin: false, authProvider: 'oidc' });
|
||||
const result = await provider.validateAccess({ id: 'user-4', username: 'user', role: 'user', authProvider: 'oidc' });
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
@@ -324,7 +324,7 @@ describe('OIDCAuthProvider', () => {
|
||||
|
||||
const { OIDCAuthProvider } = await import('@/lib/services/auth/OIDCAuthProvider');
|
||||
const provider = new OIDCAuthProvider();
|
||||
const result = await provider.validateAccess({ id: 'user-5', username: 'user', isAdmin: false, authProvider: 'oidc' });
|
||||
const result = await provider.validateAccess({ id: 'user-5', username: 'user', role: 'user', authProvider: 'oidc' });
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
@@ -193,7 +193,7 @@ describe('PlexAuthProvider', () => {
|
||||
|
||||
const { PlexAuthProvider } = await import('@/lib/services/auth/PlexAuthProvider');
|
||||
const provider = new PlexAuthProvider();
|
||||
const ok = await provider.validateAccess({ id: 'user-1', username: 'user', isAdmin: false, authProvider: 'plex' });
|
||||
const ok = await provider.validateAccess({ id: 'user-1', username: 'user', role: 'user', authProvider: 'plex' });
|
||||
|
||||
expect(ok).toBe(false);
|
||||
});
|
||||
@@ -207,7 +207,7 @@ describe('PlexAuthProvider', () => {
|
||||
|
||||
const { PlexAuthProvider } = await import('@/lib/services/auth/PlexAuthProvider');
|
||||
const provider = new PlexAuthProvider();
|
||||
const ok = await provider.validateAccess({ id: 'user-1', username: 'user', isAdmin: false, authProvider: 'plex' });
|
||||
const ok = await provider.validateAccess({ id: 'user-1', username: 'user', role: 'user', authProvider: 'plex' });
|
||||
|
||||
expect(ok).toBe(false);
|
||||
});
|
||||
@@ -222,7 +222,7 @@ describe('PlexAuthProvider', () => {
|
||||
|
||||
const { PlexAuthProvider } = await import('@/lib/services/auth/PlexAuthProvider');
|
||||
const provider = new PlexAuthProvider();
|
||||
const ok = await provider.validateAccess({ id: 'user-1', username: 'user', isAdmin: false, authProvider: 'plex' });
|
||||
const ok = await provider.validateAccess({ id: 'user-1', username: 'user', role: 'user', authProvider: 'plex' });
|
||||
|
||||
expect(ok).toBe(true);
|
||||
expect(encryptionMock.decrypt).toHaveBeenCalledWith('enc:token');
|
||||
|
||||
@@ -229,7 +229,6 @@ describe('JobQueueService', () => {
|
||||
const service = new JobQueueService();
|
||||
|
||||
await service.addPlexScanJob('lib-1', true, '/path');
|
||||
await service.addPlexMatchJob('req-1', 'ab-1', 'Title', 'Author');
|
||||
await service.addPlexRecentlyAddedJob('sched-1');
|
||||
await service.addMonitorRssFeedsJob('sched-2');
|
||||
await service.addAudibleRefreshJob('sched-3');
|
||||
@@ -241,26 +240,23 @@ describe('JobQueueService', () => {
|
||||
expect(queueMock.add.mock.calls[0][2].priority).toBe(7);
|
||||
expect(queueMock.add.mock.calls[0][1]).toEqual(expect.objectContaining({ libraryId: 'lib-1', partial: true, path: '/path' }));
|
||||
|
||||
expect(queueMock.add.mock.calls[1][0]).toBe('match_plex');
|
||||
expect(queueMock.add.mock.calls[1][2].priority).toBe(6);
|
||||
expect(queueMock.add.mock.calls[1][0]).toBe('plex_recently_added_check');
|
||||
expect(queueMock.add.mock.calls[1][2].priority).toBe(8);
|
||||
|
||||
expect(queueMock.add.mock.calls[2][0]).toBe('plex_recently_added_check');
|
||||
expect(queueMock.add.mock.calls[2][0]).toBe('monitor_rss_feeds');
|
||||
expect(queueMock.add.mock.calls[2][2].priority).toBe(8);
|
||||
|
||||
expect(queueMock.add.mock.calls[3][0]).toBe('monitor_rss_feeds');
|
||||
expect(queueMock.add.mock.calls[3][2].priority).toBe(8);
|
||||
expect(queueMock.add.mock.calls[3][0]).toBe('audible_refresh');
|
||||
expect(queueMock.add.mock.calls[3][2].priority).toBe(9);
|
||||
|
||||
expect(queueMock.add.mock.calls[4][0]).toBe('audible_refresh');
|
||||
expect(queueMock.add.mock.calls[4][2].priority).toBe(9);
|
||||
expect(queueMock.add.mock.calls[4][0]).toBe('retry_missing_torrents');
|
||||
expect(queueMock.add.mock.calls[4][2].priority).toBe(7);
|
||||
|
||||
expect(queueMock.add.mock.calls[5][0]).toBe('retry_missing_torrents');
|
||||
expect(queueMock.add.mock.calls[5][0]).toBe('retry_failed_imports');
|
||||
expect(queueMock.add.mock.calls[5][2].priority).toBe(7);
|
||||
|
||||
expect(queueMock.add.mock.calls[6][0]).toBe('retry_failed_imports');
|
||||
expect(queueMock.add.mock.calls[6][2].priority).toBe(7);
|
||||
|
||||
expect(queueMock.add.mock.calls[7][0]).toBe('cleanup_seeded_torrents');
|
||||
expect(queueMock.add.mock.calls[7][2].priority).toBe(10);
|
||||
expect(queueMock.add.mock.calls[6][0]).toBe('cleanup_seeded_torrents');
|
||||
expect(queueMock.add.mock.calls[6][2].priority).toBe(10);
|
||||
});
|
||||
|
||||
it('returns queue stats with safe defaults', async () => {
|
||||
@@ -543,7 +539,6 @@ describe('JobQueueService', () => {
|
||||
expect(processorsMock.processMonitorDownload).toHaveBeenCalled();
|
||||
expect(processorsMock.processOrganizeFiles).toHaveBeenCalled();
|
||||
expect(processorsMock.processScanPlex).toHaveBeenCalled();
|
||||
expect(processorsMock.processMatchPlex).toHaveBeenCalled();
|
||||
expect(processorsMock.processPlexRecentlyAddedCheck).toHaveBeenCalled();
|
||||
expect(processorsMock.processMonitorRssFeeds).toHaveBeenCalled();
|
||||
expect(processorsMock.processAudibleRefresh).toHaveBeenCalled();
|
||||
|
||||
Reference in New Issue
Block a user