Command Palette

Search for a command to run...

ai

AI 트렌드 자동 수집 시스템 구축기 - YouTube RSS + Gemini 요약

28개 AI/개발 YouTube 채널의 영상을 자동으로 수집하고, Gemini API로 요약하고, Notion과 이메일로 배포하는 시스템을 만들었습니다.


왜 만들었나?

AI 분야는 하루가 다르게 변화합니다. 주요 채널들의 영상을 매일 확인하기란 불가능에 가깝습니다.

그래서 만들었습니다:

  • 28개 채널에서 영상을 자동 수집
  • Gemini API로 자막 기반 요약 생성
  • Notion 데이터베이스에 자동 동기화
  • 이메일로 일일 요약 발송

시스템 아키텍처

YouTube RSS Feed (28개 채널)
        ↓
    수집 (Next.js API Route)
        ↓
    자막 추출 (youtubei.js)
        ↓ (자막 없으면)
    오디오 분석 (Gemini File API)
        ↓
    요약 생성 (Gemini 3 Flash)
        ↓
    DB 저장 (PostgreSQL + Prisma)
        ↓
    Notion 동기화 / 이메일 발송

구독 중인 채널 (28개)

한국어 채널 (20개)

  • 개발: 빌더 조쉬, 코드팩토리, 단테랩스, 노마드 코더, 조코딩, 코딩애플
  • AI 전문: 테디노트, 빵형의 개발도상국, 안될공학, 딥러닝 호형

글로벌 채널 (8개)

  • Google for Developers, Fireship, Two Minute Papers, OpenAI, Web Dev Simplified

핵심 구현

1. YouTube RSS 수집

YouTube는 각 채널마다 RSS 피드를 제공합니다. API 키 없이도 최신 영상을 가져올 수 있습니다.

import Parser from "rss-parser";
 
const parser = new Parser();
const feed = await parser.parseURL(
  `https://www.youtube.com/feeds/videos.xml?channel_id=${channelId}`
);
 
feed.items.forEach(item => {
  const videoId = item.id?.replace("yt:video:", "");
  videos.push({
    title: item.title,
    link: `https://www.youtube.com/watch?v=${videoId}`,
    pubDate: item.pubDate,
    source: channelName,
    thumbnail: `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`
  });
});

2. 3단계 Fallback 요약 시스템

모든 영상에 자막이 있는 것은 아닙니다. 3단계 Fallback을 구현했습니다.

async function summarizeVideo(video: VideoToSummarize) {
  const videoId = extractVideoId(video.link);
 
  // 1차: 자막 → Gemini 요약
  const transcript = await getTranscript(videoId);
  if (transcript) {
    return await summarizeText(transcript, { title: video.title });
  }
 
  // 2차: 오디오 다운로드 → Gemini 분석
  const audioSummary = await summarizeFromAudio(videoId, video.title);
  if (audioSummary) {
    return audioSummary;
  }
 
  // 3차: 영상 정보만으로 fallback
  const videoInfo = await getVideoInfo(videoId);
  return await summarizeFromVideoInfo(videoInfo);
}

3. 오디오 분석 (Gemini File API)

자막이 없는 영상은 오디오를 다운로드해서 Gemini에 직접 분석시킵니다.

import { GoogleAIFileManager } from "@google/generative-ai/server";
 
// 1. 오디오 다운로드 (youtubei.js 또는 ytdl-core)
const audioPath = await downloadAudio(videoId);
 
// 2. Gemini File API로 업로드
const fileManager = new GoogleAIFileManager(GEMINI_API_KEY);
const uploadResult = await fileManager.uploadFile(audioPath, {
  mimeType: "audio/mpeg"
});
 
// 3. 오디오 분석
const result = await model.generateContent([
  { fileData: { mimeType: "audio/mpeg", fileUri: uploadResult.file.uri } },
  { text: `이 오디오의 내용을 500자 이내로 요약해주세요. 영상 제목: ${title}` }
]);
 
// 4. 임시 파일 정리
fs.unlinkSync(audioPath);

4. Gemini 요약 프롬프트

일관된 형식의 요약을 위해 프롬프트를 정교하게 설계했습니다.

const prompt = `다음 유튜브 영상 자막을 500자 이내로 요약해주세요.
 
영상 제목: ${title}
 
[출력 형식]
(핵심 주제 1줄)
(주요 내용 3-5개 bullet point)
(결론/시사점 1줄)
 
자막:
${transcript.slice(0, 15000)}`;

5. Notion 동기화

요약된 영상을 Notion 데이터베이스에 자동으로 추가합니다.

import { Client } from "@notionhq/client";
 
const notion = new Client({ auth: NOTION_TRENDS_API_KEY });
 
