feat: process GutenbergKit media uploads per the app's media settings - #23142
Draft
dcalhoun wants to merge 10 commits into
Draft
feat: process GutenbergKit media uploads per the app's media settings#23142dcalhoun wants to merge 10 commits into
dcalhoun wants to merge 10 commits into
Conversation
Consumes the snapshot build of wordpress-mobile/GutenbergKit#357, which adds the MediaUploadDelegate API for host-side media upload processing. To be swapped to a tagged release before merge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds video optimization and strip-image-location accessors to AppPrefsWrapper, and a stripImageLocation passthrough to MediaUtilsWrapper, so the upcoming GutenbergKit media upload processor can read settings and strip GPS EXIF through injectable, testable wrappers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements GutenbergKit's MediaUploadDelegate to process device media picked in the experimental block editor before upload, honoring the app's media settings the same way the legacy editor pipeline does: - Images are optimized per the max size/quality settings via WPMediaUtils.getOptimizedMedia, with GPS EXIF stripped when the strip-location setting is on, and the reported mime type/extension corrected to the actual output format (non-PNG inputs, including HEIC, re-encode to JPEG). - When processing would be a no-op, the original file passes through untouched, avoiding a needless lossy re-encode. - Sideways-captured images are rotated for self-hosted sites when optimization is off (WP.com rotates server-side; issue #5737). - GIFs always pass through to preserve animation. - Videos enforce the free-plan 5-minute duration limit and transcode via WPVideoUtils/m4m only when the optimize-video setting is on, keeping the transcoded file only when smaller than the original. Transcodes are serialized to bound codec/memory pressure. - File types disallowed by the site plan are rejected with a localized message relayed to the editor as a notice. Nothing wires the processor yet; that lands separately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds JVM unit tests for the processor's decision table: optimized image output with corrected mime/extension (incl. HEIC to JPEG and PNG passthrough), no-op short-circuit, GPS stripping onto the optimized output and onto a copy when optimization is off, GIF passthrough, self-hosted orientation fix, plan-disallowed type and over-limit video rejections with localized messages, video passthrough when optimization is disabled, and same-path optimization results treated as unprocessed. Also adds a File-based isProhibitedVideoDuration overload to MediaUtilsWrapper so the processor avoids Uri.fromFile, keeping it testable on the JVM. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sets the media upload delegate on GutenbergView so device media picked in the experimental block editor is processed per the app's media settings before upload. The fragment stores and forwards the delegate following the existing setNetworkRequestListener pattern (GutenbergView tolerates assignment before or after page load), and the activity constructs the processor with its SiteModel and injected wrappers. If GutenbergKit's upload server fails to start, uploads degrade to the existing WebView path unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consumes the PR-build snapshot of WordPress-Utils-Android#156, which stops ImageUtils.getImageOrientation from logging a spurious "Volume data not found" error on every optimized upload staged in the app cache dir (GutenbergKit native media uploads). To be swapped to a tagged release once that PR merges. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
Generated by 🚫 Danger |
Contributor
Project dependencies changeslist! Upgraded Dependencies
org.wordpress.gutenbergkit:android:357-45219181e3aa60b5ce3119367758d90e6b6beb0b, (changed from v0.17.2)
org.wordpress:utils:156-2e542df55715dff22c21def058bea551ee9569d0, (changed from 3.14.0)tree +--- project :libs:editor
-| \--- org.wordpress.gutenbergkit:android:v0.17.2
+| \--- org.wordpress.gutenbergkit:android:357-45219181e3aa60b5ce3119367758d90e6b6beb0b
+--- project :libs:fluxc
-| \--- org.wordpress:utils:3.14.0
-| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10 -> 1.9.24 (*)
-| +--- org.apache.commons:commons-text:1.10.0 -> 1.15.0
-| | \--- org.apache.commons:commons-lang3:3.20.0
-| +--- com.android.volley:volley:1.2.0 -> 1.2.1
-| +--- com.google.android.material:material:1.2.1 -> 1.14.0 (*)
-| +--- androidx.swiperefreshlayout:swiperefreshlayout:1.1.0 -> 1.2.0 (*)
-| +--- androidx.recyclerview:recyclerview:1.0.0 -> 1.3.2 (*)
-| +--- org.greenrobot:eventbus:3.3.1 (*)
-| \--- androidx.core:core-ktx:1.5.0 -> 1.16.0 (*)
+| \--- org.wordpress:utils:156-2e542df55715dff22c21def058bea551ee9569d0
+| +--- org.apache.commons:commons-text:1.10.0 -> 1.15.0
+| | \--- org.apache.commons:commons-lang3:3.20.0
+| +--- com.google.android.material:material:1.2.1 -> 1.14.0 (*)
+| +--- androidx.swiperefreshlayout:swiperefreshlayout:1.1.0 -> 1.2.0 (*)
+| +--- androidx.recyclerview:recyclerview:1.0.0 -> 1.3.2 (*)
+| +--- org.greenrobot:eventbus:3.3.1 (*)
+| +--- org.greenrobot:eventbus-java:3.3.1
+| +--- androidx.core:core:1.5.0 -> 1.16.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.4.10 (*)
-+--- org.wordpress:utils:{strictly 3.14.0} -> 3.14.0 (*)
++--- org.wordpress:utils:{strictly 156-2e542df55715dff22c21def058bea551ee9569d0} -> 156-2e542df55715dff22c21def058bea551ee9569d0 (*)
-\--- org.wordpress.gutenbergkit:android:v0.17.2 (*)
+\--- org.wordpress.gutenbergkit:android:357-45219181e3aa60b5ce3119367758d90e6b6beb0b (*) |
Contributor
|
|
Contributor
|
|
Contributor
🤖 Build Failure AnalysisThis build has failures. Claude has analyzed them - check the build annotations for details. |
processVideo and processImage are guard-clause decision tables where early returns read clearer than nesting; suppress ReturnCount to match the existing house style rather than fragment the logic. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## trunk #23142 +/- ##
=======================================
Coverage 37.81% 37.81%
=======================================
Files 2343 2344 +1
Lines 127397 127488 +91
Branches 17681 17704 +23
=======================================
+ Hits 48170 48209 +39
- Misses 75271 75317 +46
- Partials 3956 3962 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
EXIF_MIME_TYPES gated the copy-and-strip branch on formats that can
carry GPS, but androidx ExifInterface.saveAttributes() can only rewrite
JPEG, PNG, and WebP. The set omitted PNG (so location-bearing PNGs
uploaded un-stripped, a regression vs. the legacy pipeline) and included
HEIC/HEIF (where saveAttributes throws an IOException that stripLocation
swallows, uploading a still-geotagged copy while appearing to honor the
setting).
Correct the set to {JPEG, PNG, WebP} and cover the PNG-stripped and
HEIC-passthrough cases in the decision-table tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
transcodeVideo logs each caught exception via .message, so Detekt's SwallowedException never fires — only TooGenericExceptionCaught does (NullPointerException and Exception are both on its generic-names list). Trim the suppression to the rule that actually triggers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GutenbergKit validates uploads in the WebView against the site's allowedMimeTypes (fetched from /wp-block-editor/v1/settings and cached on disk) before the request reaches this delegate, so it rejects most disallowed types with its own localized message first. Document that this app-side check is a fallback for the cache-miss/undefined-settings path and can over-reject when its static MimeTypes table is stricter than the server's cached list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Description
Ref CMM-1249.
Device media picked in the GutenbergKit editor (the new, experimental block editor / NBE) currently uploads raw from the WebView straight to the WordPress REST API, bypassing the app's media settings that the legacy editor honors (image optimization/resizing, quality, EXIF location stripping, video optimization).
This PR integrates GutenbergKit's new
MediaUploadDelegate(from GutenbergKit#357) so device uploads are processed natively per the app's media settings before upload, mirroring WordPress-iOS#25824. GutenbergKit runs a localhost relay server while the editor is open, hands each staged file toprocessFile, uploads via its default uploader, and relays WordPress's raw response to the editor verbatim — so attachment objects,media_details.sizes, blob-preview replacement, save-locking and error notices all behave exactly like a direct upload.What
GBKMediaUploadProcessor.processFiledoes (mirrors the iOS decision table, adapted to Android's pipeline)WPMediaUtils.getOptimizedMedia(max dimension + quality from App Settings), with GPS EXIF stripped when the "Remove location" setting is on. The reported mime type/filename is corrected to the actual output format (non-PNG inputs, including HEIC, re-encode to JPEG). When processing would be a no-op (optimization off, no strip, no rotation), the original passes through untouched — no needless lossy re-encode.WPVideoUtils/m4m path) only when the "Optimize videos" setting is on, keeping the transcoded file only when it's smaller than the original. Transcodes are serialized to bound codec/memory pressure. This matches Android's legacy behavior (where video optimization is opt-in), rather than iOS's always-transcode.The delegate is set unconditionally for the post/page GutenbergKit editor. If GutenbergKit's upload server fails to start, uploads degrade to the existing WebView path unchanged.
Testing instructions
All in the GutenbergKit editor (enable the experimental block editor for the site). Change settings between runs in App Settings → Media.
Image optimization:
Location stripping:
3. Insert a JPEG, PNG, or WebP photo with GPS EXIF, with "Remove location" on (try both with optimization on and off).
GIF:
4. Insert an animated GIF.
Video:
5. With "Optimize videos" on, insert a video wider than the width setting.
Disallowed type: