Resumen
Ejecuta semanal to recopilar YouTube resultados de busqueda for tracked topics, identificar videos published in el past 7 dias, extraer view counts y canal names, y generar un structured digest informe.
Desencadenador
Semanal cron (Mondays at 8 AM)
Programación
Semanal, Mondays at 8 AM (cron: 0 8 * * 1)
Pasos del flujo de trabajo
Cargar tracked topics
Leer topic palabras clave de un topics tabla (topic_name, search_query). Estos son el YouTube searches to ejecutar semanal.
Search YouTube for cada topic
POST to Scavio search API con plataforma: youtube for cada topic. Solicitud resultados filtrado to el past semana.
Filtrar for nuevo videos
Filtrar resultados to videos published dentro de el last 7 dias usando el published_date campo. Exclude previously visto video IDs.
Extraer video metadata
For cada nuevo video: titulo, channel_name, view_count, published_date, video_url. Almacenar in videos tabla.
Generar digest
Sort nuevo videos by view_count descending. Format as un Markdown o HTML digest grouped by topic.
Deliver digest
Enviar digest via correo electronico o Slack. Include total nuevo video conteo per topic, top video per topic, y total view conteo for el semana.
Implementacion en Python
import sqlite3
import requests
from datetime import date, timedelta
import time
DB_PATH = "youtube_digest.db"
SCRAVIO_KEY = "YOUR_API_KEY"
def init_db():
conn = sqlite3.connect(DB_PATH)
conn.executescript("""
CREATE TABLE IF NOT EXISTS topics (topic_name TEXT, search_query TEXT);
CREATE TABLE IF NOT EXISTS videos (
video_id TEXT PRIMARY KEY, topic TEXT, title TEXT,
channel TEXT, view_count INTEGER, published_date TEXT, url TEXT
);
""")
conn.commit()
return conn
def search_youtube(query: str) -> list:
resp = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": SCRAVIO_KEY},
json={"query": query, "platform": "youtube", "num": 20, "time_range": "week"}
)
resp.raise_for_status()
return resp.json().get("results", [])
def run():
conn = init_db()
week_ago = (date.today() - timedelta(days=7)).isoformat()
topics = conn.execute("SELECT topic_name, search_query FROM topics").fetchall()
digest_lines = [f"# YouTube Digest - Week of {date.today().isoformat()}\n"]
for topic_name, search_query in topics:
results = search_youtube(search_query)
new_videos = []
for r in results:
vid_id = r.get("video_id") or r.get("url", "").split("v=")[-1]
existing = conn.execute("SELECT 1 FROM videos WHERE video_id=?", (vid_id,)).fetchone()
if existing:
continue
pub_date = r.get("published_date", "")
if pub_date and pub_date < week_ago:
continue
conn.execute("INSERT OR IGNORE INTO videos VALUES (?,?,?,?,?,?,?)",
(vid_id, topic_name, r.get("title"), r.get("channel"),
r.get("view_count", 0), pub_date, r.get("url")))
new_videos.append(r)
conn.commit()
new_videos.sort(key=lambda x: x.get("view_count", 0), reverse=True)
digest_lines.append(f"\n## {topic_name} ({len(new_videos)} new videos)")
for v in new_videos[:5]:
views = f"{v.get('view_count', 0):,}"
digest_lines.append(f"- [{v.get('title')}]({v.get('url')}) | {v.get('channel')} | {views} views")
time.sleep(0.3)
digest = "\n".join(digest_lines)
print(digest)
# Send via email or Slack here
if __name__ == "__main__":
run()
Implementacion en JavaScript
const Database = require('better-sqlite3');
const fetch = require('node-fetch');
const DB_PATH = 'youtube_digest.db';
const SCRAVIO_KEY = 'YOUR_API_KEY';
const db = new Database(DB_PATH);
db.exec(`
CREATE TABLE IF NOT EXISTS topics (topic_name TEXT, search_query TEXT);
CREATE TABLE IF NOT EXISTS videos (
video_id TEXT PRIMARY KEY, topic TEXT, title TEXT,
channel TEXT, view_count INTEGER, published_date TEXT, url TEXT
);
`);
async function searchYoutube(query) {
const res = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCRAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, platform: 'youtube', num: 20, time_range: 'week' })
});
return (await res.json()).results || [];
}
async function run() {
const weekAgo = new Date(Date.now() - 7 * 86400000).toISOString().slice(0, 10);
const topics = db.prepare('SELECT topic_name, search_query FROM topics').all();
const lines = [`# YouTube Digest - ${new Date().toISOString().slice(0, 10)}`];
for (const { topic_name, search_query } of topics) {
const results = await searchYoutube(search_query);
const newVideos = [];
for (const r of results) {
const vid_id = r.video_id || (r.url || '').split('v=')[1]?.slice(0, 11);
if (!vid_id) continue;
const exists = db.prepare('SELECT 1 FROM videos WHERE video_id=?').get(vid_id);
if (exists) continue;
if (r.published_date && r.published_date < weekAgo) continue;
db.prepare('INSERT OR IGNORE INTO videos VALUES (?,?,?,?,?,?,?)').run(
vid_id, topic_name, r.title, r.channel, r.view_count || 0, r.published_date, r.url
);
newVideos.push(r);
}
newVideos.sort((a, b) => (b.view_count || 0) - (a.view_count || 0));
lines.push(`\n## ${topic_name} (${newVideos.length} new videos)`);
newVideos.slice(0, 5).forEach(v => {
lines.push(`- [${v.title}](${v.url}) | ${v.channel} | ${(v.view_count||0).toLocaleString()} views`);
});
await new Promise(r => setTimeout(r, 300));
}
console.log(lines.join('\n'));
}
run().catch(console.error);
Plataformas utilizadas
YouTube
Búsqueda de videos con transcripciones y metadatos