Repository navigation
feat(xtracter): pixivFANBOX対応を追加 - #561
Conversation
Add FANBOX image extraction, platform-scoped author accounts, metadata persistence across JSON and LanceDB, and deterministic media filenames.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces support for linking authors to multiple platform identities (such as Twitter, pixiv-fanbox, and Danbooru) by adding the author_accounts table and updating the database schema, backup services, and the Chrome extension. Feedback on these changes highlights a potential bug in AuthorRepository.create that could lead to duplicate author records, a performance issue with N+1 queries in findOrCreateBulk, and minor logic improvements in the newly added FANBOX content script regarding redundant regex matching and incorrect parsing of 'www' as a creator ID.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
/gemini review |
There was a problem hiding this comment.
Code Review
本プルリクエストでは、著者(Author)に対して「Twitter」「pixiv-fanbox」「danbooru」といった複数のプラットフォームアカウントを紐付ける機能が追加されました。これに伴い、データベーススキーマに author_accounts テーブルが導入され、バックアップ処理、インポート/エクスポート、ファイル名生成規則、および検索フィルターUIがプラットフォーム情報を考慮するように更新されています。また、Chrome拡張機能(xtracter)にpixivFANBOX対応が追加されました。レビューフィードバックでは、UIの Combobox コンポーネントにおいて optionValue をIDに変更したことで選択状態の同期や onChange の挙動が壊れる問題、FANBOXでの画像遅延読み込み(lazy-load)への考慮不足、innerText によるリフロー発生の懸念、および AuthorRepository.create で名前が空の場合に型定義違反(undefined の返却)が発生するバグが指摘されています。
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/ui/src/pro-search-builder.tsx (1)
481-486: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift作者の選択値も ID ベースに寄せることを検討してください。
optionValueはitem.idですが、保存値と復元はnameのままです。同名の別 platform/account 作者があると、選択後に最初の同名作者へ復元されます。🤖 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 `@packages/ui/src/pro-search-builder.tsx` around lines 481 - 486, The author selector is mixing ID-based options with name-based persistence, which can restore the wrong item when names collide. Update the selection flow in pro-search-builder.tsx around the autocomplete value handling so the saved criterion value uses the same ID returned by optionValue, and change the value lookup to match by id rather than name. Keep the fix consistent with the existing author selection logic in the relevant autocomplete component and props wiring so selection and restoration both use the same unique identifier.apps/server/src/components/media/pro-search-builder.tsx (1)
481-486: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift作者の選択値も ID ベースに寄せることを検討してください。
optionValueはitem.idですが、保存値と復元はnameのままです。同名の別 platform/account 作者があると、選択後に最初の同名作者へ復元されます。🤖 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 `@apps/server/src/components/media/pro-search-builder.tsx` around lines 481 - 486, The author selector is mixing ID-based options with name-based persistence, which can restore the wrong item when duplicate names exist. Update the selection flow in pro-search-builder.tsx so the criterion value is stored and restored by the same ID used by optionValue, and adjust the value lookup in the relevant select/autocomplete component to resolve by item.id instead of item.name. Make sure the surrounding props and any setter logic tied to this field use the same identifier consistently.
🧹 Nitpick comments (1)
apps/server/src/components/media/pro-search-builder.tsx (1)
466-478: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winキャストではなく型付き Combobox と type guard にしてください。
ここは package 側と同様に
Combobox<RelationOption>と"accountId" in itemで扱えます。不要なas Author/as { name: string }は避けてください。修正例
- <Combobox + <Combobox<RelationOption> ... - ? props.criterion.target === "author" - ? getAuthorLabel(item as Author) - : (item as { name: string }).name + ? "accountId" in item + ? getAuthorLabel(item) + : item.nameAs per coding guidelines,
**/*.{ts,tsx}: In application code, do not useany, unnecessaryunknown,as unknown as ..., oras any; prefer public types, type guards, Zod schemas, and explicit mappers, and only use unavoidable casts in the smallest possible scope with a comment.🤖 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 `@apps/server/src/components/media/pro-search-builder.tsx` around lines 466 - 478, The Combobox in pro-search-builder should use a typed option model instead of ad hoc casts, since the current optionLabel and optionTextValue logic relies on unnecessary `as Author` and `as { name: string }`. Update the relevant Combobox usage to `Combobox<RelationOption>` and switch the branching in the label/value callbacks to a type guard such as `"accountId" in item` so the code can safely distinguish author-like items from name-based items without unsafe casts. Keep the fix localized around the existing `autocompleteItems`, `getAuthorLabel`, and `optionLabel`/`optionTextValue` handlers.Source: Coding guidelines
🤖 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 `@apps/server/src/application/services/backup-service.ts`:
- Around line 1746-1751: The author mapping in backup-service’s media
serialization is only using the legacy author.accountId match, so authors that
exist only in author.accounts lose their accountId/platform in the dump. Update
the simpleAuthors construction in the backup export path to treat
author.accounts as the source of truth, falling back to the single available
account when author.accountId is null or missing, and ensure the chosen
account’s accountId and platform are serialized so restore can recreate
authorAccounts correctly.
- Around line 414-419: The author resolution in backup-service currently uses
author.name as the lookup key, which can merge distinct authors that share the
same display name. Update the restore path in the loop over validItems to use
the platform + accountId composite key first, matching the platform-scoped
author ID contract, and only fall back to name-based lookup if needed. Use the
existing authorMap logic around author.platform, author.accountId, and authorId
to locate and adjust the mapping.
In `@apps/server/src/components/media/pro-search-builder.tsx`:
- Around line 466-477: The author label rendering in pro-search-builder is using
getAuthorLabel in a way that always shows accountId-backed authors as (twitter),
so update the author-specific branch in the optionLabel/optionTextValue logic to
reflect the actual platform on the Author item instead of hardcoding Twitter.
Locate the label formatting in the autocomplete options for
props.criterion.target === "author" and adjust getAuthorLabel or its caller so
Fanbox/Danbooru authors display the correct platform name consistently.
In `@apps/server/src/components/media/search-filters.tsx`:
- Line 254: The author label rendering in getAuthorLabel is hardcoding the
platform as twitter for accountId-based authors, which causes non-Twitter
authors like Fanbox to be mislabeled; update the label logic used by
search-filters.tsx so it uses author.platform instead of a fixed string, and
keep the change localized to the getAuthorLabel path or its caller where the
displayed author label is built.
- Around line 253-255: The author filter is still tracking selected values by
author.name, which can collide across platforms/accounts and break duplicate
selection or individual removal. Update the selection flow in search-filters.tsx
so the MultiSelect for authors uses the stable author.id consistently in
getSelectedItemValue and the onSelect handling, matching getItemKey; keep
display text coming from getAuthorLabel while storing and comparing by ID.
In `@packages/application/src/services/lancedb-dump-service.ts`:
- Around line 793-795: After the delta sync schema migration in
syncLanceDBDelta, update the manifest version as well so downstream readers
don’t treat the dump as an old format. Use the existing manifest write path in
lancedb-dump-service (the same area that handles migrateLanceDbSchema,
deleteMediaRows, and addRowsToTables) to persist version: LANCEDB_DUMP_VERSION
after the migration and row updates complete.
In `@packages/db/src/repositories/author-repository.ts`:
- Around line 37-42: The create() flow in author-repository.ts can return
undefined for an empty author name because the deduplication loop filters out
inputs with an empty name and then exits early when uniqueInputs is empty.
Update the Author create path so it never silently returns an empty result for
invalid input: either enforce a non-empty name at the input schema boundary or
have create() explicitly throw on empty names before reaching the
uniqueInputs/authorInputKey logic. Make the same fix in the other affected
create path referenced in the comment so Promise<Author> remains consistent.
In `@packages/ui/src/pro-search-builder.tsx`:
- Around line 466-477: The author label used by the autocomplete in
pro-search-builder’s item rendering is hardcoded to show twitter for every
author with an accountId. Update the label logic used by getAuthorLabel (and any
callers in optionLabel/optionTextValue) so it derives the displayed platform
from the actual author data instead of always defaulting to twitter, ensuring
Fanbox and Danbooru candidates render with the correct platform name.
In `@packages/ui/src/search-filters.tsx`:
- Line 233: The author label rendering is hardcoded to show “(twitter)” for
accountId-based authors, which mislabels non-Twitter authors. Update the
author-label logic used by getAuthorLabel so it reads and displays
author.platform instead of a fixed platform string, and make sure the
SearchFilters/getItemLabel path still passes through the correct author data for
display.
- Around line 232-235: The author filter is still tracking selection by
author.name, so duplicate names across platforms/accounts cannot be
distinguished. Update the author selection flow in search-filters.tsx around the
author picker props to use author.id as the selected item value and in the
onSelect handling, while keeping getItemKey aligned with the same stable ID.
Ensure the selected-state lookup, toggle/removal logic, and any state passed
through the author-related helpers all compare IDs rather than names.
---
Outside diff comments:
In `@apps/server/src/components/media/pro-search-builder.tsx`:
- Around line 481-486: The author selector is mixing ID-based options with
name-based persistence, which can restore the wrong item when duplicate names
exist. Update the selection flow in pro-search-builder.tsx so the criterion
value is stored and restored by the same ID used by optionValue, and adjust the
value lookup in the relevant select/autocomplete component to resolve by item.id
instead of item.name. Make sure the surrounding props and any setter logic tied
to this field use the same identifier consistently.
In `@packages/ui/src/pro-search-builder.tsx`:
- Around line 481-486: The author selector is mixing ID-based options with
name-based persistence, which can restore the wrong item when names collide.
Update the selection flow in pro-search-builder.tsx around the autocomplete
value handling so the saved criterion value uses the same ID returned by
optionValue, and change the value lookup to match by id rather than name. Keep
the fix consistent with the existing author selection logic in the relevant
autocomplete component and props wiring so selection and restoration both use
the same unique identifier.
---
Nitpick comments:
In `@apps/server/src/components/media/pro-search-builder.tsx`:
- Around line 466-478: The Combobox in pro-search-builder should use a typed
option model instead of ad hoc casts, since the current optionLabel and
optionTextValue logic relies on unnecessary `as Author` and `as { name: string
}`. Update the relevant Combobox usage to `Combobox<RelationOption>` and switch
the branching in the label/value callbacks to a type guard such as `"accountId"
in item` so the code can safely distinguish author-like items from name-based
items without unsafe casts. Keep the fix localized around the existing
`autocompleteItems`, `getAuthorLabel`, and `optionLabel`/`optionTextValue`
handlers.
🪄 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 Plus
Run ID: 2a21be0a-3fe8-4584-a2e2-8959c84dbd84
📒 Files selected for processing (31)
apps/server/drizzle/0017_ambitious_gideon.sqlapps/server/drizzle/meta/0017_snapshot.jsonapps/server/drizzle/meta/_journal.jsonapps/server/src/application/services/backup-service.tsapps/server/src/components/media/pro-search-builder.tsxapps/server/src/components/media/search-filters.tsxapps/server/src/infrastructure/jobs/download-jobs.tsapps/server/src/tests/integration/backup/backup-service.test.tsapps/server/src/tests/integration/repository/author-dedupe.test.tsapps/server/src/tests/unit/application/services/lancedb-dump-service.test.tsapps/server/src/tests/unit/application/services/media-processing-service.test.tsapps/server/src/tests/unit/domain/media/schemas.test.tsapps/server/src/tests/unit/infrastructure/jobs/download-jobs.test.tsapps/xtracter/README.mdapps/xtracter/public/manifest.jsonapps/xtracter/src/content/danbooru.tsapps/xtracter/src/content/fanbox.tsapps/xtracter/src/content/index.tsapps/xtracter/src/content/twitter.tsapps/xtracter/src/schema.tspackages/application/src/services/lancedb-dump-service.tspackages/application/src/services/media-processing-service.tspackages/core/src/domain/authors/schemas.tspackages/core/src/domain/media/schemas.tspackages/core/src/domain/media/utils/filename-utils.tspackages/core/src/domain/repositories/author-repository.tspackages/core/tests/filename-utils.test.tspackages/db/src/repositories/author-repository.tspackages/db/src/schema.tspackages/ui/src/pro-search-builder.tsxpackages/ui/src/search-filters.tsx
概要
xtracterからpixivFANBOXの記事画像を保存・POSTできるようにします。
変更内容
検証
Summary by CodeRabbit
新機能
改善