janwebdev/symfony-social-video-bundle
最新稳定版本:1.0.0
Composer 安装命令:
composer require janwebdev/symfony-social-video-bundle
包简介
Symfony bundle for posting short videos (Reels/Shorts) to YouTube, Instagram, Facebook, X/Twitter, Threads, and TikTok
README 文档
README
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:
VideoMessageBuilderfor 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 +
#Shortsin 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_videopermission - Account: Facebook Pages only (not personal profiles)
- Upload: Local binary or public URL
- Max duration: 60 seconds
- Credential setup: Same Facebook app, add
publish_videopermission
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.publishscope 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
- symfony-social-post-bundle — text/image posting to the same platforms
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 10
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-03-21