X Server
The X Server is a Node.js automation server that handles platform-specific publishing via Playwright browser automation, API integrations, video processing, and AI-powered features.
Repository Location
The X Server source code is located in the x repository: AmericanMedia/x
Overview
Why X Server?
Many platforms don't have official APIs for all needed operations (especially livestream creation). The X Server uses Playwright to automate browser interactions and integrates with APIs where available:
- Livestream Creation — Set up streams on platforms without APIs
- Video Uploads — Upload with full metadata control
- Stream Key Retrieval — Get RTMP credentials programmatically
- Video Processing — FFmpeg-based video editing and conversion
- AI Analysis — OpenAI/LangChain integration for content analysis
- CDN Upload — Direct upload to Bunny CDN storage
Technology Stack
| Technology | Version | Purpose |
|---|---|---|
| Node.js | 20+ | Runtime |
| Express | 4.x | HTTP Server |
| Playwright | 1.57+ | Browser automation |
| FFmpeg | 5.x | Video processing |
| OpenAI | 4.x | AI integrations |
| LangChain | 0.3.x | AI orchestration |
| Axios | 1.x | HTTP client |
Configuration
Set the X Server URL in your environment:
X_SERVER_URL=http://your-x-server:3000Supported Endpoints
Livestream Endpoints
| Endpoint | Platform | Description |
|---|---|---|
/rumble-create | Rumble | Create livestream, get RTMP |
/rumble-delete | Rumble | Delete livestream |
/youtube-create | YouTube | Create YouTube Live |
/youtube-delete | YouTube | Delete YouTube Live |
/boxcast-livestream | Boxcast | Create Boxcast broadcast |
/boxcast-delete | Boxcast | Delete Boxcast broadcast |
/brighteon-create | Brighteon | Create Brighteon stream |
/odysee-create | Odysee | Create Odysee stream |
/restream-create | Restream | Create Restream event |
/banned-create | Banned.Video | Create Banned.Video stream |
Upload Endpoints
| Endpoint | Platform | Description |
|---|---|---|
/rumble-episode | Rumble | Upload video to Rumble |
/rumble-latest-episode | Rumble | Scrape latest episode info |
/rumble-latest-episodes | Rumble | Scrape multiple episodes |
/boxcast-media-upload | Boxcast | Upload media file |
/boxcast-create | Boxcast | Create broadcast |
/brighteon-upload | Brighteon | Upload video |
/brighteon-status | Brighteon | Check upload status |
/odysee-upload | Odysee | Upload video |
/odysee-status | Odysee | Check upload status |
/banned-status | Banned.Video | Check upload status |
/bitchute-create | Bitchute | Create Bitchute content |
/bitchute-upload | Bitchute | Upload video |
/bitchute-status | Bitchute | Check upload status |
/transistor-upload | Transistor | Upload podcast episode |
/transistor-transcript | Transistor | Get podcast transcripts |
/substack-create | Substack | Create newsletter post |
/substack-upload | Substack | Upload to Substack |
/substack-export | Substack | Export Substack content |
CDN & Storage Endpoints
| Endpoint | Service | Description |
|---|---|---|
/bunny-storage-upload | Bunny CDN | Upload single file to storage |
/bunny-storage-upload-multiple | Bunny CDN | Upload multiple files |
/bunny-stream-upload | Bunny CDN | Upload to streaming library |
/bunny-create-folder | Bunny CDN | Create storage folder |
Video Processing Endpoints
| Endpoint | Description |
|---|---|
/video-editor/export | Export edited video with segments |
/video-editor/status/:videoId | Check export status |
/video-editor/transcribe | Transcribe video using Deepgram |
/clips/youtube-download | Download YouTube video for clips |
/descript-upload | Upload to Descript |
/descript-create-project | Create Descript project |
/descript-status | Check Descript status |
Social & Integration Endpoints
| Endpoint | Service | Description |
|---|---|---|
/ayrshare-create | Ayrshare | Create social post |
/ayrshare-delete | Ayrshare | Delete social post |
/fb-store-token | Store Facebook auth token | |
/shortlink | Short.io | Create short links |
/telegram | Telegram | Send Telegram messages |
Utility Endpoints
| Endpoint | Description |
|---|---|
/status | Server health check |
/webhook | Git pull and restart webhook |
/nocodb/* | NocoDB database proxy |
/n8n/* | n8n workflow triggers |
/runpod/* | RunPod GPU operations |
/cloudflare-trace | Cloudflare trace lookup |
Request/Response Format
Livestream Request
POST /rumble-create
{
"title": "Episode 42: The Future",
"description": "Join us for an exciting discussion...",
"scheduledAt": "2026-02-10T14:00:00.000Z",
"thumbnailUrl": "https://example.com/thumb.jpg",
"visibility": "public"
}Livestream Response
{
"success": true,
"platformId": "v12345",
"platformUrl": "https://rumble.com/v12345-episode-42.html",
"streamUrl": "rtmp://live.rumble.com/live",
"streamKey": "abc123xyz"
}Upload Request
POST /rumble-episode
{
"title": "Episode 42: The Future",
"description": "Full episode description...",
"videoUrl": "https://cdn.example.com/video.mp4",
"thumbnailUrl": "https://example.com/thumb.jpg",
"tags": "podcast,tech,ai",
"visibility": "public"
}Upload Response
{
"success": true,
"platformId": "v67890",
"platformUrl": "https://rumble.com/v67890-episode-42.html"
}Video Editor Export Request
POST /video-editor/export
{
"videoId": "abc123",
"files": [
{
"url": "https://cdn.example.com/source.mp4",
"keepSegments": [[0, 10.5], [15.2, 30.0], [45.0, 60.0]]
}
]
}Video Editor Status Response
GET /video-editor/status/abc123
{
"status": "completed",
"progress": 100,
"outputUrl": "https://cdn.example.com/output.mp4"
}Project Structure
x/
├── server.js # Main Express server
├── routes/ # Route handlers
│ ├── index.js # Route registration
│ ├── rumble.js # Rumble endpoints
│ ├── youtube.js # YouTube endpoints
│ ├── boxcast.js # Boxcast endpoints
│ ├── brighteon.js # Brighteon endpoints
│ ├── odysee.js # Odysee endpoints
│ ├── transistor.js # Transistor endpoints
│ ├── substack.js # Substack endpoints
│ ├── bunny.js # Bunny CDN endpoints
│ ├── video-editor.js # Video editing endpoints
│ ├── clips.js # Clip creation endpoints
│ ├── ayrshare.js # Social media endpoints
│ └── ... # Additional platform routes
├── helpers/ # Business logic
│ ├── rumble/ # Rumble automation
│ ├── youtube/ # YouTube automation
│ ├── boxcast/ # Boxcast integration
│ ├── brighteon/ # Brighteon automation
│ ├── odysee/ # Odysee automation
│ ├── substack/ # Substack automation
│ ├── transistor/ # Transistor API
│ ├── bunny/ # Bunny CDN client
│ ├── video-editor/ # FFmpeg processing
│ ├── openai/ # AI integrations
│ ├── storage/ # File storage helpers
│ ├── sessions/ # Browser sessions
│ ├── loggers/ # Logging utilities
│ └── ... # Additional helpers
├── scripts/ # Standalone scripts
├── public/ # Static assets
└── .auth/ # Browser auth state (gitignored)Running the Server
Development Mode
# Using npm script
npm run dev
# Or directly
./dev-start.shProduction Mode
# With Playwright browsers
npm run prod
# Or directly
./start-playwright.shDocker Deployment
docker build -t x-server .
docker run -d -p 3000:3000 --name x-server x-serverEnvironment Variables
| Variable | Required | Description |
|---|---|---|
PORT | No | Server port (default: 3000) |
ENV | No | Environment mode (development/production) |
BUNNY_MEDIAMAGIC_API_KEY | Yes | Bunny CDN API key |
DEEPGRAM_API_KEY | Yes | Deepgram transcription key |
OPENAI_API_KEY | Yes | OpenAI API key |
AYRSHARE_API_KEY | Yes | Ayrshare social API key |
Bridge Integration
The Bridge forwards requests to X Server:
// bridge/helpers/xserver/client.js
import axios from 'axios';
const client = axios.create({
baseURL: process.env.X_SERVER_URL,
timeout: 300000, // 5 min for uploads
});
export async function createLivestream(platform, data) {
const endpoint = PLATFORM_ROUTES[platform].livestream;
const response = await client.post(endpoint, data);
return response.data;
}
export async function uploadContent(platform, data) {
const endpoint = PLATFORM_ROUTES[platform].upload;
const response = await client.post(endpoint, data);
return response.data;
}Platform Credentials
The X Server stores platform credentials internally in the .auth/ directory (gitignored):
x/
├── .auth/ # Browser authentication state
│ ├── rumble/ # Rumble session cookies
│ ├── youtube/ # YouTube auth tokens
│ └── ... # Other platform sessions
├── .env # Environment variables (gitignored)
└── .facebook-auth/ # Facebook-specific authBrowser Session Management
Playwright sessions are persisted to avoid re-authentication:
// helpers/sessions/getSession.js
import { chromium } from 'playwright';
export async function getSession(platform) {
const userDataDir = `.auth/${platform}`;
const browser = await chromium.launchPersistentContext(userDataDir, {
headless: process.env.NODE_ENV === 'production'
});
return browser;
}Error Handling
X Server errors are captured and stored in EspoCRM:
{
"success": false,
"error": "Authentication failed",
"code": "AUTH_ERROR",
"details": "Session expired, re-login required"
}The Bridge updates the PlatformPublish record:
await espoClient.update('PlatformPublish', id, {
status: 'Failed',
apiResponse: JSON.stringify(error)
});Retry Logic
When X Server fails:
- Check
apiResponsefield in EspoCRM for error details - Resolve the issue (re-auth, fix data, etc.)
- Set status back to "Queued" to retry
Health Check
curl http://your-x-server:3000/statusExpected response:
{
"ok": true,
"environment": "Digital Ocean",
"hostname": "x-server",
"user": "root",
"port": 3000,
"mode": "production"
}Deployment Options
Local Development
cd x
npm install
npm run devDigital Ocean Droplet
The server can be deployed to a Digital Ocean droplet and accessed via ngrok or direct IP.
RunPod GPU
For GPU-intensive operations (video processing), the server can run on RunPod.
NPM Scripts
| Script | Description |
|---|---|
npm run dev | Start in development mode with nodemon |
npm run prod | Start in production mode with Playwright |
npm run stop | Stop the server |
npm run status | Check if server is running |
npm run reset-auth | Reset authentication sessions |
npm run kill | Force kill server and ngrok |
npm run brighteon-upload | Run standalone Brighteon upload |
Security Considerations
Credentials
X Server stores platform passwords/cookies. Ensure it's properly secured:
- Run on internal network only or behind VPN
- Use environment variables for sensitive data
- Regular credential rotation
- Audit logging via
helpers/loggers/ .auth/directory is gitignored