Skip to content

feat(metadata): add LubimyCzytac metadata provider#324

Merged
neonsolstice merged 3 commits into
bookorbit:mainfrom
chrismansell26:BO-304-metadata-source-lubimyczytac
Jun 13, 2026
Merged

feat(metadata): add LubimyCzytac metadata provider#324
neonsolstice merged 3 commits into
bookorbit:mainfrom
chrismansell26:BO-304-metadata-source-lubimyczytac

Conversation

@chrismansell26

@chrismansell26 chrismansell26 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Adds lubimyczytac.pl as a metadata source, a Polish book/audiobook catalog with no public API, so the provider scrapes public pages.

  • New LubimyCzytacScraper and LubimyCzytacProvider (search + lookupById)
  • lubimyczytacId field added to types, DB schema, file-write fields, lock groups, extractors (PDF, CBZ, OPF), and metadata service
  • Provider registered in module, pipeline, repository, and config service
  • Provider icon, color, link, and UI wired up (quick view, details tab, edit metadata tab, provider config panel)
  • Migration: 0019_add_lubimyczytac_provider_id

Closes #304

How did you test this?

  • Unit tests added for scraper (lubimyczytac.scraper.test.ts) and provider (lubimyczytac.provider.test.ts)
  • All existing provider test fixtures updated with the new config key
  • pnpm run verify:fast passes (lint, typecheck)

Anything non-obvious in the diff?

The scraper targets public lubimyczytac.pl pages. Between-request delay set to 600ms (LUBIMYCZYTAC_BETWEEN_REQUESTS) to be polite to the site.

Checklist

  • I've read through my own diff
  • This PR was discussed in an issue and has maintainer approval (for new features)
  • Lint and tests pass locally
  • No unintended files included (build artifacts, .env, personal configs)

Summary by CodeRabbit

  • New Features

    • Added LubimyCzytac provider: search & lookup, external book links, icon/color, settings toggle, and UI support in details/quick‑view/edit metadata.
    • Read/write/persist LubimyCzytac IDs across files, OPF/XMP/ComicInfo, metadata editor, file write payloads, and stats.
  • Tests

    • Extensive unit tests for LubimyCzytac scraper/provider and parsing logic.
  • Chores

    • Database migration to add LubimyCzytac ID column.

- Add LubimyCzytac scraper and provider implementation
- Add lubimyczytacId field across types, schema, extractors, and metadata service
- Register lubimyczytac provider in module, pipeline, repository, and config service
- Add provider icon, color, link, and UI support in book detail views
- Add migration for lubimyczytac_id column

Closes bookorbit#304
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds LubimyCzytac provider support across types, DB migration and schema, server scraper/provider implementation and tests, extractor/file-write plumbing, metadata persistence and lock handling, client UI/provider links and editor fields, module wiring, and test fixtures; plus a BookCoverCard overlay UI tweak.

Changes

LubimyCzytac Provider Integration

