feat: social video uploads + hero page video + TikTok content

Hero page:
- Replace GIF with squaremcp-hero-loop.mp4 (autoplay, muted, loop)
- Update styles, scripts, tests, Dockerfile, baselines
- Deployed and verified

Social video uploads:
- Twitter/X: uploadVideoAndTweet via v1.1 media/upload + v2 tweets
- Facebook: createVideoPost via Graph API /{pageId}/videos
- Instagram: createReel via Graph API (container → poll → publish)
- TikTok: REST endpoints + OpenAPI schema for video upload

Marketing:
- TikTok content prompts, scripts, and posting schedule

Note: Remotion not mentioned in any user-facing content
This commit is contained in:
Garfield
2026-05-11 13:55:58 -04:00
parent de9d74bb2b
commit ecdf332b78
17 changed files with 854 additions and 54 deletions

View File

@@ -7,11 +7,11 @@ import { sendMessage, sendTemplate, getMessageStatus, listTemplates } from './cl
import { getProfile as getLinkedInProfile, createPost as createLinkedInPost, createVideoPost as createLinkedInVideoPost, searchConnections, sendMessage as sendLinkedInMessage } from './clients/linkedin.js';
import { getMe as getTelegramMe, sendMessage as sendTelegramMessage, sendPhoto as sendTelegramPhoto, getUpdates as getTelegramUpdates, getChat as getTelegramChat } from './clients/telegram.js';
import { getMe as getDiscordMe, getGuilds, getChannels, sendMessage as sendDiscordMessage, getMessages as getDiscordMessages } from './clients/discord.js';
import { getProfile as getInstagramProfile, getMedia as getInstagramMedia, createPost as createInstagramPost } from './clients/instagram.js';
import { searchTweets, getUserProfile, getUserTweets, createTweet } from './clients/twitter.js';
import { getProfile as getInstagramProfile, getMedia as getInstagramMedia, createImagePost as createInstagramPost, createReel as createInstagramReel } from './clients/instagram.js';
import { searchTweets, getUserProfile, getUserTweets, createTweet, uploadVideoAndTweet } from './clients/twitter.js';
import { getUserProfile as getTikTokProfile, getUserVideos, createVideo, getVideoStatus } from './clients/tiktok.js';
import { getMe as getSnapchatMe, createSnap, getAdAccounts } from './clients/snapchat.js';
import { getPage, getPosts, createPost as createFacebookPost, createPhotoPost } from './clients/facebook.js';
import { getPage, getPosts, createPost as createFacebookPost, createPhotoPost, createVideoPost as createFacebookVideoPost } from './clients/facebook.js';
const ACCOUNT_PARAM = {
account: {
@@ -468,7 +468,7 @@ export const tools: Tool[] = [
{
name: 'instagram_create_post',
description:
'Create a post on Instagram. [REQUIRES BUSINESS ACCOUNT] Only works with Instagram Business/Creator accounts connected to a Facebook Page.',
'Create an image post on Instagram. [REQUIRES BUSINESS ACCOUNT] Only works with Instagram Business/Creator accounts connected to a Facebook Page.',
inputSchema: {
type: 'object',
required: ['image_url'],
@@ -479,6 +479,20 @@ export const tools: Tool[] = [
},
},
},
{
name: 'instagram_create_reel',
description:
'Upload a video as an Instagram Reel. [REQUIRES BUSINESS ACCOUNT] Only works with Instagram Business/Creator accounts connected to a Facebook Page.',
inputSchema: {
type: 'object',
required: ['video_url'],
properties: {
video_url: { type: 'string', description: 'Publicly accessible URL of the MP4 video to post as a Reel' },
caption: { type: 'string', description: 'Reel caption text' },
account: { type: 'string', description: 'Which Instagram account to use (default: "default")' },
},
},
},
// ── Twitter/X tools ──────────────────────────────────────────
{
@@ -525,7 +539,7 @@ export const tools: Tool[] = [
{
name: 'twitter_create_tweet',
description:
'Post a tweet on Twitter/X. [REQUIRES PAID TIER] The free API tier is read-only. Upgrade required to post.',
'Post a text tweet on Twitter/X. [REQUIRES PAID TIER] The free API tier is read-only. Upgrade required to post.',
inputSchema: {
type: 'object',
required: ['text'],
@@ -535,6 +549,20 @@ export const tools: Tool[] = [
},
},
},
{
name: 'twitter_upload_video',
description:
'Upload a video and post it as a tweet on Twitter/X. Downloads the video, uploads via Twitter media API, then publishes the tweet. [REQUIRES PAID TIER] The free API tier is read-only. Upgrade required to post.',
inputSchema: {
type: 'object',
required: ['video_url', 'text'],
properties: {
video_url: { type: 'string', description: 'Publicly accessible URL of the MP4 video to post' },
text: { type: 'string', description: 'Tweet text content' },
account: { type: 'string', description: 'Which Twitter account to use (default: "default")' },
},
},
},
// ── TikTok tools ─────────────────────────────────────────────
{
@@ -679,6 +707,20 @@ export const tools: Tool[] = [
},
},
},
{
name: 'facebook_create_video_post',
description:
'Publish a video to a Facebook Page using a publicly accessible video URL. Creates a video post with optional description.',
inputSchema: {
type: 'object',
required: ['video_url'],
properties: {
video_url: { type: 'string', description: 'Publicly accessible URL of the video to post' },
description: { type: 'string', description: 'Post description text' },
account: { type: 'string', description: 'Which Facebook account to use (default: "default")' },
},
},
},
];
function acct(args: Record<string, unknown>): Account {
@@ -922,6 +964,14 @@ export async function handleToolCall(
}, customer);
break;
case 'instagram_create_reel':
result = await createInstagramReel({
video_url: args.video_url as string,
caption: args.caption as string | undefined,
account: args.account as string | undefined,
}, customer);
break;
// ── Twitter/X ───────────────────────────────────────────────
case 'twitter_search_tweets':
result = await searchTweets({
@@ -953,6 +1003,14 @@ export async function handleToolCall(
}, customer);
break;
case 'twitter_upload_video':
result = await uploadVideoAndTweet({
videoUrl: args.video_url as string,
text: args.text as string,
account: args.account as string | undefined,
}, customer);
break;
// ── TikTok ─────────────────────────────────────────────────
case 'tiktok_get_profile':
result = await getTikTokProfile({
@@ -1035,6 +1093,14 @@ export async function handleToolCall(
}, customer);
break;
case 'facebook_create_video_post':
result = await createFacebookVideoPost({
video_url: args.video_url as string,
description: args.description as string | undefined,
account: args.account as string | undefined,
}, customer);
break;
// Legacy Yahoo-prefixed names — keep working for any cached Claude sessions
case 'yahoo_get_profile':
result = await getProfile('yahoo');