janwebdev/symfony-social-video-bundle

Symfony bundle for posting short videos (Reels/Shorts) to YouTube, Instagram, Facebook, X/Twitter, Threads, and TikTok

Maintainers

Package info

github.com/janwebdev/symfony-social-video-bundle

Type:symfony-bundle

pkg:composer/janwebdev/symfony-social-video-bundle

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-03-21 15:21 UTC

This package is auto-updated.

Last update: 2026-03-21 15:22:53 UTC


README

Latest Stable Version Total Downloads License PHP Symfony

Symfony bundle for posting short videos (Reels/Shorts) to social networks.

โœจ Features

  • ๐ŸŽฌ 6 Platforms: YouTube Shorts, Instagram Reels, Facebook Reels, X/Twitter, Threads, TikTok
  • ๐Ÿ“ Flexible Sources: Local files or public URLs (platform-dependent)
  • โšก Async Support: Symfony Messenger integration
  • ๐ŸŽฏ Type Safe: PHP 8.4 readonly properties throughout
  • ๐Ÿ”„ No External SDK: All API clients built-in
  • ๐Ÿ“ Fluent API: VideoMessageBuilder for easy video post creation
  • ๐ŸŽช Event System: Before/After/Failed publish events

๐Ÿ“ฆ Installation

composer require janwebdev/symfony-social-video-bundle

Register the bundle in config/bundles.php:

return [
    // ...
    Janwebdev\SocialVideoBundle\SocialVideoBundle::class => ['all' => true],
];

โš™๏ธ Configuration

Create config/packages/social_video.yaml:

social_video:
  providers:
    youtube:
      enabled: true
      access_token: "%env(YOUTUBE_ACCESS_TOKEN)%"
      privacy_status: "public"          # public | private | unlisted

    instagram:
      enabled: true
      account_id: "%env(INSTAGRAM_ACCOUNT_ID)%"
      access_token: "%env(INSTAGRAM_ACCESS_TOKEN)%"
      graph_version: "v22.0"

    facebook:
      enabled: true
      page_id: "%env(FACEBOOK_PAGE_ID)%"
      access_token: "%env(FACEBOOK_ACCESS_TOKEN)%"
      graph_version: "v22.0"

    twitter:
      enabled: true
      api_key: "%env(TWITTER_API_KEY)%"
      api_secret: "%env(TWITTER_API_SECRET)%"
      access_token: "%env(TWITTER_ACCESS_TOKEN)%"
      access_token_secret: "%env(TWITTER_ACCESS_TOKEN_SECRET)%"

    threads:
      enabled: true
      user_id: "%env(THREADS_USER_ID)%"
      access_token: "%env(THREADS_ACCESS_TOKEN)%"
      # NOTE: Threads API requires a public video URL โ€” local files are not supported.

    tiktok:
      enabled: true
      client_key: "%env(TIKTOK_CLIENT_KEY)%"
      access_token: "%env(TIKTOK_ACCESS_TOKEN)%"
      # NOTE: Requires video.publish scope approval from TikTok. Until approved,
      # all videos are posted as private (SELF_ONLY).

Environment Variables

# YouTube Data API v3
YOUTUBE_ACCESS_TOKEN=ya29.your_oauth_token

# Instagram Graph API (Business/Creator account required)
INSTAGRAM_ACCOUNT_ID=your_ig_business_account_id
INSTAGRAM_ACCESS_TOKEN=your_page_access_token

# Facebook Graph API (Page token with publish_video permission)
FACEBOOK_PAGE_ID=your_page_id
FACEBOOK_ACCESS_TOKEN=your_page_access_token

# X/Twitter API v2 (OAuth 1.0a)
TWITTER_API_KEY=your_api_key
TWITTER_API_SECRET=your_api_secret
TWITTER_ACCESS_TOKEN=your_access_token
TWITTER_ACCESS_TOKEN_SECRET=your_access_token_secret

# Threads API
THREADS_USER_ID=your_threads_user_id
THREADS_ACCESS_TOKEN=your_threads_access_token

# TikTok Content Posting API v2
TIKTOK_CLIENT_KEY=your_client_key
TIKTOK_ACCESS_TOKEN=your_access_token

๐Ÿš€ Usage

Basic Usage

use Janwebdev\SocialVideoBundle\Message\VideoMessageBuilder;
use Janwebdev\SocialVideoBundle\Publisher\VideoPublisher;

class YourService
{
    public function __construct(private VideoPublisher $publisher) {}

