Skip to main content

Overview

The PublishingSchedulingAgent manages the complete video publishing workflow to YouTube. It handles scheduling, uploads, metadata optimization, thumbnail uploads, caption uploads, and publishing analytics.

Constructor

db
Database
required
Database instance for publish queue and analytics
credentials
Credentials
required
Credentials manager with YouTube API OAuth access
const { PublishingSchedulingAgent } = require('./agents/publishing-scheduling-agent');

const agent = new PublishingSchedulingAgent(db, credentials);

Properties

youtube
YouTubeAPI
YouTube Data API v3 client
publishQueue
Array
Queue of scheduled and published content
logger
Logger
Logger instance for tracking publishing operations

Methods

initialize()

Initializes the agent, sets up YouTube API, and loads publish queue.
return
Promise<boolean>
Returns true when initialization is complete
await agent.initialize();
// Sets up YouTube Data API v3 with OAuth credentials
// Loads existing publish queue from database

scheduleContent(productionData)

Schedules content for future publishing.
productionData
Object
required
Production data from ProductionManagementAgent
productionData.id
string
required
Production ID
productionData.script
Object
required
Video script with title
productionData.scheduledPublishTime
string
required
ISO timestamp for publishing
productionData.priority
number
required
Priority score
productionData.seo
Object
required
SEO metadata
productionData.assets
Object
required
All production assets
return
Promise<Object>
Schedule entry object
const scheduleEntry = await agent.scheduleContent(productionData);

console.log(scheduleEntry);
// {
//   productionId: 'prod_123...',
//   title: 'JavaScript Tutorial',
//   publishTime: '2026-03-10T14:00:00.000Z',
//   status: 'scheduled',
//   priority: 75,
//   metadata: {
//     seo: { title: '...', description: '...', tags: [...] },
//     thumbnail: { path: '...' },
//     video: { path: '...' },
//     captions: { path: '...' }
//   },
//   createdAt: '2026-03-05T10:00:00.000Z'
// }

publishContent(contentId)

Publishes content to YouTube immediately.
contentId
string
required
Production ID or schedule entry ID
return
Promise<Object>
Updated schedule entry with YouTube ID and URL
entry.status
string
Updated to ‘published’
entry.publishedAt
string
ISO timestamp of actual publish time
entry.youtubeId
string
YouTube video ID
entry.youtubeUrl
string
Full YouTube video URL
const published = await agent.publishContent('prod_123...');

console.log('Published:', published.youtubeUrl);
// 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'

console.log('Video ID:', published.youtubeId);
// 'dQw4w9WgXcQ'

uploadToYouTube(scheduleEntry)

Uploads video, thumbnail, and captions to YouTube.
scheduleEntry
Object
required
Schedule entry with metadata and assets
return
Promise<Object>
YouTube API response with video ID
const uploadResult = await agent.uploadToYouTube(scheduleEntry);
// Uploads:
// 1. Video file with metadata (title, description, tags, category)
// 2. Custom thumbnail
// 3. SRT captions
// Returns: { id: 'video_id', ... }

uploadThumbnail(videoId, thumbnailPath)

Uploads custom thumbnail for a video.
videoId
string
required
YouTube video ID
thumbnailPath
string
required
Path to thumbnail file
return
Promise<void>
Completes when upload succeeds
await agent.uploadThumbnail('dQw4w9WgXcQ', '/path/to/thumbnail.jpg');
// Thumbnail must be:
// - 1280x720 resolution
// - Under 2MB
// - JPEG or PNG format

uploadCaptions(videoId, captionsPath)

Uploads SRT captions for a video.
videoId
string
required
YouTube video ID
captionsPath
string
required
Path to SRT caption file
return
Promise<void>
Completes when upload succeeds
await agent.uploadCaptions('dQw4w9WgXcQ', '/path/to/captions.srt');
// Captions uploaded as English, not draft

processPublishQueue()

Processes publish queue and auto-publishes ready content.
return
Promise<number>
Number of videos published
const published = await agent.processPublishQueue();
console.log('Auto-published', published, 'videos');

// Publishes all content where:
// - publishTime <= now
// - status === 'scheduled'
// Handles errors gracefully, marking failed items as 'failed'

getUpcomingSchedule(days)

Gets upcoming scheduled publications.
days
number
default:"7"
Number of days to look ahead
return
Promise<Array<Object>>
Array of upcoming schedule entries, sorted by publish time
const upcoming = await agent.getUpcomingSchedule(7);

console.log('Upcoming publications:');
upcoming.forEach(entry => {
  console.log(`${entry.publishTime}: ${entry.title}`);
});
// 2026-03-10T14:00:00.000Z: JavaScript Tutorial
// 2026-03-12T14:00:00.000Z: Python Guide
// 2026-03-15T15:00:00.000Z: React Hooks Explained

optimizePublishTimes()

Optimizes scheduled publish times based on channel analytics.
return
Promise<void>
Completes when optimization is done
await agent.optimizePublishTimes();
// Analyzes:
// - Channel statistics
// - Historical performance
// - Optimal days (Tuesday, Wednesday, Thursday)
// - Optimal hours (14:00, 15:00, 16:00, 20:00)
// Updates schedule entries with better times

getChannelAnalytics()