Layer / File(s) Summary
Type definitions and database schema
packages/types/*, server/src/db/schema/metadata.ts, server/src/db/migrations/0019_add_lubimyczytac_provider_id.sql, server/src/db/migrations/meta/_journal.json
Adds LUBIMYCZYTAC provider key and lubimyczytacId across types, lock fields, file-write fields, and DB schema/migration.
Provider configuration and preferences
server/src/modules/metadata-preferences/*, client/src/lib/provider-colors.ts, client/src/features/settings/metadata-preferences/components/ProviderConfigPanel.vue
Registers lubimyczytac in provider defaults, DTOs, labels, status list, settings UI, colors, and test fixtures.
Client book links and metadata editing
client/src/features/book/*, client/src/lib/provider-colors.ts, client/src/features/book/lib/provider-links.ts
Adds lubimyczytacBookUrl helper, icon/color/label, extends quick view/details links, metadata editor/diff/composables and file-metadata patch to track/diff/patch lubimyczytacId.
LubimyCzytac scraper module
server/src/modules/metadata-fetch/providers/lubimyczytac/*
New scraper and parser: search/book URL builders, id/path extraction, DOM + JSON-LD parsing into structured data, with extensive tests.
LubimyCzytac provider class
server/src/modules/metadata-fetch/providers/lubimyczytac/lubimyczytac.provider.ts, tests
Adds provider implementing search and lookupById with throttling, timeout, abort-signal support, inter-request sleeps, error handling, and unit tests.
Metadata-fetch wiring and tests
server/src/modules/metadata-fetch/*
Registers provider in PROVIDER_CLASSES, updates repository/service projections and many provider test fixtures/helpers to include lubimyczytac config.
File format metadata extraction and write payloads
server/src/modules/metadata/lib/*, server/src/modules/metadata/extractors/*, server/src/modules/file-write/*, packages/types/src/file-write.ts
Parses lubimyczytacId from OPF (scheme/urn), PDF XMP, CBZ managed notes/JSON, exposes it via extractor interfaces, and includes it in file-write payloads and constants.
Metadata persistence, locks, and stats
server/src/modules/book/*, server/src/modules/book-metadata-lock/*, server/src/modules/metadata/metadata.service.ts, server/src/modules/statistics/statistics.repository.ts
Collects, applies, persists, and returns lubimyczytacId through provider-id flows, respects locks, and treats it as a provider-id signal for freshness stats.
Test updates across providers
server/src/modules/metadata-fetch/providers/* and related tests
Extends provider test fixtures and helpers to include lubimyczytac: { enabled: false } and adds dedicated LubimyCzytac provider and scraper tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • bookorbit/bookorbit#185: Similar provider-integration work adding provider ID plumbing across types, composables, and services.

Suggested reviewers

  • neonsolstice

🐇 I hopped through types and scraper code,
LubimyCzytac found its new abode.
From DB column to client link,
Parsing HTML while I blink,
Now Polish books can wander free—hop, hop, hooray!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning All changes directly support adding lubimyczytac.pl as a metadata provider. The one notable exception is BookCoverCard.vue refactoring (decoupling overlay icon from thumbnail click action), which appears unrelated to the provider implementation. Remove or justify the BookCoverCard.vue changes (lines 14/-2). If intentional, move to a separate focused PR to keep this one focused on the LubimyCzytac provider feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding LubimyCzytac as a metadata provider. It is specific, related to the changeset, and follows conventional commit format.
Description check ✅ Passed The PR description covers all required sections: what the change does (includes issues closed), how tested (unit tests, lint/typecheck), non-obvious details (scraper approach, delay), and a completed checklist. It comprehensively explains the scope.
Linked Issues check ✅ Passed The PR fully addresses issue #304's requirements by implementing search and lookupById capabilities for lubimyczytac.pl, integrating it across metadata pipeline/storage/config/UI, applying polite rate-limiting (600ms delay), and including comprehensive tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added server Changes affecting server-side code, APIs, or backend behavior. client Changes affecting the client application or frontend behavior. packages labels Jun 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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/features/book/lib/provider-links.ts`:
- Around line 1-7: The lubimyczytacBookUrl function must validate the trimmed
id: after const value = String(id).trim() check that value is non-empty and does
not start or end with a slash (and is not just "/"); if validation fails return
a safe fallback (e.g., empty string or null) or throw an error per project
convention; otherwise normalize by removing any leading slashes and then build
the path exactly as before (use existing logic: if no slash add "/-" else keep
canonical id/slug and encodeURIComponent each segment).

In
`@server/src/modules/metadata-fetch/providers/lubimyczytac/lubimyczytac.provider.ts`:
- Around line 52-56: The loop that fetches each detail (the for (const link of
links.slice(0, maxCandidates)) loop) currently calls sleep only after a prior
result is present; move the pacing call to the start of each iteration so the
configured gap (PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS) is applied
before the first detail fetch too: after checking params.signal?.aborted at the
top of the loop, call await
sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal) and
remove the results.length > 0 condition that guarded the existing sleep call so
the delay is applied unconditionally for each detail request.
🪄 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: a90a2a71-6f23-44d1-8407-fafbb364aeaa

📥 Commits

Reviewing files that changed from the base of the PR and between 10ad6f8 and d56123a.

⛔ Files ignored due to path filters (1)
  • client/public/assets/provider-icons/lubimyczytac.svg is excluded by !**/*.svg
