Skip to content

Add configurable UI setting for import match threshold - #132

Open
EdLaughton wants to merge 14 commits into
pennydreadful:developfrom
EdLaughton:claude/import-match-threshold-setting-GefjL
Open

EdLaughton wants to merge 14 commits into
pennydreadful:developfrom
EdLaughton:claude/import-match-threshold-setting-GefjL

Conversation

@EdLaughton

Copy link
Copy Markdown

Replace the hard-coded 0.50 distance threshold in CloseBookMatchSpecification with a user-configurable setting (BookImportMinimumMatchPercent).

  • Add BookImportMinimumMatchPercent to IConfigService/ConfigService (default: 50)
  • Add to MediaManagement API resource with validation (range: 50-99)
  • Wire into CloseBookMatchSpecification: threshold = 1.0 - (percent / 100.0)
  • Add UI field in Media Management > Importing section
  • Add localization keys for label and help text
  • Add unit tests for threshold conversion and behavior

Default behavior is preserved: 50% minimum match = 0.50 internal threshold.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5

Replace the hard-coded 0.50 distance threshold in CloseBookMatchSpecification
with a user-configurable setting (BookImportMinimumMatchPercent).

- Add BookImportMinimumMatchPercent to IConfigService/ConfigService (default: 50)
- Add to MediaManagement API resource with validation (range: 50-99)
- Wire into CloseBookMatchSpecification: threshold = 1.0 - (percent / 100.0)
- Add UI field in Media Management > Importing section
- Add localization keys for label and help text
- Add unit tests for threshold conversion and behavior

Default behavior is preserved: 50% minimum match = 0.50 internal threshold.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
@EdLaughton
EdLaughton force-pushed the claude/import-match-threshold-setting-GefjL branch from 5dccf0c to 622c2dc Compare March 15, 2026 21:03
claude and others added 10 commits March 15, 2026 21:10
Completed-download import previously discarded specific book context
from TrackedDownload.RemoteBook and only passed Author into the
identification pipeline. This forced a fuzzy re-identification among
all books by that author, causing mis-matches for similar titles
(e.g. issue #3 vs issue pennydreadful#6 of the same series).

Now, when a completed download was grabbed for a specific single book,
that book context is threaded through IdentificationOverrides into
CandidateService, which already supports Book-level candidate
restriction. Multi-book/omnibus downloads fall back to author-only
scoping. Null RemoteBook preserves existing behavior exactly.

Changes:
- CompletedDownloadService.Import: build IdentificationOverrides from
  RemoteBook (Author + single Book when available)
- DownloadedBooksCommandService: same override building for external
  scan commands
- DownloadedBooksImportService: accept IdentificationOverrides instead
  of Author, thread through ProcessFolder/ProcessFile
- Tests: update existing mocks, add 4 new tests covering single-book,
  multi-book, null-remote, and empty-books override scenarios

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
Add a dedicated workflow that builds this feature branch and publishes
a Docker image to ghcr.io/edlaughton/bookshelf:import-match-threshold-ui
for testing on Unraid.

Triggers on push to this branch and manual dispatch. Uses the repo's
existing build.sh and docker/Dockerfile. Targets linux/amd64 only.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
Pass METADATA_URL and HARDCOVER build-args to match the main
build workflow's Hardcover configuration.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
Both feature branches are being merged into develop, so the workflow
trigger should point there instead of the individual feature branch.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
Use (100 - percent) / 100.0 instead of 1.0 - (percent / 100.0) to avoid
IEEE 754 imprecision where 1.0 - 0.9 = 0.09999999999999998 instead of 0.1.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
Avoid testing exact floating-point boundary (0.1 == 0.1) since
0.3 / 3.0 produces 0.10000000000000002 due to IEEE 754 imprecision.
Use 0.09 (clearly below threshold) instead.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
Add Unraid Docker image publishing and import improvements
The RemoteBook-context work (147a11e) set IdentificationOverrides.Book
from remoteBook.Books when there was exactly one book. CandidateService
treats a Book override as authoritative and calls GetDbCandidatesByBook,
which requires a valid local DB book ID. If the Book object is stale or
unmapped, candidate resolution collapses to zero and import silently
fails.

Fix:
- In CompletedDownloadService and DownloadedBooksCommandService, only
  set overrides.Book when the candidate has Id > 0 and is confirmed to
  exist in the local database via IBookService.GetBook().
- In CandidateService, if a Book override produces zero candidates, fall
  back to author-scoped search instead of dead-ending.

This preserves the improved matching when a valid local book is available
while preventing import failures from invalid book overrides.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
@EdLaughton
EdLaughton force-pushed the claude/import-match-threshold-setting-GefjL branch from e29aa98 to a316daa Compare March 16, 2026 09:31
claude added 2 commits March 16, 2026 22:26
The fallback path in GetDbCandidatesByAuthor also calls
_editionService.GetCandidates(), which needs to be mocked to avoid
a NullReferenceException on the unmocked return value.

https://claude.ai/code/session_01976eMqb4mwazHh13NZkDY5
axsddlr added a commit to axsddlr/bookshelf that referenced this pull request Aug 1, 2026
…igurable match threshold

- pennydreadful#151: Paginate large Goodreads series import (page parameter)
- pennydreadful#171: Hardcover import from any username and reading status
- pennydreadful#132: Configurable match threshold (default 0.65, configurable via API/UI)
@pennydreadful

Copy link
Copy Markdown
Owner

@EdLaughton what's with the unraid workflow? can you simplify this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants