Aperçu
Interroge les hashtags de campagne suivis toutes les 6 heures, enregistre le nombre de vidéos et les totaux d'engagement, calcule la vélocité de croissance et signale les moments viraux lorsque le nombre de vidéos ou l'engagement augmente de plus de 50 % en une fenêtre de 6 heures.
Déclencheur
Toutes les 6 heures (cron: 0 */6 * * *)
Planification
Toutes les 6 heures (cron: 0 */6 * * *)
Étapes du workflow
Récupérer les statistiques des hashtags
Envoyer une requête POST à l'endpoint Scavio TikTok hashtag pour chaque hashtag suivi. Extraire video_count et total_view_count de la réponse.
Enregistrer un instantané
Écrire le hashtag, video_count, view_count et l'horodatage dans une table d'instantanés.
Calculer la vélocité de croissance
Comparer les video_count et view_count actuels avec l'instantané d'il y a 6 heures. Calculer new_videos et new_views dans la fenêtre.
Détecter le seuil viral
Signaler si new_videos dans la fenêtre dépasse un seuil (par ex., 200 nouvelles vidéos en 6 heures pour une campagne de taille moyenne). Les seuils sont configurables par hashtag.
Alerter en cas de détection virale
Envoyer une alerte Slack ou webhook avec le nom du hashtag, le nombre de nouvelles vidéos, la vélocité des vues (vues par heure) et un lien TikTok vers la page du hashtag.
Implémentation Python
import sqlite3
import requests
from datetime import datetime, timedelta
import time
DB_PATH = "tiktok_campaigns.db"
SCRAVIO_KEY = "YOUR_API_KEY"
API_BASE = "https://api.scavio.dev/api/v1/tiktok"
HEADERS = {"Authorization": f"Bearer {SCRAVIO_KEY}"}
ALERT_WEBHOOK = "https://hooks.slack.com/services/YOUR/WEBHOOK"
VIRAL_VIDEO_THRESHOLD = 200 # new videos per 6h window
def init_db():
conn = sqlite3.connect(DB_PATH)
conn.executescript("""
CREATE TABLE IF NOT EXISTS hashtags (hashtag TEXT PRIMARY KEY, viral_threshold INTEGER DEFAULT 200);
CREATE TABLE IF NOT EXISTS snapshots (
hashtag TEXT, video_count INTEGER, view_count INTEGER, ts TEXT
);
""")
conn.commit()
return conn
def fetch_hashtag_stats(hashtag: str) -> dict:
resp = requests.post(
f"{API_BASE}/hashtag/info",
headers=HEADERS,
json={"hashtag": hashtag}
)
resp.raise_for_status()
data = resp.json().get("data", {})
return {
"video_count": data.get("videoCount", 0),
"view_count": data.get("viewCount", 0)
}
def run():
conn = init_db()
now = datetime.utcnow().isoformat()
six_hours_ago = (datetime.utcnow() - timedelta(hours=6)).isoformat()
hashtags = conn.execute("SELECT hashtag, viral_threshold FROM hashtags").fetchall()
for hashtag, threshold in hashtags:
stats = fetch_hashtag_stats(hashtag)
conn.execute("INSERT INTO snapshots VALUES (?,?,?,?)",
(hashtag, stats["video_count"], stats["view_count"], now))
prev = conn.execute(
"SELECT video_count, view_count FROM snapshots "
"WHERE hashtag=? AND ts <= ? ORDER BY ts DESC LIMIT 1",
(hashtag, six_hours_ago)
).fetchone()
if prev:
new_videos = stats["video_count"] - prev[0]
new_views = stats["view_count"] - prev[1]
views_per_hour = new_views // 6
if new_videos >= (threshold or VIRAL_VIDEO_THRESHOLD):
requests.post(ALERT_WEBHOOK, json={
"text": f"Viral alert #{hashtag}: +{new_videos} videos in 6h, +{views_per_hour:,} views/hr. https://tiktok.com/tag/{hashtag}"
})
conn.commit()
time.sleep(0.5)
if __name__ == "__main__":
run()
Implémentation JavaScript
const Database = require('better-sqlite3');
const fetch = require('node-fetch');
const DB_PATH = 'tiktok_campaigns.db';
const API_BASE = 'https://api.scavio.dev/api/v1/tiktok';
const SCRAVIO_KEY = 'YOUR_API_KEY';
const HEADERS = { 'Authorization': `Bearer ${SCRAVIO_KEY}`, 'Content-Type': 'application/json' };
const ALERT_WEBHOOK = 'https://hooks.slack.com/services/YOUR/WEBHOOK';
const db = new Database(DB_PATH);
db.exec(`
CREATE TABLE IF NOT EXISTS hashtags (hashtag TEXT PRIMARY KEY, viral_threshold INTEGER DEFAULT 200);
CREATE TABLE IF NOT EXISTS snapshots (hashtag TEXT, video_count INTEGER, view_count INTEGER, ts TEXT);
`);
async function fetchHashtagStats(hashtag) {
const res = await fetch(`${API_BASE}/hashtag/info`, {
method: 'POST', headers: HEADERS,
body: JSON.stringify({ hashtag })
});
const data = (await res.json()).data || {};
return { video_count: data.videoCount || 0, view_count: data.viewCount || 0 };
}
async function run() {
const now = new Date().toISOString();
const sixHoursAgo = new Date(Date.now() - 6 * 3600000).toISOString();
const hashtags = db.prepare('SELECT hashtag, viral_threshold FROM hashtags').all();
for (const { hashtag, viral_threshold } of hashtags) {
const stats = await fetchHashtagStats(hashtag);
db.prepare('INSERT INTO snapshots VALUES (?,?,?,?)').run(hashtag, stats.video_count, stats.view_count, now);
const prev = db.prepare(
'SELECT video_count, view_count FROM snapshots WHERE hashtag=? AND ts <= ? ORDER BY ts DESC LIMIT 1'
).get(hashtag, sixHoursAgo);
if (prev) {
const newVideos = stats.video_count - prev.video_count;
const newViews = stats.view_count - prev.view_count;
if (newVideos >= (viral_threshold || 200)) {
await fetch(ALERT_WEBHOOK, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: `Viral alert #${hashtag}: +${newVideos} videos, +${Math.round(newViews/6).toLocaleString()} views/hr. https://tiktok.com/tag/${hashtag}` })
});
}
}
await new Promise(r => setTimeout(r, 500));
}
}
run().catch(console.error);
Plateformes utilisées
TikTok
Découverte de vidéos tendance, créateurs et produits