Fetches channel analytics from YouTube.
return
Promise<Object>
Channel analytics data
analytics.totalViews
number
Total channel views
analytics.subscribers
number
Current subscriber count
analytics.videos
number
Total video count
analytics.optimalDays
Array<string>
Best days to publish
analytics.optimalHours
Array<number>
Best hours to publish
const analytics = await agent.getChannelAnalytics();
// {
//   totalViews: 150000,
//   subscribers: 5000,
//   videos: 50,
//   optimalDays: ['Tuesday', 'Wednesday', 'Thursday'],
//   optimalHours: [14, 15, 16, 20]
// }

createPublishingReport()

Generates comprehensive publishing report.
return
Promise<Object>
Publishing report with statistics and performance
const report = await agent.createPublishingReport();

console.log(report);
// {
//   queueStatus: {
//     total: 10,
//     scheduled: 5,
//     published: 4,
//     failed: 1
//   },
//   upcomingPublications: [...],
//   recentPublications: [...],
//   performance: {
//     totalPublished: 4,
//     averageScheduleAccuracy: '98.5%',
//     averageDelay: '2.3 minutes',
//     publishingFrequency: '2.5 videos per week'
//   },
//   generatedAt: '2026-03-05T10:00:00.000Z'
// }

emergencyPublish(contentId, delayMinutes)

Publishes content immediately or with short delay.
contentId
string
required
Production ID
delayMinutes
number
default:"0"
Delay in minutes (0 for immediate)
return
Promise<Object>
Published or rescheduled entry
// Publish immediately
const immediate = await agent.emergencyPublish('prod_123...', 0);

// Schedule 30 minutes from now
const delayed = await agent.emergencyPublish('prod_456...', 30);

pauseScheduledContent(contentId)

Pauses scheduled content.
contentId
string
required
Production ID
return
Promise<Object>
Updated entry with status ‘paused’
const paused = await agent.pauseScheduledContent('prod_123...');
console.log('Content paused:', paused.title);

resumeScheduledContent(contentId, newPublishTime)

Resumes paused content.
contentId
string
required
Production ID
newPublishTime
string
New publish time (ISO string). If not provided, uses existing time.
return
Promise<Object>
Updated entry with status ‘scheduled’
// Resume with original time
const resumed = await agent.resumeScheduledContent('prod_123...');

// Resume with new time
const rescheduled = await agent.resumeScheduledContent(
  'prod_123...', 
  '2026-03-15T14:00:00.000Z'
);

Upload Metadata Structure

YouTube video upload includes:
{
  snippet: {
    title: seo.title,
    description: seo.description,
    tags: seo.tags,
    categoryId: seo.metadata.category.toString(),
    defaultLanguage: 'en',
    defaultAudioLanguage: 'en'
  },
  status: {
    privacyStatus: 'public', // or 'private', 'unlisted'
    publishAt: scheduleEntry.publishTime,
    selfDeclaredMadeForKids: false
  }
}

Usage Example

const { PublishingSchedulingAgent } = require('./agents/publishing-scheduling-agent');

const agent = new PublishingSchedulingAgent(db, credentials);
await agent.initialize();

// Schedule content from production
const productionData = await productionAgent.processContent(contentData);
const scheduled = await agent.scheduleContent(productionData);

console.log('Scheduled for:', scheduled.publishTime);

// View upcoming schedule
const upcoming = await agent.getUpcomingSchedule(14);
console.log('Next 14 days:', upcoming.length, 'videos');

// Auto-process queue (run this periodically)
const published = await agent.processPublishQueue();
console.log('Published:', published, 'videos');

// Generate report
const report = await agent.createPublishingReport();
console.log('Publishing accuracy:', report.performance.averageScheduleAccuracy);
console.log('Frequency:', report.performance.publishingFrequency);

// Optimize future publish times
await agent.optimizePublishTimes();

Automated Publishing Workflow

Content is added to publish queue with calculated optimal publish time from strategy.
Run processPublishQueue() on a cron job (e.g., every 5 minutes) to automatically publish content when time arrives.
Periodically run optimizePublishTimes() (e.g., weekly) to adjust scheduled times based on analytics.
Use createPublishingReport() to track accuracy, frequency, and identify issues.

Best Practices

Run processPublishQueue() every 5 minutes to ensure timely publishing. Most content publishes within 5 minutes of scheduled time.
Check for ‘failed’ status items and retry or investigate issues. Common failures: API rate limits, invalid video files, authentication errors.
Default is ‘public’. Use ‘unlisted’ for testing or ‘private’ for scheduled publishing with manual review.
Run optimizePublishTimes() weekly to adapt to audience behavior changes.
Use emergencyPublish() for time-sensitive or trending topic videos that need immediate publication.

Environment Variables

DEFAULT_PRIVACY_STATUS
string
default:"public"
Default privacy status for uploads: public, unlisted, or private

YouTube API Requirements

Requires OAuth 2.0 credentials with YouTube Data API v3 scope: https://www.googleapis.com/auth/youtube.upload
Video uploads cost 1600 quota units. Default quota is 10,000 units per day (6 uploads). Request quota increase for higher volume.
YouTube enforces rate limits on uploads. The agent includes error handling for quota exceeded errors.