📚 Content Curation
🎯 Mục tiêu bài học
Sau bài học này, bạn sẽ:
✅ Xây dựng RSS feed aggregator với keyword filtering
✅ Implement AI-powered article summarization
✅ Monitor Hacker News và Reddit cho relevant content
✅ Tạo weekly content digest email tự động
Stay informed without drowning in information. Bài này hướng dẫn automate content curation để curate, filter, và deliver relevant content.
🔍 Content Curation Overview
Content Sources to Automate:
Content Curation Sources
Checkpoint
Có mấy loại content sources chính cần monitor?
⚡ Workflow 1: RSS Feed Aggregator
Multi-Feed Reader:
RSS Aggregator
RSS Feed Configuration:
1// Define feeds to monitor2const feeds = [3 {4 name: 'TechCrunch',5 url: 'https://techcrunch.com/feed/',6 category: 'Tech News',7 priority: 'high'8 },9 {10 name: 'Hacker News',11 url: 'https://news.ycombinator.com/rss',12 category: 'Tech',13 priority: 'high'14 },15 {16 name: 'Product Hunt',17 url: 'https://www.producthunt.com/feed',18 category: 'Products',19 priority: 'medium'20 },21 {22 name: 'The Verge',23 url: 'https://www.theverge.com/rss/index.xml',24 category: 'Tech News',25 priority: 'medium'26 },27 {28 name: 'Smashing Magazine',29 url: 'https://www.smashingmagazine.com/feed/',30 category: 'Design/Dev',31 priority: 'medium'32 }33];3435return { feeds };Content Filtering & Scoring:
1const items = $input.all();23// Keywords to boost4const boostKeywords = ['ai', 'automation', 'n8n', 'workflow', 'productivity', 'no-code'];5const mustInclude = []; // If set, article must contain at least one6const exclude = ['sponsored', 'advertisement', 'promotion'];78const processedItems = [];910for (const item of items) {11 const article = item.json;12 const title = article.title.toLowerCase();13 const description = (article.description || '').toLowerCase();14 const content = title + ' ' + description;15 16 // Skip excluded content17 if (exclude.some(word => content.includes(word))) {18 continue;19 }20 21 // Check must-include keywords22 if (mustInclude.length > 0) {23 const hasRequired = mustInclude.some(word => content.includes(word));24 if (!hasRequired) continue;25 }26 27 // Calculate relevance score28 let score = 0;29 30 // Boost for keywords31 for (const keyword of boostKeywords) {32 if (title.includes(keyword)) score += 10;33 if (description.includes(keyword)) score += 5;34 }35 36 // Boost for recency37 const pubDate = new Date(article.pubDate);38 const hoursOld = (Date.now() - pubDate) / (1000 * 60 * 60);39 if (hoursOld < 6) score += 20;40 else if (hoursOld < 24) score += 10;41 else if (hoursOld < 48) score += 5;42 43 // Boost based on source priority44 const sourcePriority = article.sourcePriority || 'medium';45 if (sourcePriority === 'high') score += 15;46 else if (sourcePriority === 'medium') score += 5;47 48 processedItems.push({49 ...article,50 score,51 processedAt: new Date().toISOString()52 });53}5455// Sort by score and take top results56processedItems.sort((a, b) => b.score - a.score);5758return { items: processedItems.slice(0, 30) };Checkpoint
RSS aggregator sử dụng scoring system với những criteria nào?
🔧 Workflow 2: AI-Powered Summarization
Summarize Articles:
Article Summarizer
AI Summary Prompt:
1const article = $input.item.json;23const prompt = `4Analyze this article and provide:51. A 2-3 sentence summary62. 3-5 key takeaways as bullet points73. Relevance score (1-10) for a tech professional84. 2-3 relevant tags910Article Title: ${article.title}11Article Content: ${article.content.substring(0, 3000)}1213Respond in JSON format:14{15 "summary": "...",16 "keyTakeaways": ["...", "..."],17 "relevanceScore": 8,18 "tags": ["AI", "Automation"]19}20`;2122return { prompt };Process AI Response:
1const article = $input.item.json.article;2const aiResponse = JSON.parse($input.item.json.aiResponse);34return {5 title: article.title,6 url: article.link,7 source: article.source,8 publishedAt: article.pubDate,9 10 // AI-generated11 summary: aiResponse.summary,12 keyTakeaways: aiResponse.keyTakeaways,13 relevanceScore: aiResponse.relevanceScore,14 tags: aiResponse.tags,15 16 // Metadata17 savedAt: new Date().toISOString(),18 status: 'unread'19};Checkpoint
AI summarization prompt yêu cầu trả về những thông tin gì?
🏗️ Workflow 3: Hacker News Monitor
Track HN Discussions:
Hacker News Monitor
HN API Integration:
1// Fetch top stories2const topStoriesUrl = 'https://hacker-news.firebaseio.com/v0/topstories.json';3const topStories = await fetch(topStoriesUrl).then(r => r.json());45// Get details for top 306const stories = [];7for (const id of topStories.slice(0, 30)) {8 const storyUrl = `https://hacker-news.firebaseio.com/v0/item/${id}.json`;9 const story = await fetch(storyUrl).then(r => r.json());10 11 if (story && story.type === 'story') {12 stories.push({13 id: story.id,14 title: story.title,15 url: story.url || `https://news.ycombinator.com/item?id=${story.id}`,16 score: story.score,17 comments: story.descendants,18 by: story.by,19 time: story.time,20 hnUrl: `https://news.ycombinator.com/item?id=${story.id}`21 });22 }23}2425return { stories };Filter High-Quality Posts:
1const stories = $input.item.json.stories;23// Filter criteria4const minScore = 100;5const minComments = 20;6const interestingTopics = ['ai', 'startup', 'automation', 'programming', 'show hn'];78const filtered = stories.filter(story => {9 const title = story.title.toLowerCase();10 11 // Must meet minimum engagement12 if (story.score < minScore) return false;13 14 // Boost for interesting topics15 const isInteresting = interestingTopics.some(topic => title.includes(topic));16 17 // Accept if very popular or interesting18 return story.score >= 200 || (story.score >= minScore && isInteresting) || story.comments >= 50;19});2021return { stories: filtered };Checkpoint
Hacker News monitor filter posts dựa trên điều kiện gì?
📊 Workflow 4: Reddit Monitoring
Track Subreddit Posts:
Reddit Monitor
Reddit API Setup:
1const subreddits = ['automation', 'nocode', 'selfhosted', 'sideproject'];2const posts = [];34for (const subreddit of subreddits) {5 const url = `https://www.reddit.com/r/${subreddit}/hot.json?limit=25`;6 7 const response = await fetch(url, {8 headers: { 'User-Agent': 'n8n-content-bot/1.0' }9 });10 const data = await response.json();11 12 for (const item of data.data.children) {13 const post = item.data;14 15 posts.push({16 id: post.id,17 subreddit: post.subreddit,18 title: post.title,19 url: post.url,20 redditUrl: `https://reddit.com${post.permalink}`,21 score: post.score,22 comments: post.num_comments,23 author: post.author,24 created: new Date(post.created_utc * 1000).toISOString(),25 flair: post.link_flair_text26 });27 }28}2930// Sort by score31posts.sort((a, b) => b.score - a.score);3233return { posts: posts.slice(0, 50) };Checkpoint
Reddit monitoring theo dõi bao nhiêu subreddits?
💡 Workflow 5: Newsletter Curation
Curate Newsletter Content:
Newsletter Curator
Extract Links from Emails:
1const email = $input.item.json;2const body = email.html || email.text;34// Extract all links5const linkRegex = /<a[^>]+href=["']([^"']+)["'][^>]*>([^<]+)<\/a>/gi;6const matches = [...body.matchAll(linkRegex)];78// Filter out navigation/unsubscribe links9const excludePatterns = [10 'unsubscribe',11 'mailto:',12 'twitter.com',13 'facebook.com',14 'linkedin.com/share',15 '#',16 'javascript:'17];1819const links = matches20 .map(match => ({21 url: match[1],22 text: match[2].trim()23 }))24 .filter(link => {25 const urlLower = link.url.toLowerCase();26 return !excludePatterns.some(pattern => urlLower.includes(pattern));27 })28 .filter(link => link.text.length > 5); // Skip short link texts2930return {31 newsletter: email.from,32 subject: email.subject,33 receivedAt: email.date,34 links: links.slice(0, 20) // Limit per email35};Checkpoint
Newsletter curation extract links bằng regex pattern nào?
🌟 Workflow 6: Content Digest Generator
Generate Weekly Digest:
Weekly Content Digest
Digest Email Template:
1const content = $input.item.json;2const weekStart = new Date();3weekStart.setDate(weekStart.getDate() - 7);45const digest = `6<!DOCTYPE html>7<html>8<head>9 <style>10 body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }11 .header { text-align: center; border-bottom: 3px solid #4CAF50; padding-bottom: 20px; }12 .section { margin: 30px 0; }13 .section-title { color: #333; font-size: 18px; border-left: 4px solid #4CAF50; padding-left: 10px; }14 .item { padding: 15px 0; border-bottom: 1px solid #eee; }15 .item-title { font-weight: bold; color: #1a73e8; text-decoration: none; }16 .item-meta { color: #666; font-size: 12px; margin-top: 5px; }17 .item-summary { color: #333; margin-top: 8px; }18 .stats { background: #f5f5f5; padding: 15px; border-radius: 8px; text-align: center; }19 .stat { display: inline-block; margin: 0 20px; }20 .stat-value { font-size: 24px; font-weight: bold; color: #4CAF50; }21 </style>22</head>23<body>24 <div class="header">25 <h1>�� Weekly Content Digest</h1>26 <p>Week of ${weekStart.toLocaleDateString()}</p>27 </div>28 29 <div class="stats">30 <div class="stat">31 <div class="stat-value">${content.totalItems}</div>32 <div>Articles Curated</div>33 </div>34 <div class="stat">35 <div class="stat-value">${content.categories.length}</div>36 <div>Categories</div>37 </div>38 <div class="stat">39 <div class="stat-value">${content.topScore}</div>40 <div>Top Score</div>41 </div>42 </div>4344 ${content.categories.map(cat => `45 <div class="section">46 <h2 class="section-title">${cat.emoji} ${cat.name}</h2>47 ${cat.items.slice(0, 5).map(item => `48 <div class="item">49 <a href="${item.url}" class="item-title">${item.title}</a>50 <div class="item-meta">${item.source} • ${item.score} points</div>51 ${item.summary ? `<div class="item-summary">${item.summary}</div>` : ''}52 </div>53 `).join('')}54 </div>55 `).join('')}5657 <div style="text-align: center; margin-top: 40px; color: #666; font-size: 12px;">58 <p>Curated automatically by n8n</p>59 <p><a href="#">Manage preferences</a> | <a href="#">Unsubscribe</a></p>60 </div>61</body>62</html>63`;6465return { digest };Checkpoint
Content digest generator nhóm content theo categories như thế nào?
📋 Best Practices
DO:
- ✅ Define clear criteria for relevance
- ✅ Deduplicate across sources
- ✅ Include source attribution
- ✅ Set reasonable limits (avoid overload)
- ✅ Review and refine filters regularly
DON'T:
- ❌ Curate without purpose
- ❌ Include everything (quality > quantity)
- ❌ Ignore feedback on usefulness
- ❌ Forget to respect source terms of service
Checkpoint
Tại sao cần define clear criteria for relevance?
📝 Bài Tập Thực Hành
Build your content system:
- Set up RSS feed aggregator (5+ feeds)
- Implement keyword filtering and scoring
- Add AI summarization for top articles
- Create weekly digest email
- Track engagement metrics
Stay informed effortlessly! 📚
Checkpoint
Bạn đã hoàn thành những challenges nào trong bài tập?
🧠 Key Takeaways
- 🎯 Define your focus - Not everything is relevant
- 📊 Score content - Prioritize what matters
- 🤖 Use AI wisely - Summarize, don't replace reading
- 📧 Batch delivery - Digest > constant stream
- 🔄 Iterate filters - Refine over time
Checkpoint
Tại sao Digest > constant stream?
🚀 Bài tiếp theo
Social Media Automation — Multi-platform posting và engagement.
