feat(link): expand crawler galleries into per-image rows - #173
Conversation
A pasted gallery URL now resolves into one selectable row per image, in gallery order, with the plugin's filenames and an "image" media type. Per-image failures become individual error rows so a partially invalid gallery keeps its valid entries, and an empty gallery reports a NoFile error instead of silently vanishing. The expansion is gated on crawler plugins whose URL is not a media host, so yt-dlp-backed crawlers keep the cheap probe path. MAT-134
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
📝 WalkthroughWalkthroughGallery-aware crawler resolution now expands gallery payloads into ordered image rows, reports individual failures, preserves non-gallery probing and media handling, and supports frontend rendering and downloads through the existing Link Grabber flow. ChangesGallery resolution
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant LinkGrabberView
participant TauriResolver
participant PluginLoader
participant DownloadCommand
User->>LinkGrabberView: Analyze gallery URL
LinkGrabberView->>TauriResolver: link_resolve
TauriResolver->>PluginLoader: extract_links
PluginLoader-->>TauriResolver: gallery image payload
TauriResolver-->>LinkGrabberView: ordered image and error rows
User->>LinkGrabberView: Start selected images
LinkGrabberView->>DownloadCommand: download_start for valid selected rows
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/src/application/commands/resolve_links_gallery.rs`:
- Line 55: Update the response parsing flow around GalleryResponse
deserialization to distinguish malformed plugin payloads from valid non-gallery
responses: convert serde_json::from_str failures into a Plugin error row, while
continuing to return None only when a successfully parsed payload has a
non-"gallery" kind. Add a regression test beside the existing non-gallery
fallback test covering malformed responses.
- Around line 67-74: Bound parsed.images before mapping and collecting gallery
rows so allocations never exceed MAX_URLS. Update the surrounding method that
calls push_bounded_result to pass remaining capacity into this gallery
conversion, then limit or reject parsed.images before gallery_image_row runs
while preserving existing indexing and result behavior.
- Around line 84-98: The image URL validation in the gallery item resolution
flow must parse the complete URL rather than checking only its prefix. Update
the validation around image.url to accept only URLs with a valid HTTP(S) scheme,
a host, and case-insensitive scheme handling; keep invalid items routed through
gallery_error_row as individual plugin error rows.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ef9f3bec-0146-4509-9459-872b502ce23a
📒 Files selected for processing (7)
CHANGELOG.mdsrc-tauri/src/application/commands/mod.rssrc-tauri/src/application/commands/resolve_links.rssrc-tauri/src/application/commands/resolve_links_gallery.rssrc-tauri/src/application/commands/resolve_links_gallery_tests.rssrc/views/LinkGrabberView/__tests__/GalleryLinks.test.tsxsrc/views/LinkGrabberView/types.ts
There was a problem hiding this comment.
cubic analysis
All reported issues were addressed across 7 files
Linked issue analysis
Linked issue: MAT-134: [Lot 2] Intégrer le plugin Gallery de bout en bout
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | R-02 — A supported gallery appears as a group of selectable elements in Link Grabber. | The resolver expands a gallery into one ResolvedLinkDto per image and the frontend tests assert rows render with selection checkboxes. |
| ✅ | R-03 — Selection starts downloads via Tauri commands, without direct frontend network requests. | Image rows are produced with requires_online_probe: false and the frontend test verifies Start Selected/Start All call 'download_start' per selected image. |
| ✅ | R-04 — Gallery order, filenames (names) and media types are preserved. | Resolver preserves input order, uses plugin filename or URL basename as fallback, and sets mediaType to 'image'; tests assert order, filenames and media_type. |
| ✅ | R-05 — A per-media error is reported without cancelling valid gallery items. | Malformed image entries produce individual error rows while valid images remain; unit and frontend tests cover a partially invalid gallery scenario. |
| ✅ | R-06 — Native/ABI/WASM and frontend tests cover valid gallery, empty gallery and partially invalid response. | New host tests exercise valid, empty, partially invalid, extraction failure, and non-gallery fallthrough; three new vitest cases cover frontend rendering and download behavior. |
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Merging this PR will degrade performance by 3.46%
Performance Changes
Tip Curious why this is faster? Comment Comparing |
Malformed extract_links JSON now yields a plugin error row instead of falling through to a HEAD probe of the gallery page. Expansion is capped at the resolve output's remaining capacity, so an oversized gallery truncates (with a warn log) instead of failing the whole request after partial work. Image URLs are validated with url::Url (http/https scheme, case-insensitive, host required) instead of a string prefix check.
|
@codspeedbot fix this regression |
I looked into the flagged regression and I don't think there's a real regression here to fix — the numbers are measurement noise rather than a code slowdown. Here's the reasoning: The regressed benchmarks measure functions this PR never touches.
This PR only adds gallery resolution in The pattern is classic layout noise, not a slowdown. These are sub-microsecond micro-benchmarks (≈94–550 ns). Under the Simulation instrument, functions this small are very sensitive to binary layout/alignment, which shifts whenever unrelated code is added elsewhere in the crate. The tell-tale sign here is that the "improvements" mirror the "regressions" almost symmetrically:
A genuine algorithmic regression wouldn't make one variant of the same trivial function slower and another faster; that's the fingerprint of code being relaid-out, not doing more work. What I'd recommend instead of a code change: Making edits to unrelated domain code just to nudge these counts would add churn and risk without fixing anything real. So I'm not committing a change. Instead you can safely acknowledge these on CodSpeed. If you'd like to make these micro-benchmarks less noisy going forward, the durable fix is to give the tiny domain benchmarks more work per iteration (e.g. iterate over a small batch of inputs inside If you believe one of these paths is genuinely on the gallery code path and I've missed a link, point me at it and I'll dig in further. Summary
Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot. |
Summary
Implements MAT-134 (Lot 2): a supported gallery URL pasted into the Link Grabber now resolves into one selectable, downloadable row per image.
handle_resolve_linksgains a gallery branch for crawler plugins: whenextract_linksanswers with akind: "gallery"payload, the gallery URL expands 1→N, mirroring the existing hoster expansion. The branch is gated oncategory == Crawler && !is_media_url(url)so yt-dlp-backed crawlers (YouTube, Vimeo, SoundCloud) keep the cheap probe path and never shell out per pasted URL.Changes
application/commands/resolve_links_gallery.rs(new): parses the plugin's gallery JSON and builds per-imageResolvedLinkDtorows — gallery order preserved, plugin filenames kept (URL basename as fallback),mediaType: "image",isMedia: falseso no yt-dlp dialog,requiresOnlineProbe: falsesince the provider API already vouched for the URLsNoFileerror row. A non-gallery payload falls through to the generic HEAD proberesolve_links.rs: crawler gate wiring; gallery rows go throughpush_bounded_resultso theMAX_URLScap holdstypes.ts:mediaTypeunion gains"image"download_startcommand pathTesting
resolve_links_gallery_tests.rs: order/names/types, empty gallery, partially invalid gallery, extraction failure, non-gallery fallthrough, media-host crawlers never callextract_linksGalleryLinks.test.tsx: rows render in gallery order without a media button, Start Selected invokesdownload_startper selected image, a per-item error row doesn't block the valid imagescargo clippy --workspace -- -D warningsclean, 1690 backend tests pass,npx oxlint .clean, 728 frontend tests passCompanion PR on the plugin repo declares the Imgur/Flickr config keys (R-01): mpiton/vortex-mod-gallery#4
MAT-134
Summary by cubic
Pasting a supported gallery URL now expands into one selectable row per image in Link Grabber. Order and filenames are preserved, per-item failures show as error rows, and the expansion is hardened with strict validation and limits.
New Features
kind: "gallery", one URL becomes N image rows (mediaType: "image",isMedia: false,requiresOnlineProbe: false).!is_media_url) soyt-dlp-backed hosts (YouTube, Vimeo, SoundCloud) keep the cheap probe path; non-gallery payloads fall back to the generic probe.NoFileerror; invalid items produce named error rows without dropping valid images. Frontend adds"image"tomediaType; downloads still start via existing Tauri commands.Bug Fixes
extract_linksJSON now yields a plugin error row instead of probing the gallery page.url(http/https, host required, scheme case-insensitive).Written for commit 967ab66. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes