fix(tiktok): resize oversized photos before PULL_FROM_URL - #120
Merged
Merged
Conversation
added 2 commits
June 26, 2026 12:23
TikTok photo posts hand the platform our media URLs and let it pull the
bytes, so they never went through MediaOptimizer like the upload-based
publishers do. An image wider than 1080px reached TikTok untouched and was
rejected with picture_size_check_failed ("Image dimensions exceed limits").
Photos within spec still pass through unchanged. Oversized ones (or images
with unknown dimensions) are downloaded, resized to TikTok's 1080px spec,
hosted on the public disk, and that URL is handed to TikTok instead. The
derivative is pruned once TikTok has pulled it.
Reuses the same hosted-derivative pattern Instagram/Threads already use for
aspect-ratio cropping; the TikTok max_width config was previously dead code.
Direct unit tests for the new MediaItem::width()/height() accessors and MediaOptimizer::maxWidthForPlatform(), plus drop a redundant inline comment.
4 tasks
added 4 commits
June 26, 2026 12:42
…optimization Adds a test for the resize download-failure branch, and tightens the resize mocks to assert optimization is requested for Platform::TikTok specifically.
…publish The default disk (r2) is configured with throw => true, so Storage::delete re-throws on a failed delete. Running that inside the finally meant a delete failure could discard the publishPhotos return value and surface an already-live TikTok post as a failure (risking a duplicate re-publish). Move cleanup into a pruneDerivatives helper that swallows storage errors, and wrap the resize/host step so decoder/storage failures surface as a categorized TikTokPublishException instead of an uncategorized error.
…se URL - Multi-image carousel: only the oversized photo is resized, order preserved, the compliant one passes through untouched. - Cleanup runs even when publishing fails (no orphaned derivative). - A throwing Storage::delete does not turn a successful publish into a failure. - Replace hardcoded https://open.tiktokapis.com/v2 with config('trypost.platforms.tiktok.api') so the fakes can't drift from the configured (overridable) host.
… files
Convert TikTokCreatorInfoTest and TikTokPublishExceptionTest to fake against
config('trypost.platforms.tiktok.api') instead of the hardcoded host, matching
the TikTokPublisherTest cleanup. TikTokControllerTest is left as-is: its only
TikTok URL is a Socialite authorize stub, which has no config counterpart.
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.
Problem
A production post failed to publish to TikTok with "Image dimensions exceed limits" (
picture_size_check_failed). The image was 1254×1254; TikTok caps photo width at 1080px (confirmed by postiz's own error map: "Picture must not exceed 1080p").Root cause
TikTok photo posts use
source: PULL_FROM_URLwith the raw stored media URLs — TikTok fetches the bytes from us, so we never hold them and the photos never went throughMediaOptimizerlike every other image publisher (X, Bluesky, LinkedIn, Pinterest, Mastodon, Discord) does. ThePlatform::TikTok => ['max_width' => 1080]config inMediaOptimizerwas effectively dead code.Fix
For each TikTok photo:
width ≤ 1080) → publish the original URL unchanged (today's behavior, zero overhead);optimizeImage(TikTok)→ host the resized copy on the default disk → hand TikTok that URL. The derivative is pruned in afinallyoncewaitForPublishStatusconfirms TikTok has pulled it.This reuses the exact hosted-derivative pattern Instagram/Threads already use in
CropsImageForAspectRatio(download → process →Storage::put→Storage::url) — just resize instead of crop. The TikTokmax_widthconfig is now actually applied.Changes
TikTokPublisher::publishPhotos— resolve compliant vs oversized, host derivative for oversized, prune after publish.MediaOptimizer::maxWidthForPlatform()— single source of truth for the 1080 cap.MediaItemDTO — carriesmetaand exposeswidth()/height()so dimensions are checked without a download.Tests
social-tiktok-photos/), never the raw URL; derivative is pruned afterward.