← back to Goodquestion Ai

scripts/youtube-privatize-all.cjs

146 lines

/**
 * List all videos on the Agent Abrams channel and set them to PRIVATE.
 */
const { google } = require('googleapis');
const fs = require('fs');
const path = require('path');

require('dotenv').config({ path: path.join(__dirname, '..', '.env') });

const CLIENT_ID = process.env.YOUTUBE_CLIENT_ID;
const CLIENT_SECRET = process.env.YOUTUBE_CLIENT_SECRET;
const REDIRECT_URI = process.env.YOUTUBE_REDIRECT_URI || 'http://localhost:3456/oauth/callback';
const TOKEN_PATH = path.join(__dirname, '..', '.youtube-token.json');
const CHANNEL_ID = 'UCUyOiEMZPSUGUr3HCc1vE1w';

async function main() {
  const tokens = JSON.parse(fs.readFileSync(TOKEN_PATH, 'utf-8'));
  const oauth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI);
  oauth2Client.setCredentials(tokens);

  // Auto-refresh token if expired
  oauth2Client.on('tokens', (newTokens) => {
    const merged = { ...tokens, ...newTokens };
    fs.writeFileSync(TOKEN_PATH, JSON.stringify(merged, null, 2));
    console.log('Token refreshed and saved.');
  });

  const youtube = google.youtube({ version: 'v3', auth: oauth2Client });

  // Step 1: List ALL videos on the channel (paginated)
  console.log(`\n=== Listing all videos on channel ${CHANNEL_ID} ===\n`);

  let allVideos = [];
  let nextPageToken = null;

  do {
    const searchRes = await youtube.search.list({
      part: ['snippet'],
      channelId: CHANNEL_ID,
      maxResults: 50,
      type: ['video'],
      pageToken: nextPageToken || undefined,
    });

    const items = searchRes.data.items || [];
    for (const item of items) {
      allVideos.push({
        id: item.id.videoId,
        title: item.snippet.title,
        publishedAt: item.snippet.publishedAt,
      });
    }

    nextPageToken = searchRes.data.nextPageToken;
  } while (nextPageToken);

  console.log(`Found ${allVideos.length} video(s):\n`);

  if (allVideos.length === 0) {
    console.log('No videos found on this channel.');
    return;
  }

  for (const v of allVideos) {
    console.log(`  [${v.id}] ${v.title} (${v.publishedAt})`);
  }

  // Step 2: Get current status of each video, then set to PRIVATE
  console.log(`\n=== Setting all ${allVideos.length} videos to PRIVATE ===\n`);

  const results = { privatized: [], alreadyPrivate: [], failed: [] };

  for (const v of allVideos) {
    try {
      // Get current video details (need snippet + status for update)
      const detailRes = await youtube.videos.list({
        part: ['snippet', 'status'],
        id: [v.id],
      });

      if (!detailRes.data.items || detailRes.data.items.length === 0) {
        console.log(`  SKIP: ${v.id} — not found in video details`);
        results.failed.push({ id: v.id, title: v.title, reason: 'not found' });
        continue;
      }

      const video = detailRes.data.items[0];
      const currentPrivacy = video.status.privacyStatus;

      if (currentPrivacy === 'private') {
        console.log(`  ALREADY PRIVATE: [${v.id}] ${v.title}`);
        results.alreadyPrivate.push({ id: v.id, title: v.title });
        continue;
      }

      // Update to private
      await youtube.videos.update({
        part: ['status'],
        requestBody: {
          id: v.id,
          status: {
            privacyStatus: 'private',
            selfDeclaredMadeForKids: video.status.selfDeclaredMadeForKids || false,
          },
        },
      });

      console.log(`  PRIVATIZED: [${v.id}] ${v.title} (was: ${currentPrivacy})`);
      results.privatized.push({ id: v.id, title: v.title, was: currentPrivacy });

    } catch (err) {
      console.error(`  FAILED: [${v.id}] ${v.title} — ${err.message}`);
      results.failed.push({ id: v.id, title: v.title, reason: err.message });
    }
  }

  // Summary
  console.log('\n=== SUMMARY ===');
  console.log(`Total videos found: ${allVideos.length}`);
  console.log(`Privatized: ${results.privatized.length}`);
  console.log(`Already private: ${results.alreadyPrivate.length}`);
  console.log(`Failed: ${results.failed.length}`);

  if (results.privatized.length > 0) {
    console.log('\nNewly privatized:');
    for (const v of results.privatized) {
      console.log(`  [${v.id}] ${v.title} (was ${v.was})`);
    }
  }

  if (results.failed.length > 0) {
    console.log('\nFailed:');
    for (const v of results.failed) {
      console.log(`  [${v.id}] ${v.title} — ${v.reason}`);
    }
  }
}

main().catch(err => {
  console.error('Fatal error:', err.message);
  if (err.code === 401) {
    console.error('\nToken may be expired. Try running youtube-auth.cjs to re-authenticate.');
  }
  process.exit(1);
});