YouTube Metadata & Partial Retry
Two publishing bugs that show up together when a post targets Facebook, Instagram and YouTube:
- YouTube videos created through the API key landed as "Untitled Video" with no tags.
- After one platform failed, fixing the post and clicking Post again re-published to every platform — duplicating the posts that had already succeeded.
1. YouTube metadata fallbacks
Why it happened
packages/db/server/services/plugins/youtube.plugin.ts built the upload with:
title: settings?.title || postDetails.title || 'Untitled Video',
tags: settings?.tags || [],The API-key endpoint never sent platformSettings, and postDetails.title is empty for that flow. Only the web modal enforced a title, so API posts silently became "Untitled Video".
How it works now
packages/db/server/utils/youtube-metadata.ts owns the fallbacks:
| Helper | Rule |
|---|---|
resolveTitle(explicit, fallback, content) | Explicit title wins (trimmed, ≤100 chars). Otherwise the first meaningful content line, with URLs, @handles and #hashtags stripped. 'Untitled Video' only when there is no content at all. |
resolveTags(explicit, content, title) | Explicit tags win (array or comma-separated, de-duped, # stripped). Otherwise #hashtags first, then significant words (≥4 chars, stopwords removed), lowercased and de-duped. Max 5 tags, 30 chars each, 500 chars total. |
resolveDescription(content) | Clamped to 5000 chars. |
The plugin calls them at upload time, so the fallback applies to the dashboard, the API key, scheduled posts and retries alike. The web modal still requires an explicit YouTube title — the fallback is for callers that cannot provide one.
Providing values through the API
POST /api/v1/cli/post now accepts platformSettings, passed straight into the post:
{
"content": "Historic night at the Nou Camp...",
"platforms": ["facebook", "instagram", "youtube"],
"media": { "video": "https://example.com/clip.mp4" },
"platformSettings": {
"youtube": {
"title": "Historic night at the Nou Camp",
"tags": ["ligamx", "futbol"],
"privacyStatus": "public"
}
}
}Omit title/tags and they are derived from content.
2. Retrying only the failed platform
Why duplicates happened
postService.update()deleted allplatform_postsrows and recreated them aspendingwhenevertargetPlatformswas sent (the UI always sends it). The record of which platforms had already published was erased.AutoPostService.triggerSocialMediaPost()iterated over every row, so the next trigger published to all of them again.
How it works now
syncPlatformPostsAfterUpdate()(inpost.service.ts) preserves rows whose status ispublishedfor accounts still targeted. Removed accounts and non-published rows are deleted; only accounts without a surviving row are inserted aspending. Editing therefore resets exactly the failed platform.triggerSocialMediaPost()skips any row whose status is notpending. This is the universal guard, so the cron, POST, PUT, CLI and MCPpublish-nowpaths can no longer republish a live post.postService.recomputeStatusFromPlatforms()derives the post-level status from all rows: anyfailed→failed; else anypublished→published; elsepending. Only writes when the value changes, sopublishedAtis stable. This replaces last-writer-wins, which could hide a partial failure behindpublished.
The resulting flow
- Post to FB + IG + YT → FB and IG succeed, YT fails.
- Edit the caption and click Post.
update()keeps the FB/IG rowspublishedand recreates the YT row aspending.- The trigger skips FB/IG and uploads only YT — now with a derived title and tags.
- Post-level status becomes
publishedonce every row is published.
Files touched
packages/db/server/utils/youtube-metadata.ts(new)packages/db/server/services/plugins/youtube.plugin.tspackages/scheduler/server/api/v1/cli/post.post.tspackages/db/server/services/post.service.tspackages/db/server/services/post-batch.service.tspackages/scheduler/server/services/AutoPost.service.tspackages/scheduler/server/api/v1/posts/index.post.tspackages/scheduler/server/api/v1/posts/[id]/index.put.ts
How to verify
- API key, no
platformSettings: YouTube title is the first content line and tags are 3–5 derived terms. - API key with
platformSettings.youtube.title/tags: those values win. - Partial failure: after an edit + Post, the successful platforms'
publishedAtandpublishDetailmust be unchanged, and only the failed row hits the network.