Documentation Index
Fetch the complete documentation index at: https://mintlify.com/darkzOGx/youtube-automation-agent/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The YouTube Automation Agent can be extended to manage multiple YouTube channels simultaneously, each with its own configuration, credentials, and content strategy.Architecture for Multi-Channel Support
Channel Configuration Structure
Create a multi-channel configuration system:config/channels.json
{
"channels": [
{
"id": "tech-channel",
"name": "Tech Insights Daily",
"enabled": true,
"youtube": {
"channelId": "UC...",
"credentialsPath": "./config/credentials-tech.json",
"tokensPath": "./config/tokens-tech.json"
},
"content": {
"types": ["tutorial", "explainer", "review"],
"postingFrequency": "daily",
"preferredPostTime": "14:00",
"targetAudience": "Tech enthusiasts and developers"
},
"ai": {
"model": "gpt-4-turbo-preview",
"temperature": 0.7,
"tone": "professional and technical"
}
},
{
"id": "lifestyle-channel",
"name": "Daily Life Hacks",
"enabled": true,
"youtube": {
"channelId": "UC...",
"credentialsPath": "./config/credentials-lifestyle.json",
"tokensPath": "./config/tokens-lifestyle.json"
},
"content": {
"types": ["list", "tutorial", "story"],
"postingFrequency": "daily",
"preferredPostTime": "10:00",
"targetAudience": "General audience seeking life improvements"
},
"ai": {
"model": "gpt-4-turbo-preview",
"temperature": 0.8,
"tone": "friendly and conversational"
}
}
]
}
Multi-Channel Manager Implementation
Creating the Channel Manager
utils/channel-manager.js
const fs = require('fs').promises;
const path = require('path');
const { Logger } = require('./logger');
const { CredentialManager } = require('./credential-manager');
const { Database } = require('../database/db');
class ChannelManager {
constructor() {
this.logger = new Logger('ChannelManager');
this.channels = new Map();
this.configPath = path.join(__dirname, '..', 'config', 'channels.json');
}
async initialize() {
try {
this.logger.info('Initializing Multi-Channel Manager...');
// Load channel configurations
const config = await this.loadChannelConfig();
// Initialize each channel
for (const channelConfig of config.channels) {
if (channelConfig.enabled) {
await this.initializeChannel(channelConfig);
}
}
this.logger.success(`Initialized ${this.channels.size} channels`);
return true;
} catch (error) {
this.logger.error('Failed to initialize channel manager:', error);
throw error;
}
}
async loadChannelConfig() {
try {
const data = await fs.readFile(this.configPath, 'utf8');
return JSON.parse(data);
} catch (error) {
this.logger.error('Failed to load channel config:', error);
throw error;
}
}
async initializeChannel(config) {
try {
this.logger.info(`Initializing channel: ${config.name}`);
// Create separate database for channel
const db = new Database();
db.dbPath = path.join(
__dirname, '..', 'data',
`youtube_automation_${config.id}.db`
);
await db.initialize();
// Create credential manager for channel
const credentials = new CredentialManager();
credentials.credentialsPath = config.youtube.credentialsPath;
credentials.tokensPath = config.youtube.tokensPath;
await credentials.initialize();
// Store channel instance
this.channels.set(config.id, {
config,
db,
credentials,
agents: null, // Will be initialized later
stats: {
totalVideos: 0,
totalViews: 0,
lastPublished: null
}
});
this.logger.success(`Channel initialized: ${config.name}`);
} catch (error) {
this.logger.error(`Failed to initialize channel ${config.id}:`, error);
throw error;
}
}
getChannel(channelId) {
return this.channels.get(channelId);
}
getAllChannels() {
return Array.from(this.channels.values());
}
getEnabledChannels() {
return this.getAllChannels().filter(ch => ch.config.enabled);
}
async updateChannelConfig(channelId, updates) {
const channel = this.channels.get(channelId);
if (!channel) {
throw new Error(`Channel not found: ${channelId}`);
}
// Update config
Object.assign(channel.config, updates);
// Save to file
await this.saveChannelConfig();
this.logger.info(`Channel config updated: ${channelId}`);
}
async saveChannelConfig() {
const config = {
channels: this.getAllChannels().map(ch => ch.config)
};
await fs.writeFile(
this.configPath,
JSON.stringify(config, null, 2)
);
}
async getChannelStats(channelId) {
const channel = this.channels.get(channelId);
if (!channel) {
throw new Error(`Channel not found: ${channelId}`);
}
// Get stats from database
const stats = await channel.db.getStats();
// Get recent performance
const recentVideos = await channel.db.getAllRows(
`SELECT * FROM publish_schedule
WHERE status = 'published'
ORDER BY published_at DESC
LIMIT 10`
);
return {
...stats,
channelId,
channelName: channel.config.name,
recentVideos
};
}
}
module.exports = { ChannelManager };
Modified Main Application
Multi-Channel YouTubeAutomationAgent
index-multi.js
const express = require('express');
const { Logger } = require('./utils/logger');
const { ChannelManager } = require('./utils/channel-manager');
const { ContentStrategyAgent } = require('./agents/content-strategy-agent');
const { ScriptWriterAgent } = require('./agents/script-writer-agent');
const { ThumbnailDesignerAgent } = require('./agents/thumbnail-designer-agent');
const { SEOOptimizerAgent } = require('./agents/seo-optimizer-agent');
const { ProductionManagementAgent } = require('./agents/production-management-agent');
const { PublishingSchedulingAgent } = require('./agents/publishing-scheduling-agent');
const { AnalyticsOptimizationAgent } = require('./agents/analytics-optimization-agent');
const chalk = require('chalk');
class MultiChannelYouTubeAgent {
constructor() {
this.logger = new Logger('MultiChannelAgent');
this.channelManager = null;
this.app = express();
this.isInitialized = false;
}
async initialize() {
try {
console.log(chalk.cyan.bold('\n🎬 Multi-Channel YouTube Automation Agent v2.0'));
console.log(chalk.gray('─'.repeat(50)));
// Initialize channel manager
this.logger.info('Initializing channel manager...');
this.channelManager = new ChannelManager();
await this.channelManager.initialize();
// Initialize agents for each channel
this.logger.info('Initializing agents for all channels...');
await this.initializeAllChannelAgents();
// Setup API
this.setupAPI();
this.isInitialized = true;
this.logger.success('Multi-channel agent initialized successfully!');
return true;
} catch (error) {
this.logger.error('Failed to initialize:', error);
return false;
}
}
async initializeAllChannelAgents() {
const channels = this.channelManager.getAllChannels();
for (const channel of channels) {
await this.initializeChannelAgents(channel);
}
}
async initializeChannelAgents(channel) {
this.logger.info(`Initializing agents for: ${channel.config.name}`);
channel.agents = {
strategy: new ContentStrategyAgent(channel.db, channel.credentials),
scriptWriter: new ScriptWriterAgent(channel.db, channel.credentials),
thumbnailDesigner: new ThumbnailDesignerAgent(channel.db, channel.credentials),
seoOptimizer: new SEOOptimizerAgent(channel.db, channel.credentials),
production: new ProductionManagementAgent(channel.db, channel.credentials),
publishing: new PublishingSchedulingAgent(channel.db, channel.credentials),
analytics: new AnalyticsOptimizationAgent(channel.db, channel.credentials)
};
// Initialize each agent with channel-specific config
for (const [name, agent] of Object.entries(channel.agents)) {
// Pass channel config to agent
agent.channelConfig = channel.config;
await agent.initialize();
this.logger.info(`✓ ${name} agent initialized for ${channel.config.name}`);
}
}
setupAPI() {
this.app.use(express.json());
// Health check for all channels
this.app.get('/health', (req, res) => {
const channels = this.channelManager.getAllChannels().map(ch => ({
id: ch.config.id,
name: ch.config.name,
enabled: ch.config.enabled,
agentsInitialized: ch.agents !== null
}));
res.json({
status: 'healthy',
initialized: this.isInitialized,
channels,
timestamp: new Date().toISOString()
});
});
// Generate content for specific channel
this.app.post('/generate/:channelId', async (req, res) => {
try {
const { channelId } = req.params;
const { topic, style, length } = req.body;
const channel = this.channelManager.getChannel(channelId);
if (!channel) {
return res.status(404).json({ error: 'Channel not found' });
}
const result = await this.generateContentForChannel(
channel, topic, style, length
);
res.json({ success: true, result });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Get analytics for specific channel
this.app.get('/analytics/:channelId', async (req, res) => {
try {
const { channelId } = req.params;
const channel = this.channelManager.getChannel(channelId);
if (!channel) {
return res.status(404).json({ error: 'Channel not found' });
}
const analytics = await channel.agents.analytics.getRecentAnalytics();
res.json(analytics);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Get schedule for specific channel
this.app.get('/schedule/:channelId', async (req, res) => {
try {
const { channelId } = req.params;
const channel = this.channelManager.getChannel(channelId);
if (!channel) {
return res.status(404).json({ error: 'Channel not found' });
}
const schedule = await channel.db.getUpcomingSchedule();
res.json(schedule);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Get all channels overview
this.app.get('/channels', async (req, res) => {
try {
const channels = await Promise.all(
this.channelManager.getAllChannels().map(async ch => {
const stats = await this.channelManager.getChannelStats(ch.config.id);
return {
id: ch.config.id,
name: ch.config.name,
enabled: ch.config.enabled,
stats
};
})
);
res.json({ channels });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
}
async generateContentForChannel(channel, topic = null, style = null, length = 'medium') {
this.logger.info(`Generating content for channel: ${channel.config.name}`);
// Use channel-specific configuration
const agents = channel.agents;
// Generate content with channel context
const strategy = await agents.strategy.generateContentStrategy(topic);
const script = await agents.scriptWriter.generateScript(strategy);
const thumbnail = await agents.thumbnailDesigner.generateThumbnail(script);
const seoData = await agents.seoOptimizer.optimize(script, strategy);
const productionData = await agents.production.processContent({
strategy,
script,
thumbnail,
seo: seoData,
channelId: channel.config.id
});
const contentId = await channel.db.saveProductionData(productionData);
return {
channelId: channel.config.id,
channelName: channel.config.name,
contentId,
title: script.title,
scheduledFor: productionData.scheduledPublishTime
};
}
async start() {
const initialized = await this.initialize();
if (!initialized) {
console.log(chalk.red('\n❌ Failed to initialize. Please check your configuration.'));
process.exit(1);
}
const PORT = process.env.PORT || 3456;
this.app.listen(PORT, () => {
console.log(chalk.green(`\n✅ Multi-Channel Agent running on port ${PORT}`));
console.log(chalk.gray('─'.repeat(50)));
console.log(chalk.white('📊 Dashboard: ') + chalk.cyan(`http://localhost:${PORT}/channels`));
console.log(chalk.white('🔧 Health: ') + chalk.cyan(`http://localhost:${PORT}/health`));
console.log(chalk.gray('─'.repeat(50)));
const channels = this.channelManager.getAllChannels();
console.log(chalk.yellow(`\n🤖 Managing ${channels.length} channels:`));
channels.forEach(ch => {
console.log(chalk.white(` - ${ch.config.name} (${ch.config.id})${ch.config.enabled ? '' : ' [DISABLED]'}`));
});
});
}
}
if (require.main === module) {
const agent = new MultiChannelYouTubeAgent();
agent.start().catch(error => {
console.error(chalk.red('Fatal error:'), error);
process.exit(1);
});
}
module.exports = { MultiChannelYouTubeAgent };
Multi-Channel Scheduler
Coordinated Scheduling
schedules/multi-channel-automation.js
const cron = require('node-cron');
const { Logger } = require('../utils/logger');
class MultiChannelAutomation {
constructor(channelManager) {
this.channelManager = channelManager;
this.logger = new Logger('MultiChannelAutomation');
this.scheduledTasks = new Map();
this.isEnabled = true;
}
async initialize() {
this.logger.info('Initializing multi-channel automation...');
// Setup tasks for each channel
const channels = this.channelManager.getEnabledChannels();
for (const channel of channels) {
await this.setupChannelTasks(channel);
}
this.logger.success('Multi-channel automation initialized');
return true;
}
async setupChannelTasks(channel) {
const channelId = channel.config.id;
const postTime = channel.config.content.preferredPostTime || '14:00';
const [hour, minute] = postTime.split(':');
// Daily content generation
const taskKey = `${channelId}-daily-generation`;
this.scheduledTasks.set(taskKey,
cron.schedule(`${minute} ${hour} * * *`, async () => {
if (this.isEnabled && channel.config.enabled) {
await this.generateContentForChannel(channel);
}
}, { scheduled: true })
);
this.logger.info(`Scheduled daily generation for ${channel.config.name} at ${postTime}`);
}
async generateContentForChannel(channel) {
try {
this.logger.info(`Starting content generation for: ${channel.config.name}`);
const agents = channel.agents;
// Check if should generate based on frequency
const shouldGenerate = await this.shouldGenerateContent(channel);
if (!shouldGenerate) {
this.logger.info(`Skipping ${channel.config.name} - sufficient content in buffer`);
return;
}
// Generate full content pipeline
const strategy = await agents.strategy.generateContentStrategy();
const script = await agents.scriptWriter.generateScript(strategy);
const thumbnail = await agents.thumbnailDesigner.generateThumbnail(script);
const seoData = await agents.seoOptimizer.optimize(script, strategy);
const productionData = await agents.production.processContent({
strategy, script, thumbnail, seo: seoData
});
await agents.publishing.scheduleContent(productionData);
this.logger.success(`Content generated for ${channel.config.name}: ${script.title}`);
} catch (error) {
this.logger.error(`Content generation failed for ${channel.config.name}:`, error);
}
}
async shouldGenerateContent(channel) {
const upcomingContent = await channel.db.getUpcomingSchedule(3);
const frequency = channel.config.content.postingFrequency || 'daily';
const requiredBuffer = {
'daily': 3,
'every-2-days': 2,
'3-per-week': 2,
'weekly': 1
};
return upcomingContent.length < (requiredBuffer[frequency] || 3);
}
}
module.exports = { MultiChannelAutomation };
Each channel operates independently with its own:
- Database instance
- YouTube credentials
- Content strategy
- Publishing schedule
- Analytics tracking
Running Multi-Channel Setup
Starting the Multi-Channel Agent
# Use the multi-channel version
node index-multi.js
Package.json Scripts
package.json
{
"scripts": {
"start:multi": "node index-multi.js",
"channel:add": "node scripts/add-channel.js",
"channel:list": "node scripts/list-channels.js",
"channel:disable": "node scripts/disable-channel.js"
}
}
API Rate Limits: Be mindful of YouTube API quotas when managing multiple channels:
- Each channel uses separate API quota
- Default quota: 10,000 units/day per project
- Consider creating separate Google Cloud projects for high-volume channels
- Implement rate limiting and retry logic
Best Practices
Resource Management
Resource Management
- Use separate databases to avoid data conflicts
- Implement connection pooling for efficiency
- Monitor memory usage across all channels
- Schedule tasks at different times to distribute load
Error Isolation
Error Isolation
- Failures in one channel shouldn’t affect others
- Implement per-channel error logging
- Use try-catch blocks around channel-specific operations
- Set up monitoring alerts per channel
Content Strategy
Content Strategy
- Keep content strategies distinct per channel
- Avoid duplicate content across channels
- Maintain different posting schedules
- Customize SEO for each channel’s niche
Next Steps
Customization
Customize agent behavior
Troubleshooting
Resolve common issues