Skip to main content

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

  • 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
  • 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
  • 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

Build docs developers (and LLMs) love