📒 Files selected for processing (64)
  • client/src/features/book/components/BookQuickView.vue
  • client/src/features/book/components/detail/tabs/DetailsTab.vue
  • client/src/features/book/components/detail/tabs/EditMetadataTab.vue
  • client/src/features/book/composables/useFileMetadata.ts
  • client/src/features/book/composables/useMetadataDiff.ts
  • client/src/features/book/composables/useMetadataEditor.ts
  • client/src/features/book/lib/file-metadata-patch.ts
  • client/src/features/book/lib/metadata-refresh-feedback.ts
  • client/src/features/book/lib/provider-icons.ts
  • client/src/features/book/lib/provider-links.ts
  • client/src/features/settings/metadata-preferences/components/ProviderConfigPanel.vue
  • client/src/lib/provider-colors.ts
  • packages/types/src/book.ts
  • packages/types/src/file-write.ts
  • packages/types/src/metadata-fetch.ts
  • packages/types/src/metadata-lock.ts
  • packages/types/src/metadata-preferences.ts
  • server/src/db/migrations/0019_add_lubimyczytac_provider_id.sql
  • server/src/db/migrations/meta/0019_snapshot.json
  • server/src/db/migrations/meta/_journal.json
  • server/src/db/schema/metadata.ts
  • server/src/modules/book-metadata-fetch/book-metadata-fetch-orchestrator.service.ts
  • server/src/modules/book-metadata-lock/book-metadata-lock.service.ts
  • server/src/modules/book/book.service.ts
  • server/src/modules/book/dto/update-book-metadata.dto.ts
  • server/src/modules/cover/providers/itunes-cover-provider.test.ts
  • server/src/modules/file-write/file-write.constants.ts
  • server/src/modules/file-write/file-write.repository.ts
  • server/src/modules/file-write/interfaces/book-write-payload.interface.ts
  • server/src/modules/metadata-fetch/metadata-fetch-pipeline.test.ts
  • server/src/modules/metadata-fetch/metadata-fetch.controller.test.ts
  • server/src/modules/metadata-fetch/metadata-fetch.module.test.ts
  • server/src/modules/metadata-fetch/metadata-fetch.module.ts
  • server/src/modules/metadata-fetch/metadata-fetch.repository.ts
  • server/src/modules/metadata-fetch/metadata-fetch.service.ts
  • server/src/modules/metadata-fetch/providers/amazon/amazon.provider.test.ts
  • server/src/modules/metadata-fetch/providers/audible/audible.provider.test.ts
  • server/src/modules/metadata-fetch/providers/audnexus/audnexus.provider.test.ts
  • server/src/modules/metadata-fetch/providers/comicvine/comicvine.provider.test.ts
  • server/src/modules/metadata-fetch/providers/goodreads/goodreads.provider.test.ts
  • server/src/modules/metadata-fetch/providers/google/google.provider.test.ts
  • server/src/modules/metadata-fetch/providers/hardcover/hardcover.provider.test.ts
  • server/src/modules/metadata-fetch/providers/itunes/itunes.provider.test.ts
  • server/src/modules/metadata-fetch/providers/kobo/kobo.provider.test.ts
  • server/src/modules/metadata-fetch/providers/lubimyczytac/lubimyczytac.provider.test.ts
  • server/src/modules/metadata-fetch/providers/lubimyczytac/lubimyczytac.provider.ts
  • server/src/modules/metadata-fetch/providers/lubimyczytac/lubimyczytac.scraper.test.ts
  • server/src/modules/metadata-fetch/providers/lubimyczytac/lubimyczytac.scraper.ts
  • server/src/modules/metadata-fetch/providers/open-library/open-library.provider.test.ts
  • server/src/modules/metadata-fetch/providers/provider-constants.ts
  • server/src/modules/metadata-fetch/providers/ranobedb/ranobedb.provider.test.ts
  • server/src/modules/metadata-preferences/dto/update-provider-config.dto.ts
  • server/src/modules/metadata-preferences/provider-config.service.test.ts
  • server/src/modules/metadata-preferences/provider-config.service.ts
  • server/src/modules/metadata/extractors/comic-format.extractor.ts
  • server/src/modules/metadata/extractors/format-extractor.interface.ts
  • server/src/modules/metadata/extractors/opf-metadata.mapper.ts
  • server/src/modules/metadata/extractors/pdf-format.extractor.ts
  • server/src/modules/metadata/lib/cbz-metadata.ts
  • server/src/modules/metadata/lib/opf-parser.ts
  • server/src/modules/metadata/lib/pdf-parser.ts
  • server/src/modules/metadata/lib/pdf-xmp-reader.ts
  • server/src/modules/metadata/metadata.service.ts
  • server/src/modules/statistics/statistics.repository.ts