// 페이지 생성
const page = await notion.pages.create({
  parent: { database_id: NOTION_TRENDS_DB_ID },
  properties: {
    Title: { title: [{ text: { content: video.title } }] },
    Source: { select: { name: video.source } },
    Link: { url: video.link },
    PubDate: { date: { start: video.pubDate.toISOString().split("T")[0] } }
  }
});
 
// 본문에 요약 내용 추가
await notion.blocks.children.append({
  block_id: page.id,
  children: [
    { type: "bookmark", bookmark: { url: video.link } },
    { type: "divider", divider: {} },
    ...summaryToBlocks(video.summary)  // bullet point 변환
  ]
});

6. 이메일 발송

HTML 템플릿으로 깔끔한 이메일을 발송합니다.

import nodemailer from "nodemailer";
 
const transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.GMAIL_USER,
    pass: process.env.GMAIL_APP_PASSWORD
  }
});
 
await transporter.sendMail({
  from: GMAIL_USER,
  to: GMAIL_USER,
  subject: `🤖 AI Trends Daily - ${today} (${videos.length}개 영상)`,
  html: generateEmailTemplate(videos)
});

API 엔드포인트

엔드포인트설명
POST /api/trends/refreshYouTube RSS 수집
POST /api/trends/summarize영상 요약 생성 (limit 파라미터)
POST /api/trends/send-email이메일 발송
POST /api/trends/sync-notionNotion 동기화
POST /api/trends/daily전체 작업 한번에 실행

Rate Limit 관리

Gemini Free Tier는 분당 15회 요청 제한이 있습니다.

// 4.5초 간격으로 호출 (분당 약 13회)
for (const video of videos) {
  await summarizeAndSave(video);
  await new Promise(r => setTimeout(r, 4500));
}

YouTube Shorts 정규화

Shorts URL과 일반 URL을 같은 영상으로 인식하도록 정규화합니다.

function normalizeYouTubeLink(link: string): string {
  const shortsMatch = link.match(/youtube\.com\/shorts\/([a-zA-Z0-9_-]+)/);
  if (shortsMatch) {
    return `https://www.youtube.com/watch?v=${shortsMatch[1]}`;
  }
  return link;
}

이렇게 하면 DB unique constraint에서 중복을 방지할 수 있습니다.

데이터베이스 스키마

model TrendVideo {
  id        Int      @id @default(autoincrement())
  title     String   @db.VarChar(500)
  link      String   @unique @db.VarChar(1000)
  pubDate   DateTime @map("pub_date")
  source    String   @db.VarChar(100)      // 채널명
  thumbnail String?  @db.VarChar(1000)
  summary   String?  @db.Text              // Gemini 요약
  emailSent Boolean  @default(false)
  createdAt DateTime @default(now())
 
  @@index([pubDate(sort: Desc)])
  @@index([emailSent])
  @@map("trend_videos")
}
 
model YouTubeChannel {
  id        Int      @id @default(autoincrement())
  channelId String   @unique @db.VarChar(30)
  name      String   @db.VarChar(100)
  category  String   @default("korean")    // korean | global
  active    Boolean  @default(true)
 
  @@map("youtube_channels")
}

블로그와의 연동

이 서비스(포트 7001)는 블로그(포트 7000)와 같은 PostgreSQL DB를 공유합니다.

ai-trends-collector (포트 7001)  ← 데이터 수집/요약
        ↓
   PostgreSQL (공유)
        ↓
devlop-blog (포트 7000)  ← 프론트엔드 렌더링

블로그의 /trends 페이지에서 수집된 영상들을 볼 수 있습니다.

자동화 스케줄링

로컬 환경에서는 node-cron을 사용합니다.

import cron from "node-cron";
 
// 매일 00:00 - 트렌드 수집
cron.schedule("0 0 * * *", updateAiTrends);
 
// 매일 01:00 - 영상 요약 (20개)
cron.schedule("0 1 * * *", () => summarizeVideosBatch(20));
 
// 매일 02:00 - Notion + 이메일
cron.schedule("0 2 * * *", async () => {
  await syncTodaySummariesToNotion();
  await sendTrendsSummaryEmail();
});

Cloud Run 배포 시에는 Google Cloud Scheduler를 사용합니다.

성과

  • 일일 처리량: 50~100개 영상
  • 요약 성공률: 약 85% (자막 + 오디오 fallback)
  • 비용: Gemini Free Tier로 무료 운영

개선 계획

  • 실패한 요약 자동 재시도
  • Sentry 에러 모니터링
  • Slack 알림 연동
  • 요약 품질 평가 시스템

GitHub: ai-trends-collector 저장소