    public function postVideo(): void
    {
        $message = VideoMessageBuilder::create()
            ->setVideoPath('/path/to/reel.mp4')          // local file
            // OR: ->setVideoUrl('https://cdn.example.com/reel.mp4')
            ->setTitle('My Amazing Short #Shorts')
            ->setDescription('Check this out!')
            ->addHashtag('reels')
            ->addHashtag('fyp')
            ->setPrivacy('public')
            ->forNetworks(['youtube', 'instagram', 'tiktok'])
            ->build();

        $results = $this->publisher->publish($message);

        foreach ($results as $result) {
            if ($result->isSuccess()) {
                echo "{$result->getProviderName()}: {$result->getPostUrl()}\n";
            } else {
                echo "Failed: {$result->getErrorMessage()}\n";
            }
        }
    }
}

Async Publishing (requires symfony/messenger)

// Dispatch to message queue
$this->publisher->publishAsync($message);

Check Results

$results = $this->publisher->publish($message);

if ($results->isAllSuccessful()) {
    echo "Posted to all networks!\n";
}

$ytResult = $results->getResult('youtube');
if ($ytResult?->isSuccess()) {
    echo "YouTube URL: " . $ytResult->getPostUrl() . "\n";
}

foreach ($results->getFailed() as $result) {
    echo "Failed on {$result->getProviderName()}: {$result->getErrorMessage()}\n";
}

Event Listeners

use Janwebdev\SocialVideoBundle\Publisher\Event\AfterPublishEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class VideoPostSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [AfterPublishEvent::class => 'onAfterPublish'];
    }

    public function onAfterPublish(AfterPublishEvent $event): void
    {
        foreach ($event->results->getSuccessful() as $result) {
            // Log to database, send notifications, etc.
        }
    }
}

๐Ÿ“š Platform Reference

YouTube Shorts

  • Auth: OAuth 2.0 user token (YOUTUBE_ACCESS_TOKEN)
  • Upload: Resumable PUT upload (Google's resumable upload protocol)
  • Shorts: Automatic classification โ€” vertical (9:16) + โ‰ค3 min + #Shorts in title/description
  • Credential setup: Google Cloud Console โ†’ Create Project โ†’ Enable YouTube Data API v3 โ†’ OAuth 2.0 credentials

Instagram Reels

  • Auth: Page Access Token (long-lived)
  • Account: Instagram Business or Creator account required
  • Upload: Local files via rupload.facebook.com OR public video URL
  • Max duration: 90 seconds
  • Required permissions: instagram_basic, instagram_content_publish
  • Credential setup: Facebook Developers โ†’ App โ†’ Instagram product

Facebook Reels

  • Auth: Page Access Token with publish_video permission
  • Account: Facebook Pages only (not personal profiles)
  • Upload: Local binary or public URL
  • Max duration: 60 seconds
  • Credential setup: Same Facebook app, add publish_video permission

X/Twitter

  • Auth: OAuth 1.0a (api_key, api_secret, access_token, access_token_secret)
  • Upload: Chunked INIT/APPEND/FINALIZE (5 MB chunks)
  • Max duration: 140 seconds. Max file: 512 MB
  • Rate limit (Free tier): 17 upload sessions per 24 hours
  • Credential setup: X Developer Portal โ†’ App โ†’ Keys & Tokens

Threads

  • Auth: Threads OAuth 2.0 user token
  • โš ๏ธ URL only: Threads API does not support binary upload. Use setVideoUrl() with a publicly accessible video URL.
  • Max duration: 5 minutes
  • Required permissions: threads_basic, threads_content_publish
  • Credential setup: Facebook Developers โ†’ App โ†’ Threads product

TikTok

  • Auth: OAuth 2.0 Bearer token
  • โš ๏ธ Scope approval required: video.publish scope requires business developer account and TikTok audit (5โ€“10 business days). Until approved, all videos are private (SELF_ONLY).
  • Upload: Local files (10 MB chunked) or public URL
  • Max duration: 5 minutes. Rate limit: 6 init requests/min
  • Credential setup: TikTok for Developers โ†’ App โ†’ Content Posting API โ†’ Apply for video.publish

๐Ÿงช Testing

# Run tests
composer run-tests

# Static analysis (PHPStan level 9)
composer run-static-analysis

# Code style check
composer check-code-style

# Fix code style
composer fix-code-style

๐Ÿ“– Upload Matrix

Platform Local File Public URL
YouTube Shorts โœ… โœ… (download first)
Instagram Reels โœ… (rupload) โœ… (video_url)
Facebook Reels โœ… (rupload) โœ… (file_url)
X/Twitter โœ… โœ… (download first)
Threads โŒ โœ… required
TikTok โœ… (chunked) โœ… (PULL_FROM_URL)

๐Ÿ“„ License

MIT License. See LICENSE file.

๐Ÿ‘ Credits

Built by Yan Rogozinsky as part of the Symfony Social Post Bundle ecosystem.

๐Ÿ”— Related