Comment on lines +1 to +7
export function lubimyczytacBookUrl(id: string): string {
const value = String(id).trim()
// New data stores the canonical "id/slug" path. lubimyczytac.pl 404s on a slug-less id,
// so legacy bare-numeric ids get a placeholder slug segment to keep the link valid.
const path = value.includes('/') ? value : `${value}/-`
return `https://lubimyczytac.pl/ksiazka/${path.split('/').map(encodeURIComponent).join('/')}`
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add input validation for edge-case strings.

The function does not validate that id is non-empty after trimming or that slash patterns are well-formed. Edge cases that could produce malformed URLs:

  1. Whitespace-only input: A string like " " is truthy in the caller's check (if (ids.lubimyczytac)), but after trim() becomes "", resulting in path = "/-" and a double-slash URL: https://lubimyczytac.pl/ksiazka//-.
  2. Malformed slash inputs: Inputs like "/" (slash only) or "/123" (leading slash) would produce invalid double-slash URLs.

The components perform truthy checks before calling this function, which prevents null, undefined, and empty strings, but whitespace-only strings bypass that check.

🛡️ Suggested input validation
 export function lubimyczytacBookUrl(id: string): string {
   const value = String(id).trim()
+  if (!value) {
+    throw new Error('lubimyczytac ID cannot be empty')
+  }
   // New data stores the canonical "id/slug" path. lubimyczytac.pl 404s on a slug-less id,
   // so legacy bare-numeric ids get a placeholder slug segment to keep the link valid.
   const path = value.includes('/') ? value : `${value}/-`
   return `https://lubimyczytac.pl/ksiazka/${path.split('/').map(encodeURIComponent).join('/')}`
 }

Alternatively, if throwing is undesirable, return a safe fallback or validate the format more strictly (e.g., reject leading/trailing slashes).

🤖 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/features/book/lib/provider-links.ts` around lines 1 - 7, The
lubimyczytacBookUrl function must validate the trimmed id: after const value =
String(id).trim() check that value is non-empty and does not start or end with a
slash (and is not just "/"); if validation fails return a safe fallback (e.g.,
empty string or null) or throw an error per project convention; otherwise
normalize by removing any leading slashes and then build the path exactly as
before (use existing logic: if no slash add "/-" else keep canonical id/slug and
encodeURIComponent each segment).

Comment on lines +52 to +56
for (const link of links.slice(0, maxCandidates)) {
if (params.signal?.aborted) break;
if (results.length > 0) {
await sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Apply the configured request gap before the first detail fetch.

On Line 54, the delay only runs after at least one result is already added, so the search request and first book-page request run back-to-back. That bypasses the configured between-request pacing and raises throttling risk.

💡 Proposed fix
   for (const link of links.slice(0, maxCandidates)) {
     if (params.signal?.aborted) break;
-    if (results.length > 0) {
-      await sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal);
-    }
+    // Keep a gap between the search request and every detail-page request.
+    await sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal);
     const candidate = await this.fetchByUrl(link.url, link.providerId, params.signal);
     if (candidate) results.push(candidate);
   }
📝 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.

Suggested change
for (const link of links.slice(0, maxCandidates)) {
if (params.signal?.aborted) break;
if (results.length > 0) {
await sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal);
}
for (const link of links.slice(0, maxCandidates)) {
if (params.signal?.aborted) break;
// Keep a gap between the search request and every detail-page request.
await sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal);
const candidate = await this.fetchByUrl(link.url, link.providerId, params.signal);
if (candidate) results.push(candidate);
}
🤖 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/lubimyczytac/lubimyczytac.provider.ts`
around lines 52 - 56, The loop that fetches each detail (the for (const link of
links.slice(0, maxCandidates)) loop) currently calls sleep only after a prior
result is present; move the pacing call to the start of each iteration so the
configured gap (PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS) is applied
before the first detail fetch too: after checking params.signal?.aborted at the
top of the loop, call await
sleep(PROVIDER_DELAYS_MS.LUBIMYCZYTAC_BETWEEN_REQUESTS, params.signal) and
remove the results.length > 0 condition that guarded the existing sleep call so
the delay is applied unconditionally for each detail request.

… click prefers details

The overlay primary button should always open the reader regardless of
the thumbnailClickAction setting. That setting only controls card click
behaviour.
…click prefers details

When thumbnailClickAction is 'details', a dedicated Read button now
appears in the overlay top row so users can still open the reader
directly without changing their preference.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
client/src/features/book/components/BookCoverCard.vue (2)

530-536: ⚡ Quick win

Consider adding an accessible label to the explicit Read button.

The new explicit Read button is icon-only and lacks an aria-label attribute. Screen reader users may not understand the button's purpose. Consider adding aria-label="Read book" or similar descriptive text.

Note: The adjacent Quick View button (lines 527-529) also lacks an aria-label, so this may be a broader pattern in the component worth addressing.

♿ Proposed accessibility improvement
 <button
   v-if="showExplicitReadButton"
   class="p-[3cqi] rounded-[2.5cqi] bg-black/50 hover:bg-black/30 transition-colors text-white"
+  aria-label="Read book"
   `@click.stop`="openPrimaryFileExplicit"
 >
   <BookOpen class="size-[12cqi]" />
 </button>
🤖 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/features/book/components/BookCoverCard.vue` around lines 530 -
536, The explicit Read button in the BookCoverCard.vue component is icon-only
and missing an accessibility label; update the button element that calls
openPrimaryFileExplicit to include a descriptive aria-label (for example
aria-label="Read book (explicit content)" or similar), and likewise add an
appropriate aria-label to the adjacent Quick View button (the icon-only button
above that opens the quick view) so both icon-only controls are announced to
screen readers; ensure the labels are concise and contextually distinguish the
two actions.

257-258: ⚡ Quick win

Consolidate duplicate computed logic.

isPrimaryClickAvailable (line 257) and showPrimaryOverlayAction (line 258) have identical implementations. Consider removing the duplication by having one reference the other or using a single computed property for both purposes.

♻️ Proposed consolidation

Option 1: Reuse showPrimaryOverlayAction directly

-const isPrimaryClickAvailable = computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value != null && !isMissing.value))
-const showPrimaryOverlayAction = computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value != null && !isMissing.value))
+const showPrimaryOverlayAction = computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value != null && !isMissing.value))

Then on line 388, replace isPrimaryClickAvailable with showPrimaryOverlayAction.

Option 2: Have one reference the other

 const isPrimaryClickAvailable = computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value != null && !isMissing.value))
-const showPrimaryOverlayAction = computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value != null && !isMissing.value))
+const showPrimaryOverlayAction = computed(() => isPrimaryClickAvailable.value)
🤖 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/features/book/components/BookCoverCard.vue` around lines 257 -
258, The two computed properties isPrimaryClickAvailable and
showPrimaryOverlayAction in BookCoverCard.vue contain identical logic; remove
the duplication by keeping a single computed (e.g., showPrimaryOverlayAction =
computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value !=
null && !isMissing.value))) and make isPrimaryClickAvailable a simple alias
referencing that computed (or remove isPrimaryClickAvailable and replace its
usages with showPrimaryOverlayAction); update all usages (e.g., the reference
noted near line 388) to use the remaining computed so only one source of truth
remains.
🤖 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.

