feat(library): allow a custom picture per genre#426
Conversation
Genre tiles and the genre detail header rendered a fixed generic icon with no way to customize it. Adds a manual per-genre picture, mirroring the existing artist/album manual-image override pattern: a new genre.artwork_id column, set_genre_artwork_from_file / clear_genre_artwork commands (magic-byte validated, hash-addressed in the shared per-profile artwork dir), and a GenreImagePickerModal opened from a Pencil overlay on both the library grid tile and the detail page header. Closes #424
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughCette évolution ajoute l’artwork manuel des genres avec persistance SQL, commandes Tauri, chemins d’image, modale de sélection/suppression, affichage dans la bibliothèque et le détail, ainsi que les traductions associées. ChangesArtwork manuel des genres
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant GenreDetailView
participant GenreImagePickerModal
participant browse_ts
participant BackendTauri
GenreDetailView->>GenreImagePickerModal: ouvre la modale d’artwork
GenreImagePickerModal->>browse_ts: appelle setGenreArtworkFromFile
browse_ts->>BackendTauri: invoque la commande backend
BackendTauri-->>GenreImagePickerModal: retourne le résultat
GenreImagePickerModal-->>GenreDetailView: déclenche le rafraîchissement
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@src-tauri/crates/app/src/commands/browse.rs`:
- Around line 717-735: Update the artwork file flow around create_dir_all, read,
hashing, and write to run inside a tokio::task::spawn_blocking closure. Replace
unbounded std::fs::read with bounded reading of at most MAX_IMAGE_BYTES + 1
bytes, reject inputs exceeding MAX_IMAGE_BYTES, then preserve format detection,
hashing, and deduplicated target writing within the blocking task.
In `@src/components/common/GenreImagePickerModal.tsx`:
- Around line 32-33: Reset the error state when the modal transitions to open by
updating the isOpen handling around the error state in GenreImagePickerModal.
Ensure setError clears the previous message on each isOpen=true transition,
while preserving error updates during the current application attempt.
In `@src/components/views/LibraryView.tsx`:
- Around line 2208-2218: Update the Artwork instance in the genre button to use
an empty alt value instead of genre.name, keeping the adjacent genre.name text
as the sole accessible label for both the loaded image and placeholder.
In `@src/lib/tauri/browse.ts`:
- Around line 322-330: Update the invoke calls in setGenreArtworkFromFile and
clearGenreArtwork to use the explicit void generic, preserving their
Promise<void> return contracts.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: cbf62939-cc35-4a02-bbd0-eef401a48e51
📒 Files selected for processing (27)
docs/features/library.mdsrc-tauri/crates/app/src/commands/browse.rssrc-tauri/crates/app/src/commands/deezer.rssrc-tauri/crates/app/src/lib.rssrc-tauri/migrations/profile/20260721103000_genre_artwork.sqlsrc/components/common/GenreImagePickerModal.tsxsrc/components/views/GenreDetailView.tsxsrc/components/views/LibraryView.tsxsrc/i18n/locales/ar.jsonsrc/i18n/locales/de.jsonsrc/i18n/locales/en.jsonsrc/i18n/locales/es.jsonsrc/i18n/locales/fr.jsonsrc/i18n/locales/hi.jsonsrc/i18n/locales/id.jsonsrc/i18n/locales/it.jsonsrc/i18n/locales/ja.jsonsrc/i18n/locales/ko.jsonsrc/i18n/locales/nl.jsonsrc/i18n/locales/pt-BR.jsonsrc/i18n/locales/pt.jsonsrc/i18n/locales/ru.jsonsrc/i18n/locales/tr.jsonsrc/i18n/locales/zh-CN.jsonsrc/i18n/locales/zh-TW.jsonsrc/lib/tauri/browse.tssrc/lib/tauri/detail.ts
- Bound the manual genre-picture read to MAX_IMAGE_BYTES + 1 and move create_dir_all/read/hash/write off the async runtime via spawn_blocking, instead of an unbounded std::fs::read on the tokio worker thread. - Reset GenreImagePickerModal's error state when it closes, so a stale message from a previous attempt doesn't linger on reopen. - Genre grid tile: alt="" on the Artwork image since the adjacent genre name text is already the button's accessible label — avoids double announcement. - setGenreArtworkFromFile/clearGenreArtwork: explicit invoke<void> generic, matching the sibling clearArtistArtwork/clearAlbumMotionArtwork wrappers.
Summary
genre.artwork_idcolumn,set_genre_artwork_from_file/clear_genre_artworkcommands (magic-byte validated jpg/png/webp, hash-addressed in the shared per-profileartwork/dir,source = 'manual'), and aGenreImagePickerModalopened from aPenciloverlay on both the grid tile and the detail header.list_genres/get_genre_detailnow resolve and ship the artwork path (same slim-row +artwork_baseeconomy as albums/artists).genreImagePicker.*propagated to all 17 locales.Test plan
cargo check --workspace --all-targets— greenbun run typecheck— greenbun run lint— greencargo test --workspace— blocked locally by disk space (link step: "No space left on device"), not a code issue; relying on CI for this runCloses #424
https://claude.ai/code/session_01F9cgAgcbjFFe74k9vTEcjV
Summary by CodeRabbit