feat(metadata): add RanobeDB as metadata provider#185
Conversation
Introduces a new metadata provider to fetch book metadata from RanobeDB. - Adds `ranobedb.client` to interact with the RanobeDB API. - Implements `ranobedb.mapper` to map RanobeDB data to the internal metadata schema. - Maps native Japanese titles to subtitles. - Uses the original language as a fallback for the language field. - Parses specific release dates to determine the original publication year. - Registers RanobeDB as an available provider in the preferences UI. - Adds `ranobedb_id` to the metadata database schema. - Removes the `bookId` override when manually performing a metadata search in the UI. Closes bookorbit#114
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR adds RanobeDB as a complete metadata source to BookOrbit: types and DB schema, a rate-limited RanobeDB HTTP client, mapping logic to MetadataCandidate, a RanobeDB provider implementation registered in DI, orchestration to persist and surface ranobedbId, provider configuration defaults, and client UI/editor integration for managing ranobedbId. ChangesRanobeDB Metadata Provider Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.ts (2)
82-92: 💤 Low valueConsider adding inline comment for publishedYear fallback logic.
The cascading fallback logic (release date → c_release_dates[olang] → c_release_date) is sophisticated and would benefit from a brief comment explaining the priority order.
📝 Suggested inline comment
function resolvePublishedYear(book: RanobeDbBook, release: RanobeDbRelease | undefined): number | undefined { + // Priority: English release date > original language release date > computed release date if (release?.release_date) { const year = parseDateInt(release.release_date); if (year) return year; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.ts` around lines 82 - 92, Add a brief inline comment inside resolvePublishedYear explaining the fallback priority used to determine publishedYear: first prefer release.release_date (parsed via parseDateInt), then fall back to book.c_release_dates keyed by book.olang (if present), and finally use book.c_release_date; mention that parseDateInt may return undefined so each branch checks and returns the first valid year. Place this comment above the conditional block so future readers understand the cascade and rationale.
8-12: 💤 Low valueConsider adding inline comment for year range validation.
The year range 1000-2200 is reasonable for publication dates, but a brief comment explaining this validation would improve readability for future maintainers.
📝 Suggested inline comment
export function parseDateInt(value: number | null | undefined): number | undefined { if (!value) return undefined; const year = Math.floor(value / 10000); + // Validate year is within plausible publication range return year >= 1000 && year <= 2200 ? year : undefined; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.ts` around lines 8 - 12, The parseDateInt function uses a hard-coded year check (year >= 1000 && year <= 2200) with no explanation; add a brief inline comment above the conditional in parseDateInt explaining that the 1000–2200 range is chosen to filter out malformed timestamps while covering expected publication dates (e.g., historical works and near-future entries), and note that the upper bound is conservative and can be adjusted if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@client/src/lib/__tests__/provider-colors.spec.ts`:
- Around line 5-67: Tests expect ranobedb color '`#E53935`' but the implementation
(PROVIDER_HEX.ranobedb) returns '`#a78cff`', causing failures in getProviderColor,
providerBadgeStyle, and providerChipStyle specs; fix by either (A) updating the
tests to expect '`#a78cff`' wherever '`#E53935`' is asserted (in getProviderColor
spec, providerBadgeStyle assertion of style.color, and providerChipStyle
assertions) or (B) changing the source constant PROVIDER_HEX.ranobedb in
provider-colors.ts to '`#E53935`' so getProviderColor, providerBadgeStyle, and
providerChipStyle return the expected value—pick one approach and make
consistent updates across the referenced symbols (getProviderColor,
providerBadgeStyle, providerChipStyle, PROVIDER_HEX.ranobedb).
In `@client/src/lib/provider-colors.ts`:
- Line 13: The exported color for the provider "ranobedb" in provider-colors.ts
conflicts with the spec; update the mapping so getProviderColor('ranobedb')
returns the expected value (`#E53935`). Locate the color map (the object exported
from provider-colors.ts) and change the value for the "ranobedb" key from
'`#a78cff`' to '`#E53935`', then run the provider-colors.spec.ts tests to confirm
badge/chip style checks pass.
In
`@server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.test.ts`:
- Around line 114-117: The test in ranobedb.mapper.test.ts duplicates the same
out-of-range assertion for parseDateInt (both
expect(parseDateInt(9990101)).toBeUndefined()); update the second assertion to
use a different out-of-range value (e.g.,
expect(parseDateInt(22010101)).toBeUndefined()) so you validate both low/high
year boundaries for the parseDateInt function.
---
Nitpick comments:
In `@server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.ts`:
- Around line 82-92: Add a brief inline comment inside resolvePublishedYear
explaining the fallback priority used to determine publishedYear: first prefer
release.release_date (parsed via parseDateInt), then fall back to
book.c_release_dates keyed by book.olang (if present), and finally use
book.c_release_date; mention that parseDateInt may return undefined so each
branch checks and returns the first valid year. Place this comment above the
conditional block so future readers understand the cascade and rationale.
- Around line 8-12: The parseDateInt function uses a hard-coded year check (year
>= 1000 && year <= 2200) with no explanation; add a brief inline comment above
the conditional in parseDateInt explaining that the 1000–2200 range is chosen to
filter out malformed timestamps while covering expected publication dates (e.g.,
historical works and near-future entries), and note that the upper bound is
conservative and can be adjusted if needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 58c13a15-0720-4b2e-8a74-bb6388bdb0b9
📒 Files selected for processing (44)
client/src/features/book/components/detail/tabs/EditMetadataTab.vueclient/src/features/book/components/detail/tabs/MetadataSearchDrawer.vueclient/src/features/book/composables/useMetadataDiff.tsclient/src/features/book/composables/useMetadataEditor.tsclient/src/features/book/composables/useRefreshMetadata.tsclient/src/features/settings/metadata-preferences/components/ProviderConfigPanel.vueclient/src/lib/__tests__/provider-colors.spec.tsclient/src/lib/provider-colors.tspackages/types/src/metadata-fetch.tspackages/types/src/metadata-lock.tspackages/types/src/metadata-preferences.tsserver/src/db/migrations/0011_add_ranobedb_id.sqlserver/src/db/migrations/meta/0011_snapshot.jsonserver/src/db/migrations/meta/_journal.jsonserver/src/db/schema/metadata.tsserver/src/modules/book-metadata-fetch/book-metadata-fetch-orchestrator.service.tsserver/src/modules/book-metadata-lock/book-metadata-lock.service.tsserver/src/modules/book/book.service.tsserver/src/modules/book/dto/update-book-metadata.dto.tsserver/src/modules/cover/providers/itunes-cover-provider.test.tsserver/src/modules/metadata-fetch/metadata-fetch.module.test.tsserver/src/modules/metadata-fetch/metadata-fetch.module.tsserver/src/modules/metadata-fetch/metadata-fetch.repository.tsserver/src/modules/metadata-fetch/metadata-fetch.service.tsserver/src/modules/metadata-fetch/providers/amazon/amazon.provider.test.tsserver/src/modules/metadata-fetch/providers/audible/audible.provider.test.tsserver/src/modules/metadata-fetch/providers/audnexus/audnexus.provider.test.tsserver/src/modules/metadata-fetch/providers/comicvine/comicvine.provider.test.tsserver/src/modules/metadata-fetch/providers/goodreads/goodreads.provider.test.tsserver/src/modules/metadata-fetch/providers/google/google.provider.test.tsserver/src/modules/metadata-fetch/providers/hardcover/hardcover.provider.test.tsserver/src/modules/metadata-fetch/providers/itunes/itunes.provider.test.tsserver/src/modules/metadata-fetch/providers/open-library/open-library.provider.test.tsserver/src/modules/metadata-fetch/providers/provider-constants.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.client.test.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.client.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.test.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.provider.test.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.provider.tsserver/src/modules/metadata-fetch/providers/ranobedb/ranobedb.types.tsserver/src/modules/metadata-preferences/dto/update-provider-config.dto.tsserver/src/modules/metadata-preferences/provider-config.service.test.tsserver/src/modules/metadata-preferences/provider-config.service.ts
| audible: '#FF8A00', | ||
| audnexus: '#FF5ADD', | ||
| comicvine: '#ffdb0f', | ||
| ranobedb: '#a78cff', |
There was a problem hiding this comment.
Color mismatch with the new spec — tests will fail.
provider-colors.spec.ts asserts getProviderColor('ranobedb') returns #E53935 (and checks the same value in badge/chip styles), but this source defines #a78cff. These conflict, so the new test suite will fail. Reconcile the two on the intended color (the consolidated note is on the spec file).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@client/src/lib/provider-colors.ts` at line 13, The exported color for the
provider "ranobedb" in provider-colors.ts conflicts with the spec; update the
mapping so getProviderColor('ranobedb') returns the expected value (`#E53935`).
Locate the color map (the object exported from provider-colors.ts) and change
the value for the "ranobedb" key from '`#a78cff`' to '`#E53935`', then run the
provider-colors.spec.ts tests to confirm badge/chip style checks pass.
| it('returns undefined for years out of plausible range', () => { | ||
| expect(parseDateInt(9990101)).toBeUndefined(); | ||
| expect(parseDateInt(9990101)).toBeUndefined(); | ||
| }); |
There was a problem hiding this comment.
Duplicate test assertion on line 116.
Line 116 repeats the same assertion as line 115. The second assertion should test a different out-of-range value to ensure both boundaries are validated (e.g., year too high: 22010101).
🔧 Proposed fix
it('returns undefined for years out of plausible range', () => {
expect(parseDateInt(9990101)).toBeUndefined();
- expect(parseDateInt(9990101)).toBeUndefined();
+ expect(parseDateInt(22010101)).toBeUndefined();
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('returns undefined for years out of plausible range', () => { | |
| expect(parseDateInt(9990101)).toBeUndefined(); | |
| expect(parseDateInt(9990101)).toBeUndefined(); | |
| }); | |
| it('returns undefined for years out of plausible range', () => { | |
| expect(parseDateInt(9990101)).toBeUndefined(); | |
| expect(parseDateInt(22010101)).toBeUndefined(); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.mapper.test.ts`
around lines 114 - 117, The test in ranobedb.mapper.test.ts duplicates the same
out-of-range assertion for parseDateInt (both
expect(parseDateInt(9990101)).toBeUndefined()); update the second assertion to
use a different out-of-range value (e.g.,
expect(parseDateInt(22010101)).toBeUndefined()) so you validate both low/high
year boundaries for the parseDateInt function.
|
This looks great, I ran end-to-end tests and everything passed. |
|
🎉 This PR is included in version 1.8.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
* feat(metadata): add RanobeDB metadata provider Introduces a new metadata provider to fetch book metadata from RanobeDB. - Adds `ranobedb.client` to interact with the RanobeDB API. - Implements `ranobedb.mapper` to map RanobeDB data to the internal metadata schema. - Maps native Japanese titles to subtitles. - Uses the original language as a fallback for the language field. - Parses specific release dates to determine the original publication year. - Registers RanobeDB as an available provider in the preferences UI. - Adds `ranobedb_id` to the metadata database schema. - Removes the `bookId` override when manually performing a metadata search in the UI. Closes bookorbit#114
What does this PR do?
This PR introduces a brand new metadata provider to fetch book metadata from RanobeDB.
Key additions and features:
ranobedb.clientto interact with the RanobeDB API.ranobedb.mapperto map RanobeDB data to our internal metadata schema, which includes:ProviderConfigPanel).ranobedb_idcolumn.bookIdoverride when manually performing a metadata search in the UI.Closes #114
How did you test this?
ranobedb.client.test.ts,ranobedb.mapper.test.ts,ranobedb.provider.test.ts).Screenshots
Anything non-obvious in the diff?
0011_add_ranobedb_id.sql) to track theranobedb_idfor books linked to this provider.provider-colors.tshas been updated with a new color mapped to RanobeDB for the UI badges.Checklist
.env, personal configs)Summary by CodeRabbit