Nitpick comments:
In `@client/src/features/book/components/BookCoverCard.vue`:
- Around line 530-536: The explicit Read button in the BookCoverCard.vue
component is icon-only and missing an accessibility label; update the button
element that calls openPrimaryFileExplicit to include a descriptive aria-label
(for example aria-label="Read book (explicit content)" or similar), and likewise
add an appropriate aria-label to the adjacent Quick View button (the icon-only
button above that opens the quick view) so both icon-only controls are announced
to screen readers; ensure the labels are concise and contextually distinguish
the two actions.
- Around line 257-258: The two computed properties isPrimaryClickAvailable and
showPrimaryOverlayAction in BookCoverCard.vue contain identical logic; remove
the duplication by keeping a single computed (e.g., showPrimaryOverlayAction =
computed(() => thumbnailClickAction.value === 'details' || (primaryFile.value !=
null && !isMissing.value))) and make isPrimaryClickAvailable a simple alias
referencing that computed (or remove isPrimaryClickAvailable and replace its
usages with showPrimaryOverlayAction); update all usages (e.g., the reference
noted near line 388) to use the remaining computed so only one source of truth
remains.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e1e296fe-1b3f-41aa-b9b3-4c9c74bb6212

📥 Commits

Reviewing files that changed from the base of the PR and between 9ab0d07 and f561308.

📒 Files selected for processing (1)
  • client/src/features/book/components/BookCoverCard.vue

@neonsolstice
neonsolstice merged commit 705dd9c into bookorbit:main Jun 13, 2026
25 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.11.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released Issue or PR is included in a released version. label Jun 20, 2026
@kyych

kyych commented Jun 29, 2026

Copy link
Copy Markdown

@chrismansell26 is that working for you? I just created issue recently regarding this feature #469

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

Labels

client Changes affecting the client application or frontend behavior. packages released Issue or PR is included in a released version. server Changes affecting server-side code, APIs, or backend behavior.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] New Metadata source LubimyCzytac.pl ( for users from Poland )

3 participants