crea-ka: couverture 13 plateformes (Apify) + refresh auto 7j + max-parallélisme
- +patreon-apify +discord-apify (code invit sensible à la casse via URL) - run_actor_sharded : N runs parallèles (défaut 32x2Go), retry+jitter, hook target_of - rotation hebdo (APIFY_REVISIT_DAYS=7) : le watch PM2 quotidien couvre tout le bassin en <=7j - +tavily-seed (1271 graines moissonnées) +snowball-ig (related_profiles) pour lexpansion - frontend : stats/badges/contenu récent par plateforme Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 changed files +2,211 −217
modified
creaka/connectors/apify_social.py
+150 −37
@@ -27,7 +27,9 @@ Uniquement des profils PUBLICS (§15) ; un profil privé/introuvable est ignoré | |||||
| 27 | from __future__ import annotations | 27 | from __future__ import annotations | ||
| 28 | 28 | ||||
| 29 | import os | 29 | import os | ||
| 30 | +import random | ||||
| 30 | import time | 31 | import time | ||
| 32 | +from concurrent.futures import ThreadPoolExecutor, as_completed | ||||
| 31 | from datetime import datetime, timedelta, timezone | 33 | from datetime import datetime, timedelta, timezone | ||
| 32 | 34 | ||||
| 33 | import requests | 35 | import requests | ||
@@ -42,34 +44,60 @@ APIFY_API = "https://api.apify.com/v2" | |||||
| 42 | ACTOR_OWNER = "gorgeous_thistle" | 44 | ACTOR_OWNER = "gorgeous_thistle" | ||
| 43 | RESIDENTIAL = {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"]} | 45 | RESIDENTIAL = {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"]} | ||
| 44 | 46 | ||||
| 45 | − | 47 | +# --- parallélisme : on dispose de 256 Go de RAM Apify → au lieu d'UN run à | ||
| 46 | −def run_actor(name: str, run_input: dict, *, timeout_s: int = 2400, | 48 | +# 1 Go, on éclate le lot en tranches lancées EN PARALLÈLE, chacune avec plus de | ||
| 47 | − memory_mb: int = 1024) -> list[dict]: | 49 | +# mémoire (donc plus de CPU/vCPU côté Apify) et une concurrence interne accrue. | ||
| 48 | − """Lance un acteur KA sur Apify et retourne les items de son dataset. | 50 | +# profil « max parallélisme » : ces acteurs sont I/O-bound (requêtes proxy), | ||
| 49 | − | 51 | +# donc BEAUCOUP de petits runs > peu de gros runs. 32 × 2 Go = 64 Go de pointe | ||
| 50 | − Run asynchrone + polling (run-sync plafonne à 300 s, trop court pour les | 52 | +# (large sous les 256 Go / 128 runs concurrents du plan). | ||
| 51 | − gros lots). Le run est avorté si `timeout_s` est dépassé. | 53 | +SHARD_SIZE = int(os.environ.get("APIFY_SHARD_SIZE", "60")) # handles / run | ||
| 52 | − """ | 54 | +MAX_SHARDS = int(os.environ.get("APIFY_MAX_SHARDS", "32")) # runs simultanés | ||
| 55 | +RUN_MEMORY_MB = int(os.environ.get("APIFY_RUN_MEMORY_MB", "2048")) # /run | ||||
| 56 | +RUN_CONCURRENCY = int(os.environ.get("APIFY_RUN_CONCURRENCY", "10")) # interne (max 10) | ||||
| 57 | +# rafraîchissement : un compte est re-sondé s'il n'a pas été enrichi depuis | ||||
| 58 | +# REVISIT_DAYS jours. Le watch quotidien couvre ainsi TOUT le bassin en ≤ N j. | ||||
| 59 | +REVISIT_DAYS = int(os.environ.get("APIFY_REVISIT_DAYS", "7")) | ||||
| 60 | + | ||||
| 61 | + | ||||
| 62 | +def _token() -> str: | ||||
| 53 | token = os.environ.get("APIFY_TOKEN") | 63 | token = os.environ.get("APIFY_TOKEN") | ||
| 54 | if not token: | 64 | if not token: | ||
| 55 | raise SkipSource("APIFY_TOKEN manquant (voir .env)") | 65 | raise SkipSource("APIFY_TOKEN manquant (voir .env)") | ||
| 56 | − headers = {"Authorization": f"Bearer {token}"} | 66 | + return token | ||
| 57 | − resp = requests.post( | 67 | + | ||
| 58 | − f"{APIFY_API}/acts/{ACTOR_OWNER}~{name}/runs", | 68 | + | ||
| 59 | − json=run_input, headers=headers, | 69 | +def _launch(name: str, run_input: dict, memory_mb: int, | ||
| 60 | − params={"memory": memory_mb}, timeout=60) | 70 | + retries: int = 6) -> str: | ||
| 71 | + """Démarre un run. Retry sur 400/429 (limite mémoire concurrente atteinte : | ||||
| 72 | + elle se libère quand d'autres tranches terminent) avec backoff.""" | ||||
| 73 | + headers = {"Authorization": f"Bearer {_token()}"} | ||||
| 74 | + for attempt in range(retries): | ||||
| 75 | + resp = requests.post( | ||||
| 76 | + f"{APIFY_API}/acts/{ACTOR_OWNER}~{name}/runs", | ||||
| 77 | + json=run_input, headers=headers, | ||||
| 78 | + params={"memory": memory_mb}, timeout=60) | ||||
| 79 | + if resp.status_code in (400, 429, 402) or resp.status_code >= 500: | ||||
| 80 | + if attempt < retries - 1: | ||||
| 81 | + # backoff + jitter : désynchronise les tranches (évite le | ||||
| 82 | + # lockstep où toutes redemandent la RAM au même instant) | ||||
| 83 | + time.sleep(min(60, 8 * (attempt + 1)) + random.uniform(0, 6)) | ||||
| 84 | + continue | ||||
| 85 | + resp.raise_for_status() | ||||
| 86 | + return resp.json()["data"]["id"] | ||||
| 61 | resp.raise_for_status() | 87 | resp.raise_for_status() | ||
| 62 | − run_id = resp.json()["data"]["id"] | 88 | + return resp.json()["data"]["id"] | ||
| 89 | + | ||||
| 90 | + | ||||
| 91 | +def _await_items(run_id: str, name: str, timeout_s: int) -> list[dict]: | ||||
| 92 | + headers = {"Authorization": f"Bearer {_token()}"} | ||||
| 63 | t0 = time.time() | 93 | t0 = time.time() | ||
| 64 | − status: dict = {} | ||||
| 65 | while True: | 94 | while True: | ||
| 66 | time.sleep(15) | 95 | time.sleep(15) | ||
| 67 | r = requests.get(f"{APIFY_API}/actor-runs/{run_id}", | 96 | r = requests.get(f"{APIFY_API}/actor-runs/{run_id}", | ||
| 68 | headers=headers, timeout=60) | 97 | headers=headers, timeout=60) | ||
| 69 | r.raise_for_status() | 98 | r.raise_for_status() | ||
| 70 | status = r.json()["data"] | 99 | status = r.json()["data"] | ||
| 71 | − if status["status"] in ("SUCCEEDED", "FAILED", "ABORTED", | 100 | + if status["status"] in ("SUCCEEDED", "FAILED", "ABORTED", "TIMED-OUT"): | ||
| 72 | − "TIMED-OUT"): | ||||
| 73 | break | 101 | break | ||
| 74 | if time.time() - t0 > timeout_s: | 102 | if time.time() - t0 > timeout_s: | ||
| 75 | requests.post(f"{APIFY_API}/actor-runs/{run_id}/abort", | 103 | requests.post(f"{APIFY_API}/actor-runs/{run_id}/abort", | ||
@@ -93,24 +121,68 @@ def run_actor(name: str, run_input: dict, *, timeout_s: int = 2400, | |||||
| 93 | offset += 1000 | 121 | offset += 1000 | ||
| 94 | 122 | ||||
| 95 | 123 | ||||
| 124 | +def run_actor(name: str, run_input: dict, *, timeout_s: int = 2400, | ||||
| 125 | + memory_mb: int = RUN_MEMORY_MB) -> list[dict]: | ||||
| 126 | + """Un seul run (recherche, petit lot).""" | ||||
| 127 | + return _await_items(_launch(name, run_input, memory_mb), name, timeout_s) | ||||
| 128 | + | ||||
| 129 | + | ||||
| 130 | +def run_actor_sharded(name: str, base_input: dict, usernames: list[str], *, | ||||
| 131 | + timeout_s: int = 2400, | ||||
| 132 | + shard_size: int = SHARD_SIZE, | ||||
| 133 | + max_shards: int = MAX_SHARDS, | ||||
| 134 | + memory_mb: int = RUN_MEMORY_MB) -> list[dict]: | ||||
| 135 | + """Éclate `usernames` en tranches lancées EN PARALLÈLE sur Apify. | ||||
| 136 | + | ||||
| 137 | + Chaque tranche = un run indépendant (mémoire dédiée → plus de CPU). On | ||||
| 138 | + plafonne à `max_shards` runs simultanés (256 Go de RAM = large marge : | ||||
| 139 | + 12 × 4 Go = 48 Go). Les datasets sont fusionnés. Une tranche qui échoue | ||||
| 140 | + n'annule pas les autres. | ||||
| 141 | + """ | ||||
| 142 | + if not usernames: | ||||
| 143 | + return [] | ||||
| 144 | + n = max(1, min(max_shards, | ||||
| 145 | + (len(usernames) + shard_size - 1) // shard_size)) | ||||
| 146 | + shards = [usernames[i::n] for i in range(n)] # répartition équilibrée | ||||
| 147 | + items: list[dict] = [] | ||||
| 148 | + with ThreadPoolExecutor(max_workers=n) as pool: | ||||
| 149 | + futs = {pool.submit(run_actor, name, | ||||
| 150 | + {**base_input, "usernames": shard}, | ||||
| 151 | + timeout_s=timeout_s, memory_mb=memory_mb): i | ||||
| 152 | + for i, shard in enumerate(shards) if shard} | ||||
| 153 | + for fut in as_completed(futs): | ||||
| 154 | + try: | ||||
| 155 | + items.extend(fut.result()) | ||||
| 156 | + except Exception as exc: # une tranche morte ne bloque pas le reste | ||||
| 157 | + print(f"[crea-ka] {name} tranche {futs[fut]} échouée : {exc}") | ||||
| 158 | + return items | ||||
| 159 | + | ||||
| 160 | + | ||||
| 96 | class _ApifySocialEnrich(BaseConnector): | 161 | class _ApifySocialEnrich(BaseConnector): | ||
| 97 | """Base commune des enrichissements Apify (un acteur par plateforme).""" | 162 | """Base commune des enrichissements Apify (un acteur par plateforme).""" | ||
| 98 | 163 | ||||
| 99 | kind = "enrichment" | 164 | kind = "enrichment" | ||
| 100 | platform = "" # plateforme canonique (§6.2) | 165 | platform = "" # plateforme canonique (§6.2) | ||
| 101 | actor = "" # nom court de l'acteur (ka-instagram…) | 166 | actor = "" # nom court de l'acteur (ka-instagram…) | ||
| 102 | − cap = 300 # comptes max par run (maîtrise du coût) | 167 | + cap = 3000 # comptes max par passage (shardé en parallèle) | ||
| 103 | − revisit_days = 5 # ne pas re-sonder un compte plus frais que ça | 168 | + revisit_days = REVISIT_DAYS # re-sonde hebdo par défaut (env APIFY_REVISIT_DAYS) | ||
| 104 | content_key = "" # clé du contenu récent dans l'item acteur | 169 | content_key = "" # clé du contenu récent dans l'item acteur | ||
| 105 | # clés d'item copiées telles quelles dans account.metrics si non nulles | 170 | # clés d'item copiées telles quelles dans account.metrics si non nulles | ||
| 106 | metric_map: dict[str, str] = {} | 171 | metric_map: dict[str, str] = {} | ||
| 107 | 172 | ||||
| 173 | + @property | ||||
| 174 | + def _stamp_key(self) -> str: | ||||
| 175 | + # tampon PROPRE au connecteur : quand CE connecteur a enrichi ce compte. | ||||
| 176 | + # On ne se base PAS sur acc.last_checked, re-tamponné par la découverte | ||||
| 177 | + # (kick-decouverte etc.) même sans enrichissement → fausse fraîcheur. | ||||
| 178 | + return f"{self.source_id}_at" | ||||
| 179 | + | ||||
| 108 | def _stale(self, acc) -> bool: | 180 | def _stale(self, acc) -> bool: | ||
| 109 | − if not acc.last_checked: | 181 | + stamp = (acc.metrics or {}).get(self._stamp_key) | ||
| 182 | + if not stamp: | ||||
| 110 | return True | 183 | return True | ||
| 111 | try: | 184 | try: | ||
| 112 | − seen = datetime.fromisoformat( | 185 | + seen = datetime.fromisoformat(str(stamp).replace("Z", "+00:00")) | ||
| 113 | − acc.last_checked.replace("Z", "+00:00")) | ||||
| 114 | except ValueError: | 186 | except ValueError: | ||
| 115 | return True | 187 | return True | ||
| 116 | return (datetime.now(timezone.utc) - seen | 188 | return (datetime.now(timezone.utc) - seen | ||
@@ -119,6 +191,16 @@ class _ApifySocialEnrich(BaseConnector): | |||||
| 119 | def extra_input(self) -> dict: | 191 | def extra_input(self) -> dict: | ||
| 120 | return {} | 192 | return {} | ||
| 121 | 193 | ||||
| 194 | + def target_of(self, acc) -> str: | ||||
| 195 | + """Valeur envoyée à l'acteur pour ce compte (défaut : le handle). | ||||
| 196 | + | ||||
| 197 | + Certaines plateformes exigent autre chose que le handle minusculé — | ||||
| 198 | + ex. Discord, dont le code d'invitation est SENSIBLE À LA CASSE et doit | ||||
| 199 | + être repris depuis l'URL. Le rapprochement se fait ensuite en | ||||
| 200 | + minuscules des deux côtés. | ||||
| 201 | + """ | ||||
| 202 | + return acc.handle | ||||
| 203 | + | ||||
| 122 | def enrich(self, creators: list[Creator]) -> list[Creator]: | 204 | def enrich(self, creators: list[Creator]) -> list[Creator]: | ||
| 123 | targets: dict[str, list] = {} | 205 | targets: dict[str, list] = {} | ||
| 124 | for cr in creators: | 206 | for cr in creators: | ||
@@ -126,22 +208,23 @@ class _ApifySocialEnrich(BaseConnector): | |||||
| 126 | if a.platform == self.platform and a.handle), None) | 208 | if a.platform == self.platform and a.handle), None) | ||
| 127 | if acc is None or not self._stale(acc): | 209 | if acc is None or not self._stale(acc): | ||
| 128 | continue | 210 | continue | ||
| 129 | − targets.setdefault(acc.handle, []).append((cr, acc)) | 211 | + targets.setdefault(self.target_of(acc), []).append((cr, acc)) | ||
| 130 | if len(targets) >= self.cap: | 212 | if len(targets) >= self.cap: | ||
| 131 | break | 213 | break | ||
| 132 | if not targets: | 214 | if not targets: | ||
| 133 | return [] | 215 | return [] | ||
| 134 | − items = run_actor(self.actor, { | 216 | + items = run_actor_sharded( | ||
| 135 | − "usernames": sorted(targets), | 217 | + self.actor, | ||
| 136 | − "proxyConfiguration": RESIDENTIAL, | 218 | + {"proxyConfiguration": RESIDENTIAL, | ||
| 137 | − **self.extra_input(), | 219 | + "concurrency": RUN_CONCURRENCY, | ||
| 138 | − }) | 220 | + **self.extra_input()}, | ||
| 221 | + sorted(targets)) | ||||
| 139 | by_handle = {str(it.get("username") or "").lower(): it | 222 | by_handle = {str(it.get("username") or "").lower(): it | ||
| 140 | for it in items if it.get("kind") == "profile"} | 223 | for it in items if it.get("kind") == "profile"} | ||
| 141 | enriched: list[Creator] = [] | 224 | enriched: list[Creator] = [] | ||
| 142 | self.errors = 0 | 225 | self.errors = 0 | ||
| 143 | for handle, pairs in targets.items(): | 226 | for handle, pairs in targets.items(): | ||
| 144 | − it = by_handle.get(handle) | 227 | + it = by_handle.get(handle.lower()) | ||
| 145 | if it is None: | 228 | if it is None: | ||
| 146 | continue | 229 | continue | ||
| 147 | if not it.get("found"): | 230 | if not it.get("found"): | ||
@@ -163,6 +246,7 @@ class _ApifySocialEnrich(BaseConnector): | |||||
| 163 | if it.get(src) is not None} | 246 | if it.get(src) is not None} | ||
| 164 | if self.content_key and it.get(self.content_key): | 247 | if self.content_key and it.get(self.content_key): | ||
| 165 | metrics[self.content_key] = it[self.content_key][:12] | 248 | metrics[self.content_key] = it[self.content_key][:12] | ||
| 249 | + metrics[self._stamp_key] = now_iso() # tampon d'enrichissement propre | ||||
| 166 | acc.metrics.update(metrics) | 250 | acc.metrics.update(metrics) | ||
| 167 | if not cr.avatar_url and it.get("avatar"): | 251 | if not cr.avatar_url and it.get("avatar"): | ||
| 168 | cr.avatar_url = it["avatar"] | 252 | cr.avatar_url = it["avatar"] | ||
@@ -195,7 +279,7 @@ class ApifyInstagram(_ApifySocialEnrich): | |||||
| 195 | source_id = "instagram-apify" | 279 | source_id = "instagram-apify" | ||
| 196 | platform = "instagram" | 280 | platform = "instagram" | ||
| 197 | actor = "ka-instagram" | 281 | actor = "ka-instagram" | ||
| 198 | − cap = 400 | 282 | + cap = 1800 | ||
| 199 | content_key = "recent_posts" | 283 | content_key = "recent_posts" | ||
| 200 | metric_map = {"following": "following", "posts_count": "posts", | 284 | metric_map = {"following": "following", "posts_count": "posts", | ||
| 201 | "category": "category", "is_business": "is_business", | 285 | "category": "category", "is_business": "is_business", | ||
@@ -224,7 +308,7 @@ class ApifyTikTok(_ApifySocialEnrich): | |||||
| 224 | source_id = "tiktok-apify" | 308 | source_id = "tiktok-apify" | ||
| 225 | platform = "tiktok" | 309 | platform = "tiktok" | ||
| 226 | actor = "ka-tiktok" | 310 | actor = "ka-tiktok" | ||
| 227 | − cap = 300 | 311 | + cap = 1800 | ||
| 228 | content_key = "recent_videos" | 312 | content_key = "recent_videos" | ||
| 229 | metric_map = {"following": "following", "total_likes": "likes", | 313 | metric_map = {"following": "following", "total_likes": "likes", | ||
| 230 | "videos_count": "videos", "region": "region", | 314 | "videos_count": "videos", "region": "region", | ||
@@ -245,7 +329,7 @@ class ApifyX(_ApifySocialEnrich): | |||||
| 245 | source_id = "x-apify" | 329 | source_id = "x-apify" | ||
| 246 | platform = "x" | 330 | platform = "x" | ||
| 247 | actor = "ka-x" | 331 | actor = "ka-x" | ||
| 248 | − cap = 300 | 332 | + cap = 1800 | ||
| 249 | content_key = "recent_tweets" | 333 | content_key = "recent_tweets" | ||
| 250 | metric_map = {"following": "following", "tweets_count": "tweets", | 334 | metric_map = {"following": "following", "tweets_count": "tweets", | ||
| 251 | "location": "location", "created_at": "created_at", | 335 | "location": "location", "created_at": "created_at", | ||
@@ -269,7 +353,7 @@ class ApifyFacebook(_ApifySocialEnrich): | |||||
| 269 | source_id = "facebook-apify" | 353 | source_id = "facebook-apify" | ||
| 270 | platform = "facebook" | 354 | platform = "facebook" | ||
| 271 | actor = "ka-facebook" | 355 | actor = "ka-facebook" | ||
| 272 | − cap = 100 | 356 | + cap = 400 | ||
| 273 | revisit_days = 7 | 357 | revisit_days = 7 | ||
| 274 | metric_map = {"category": "category"} | 358 | metric_map = {"category": "category"} | ||
| 275 | 359 | ||||
@@ -306,7 +390,7 @@ class ApifyYouTube(_ApifySocialEnrich): | |||||
| 306 | source_id = "youtube-apify" | 390 | source_id = "youtube-apify" | ||
| 307 | platform = "youtube" | 391 | platform = "youtube" | ||
| 308 | actor = "ka-youtube" | 392 | actor = "ka-youtube" | ||
| 309 | − cap = 300 | 393 | + cap = 1800 | ||
| 310 | content_key = "recent_videos" | 394 | content_key = "recent_videos" | ||
| 311 | metric_map = {"videos_count": "videos", "country": "country", | 395 | metric_map = {"videos_count": "videos", "country": "country", | ||
| 312 | "keywords": "keywords", "channel_id": "channel_id", | 396 | "keywords": "keywords", "channel_id": "channel_id", | ||
@@ -318,7 +402,7 @@ class ApifyTwitch(_ApifySocialEnrich): | |||||
| 318 | source_id = "twitch-apify" | 402 | source_id = "twitch-apify" | ||
| 319 | platform = "twitch" | 403 | platform = "twitch" | ||
| 320 | actor = "ka-twitch" | 404 | actor = "ka-twitch" | ||
| 321 | − cap = 300 | 405 | + cap = 1200 | ||
| 322 | content_key = "recent_videos" | 406 | content_key = "recent_videos" | ||
| 323 | metric_map = {"is_partner": "is_partner", "is_affiliate": "is_affiliate", | 407 | metric_map = {"is_partner": "is_partner", "is_affiliate": "is_affiliate", | ||
| 324 | "team": "team", "created_at": "created_at", | 408 | "team": "team", "created_at": "created_at", | ||
@@ -334,7 +418,7 @@ class ApifyKick(_ApifySocialEnrich): | |||||
| 334 | source_id = "kick-apify" | 418 | source_id = "kick-apify" | ||
| 335 | platform = "kick" | 419 | platform = "kick" | ||
| 336 | actor = "ka-kick" | 420 | actor = "ka-kick" | ||
| 337 | − cap = 120 | 421 | + cap = 600 | ||
| 338 | metric_map = {"is_live_now": "is_live_now", "live_viewers": "live_viewers", | 422 | metric_map = {"is_live_now": "is_live_now", "live_viewers": "live_viewers", | ||
| 339 | "subscription_enabled": "subscription_enabled", | 423 | "subscription_enabled": "subscription_enabled", | ||
| 340 | "recent_categories": "recent_categories"} | 424 | "recent_categories": "recent_categories"} | ||
@@ -381,13 +465,42 @@ class ApifyFansly(_ApifySocialEnrich): | |||||
| 381 | source_id = "fansly-apify" | 465 | source_id = "fansly-apify" | ||
| 382 | platform = "fansly" | 466 | platform = "fansly" | ||
| 383 | actor = "ka-fansly" | 467 | actor = "ka-fansly" | ||
| 384 | − cap = 200 | 468 | + cap = 600 | ||
| 385 | revisit_days = 7 | 469 | revisit_days = 7 | ||
| 386 | metric_map = {"posts_count": "posts", "images_count": "images", | 470 | metric_map = {"posts_count": "posts", "images_count": "images", | ||
| 387 | "videos_count": "videos", "likes": "likes", | 471 | "videos_count": "videos", "likes": "likes", | ||
| 388 | "following": "following", "location": "location"} | 472 | "following": "following", "location": "location"} | ||
| 389 | 473 | ||||
| 390 | 474 | ||||
| 475 | +class ApifyPatreon(_ApifySocialEnrich): | ||||
| 476 | + source_id = "patreon-apify" | ||||
| 477 | + platform = "patreon" | ||||
| 478 | + actor = "ka-patreon" | ||||
| 479 | + cap = 400 | ||||
| 480 | + revisit_days = 7 | ||||
| 481 | + metric_map = {"patrons": "patrons", "posts_count": "posts", | ||||
| 482 | + "is_monthly": "is_monthly"} | ||||
| 483 | + | ||||
| 484 | + | ||||
| 485 | +class ApifyDiscord(_ApifySocialEnrich): | ||||
| 486 | + source_id = "discord-apify" | ||||
| 487 | + platform = "discord" | ||||
| 488 | + actor = "ka-discord" | ||||
| 489 | + cap = 400 | ||||
| 490 | + revisit_days = 7 | ||||
| 491 | + metric_map = {"members": "members", "online": "online", "boosts": "boosts", | ||||
| 492 | + "partnered": "partnered", "guild_id": "guild_id"} | ||||
| 493 | + | ||||
| 494 | + def target_of(self, acc) -> str: | ||||
| 495 | + """Code d'invitation SENSIBLE À LA CASSE, repris de l'URL (pas du | ||||
| 496 | + handle minusculé) : discord.gg/<CODE> ou discord.com/invite/<CODE>.""" | ||||
| 497 | + url = acc.url or "" | ||||
| 498 | + for sep in ("discord.gg/", "discord.com/invite/", "/invite/"): | ||||
| 499 | + if sep in url: | ||||
| 500 | + return url.split(sep, 1)[1].split("/")[0].split("?")[0] | ||||
| 501 | + return acc.handle | ||||
| 502 | + | ||||
| 503 | + | ||||
| 391 | # --- découverte Instagram (topsearch, mots-clés QC) --------------------------- | 504 | # --- découverte Instagram (topsearch, mots-clés QC) --------------------------- | ||
| 392 | 505 | ||||
| 393 | # thèmes × marqueurs QC — mêmes familles que youtube-recherche, adaptées à la | 506 | # thèmes × marqueurs QC — mêmes familles que youtube-recherche, adaptées à la | ||
added
creaka/connectors/snowball.py
+75 −0
@@ -0,0 +1,75 @@ | |||||
| 1 | +# ============================================================================== | ||||
| 2 | +# Author: Simon-Pierre Boucher <contact@spboucher.ai> | ||||
| 3 | +# File: creaka/connectors/snowball.py | ||||
| 4 | +# Desc: Connecteur DÉCOUVERTE par boule de neige — exploite les profils | ||||
| 5 | +# reliés (`related_profiles`) captés par l'enrichissement Instagram | ||||
| 6 | +# (instagram-apify) pour créer de nouvelles fiches. C'est le levier | ||||
| 7 | +# d'échelle : chaque profil IG suggère ~10-20 comptes similaires → | ||||
| 8 | +# parcours en largeur qui fait croître le bassin de dizaines de milliers | ||||
| 9 | +# au fil des vagues quotidiennes. Aucune requête réseau (lit la base). | ||||
| 10 | +# ============================================================================== | ||||
| 11 | +"""Découverte par boule de neige sur les profils reliés Instagram. | ||||
| 12 | + | ||||
| 13 | +Déclaré `enrichment` pour recevoir la liste des créateurs existants, mais il | ||||
| 14 | +RETOURNE de NOUVELLES fiches (le pipeline sync_source les ajoute par uid). On | ||||
| 15 | +lit `account.metrics["related_profiles"]` (posé par instagram-apify), on écarte | ||||
| 16 | +les handles déjà connus, et on crée une graine par nouveau compte suggéré. | ||||
| 17 | +Signal `mention` (0.60) : proximité algorithmique, à confirmer par | ||||
| 18 | +l'enrichissement — sous le seuil de publication tant que non vérifié (§12.1). | ||||
| 19 | +""" | ||||
| 20 | +from __future__ import annotations | ||||
| 21 | + | ||||
| 22 | +from ..identity import account | ||||
| 23 | +from ..normalize import canonical_url | ||||
| 24 | +from ..schema import Creator | ||||
| 25 | +from .base import BaseConnector | ||||
| 26 | + | ||||
| 27 | + | ||||
| 28 | +class SnowballConnector(BaseConnector): | ||||
| 29 | + source_id = "snowball-ig" | ||||
| 30 | + kind = "enrichment" | ||||
| 31 | + max_new = 4000 # garde-fou par vague | ||||
| 32 | + | ||||
| 33 | + def enrich(self, creators: list[Creator]) -> list[Creator]: | ||||
| 34 | + known: set[str] = set() | ||||
| 35 | + for cr in creators: | ||||
| 36 | + for a in cr.platforms: | ||||
| 37 | + if a.platform == "instagram": | ||||
| 38 | + known.add(a.handle) | ||||
| 39 | + new: list[Creator] = [] | ||||
| 40 | + emitted: set[str] = set() | ||||
| 41 | + for cr in creators: | ||||
| 42 | + ig = next((a for a in cr.platforms | ||||
| 43 | + if a.platform == "instagram"), None) | ||||
| 44 | + if ig is None: | ||||
| 45 | + continue | ||||
| 46 | + for rel in (ig.metrics or {}).get("related_profiles", []) or []: | ||||
| 47 | + handle = (rel.get("username") if isinstance(rel, dict) | ||||
| 48 | + else rel) | ||||
| 49 | + handle = (handle or "").strip().lstrip("@").lower() | ||||
| 50 | + if (not handle or rel and isinstance(rel, dict) | ||||
| 51 | + and rel.get("is_private")): | ||||
| 52 | + continue | ||||
| 53 | + if handle in known or handle in emitted: | ||||
| 54 | + continue | ||||
| 55 | + emitted.add(handle) | ||||
| 56 | + try: | ||||
| 57 | + acc = account("instagram", handle, "mention", | ||||
| 58 | + url=canonical_url("instagram", handle), | ||||
| 59 | + verified=(rel.get("is_verified") | ||||
| 60 | + if isinstance(rel, dict) | ||||
| 61 | + else None)).finalize() | ||||
| 62 | + except Exception: | ||||
| 63 | + continue | ||||
| 64 | + name = (rel.get("full_name") if isinstance(rel, dict) | ||||
| 65 | + else None) or handle | ||||
| 66 | + new.append(Creator( | ||||
| 67 | + source=self.source_id, | ||||
| 68 | + external_id=f"instagram:{handle}", | ||||
| 69 | + display_name=name, | ||||
| 70 | + platforms=[acc], | ||||
| 71 | + notes="découvert par boule de neige (profils reliés IG)", | ||||
| 72 | + )) | ||||
| 73 | + if len(new) >= self.max_new: | ||||
| 74 | + return new | ||||
| 75 | + return new | ||||
added
creaka/connectors/tavily_seed.py
+71 −0
@@ -0,0 +1,71 @@ | |||||
| 1 | +# ============================================================================== | ||||
| 2 | +# Author: Simon-Pierre Boucher <contact@spboucher.ai> | ||||
| 3 | +# File: creaka/connectors/tavily_seed.py | ||||
| 4 | +# Desc: Connecteur DÉCOUVERTE à grande échelle — graines de créateurs | ||||
| 5 | +# québécois moissonnées par le Tavily scout (outils/creator-harvest.py | ||||
| 6 | +# du dépôt groupe-ka-connecteurs) : handles sociaux extraits des pages | ||||
| 7 | +# d'annuaires/palmarès/agences QC. Dataset local (aucune requête ici) : | ||||
| 8 | +# data/seed/qc_creator_seeds.jsonl. L'enrichissement (Apify) vérifie | ||||
| 9 | +# ensuite l'existence et remplit nom/abonnés/contenu. | ||||
| 10 | +# ============================================================================== | ||||
| 11 | +"""Découverte massive par moisson web (Tavily). | ||||
| 12 | + | ||||
| 13 | +Chaque ligne du seed = `{"platform": "...", "handle": "..."}`. On crée une | ||||
| 14 | +fiche par handle avec un compte de plateforme (signal `listes_medias` 0.85 : | ||||
| 15 | +issu de listes publiques concordantes). Les handles qui n'existent pas seront | ||||
| 16 | +simplement non enrichis (found=false côté Apify) ; un balayage d'archivage | ||||
| 17 | +retire à terme les fiches jamais confirmées. But : élargir le bassin de | ||||
| 18 | +créateurs de plusieurs milliers par vague, sans requête réseau à ce stade. | ||||
| 19 | +""" | ||||
| 20 | +from __future__ import annotations | ||||
| 21 | + | ||||
| 22 | +import json | ||||
| 23 | +from pathlib import Path | ||||
| 24 | + | ||||
| 25 | +from ..identity import account | ||||
| 26 | +from ..normalize import canonical_url | ||||
| 27 | +from ..schema import Creator | ||||
| 28 | +from .base import BaseConnector | ||||
| 29 | + | ||||
| 30 | +SEED_PATH = (Path(__file__).resolve().parent.parent.parent | ||||
| 31 | + / "data" / "seed" / "qc_creator_seeds.jsonl") | ||||
| 32 | + | ||||
| 33 | + | ||||
| 34 | +class TavilySeedConnector(BaseConnector): | ||||
| 35 | + source_id = "tavily-seed" | ||||
| 36 | + kind = "discovery" | ||||
| 37 | + | ||||
| 38 | + def fetch(self) -> list[Creator]: | ||||
| 39 | + if not SEED_PATH.exists(): | ||||
| 40 | + return [] # pas encore de moisson : passage vide, pas d'erreur | ||||
| 41 | + creators: list[Creator] = [] | ||||
| 42 | + seen: set[str] = set() | ||||
| 43 | + for line in SEED_PATH.read_text(encoding="utf-8").splitlines(): | ||||
| 44 | + line = line.strip() | ||||
| 45 | + if not line: | ||||
| 46 | + continue | ||||
| 47 | + try: | ||||
| 48 | + row = json.loads(line) | ||||
| 49 | + except json.JSONDecodeError: | ||||
| 50 | + continue | ||||
| 51 | + platform = (row.get("platform") or "").strip().lower() | ||||
| 52 | + handle = (row.get("handle") or "").strip().lstrip("@").lower() | ||||
| 53 | + if not platform or not handle: | ||||
| 54 | + continue | ||||
| 55 | + key = f"{platform}:{handle}" | ||||
| 56 | + if key in seen: | ||||
| 57 | + continue | ||||
| 58 | + seen.add(key) | ||||
| 59 | + try: | ||||
| 60 | + acc = account(platform, handle, "listes_medias", | ||||
| 61 | + url=canonical_url(platform, handle)).finalize() | ||||
| 62 | + except Exception: | ||||
| 63 | + continue | ||||
| 64 | + creators.append(Creator( | ||||
| 65 | + source=self.source_id, | ||||
| 66 | + external_id=key, | ||||
| 67 | + display_name=handle, # nom réel rempli à l'enrichissement | ||||
| 68 | + platforms=[acc], | ||||
| 69 | + notes="découvert par moisson web Tavily (annuaires/palmarès QC)", | ||||
| 70 | + )) | ||||
| 71 | + return creators | ||||
modified
creaka/ingest.py
+2 −2
@@ -30,10 +30,10 @@ from .dedup import dedupe | |||||
| 30 | # ordre d'exécution des connecteurs d'enrichissement — link-in-bio vers la | 30 | # ordre d'exécution des connecteurs d'enrichissement — link-in-bio vers la | ||
| 31 | # fin (il consomme les link_in_bio_url des étapes précédentes) ; bio-liens en | 31 | # fin (il consomme les link_in_bio_url des étapes précédentes) ; bio-liens en | ||
| 32 | # tout dernier (il relit les bios enrichies, sans aucune requête) | 32 | # tout dernier (il relit les bios enrichies, sans aucune requête) | ||
| 33 | −ENRICH_ORDER = ["instagram-apify", "tiktok-apify", "x-apify", | 33 | +ENRICH_ORDER = ["instagram-apify", "snowball-ig", "tiktok-apify", "x-apify", | ||
| 34 | "facebook-apify", "threads-apify", "snapchat-apify", | 34 | "facebook-apify", "threads-apify", "snapchat-apify", | ||
| 35 | "youtube-apify", "twitch-apify", "kick-apify", | 35 | "youtube-apify", "twitch-apify", "kick-apify", | ||
| 36 | − "fansly-apify", | 36 | + "fansly-apify", "patreon-apify", "discord-apify", | ||
| 37 | "instagram-profil", "tiktok-profil", "youtube", "twitch", | 37 | "instagram-profil", "tiktok-profil", "youtube", "twitch", | ||
| 38 | "x-profil", "balados-rss", "podcastindex", | 38 | "x-profil", "balados-rss", "podcastindex", | ||
| 39 | "link-in-bio", "bio-liens", "region-bio"] | 39 | "link-in-bio", "bio-liens", "region-bio"] | ||
added
data/seed/qc_creator_seeds.jsonl
+1271 −0
@@ -0,0 +1,1271 @@ | |||||
| 1 | +{"platform": "instagram", "handle": "ppscanada"} | ||||
| 2 | +{"platform": "instagram", "handle": "engageunhumoriste"} | ||||
| 3 | +{"platform": "youtube", "handle": "engageunhumoriste"} | ||||
| 4 | +{"platform": "x", "handle": "etiennefg"} | ||||
| 5 | +{"platform": "instagram", "handle": "etiennefg"} | ||||
| 6 | +{"platform": "x", "handle": "icircpremiere"} | ||||
| 7 | +{"platform": "x", "handle": "lexpresstoronto"} | ||||
| 8 | +{"platform": "instagram", "handle": "journal_larotonde"} | ||||
| 9 | +{"platform": "x", "handle": "larotonde"} | ||||
| 10 | +{"platform": "x", "handle": "historicacanada"} | ||||
| 11 | +{"platform": "instagram", "handle": "levraijodion"} | ||||
| 12 | +{"platform": "instagram", "handle": "evelyne.r.m"} | ||||
| 13 | +{"platform": "x", "handle": "onfr_tfo"} | ||||
| 14 | +{"platform": "x", "handle": "icirctele"} | ||||
| 15 | +{"platform": "x", "handle": "radiocanadainfo"} | ||||
| 16 | +{"platform": "instagram", "handle": "_lebalbuzard"} | ||||
| 17 | +{"platform": "instagram", "handle": "lecourrierdelanouvelleecosse"} | ||||
| 18 | +{"platform": "tiktok", "handle": "le.courrier"} | ||||
| 19 | +{"platform": "youtube", "handle": "lecourrierdelanouvelle-ecosse"} | ||||
| 20 | +{"platform": "x", "handle": "courrierne1937"} | ||||
| 21 | +{"platform": "twitch", "handle": "montreal"} | ||||
| 22 | +{"platform": "twitch", "handle": "events"} | ||||
| 23 | +{"platform": "instagram", "handle": "seb.lerouxx"} | ||||
| 24 | +{"platform": "instagram", "handle": "amealbert_"} | ||||
| 25 | +{"platform": "instagram", "handle": "nu.skin____"} | ||||
| 26 | +{"platform": "instagram", "handle": "erzu.lie"} | ||||
| 27 | +{"platform": "instagram", "handle": "canada.council"} | ||||
| 28 | +{"platform": "tiktok", "handle": "cbcmontreal"} | ||||
| 29 | +{"platform": "instagram", "handle": "6000mhz"} | ||||
| 30 | +{"platform": "tiktok", "handle": "lp_lapresse"} | ||||
| 31 | +{"platform": "x", "handle": "lp_lapresse"} | ||||
| 32 | +{"platform": "twitch", "handle": "xqc"} | ||||
| 33 | +{"platform": "x", "handle": "cache"} | ||||
| 34 | +{"platform": "twitch", "handle": "dominic"} | ||||
| 35 | +{"platform": "twitch", "handle": "zhartan"} | ||||
| 36 | +{"platform": "twitch", "handle": "p4sc4l"} | ||||
| 37 | +{"platform": "twitch", "handle": "th0ny"} | ||||
| 38 | +{"platform": "twitch", "handle": "marhados"} | ||||
| 39 | +{"platform": "twitch", "handle": "thelfus"} | ||||
| 40 | +{"platform": "twitch", "handle": "corstrix"} | ||||
| 41 | +{"platform": "instagram", "handle": "mathieupellerin"} | ||||
| 42 | +{"platform": "instagram", "handle": "papimelv"} | ||||
| 43 | +{"platform": "twitch", "handle": "gfz_parfait"} | ||||
| 44 | +{"platform": "instagram", "handle": "lewislefou"} | ||||
| 45 | +{"platform": "instagram", "handle": "cocottee"} | ||||
| 46 | +{"platform": "instagram", "handle": "elijah"} | ||||
| 47 | +{"platform": "instagram", "handle": "shahinouest"} | ||||
| 48 | +{"platform": "instagram", "handle": "gfz.parfait"} | ||||
| 49 | +{"platform": "instagram", "handle": "alybrassard"} | ||||
| 50 | +{"platform": "instagram", "handle": "achillefps"} | ||||
| 51 | +{"platform": "instagram", "handle": "arnaud.od"} | ||||
| 52 | +{"platform": "instagram", "handle": "commuquebec"} | ||||
| 53 | +{"platform": "twitch", "handle": "directory"} | ||||
| 54 | +{"platform": "twitch", "handle": "commuquebec"} | ||||
| 55 | +{"platform": "x", "handle": "commuquebec"} | ||||
| 56 | +{"platform": "instagram", "handle": "lelobby.lotoquebec"} | ||||
| 57 | +{"platform": "youtube", "handle": "lelobby-lotoquebec"} | ||||
| 58 | +{"platform": "twitch", "handle": "lotoquebec"} | ||||
| 59 | +{"platform": "twitch", "handle": "acegamersam"} | ||||
| 60 | +{"platform": "twitch", "handle": "alsenic"} | ||||
| 61 | +{"platform": "twitch", "handle": "annamoonz"} | ||||
| 62 | +{"platform": "twitch", "handle": "araashi_"} | ||||
| 63 | +{"platform": "twitch", "handle": "ashtaal"} | ||||
| 64 | +{"platform": "twitch", "handle": "avecsimon"} | ||||
| 65 | +{"platform": "twitch", "handle": "bastienart"} | ||||
| 66 | +{"platform": "twitch", "handle": "lebergy"} | ||||
| 67 | +{"platform": "twitch", "handle": "bethlame"} | ||||
| 68 | +{"platform": "twitch", "handle": "bubblymarie"} | ||||
| 69 | +{"platform": "twitch", "handle": "cafeinelau"} | ||||
| 70 | +{"platform": "twitch", "handle": "camgrandebrune"} | ||||
| 71 | +{"platform": "twitch", "handle": "canellotv"} | ||||
| 72 | +{"platform": "twitch", "handle": "capt_n_bill"} | ||||
| 73 | +{"platform": "twitch", "handle": "charest"} | ||||
| 74 | +{"platform": "twitch", "handle": "charlene"} | ||||
| 75 | +{"platform": "x", "handle": "fr"} | ||||
| 76 | +{"platform": "instagram", "handle": "chanou__"} | ||||
| 77 | +{"platform": "instagram", "handle": "lychesrychee"} | ||||
| 78 | +{"platform": "instagram", "handle": "thesonofhan"} | ||||
| 79 | +{"platform": "instagram", "handle": "itzkevtvv"} | ||||
| 80 | +{"platform": "instagram", "handle": "collabstr"} | ||||
| 81 | +{"platform": "tiktok", "handle": "collabstr.com"} | ||||
| 82 | +{"platform": "instagram", "handle": "heyraion"} | ||||
| 83 | +{"platform": "instagram", "handle": "dwyane101"} | ||||
| 84 | +{"platform": "instagram", "handle": "kevinhana_"} | ||||
| 85 | +{"platform": "instagram", "handle": "itslemonsquares"} | ||||
| 86 | +{"platform": "instagram", "handle": "cadiegrace"} | ||||
| 87 | +{"platform": "instagram", "handle": "awkventurer"} | ||||
| 88 | +{"platform": "instagram", "handle": "babyybaconator"} | ||||
| 89 | +{"platform": "instagram", "handle": "rychee"} | ||||
| 90 | +{"platform": "instagram", "handle": "farhadxray"} | ||||
| 91 | +{"platform": "instagram", "handle": "katbyday"} | ||||
| 92 | +{"platform": "instagram", "handle": "ermillyy"} | ||||
| 93 | +{"platform": "instagram", "handle": "thechocolatecanvas"} | ||||
| 94 | +{"platform": "instagram", "handle": "queenglitterchaos"} | ||||
| 95 | +{"platform": "instagram", "handle": "yeaitsmt"} | ||||
| 96 | +{"platform": "instagram", "handle": "reaperky7"} | ||||
| 97 | +{"platform": "instagram", "handle": "villanarei"} | ||||
| 98 | +{"platform": "instagram", "handle": "ggria"} | ||||
| 99 | +{"platform": "instagram", "handle": "itsbenmalka"} | ||||
| 100 | +{"platform": "instagram", "handle": "chanou"} | ||||
| 101 | +{"platform": "instagram", "handle": "kevinhana"} | ||||
| 102 | +{"platform": "instagram", "handle": "ogrobinson10"} | ||||
| 103 | +{"platform": "instagram", "handle": "marcelo"} | ||||
| 104 | +{"platform": "instagram", "handle": "shinanova"} | ||||
| 105 | +{"platform": "instagram", "handle": "victoriacharlton"} | ||||
| 106 | +{"platform": "instagram", "handle": "oliprimeau"} | ||||
| 107 | +{"platform": "instagram", "handle": "lysandrenadeau"} | ||||
| 108 | +{"platform": "instagram", "handle": "enola.bedard"} | ||||
| 109 | +{"platform": "instagram", "handle": "sj.bleau"} | ||||
| 110 | +{"platform": "instagram", "handle": "laurent.dagenais"} | ||||
| 111 | +{"platform": "instagram", "handle": "aliciamoffet"} | ||||
| 112 | +{"platform": "instagram", "handle": "olivierprimeaubc"} | ||||
| 113 | +{"platform": "instagram", "handle": "elisabethrioux"} | ||||
| 114 | +{"platform": "instagram", "handle": "lefitcook"} | ||||
| 115 | +{"platform": "instagram", "handle": "claudiemercier_"} | ||||
| 116 | +{"platform": "instagram", "handle": "marc_fitt"} | ||||
| 117 | +{"platform": "instagram", "handle": "victoria.charlton"} | ||||
| 118 | +{"platform": "instagram", "handle": "maxgourgues"} | ||||
| 119 | +{"platform": "instagram", "handle": "lucierheaume"} | ||||
| 120 | +{"platform": "instagram", "handle": "rosalielessard_"} | ||||
| 121 | +{"platform": "tiktok", "handle": "enola.bedard"} | ||||
| 122 | +{"platform": "tiktok", "handle": "sjbleau"} | ||||
| 123 | +{"platform": "tiktok", "handle": "laurent.dagenais"} | ||||
| 124 | +{"platform": "tiktok", "handle": "shinanova"} | ||||
| 125 | +{"platform": "tiktok", "handle": "aliciamoffet"} | ||||
| 126 | +{"platform": "tiktok", "handle": "oliprimeau"} | ||||
| 127 | +{"platform": "tiktok", "handle": "lysandrenadeau"} | ||||
| 128 | +{"platform": "tiktok", "handle": "elisabeth.rioux"} | ||||
| 129 | +{"platform": "tiktok", "handle": "lefitcook"} | ||||
| 130 | +{"platform": "tiktok", "handle": "claudiemercier"} | ||||
| 131 | +{"platform": "tiktok", "handle": "victoriacharltonn"} | ||||
| 132 | +{"platform": "tiktok", "handle": "maxgourgues"} | ||||
| 133 | +{"platform": "tiktok", "handle": "lucie_rheaume"} | ||||
| 134 | +{"platform": "tiktok", "handle": "rosalielessard_"} | ||||
| 135 | +{"platform": "youtube", "handle": "enola.bedard"} | ||||
| 136 | +{"platform": "youtube", "handle": "sjbleau"} | ||||
| 137 | +{"platform": "youtube", "handle": "laurentdagenais"} | ||||
| 138 | +{"platform": "youtube", "handle": "shinanovayt"} | ||||
| 139 | +{"platform": "youtube", "handle": "aliciamoffetchannel"} | ||||
| 140 | +{"platform": "youtube", "handle": "olivierprimeau"} | ||||
| 141 | +{"platform": "youtube", "handle": "lysandrenadeau"} | ||||
| 142 | +{"platform": "youtube", "handle": "elisabethrioux7657"} | ||||
| 143 | +{"platform": "youtube", "handle": "lefitcook"} | ||||
| 144 | +{"platform": "youtube", "handle": "claudiemercier"} | ||||
| 145 | +{"platform": "youtube", "handle": "marcfitt"} | ||||
| 146 | +{"platform": "youtube", "handle": "victoriacharlton"} | ||||
| 147 | +{"platform": "youtube", "handle": "maxgourgues7062"} | ||||
| 148 | +{"platform": "youtube", "handle": "lucierheaume6512"} | ||||
| 149 | +{"platform": "youtube", "handle": "rosalielessardd"} | ||||
| 150 | +{"platform": "instagram", "handle": "sjbleau"} | ||||
| 151 | +{"platform": "instagram", "handle": "elisabeth.rioux"} | ||||
| 152 | +{"platform": "instagram", "handle": "claudiemercier"} | ||||
| 153 | +{"platform": "instagram", "handle": "marcfitt"} | ||||
| 154 | +{"platform": "instagram", "handle": "lucie"} | ||||
| 155 | +{"platform": "instagram", "handle": "rosalielessard"} | ||||
| 156 | +{"platform": "twitch", "handle": "quebec"} | ||||
| 157 | +{"platform": "twitch", "handle": "twitch"} | ||||
| 158 | +{"platform": "twitch", "handle": "assets"} | ||||
| 159 | +{"platform": "twitch", "handle": "videos"} | ||||
| 160 | +{"platform": "twitch", "handle": "inlacrimaelacrima"} | ||||
| 161 | +{"platform": "twitch", "handle": "acadianwoman"} | ||||
| 162 | +{"platform": "twitch", "handle": "alisonator"} | ||||
| 163 | +{"platform": "tiktok", "handle": "alisonation"} | ||||
| 164 | +{"platform": "twitch", "handle": "acadie"} | ||||
| 165 | +{"platform": "twitch", "handle": "acadiestream"} | ||||
| 166 | +{"platform": "x", "handle": "foxacadian"} | ||||
| 167 | +{"platform": "instagram", "handle": "foxacadian"} | ||||
| 168 | +{"platform": "instagram", "handle": "xboxuk"} | ||||
| 169 | +{"platform": "instagram", "handle": "noblechairs"} | ||||
| 170 | +{"platform": "instagram", "handle": "bethesda_uk"} | ||||
| 171 | +{"platform": "twitch", "handle": "acadianfox"} | ||||
| 172 | +{"platform": "x", "handle": "compose"} | ||||
| 173 | +{"platform": "x", "handle": "pixelatedvicka"} | ||||
| 174 | +{"platform": "x", "handle": "ff_xiv_en"} | ||||
| 175 | +{"platform": "x", "handle": "xboxuk"} | ||||
| 176 | +{"platform": "x", "handle": "xbox"} | ||||
| 177 | +{"platform": "x", "handle": "noblechairs"} | ||||
| 178 | +{"platform": "x", "handle": "bethesda_uk"} | ||||
| 179 | +{"platform": "x", "handle": "tos"} | ||||
| 180 | +{"platform": "x", "handle": "privacy"} | ||||
| 181 | +{"platform": "x", "handle": "articles"} | ||||
| 182 | +{"platform": "x", "handle": "resources"} | ||||
| 183 | +{"platform": "x", "handle": "en"} | ||||
| 184 | +{"platform": "instagram", "handle": "pixelatedvicka"} | ||||
| 185 | +{"platform": "instagram", "handle": "ff_xiv_en"} | ||||
| 186 | +{"platform": "instagram", "handle": "cbc"} | ||||
| 187 | +{"platform": "x", "handle": "cbc"} | ||||
| 188 | +{"platform": "tiktok", "handle": "alisonator"} | ||||
| 189 | +{"platform": "instagram", "handle": "minutemaquillage"} | ||||
| 190 | +{"platform": "instagram", "handle": "jeanfrancoiscd"} | ||||
| 191 | +{"platform": "instagram", "handle": "avedacanada"} | ||||
| 192 | +{"platform": "instagram", "handle": "virginievandelac"} | ||||
| 193 | +{"platform": "x", "handle": "vvandelac"} | ||||
| 194 | +{"platform": "instagram", "handle": "artistparmarilyn"} | ||||
| 195 | +{"platform": "tiktok", "handle": "artistparmarilyn"} | ||||
| 196 | +{"platform": "youtube", "handle": "artistparmarilyn"} | ||||
| 197 | +{"platform": "instagram", "handle": "lilirougecosmetics"} | ||||
| 198 | +{"platform": "tiktok", "handle": "lilirougecosmetics"} | ||||
| 199 | +{"platform": "instagram", "handle": "lapetitevengeance"} | ||||
| 200 | +{"platform": "instagram", "handle": "marcomarsolais"} | ||||
| 201 | +{"platform": "instagram", "handle": "aj.makeup"} | ||||
| 202 | +{"platform": "instagram", "handle": "sabiehairstylist"} | ||||
| 203 | +{"platform": "instagram", "handle": "luggageandlipstick"} | ||||
| 204 | +{"platform": "x", "handle": "luggage_lipstik"} | ||||
| 205 | +{"platform": "instagram", "handle": "bontraveler"} | ||||
| 206 | +{"platform": "instagram", "handle": "dominicpoirot"} | ||||
| 207 | +{"platform": "instagram", "handle": "lfayos"} | ||||
| 208 | +{"platform": "instagram", "handle": "loredana"} | ||||
| 209 | +{"platform": "instagram", "handle": "miss"} | ||||
| 210 | +{"platform": "instagram", "handle": "dermacureqc"} | ||||
| 211 | +{"platform": "instagram", "handle": "emmasroadmap"} | ||||
| 212 | +{"platform": "instagram", "handle": "antonioortegacouture"} | ||||
| 213 | +{"platform": "instagram", "handle": "mmodemtl"} | ||||
| 214 | +{"platform": "tiktok", "handle": "mmodemtl"} | ||||
| 215 | +{"platform": "youtube", "handle": "mmodelagrappemetropolitain4872"} | ||||
| 216 | +{"platform": "x", "handle": "linbleu"} | ||||
| 217 | +{"platform": "x", "handle": "gouvqc"} | ||||
| 218 | +{"platform": "instagram", "handle": "ellequebec"} | ||||
| 219 | +{"platform": "tiktok", "handle": "ellequebec"} | ||||
| 220 | +{"platform": "x", "handle": "ellequebec"} | ||||
| 221 | +{"platform": "instagram", "handle": "fringueefutee"} | ||||
| 222 | +{"platform": "instagram", "handle": "urbainedeschamps"} | ||||
| 223 | +{"platform": "instagram", "handle": "cestelle.ca"} | ||||
| 224 | +{"platform": "tiktok", "handle": "cestelle.ca"} | ||||
| 225 | +{"platform": "x", "handle": "cestellemode"} | ||||
| 226 | +{"platform": "instagram", "handle": "centrerockland"} | ||||
| 227 | +{"platform": "x", "handle": "centrerockland"} | ||||
| 228 | +{"platform": "instagram", "handle": "destinationnb"} | ||||
| 229 | +{"platform": "instagram", "handle": "village_acadien"} | ||||
| 230 | +{"platform": "youtube", "handle": "villagehistoriqueacadien_nb"} | ||||
| 231 | +{"platform": "instagram", "handle": "clubsportifmaa"} | ||||
| 232 | +{"platform": "instagram", "handle": "timeoutmontreal"} | ||||
| 233 | +{"platform": "instagram", "handle": "b52fit"} | ||||
| 234 | +{"platform": "instagram", "handle": "epix"} | ||||
| 235 | +{"platform": "instagram", "handle": "morphobleu.studio"} | ||||
| 236 | +{"platform": "instagram", "handle": "monstergymmtl"} | ||||
| 237 | +{"platform": "instagram", "handle": "cepsum"} | ||||
| 238 | +{"platform": "x", "handle": "cflri_icrcp"} | ||||
| 239 | +{"platform": "instagram", "handle": "econofitness"} | ||||
| 240 | +{"platform": "instagram", "handle": "jessica.b.25"} | ||||
| 241 | +{"platform": "instagram", "handle": "laulabo"} | ||||
| 242 | +{"platform": "instagram", "handle": "kaily"} | ||||
| 243 | +{"platform": "instagram", "handle": "fitnesssanteplus"} | ||||
| 244 | +{"platform": "tiktok", "handle": "fitnesssanteplus"} | ||||
| 245 | +{"platform": "instagram", "handle": "_chez_ashton_"} | ||||
| 246 | +{"platform": "instagram", "handle": "_qu"} | ||||
| 247 | +{"platform": "instagram", "handle": "_la_banquise_"} | ||||
| 248 | +{"platform": "instagram", "handle": "_le_plateau_"} | ||||
| 249 | +{"platform": "instagram", "handle": "_montr"} | ||||
| 250 | +{"platform": "instagram", "handle": "_poutineville_"} | ||||
| 251 | +{"platform": "instagram", "handle": "mywanderingvoyage"} | ||||
| 252 | +{"platform": "tiktok", "handle": "mywanderingvoyage"} | ||||
| 253 | +{"platform": "youtube", "handle": "mywanderingvoyage"} | ||||
| 254 | +{"platform": "instagram", "handle": "ontario"} | ||||
| 255 | +{"platform": "instagram", "handle": "scichefqc"} | ||||
| 256 | +{"platform": "x", "handle": "scichefqc"} | ||||
| 257 | +{"platform": "x", "handle": "francoislegault"} | ||||
| 258 | +{"platform": "instagram", "handle": "francoislegault"} | ||||
| 259 | +{"platform": "instagram", "handle": "frederiqueguay"} | ||||
| 260 | +{"platform": "x", "handle": "frederiqueguay"} | ||||
| 261 | +{"platform": "instagram", "handle": "urbanblisslife"} | ||||
| 262 | +{"platform": "tiktok", "handle": "urbanblisslife"} | ||||
| 263 | +{"platform": "x", "handle": "urbanblisslife"} | ||||
| 264 | +{"platform": "instagram", "handle": "noussommes.cafe"} | ||||
| 265 | +{"platform": "instagram", "handle": "berniebeigne"} | ||||
| 266 | +{"platform": "instagram", "handle": "lindork"} | ||||
| 267 | +{"platform": "instagram", "handle": "smithani"} | ||||
| 268 | +{"platform": "instagram", "handle": "suko287"} | ||||
| 269 | +{"platform": "instagram", "handle": "pamelinachang"} | ||||
| 270 | +{"platform": "instagram", "handle": "ginger"} | ||||
| 271 | +{"platform": "instagram", "handle": "erinbayly"} | ||||
| 272 | +{"platform": "instagram", "handle": "patisserie.coco"} | ||||
| 273 | +{"platform": "instagram", "handle": "kinkaizakayamtl"} | ||||
| 274 | +{"platform": "instagram", "handle": "raviolismaixiangyuan"} | ||||
| 275 | +{"platform": "instagram", "handle": "ottoyakitori"} | ||||
| 276 | +{"platform": "instagram", "handle": "fairmountbagel"} | ||||
| 277 | +{"platform": "instagram", "handle": "stviateurbagel"} | ||||
| 278 | +{"platform": "instagram", "handle": "bargeorgemtl"} | ||||
| 279 | +{"platform": "instagram", "handle": "lemalnecessaire"} | ||||
| 280 | +{"platform": "instagram", "handle": "lepetitdep"} | ||||
| 281 | +{"platform": "instagram", "handle": "kemcoba"} | ||||
| 282 | +{"platform": "instagram", "handle": "ladiperie"} | ||||
| 283 | +{"platform": "instagram", "handle": "zettiscremerie"} | ||||
| 284 | +{"platform": "instagram", "handle": "gibeauorangejulep"} | ||||
| 285 | +{"platform": "instagram", "handle": "restaurantaupieddecochon"} | ||||
| 286 | +{"platform": "instagram", "handle": "restaurant_cadet"} | ||||
| 287 | +{"platform": "instagram", "handle": "fiorellinosnackbar"} | ||||
| 288 | +{"platform": "instagram", "handle": "boustanrestaurant"} | ||||
| 289 | +{"platform": "instagram", "handle": "restolabanquise"} | ||||
| 290 | +{"platform": "instagram", "handle": "restobarmontrealpoutine"} | ||||
| 291 | +{"platform": "instagram", "handle": "schwartzsofficial"} | ||||
| 292 | +{"platform": "instagram", "handle": "ginger_mariah"} | ||||
| 293 | +{"platform": "instagram", "handle": "larisaopar"} | ||||
| 294 | +{"platform": "instagram", "handle": "biancaangotti"} | ||||
| 295 | +{"platform": "instagram", "handle": "jillds"} | ||||
| 296 | +{"platform": "instagram", "handle": "chels.robbins"} | ||||
| 297 | +{"platform": "instagram", "handle": "jengeegee"} | ||||
| 298 | +{"platform": "instagram", "handle": "shevonlam"} | ||||
| 299 | +{"platform": "instagram", "handle": "anisha_natalie"} | ||||
| 300 | +{"platform": "instagram", "handle": "gina._._marie"} | ||||
| 301 | +{"platform": "instagram", "handle": "dani.kuni"} | ||||
| 302 | +{"platform": "instagram", "handle": "maryannstep"} | ||||
| 303 | +{"platform": "instagram", "handle": "hopeful_li_soon"} | ||||
| 304 | +{"platform": "instagram", "handle": "fromnikiwithlove"} | ||||
| 305 | +{"platform": "instagram", "handle": "debs_wolf"} | ||||
| 306 | +{"platform": "instagram", "handle": "piggtailgirl"} | ||||
| 307 | +{"platform": "instagram", "handle": "rachelsrunway"} | ||||
| 308 | +{"platform": "instagram", "handle": "sketpicaljess"} | ||||
| 309 | +{"platform": "instagram", "handle": "justalillost"} | ||||
| 310 | +{"platform": "instagram", "handle": "elliotgaltgirl"} | ||||
| 311 | +{"platform": "instagram", "handle": "dr.neuroshannon"} | ||||
| 312 | +{"platform": "instagram", "handle": "sparrowandherbabies"} | ||||
| 313 | +{"platform": "instagram", "handle": "hiphu"} | ||||
| 314 | +{"platform": "instagram", "handle": "ansareece"} | ||||
| 315 | +{"platform": "instagram", "handle": "donopon"} | ||||
| 316 | +{"platform": "instagram", "handle": "hip_bean"} | ||||
| 317 | +{"platform": "instagram", "handle": "jaypeacee"} | ||||
| 318 | +{"platform": "instagram", "handle": "miktacular"} | ||||
| 319 | +{"platform": "instagram", "handle": "_paula.espinoza_"} | ||||
| 320 | +{"platform": "instagram", "handle": "dgordaneer"} | ||||
| 321 | +{"platform": "instagram", "handle": "pundogz"} | ||||
| 322 | +{"platform": "instagram", "handle": "anothernisha"} | ||||
| 323 | +{"platform": "instagram", "handle": "michelle835"} | ||||
| 324 | +{"platform": "instagram", "handle": "violet_pretty"} | ||||
| 325 | +{"platform": "instagram", "handle": "lillhabits"} | ||||
| 326 | +{"platform": "instagram", "handle": "habanerogal"} | ||||
| 327 | +{"platform": "instagram", "handle": "hojurific81"} | ||||
| 328 | +{"platform": "instagram", "handle": "devonhamplas"} | ||||
| 329 | +{"platform": "instagram", "handle": "dani_beee"} | ||||
| 330 | +{"platform": "instagram", "handle": "hunkaa.a"} | ||||
| 331 | +{"platform": "instagram", "handle": "adventuresofdustydoodle"} | ||||
| 332 | +{"platform": "instagram", "handle": "bestofshi"} | ||||
| 333 | +{"platform": "instagram", "handle": "asianting24"} | ||||
| 334 | +{"platform": "instagram", "handle": "shanss33"} | ||||
| 335 | +{"platform": "instagram", "handle": "miss_erin"} | ||||
| 336 | +{"platform": "instagram", "handle": "maepiq"} | ||||
| 337 | +{"platform": "instagram", "handle": "leslievarty"} | ||||
| 338 | +{"platform": "instagram", "handle": "mxmlvanity"} | ||||
| 339 | +{"platform": "instagram", "handle": "ofeliamtl2014"} | ||||
| 340 | +{"platform": "instagram", "handle": "kristenanto"} | ||||
| 341 | +{"platform": "instagram", "handle": "northernmint"} | ||||
| 342 | +{"platform": "instagram", "handle": "phoenixindacity"} | ||||
| 343 | +{"platform": "instagram", "handle": "kormachameleon"} | ||||
| 344 | +{"platform": "instagram", "handle": "liiveitout"} | ||||
| 345 | +{"platform": "instagram", "handle": "bom.yeg"} | ||||
| 346 | +{"platform": "instagram", "handle": "willing_an_abel"} | ||||
| 347 | +{"platform": "instagram", "handle": "natalie.mw"} | ||||
| 348 | +{"platform": "instagram", "handle": "jennie_fer"} | ||||
| 349 | +{"platform": "instagram", "handle": "alexandrabeley"} | ||||
| 350 | +{"platform": "instagram", "handle": "activechacha"} | ||||
| 351 | +{"platform": "instagram", "handle": "katierainboww"} | ||||
| 352 | +{"platform": "instagram", "handle": "thatjenk"} | ||||
| 353 | +{"platform": "instagram", "handle": "joannechau7"} | ||||
| 354 | +{"platform": "instagram", "handle": "globaljesus"} | ||||
| 355 | +{"platform": "instagram", "handle": "lieu.ski"} | ||||
| 356 | +{"platform": "instagram", "handle": "cup_of_josephine"} | ||||
| 357 | +{"platform": "instagram", "handle": "argenplath"} | ||||
| 358 | +{"platform": "instagram", "handle": "mig14"} | ||||
| 359 | +{"platform": "instagram", "handle": "genevieveshylo"} | ||||
| 360 | +{"platform": "tiktok", "handle": "lindorable"} | ||||
| 361 | +{"platform": "x", "handle": "lindork"} | ||||
| 362 | +{"platform": "x", "handle": "stviateurbagel"} | ||||
| 363 | +{"platform": "x", "handle": "pieddecochonmtl"} | ||||
| 364 | +{"platform": "x", "handle": "boustanmontreal"} | ||||
| 365 | +{"platform": "x", "handle": "montrealpoutine"} | ||||
| 366 | +{"platform": "instagram", "handle": "anisha"} | ||||
| 367 | +{"platform": "instagram", "handle": "gina"} | ||||
| 368 | +{"platform": "instagram", "handle": "hopeful"} | ||||
| 369 | +{"platform": "instagram", "handle": "debs"} | ||||
| 370 | +{"platform": "instagram", "handle": "rumbiman"} | ||||
| 371 | +{"platform": "instagram", "handle": "hip"} | ||||
| 372 | +{"platform": "instagram", "handle": "violet"} | ||||
| 373 | +{"platform": "instagram", "handle": "dani"} | ||||
| 374 | +{"platform": "instagram", "handle": "rwlovesfood"} | ||||
| 375 | +{"platform": "instagram", "handle": "arthursmtl"} | ||||
| 376 | +{"platform": "instagram", "handle": "willing"} | ||||
| 377 | +{"platform": "instagram", "handle": "jennie"} | ||||
| 378 | +{"platform": "instagram", "handle": "cup"} | ||||
| 379 | +{"platform": "instagram", "handle": "ohayocafemtl"} | ||||
| 380 | +{"platform": "instagram", "handle": "mapoulemouillee"} | ||||
| 381 | +{"platform": "instagram", "handle": "marcisurlaplaza"} | ||||
| 382 | +{"platform": "instagram", "handle": "tovogueorbust"} | ||||
| 383 | +{"platform": "x", "handle": "tovogueorbust"} | ||||
| 384 | +{"platform": "instagram", "handle": "glowtherapy"} | ||||
| 385 | +{"platform": "instagram", "handle": "mollylowerealtor"} | ||||
| 386 | +{"platform": "instagram", "handle": "mosaic_homes"} | ||||
| 387 | +{"platform": "instagram", "handle": "passion.escalade"} | ||||
| 388 | +{"platform": "instagram", "handle": "canyoningquebec"} | ||||
| 389 | +{"platform": "instagram", "handle": "au_canot_volant"} | ||||
| 390 | +{"platform": "instagram", "handle": "flora.bidaud"} | ||||
| 391 | +{"platform": "instagram", "handle": "ferme5etoiles"} | ||||
| 392 | +{"platform": "instagram", "handle": "meretmonde"} | ||||
| 393 | +{"platform": "instagram", "handle": "parckiamika"} | ||||
| 394 | +{"platform": "instagram", "handle": "parcpoissonblanc"} | ||||
| 395 | +{"platform": "instagram", "handle": "noryak_aventures"} | ||||
| 396 | +{"platform": "instagram", "handle": "noryak"} | ||||
| 397 | +{"platform": "instagram", "handle": "duvetnor"} | ||||
| 398 | +{"platform": "instagram", "handle": "echappee.bleue"} | ||||
| 399 | +{"platform": "instagram", "handle": "aventurequebec"} | ||||
| 400 | +{"platform": "instagram", "handle": "nature_aventure"} | ||||
| 401 | +{"platform": "instagram", "handle": "attitudenordique"} | ||||
| 402 | +{"platform": "instagram", "handle": "lesvagueshsp"} | ||||
| 403 | +{"platform": "instagram", "handle": "nature"} | ||||
| 404 | +{"platform": "instagram", "handle": "ottawatourism"} | ||||
| 405 | +{"platform": "tiktok", "handle": "ottawatourism"} | ||||
| 406 | +{"platform": "instagram", "handle": "liftoronto"} | ||||
| 407 | +{"platform": "youtube", "handle": "acpnation"} | ||||
| 408 | +{"platform": "x", "handle": "acpnation"} | ||||
| 409 | +{"platform": "x", "handle": "tele_mag_quebec"} | ||||
| 410 | +{"platform": "instagram", "handle": "tourismeontario"} | ||||
| 411 | +{"platform": "instagram", "handle": "_seripop_"} | ||||
| 412 | +{"platform": "instagram", "handle": "spotify"} | ||||
| 413 | +{"platform": "x", "handle": "spotify"} | ||||
| 414 | +{"platform": "instagram", "handle": "francomusique"} | ||||
| 415 | +{"platform": "x", "handle": "rocharchambault"} | ||||
| 416 | +{"platform": "instagram", "handle": "francaisavenir"} | ||||
| 417 | +{"platform": "x", "handle": "francaisavenir"} | ||||
| 418 | +{"platform": "instagram", "handle": "af_ottawa"} | ||||
| 419 | +{"platform": "x", "handle": "afottawa"} | ||||
| 420 | +{"platform": "instagram", "handle": "safwanmtl"} | ||||
| 421 | +{"platform": "instagram", "handle": "_celine_dion_concert.jpg"} | ||||
| 422 | +{"platform": "instagram", "handle": "hhqcofficiel"} | ||||
| 423 | +{"platform": "x", "handle": "hhqc"} | ||||
| 424 | +{"platform": "x", "handle": "hockeyrapper"} | ||||
| 425 | +{"platform": "instagram", "handle": "impac5canada"} | ||||
| 426 | +{"platform": "x", "handle": "impac5canada"} | ||||
| 427 | +{"platform": "instagram", "handle": "mtlelectronicmusic"} | ||||
| 428 | +{"platform": "instagram", "handle": "polyson"} | ||||
| 429 | +{"platform": "x", "handle": "edmmontreal"} | ||||
| 430 | +{"platform": "instagram", "handle": "edmtrain"} | ||||
| 431 | +{"platform": "instagram", "handle": "cassian"} | ||||
| 432 | +{"platform": "instagram", "handle": "bushbabybeats"} | ||||
| 433 | +{"platform": "instagram", "handle": "codymusic_"} | ||||
| 434 | +{"platform": "instagram", "handle": "whalesfm"} | ||||
| 435 | +{"platform": "instagram", "handle": "duskymusic"} | ||||
| 436 | +{"platform": "instagram", "handle": "romanceplanet"} | ||||
| 437 | +{"platform": "instagram", "handle": "avenueonemusic"} | ||||
| 438 | +{"platform": "instagram", "handle": "catalystgmail.com2"} | ||||
| 439 | +{"platform": "instagram", "handle": "sietch514"} | ||||
| 440 | +{"platform": "instagram", "handle": "rosasharin"} | ||||
| 441 | +{"platform": "instagram", "handle": "flytzmusic"} | ||||
| 442 | +{"platform": "instagram", "handle": "giorgia_angiuli"} | ||||
| 443 | +{"platform": "instagram", "handle": "felixpatry_"} | ||||
| 444 | +{"platform": "instagram", "handle": "kendal_ritmofatale"} | ||||
| 445 | +{"platform": "instagram", "handle": "mcmandiz"} | ||||
| 446 | +{"platform": "instagram", "handle": "noprospectscollective"} | ||||
| 447 | +{"platform": "instagram", "handle": "t78official"} | ||||
| 448 | +{"platform": "youtube", "handle": "emersonwoolf"} | ||||
| 449 | +{"platform": "instagram", "handle": "djprosper22"} | ||||
| 450 | +{"platform": "instagram", "handle": "1djjfro"} | ||||
| 451 | +{"platform": "instagram", "handle": "shiftermagazine"} | ||||
| 452 | +{"platform": "x", "handle": "shiftermagazine"} | ||||
| 453 | +{"platform": "instagram", "handle": "mrfloetic"} | ||||
| 454 | +{"platform": "instagram", "handle": "rxckz"} | ||||
| 455 | +{"platform": "instagram", "handle": "nightafternight"} | ||||
| 456 | +{"platform": "instagram", "handle": "eazyeldee"} | ||||
| 457 | +{"platform": "instagram", "handle": "djcsik"} | ||||
| 458 | +{"platform": "instagram", "handle": "sebcwestcoast"} | ||||
| 459 | +{"platform": "instagram", "handle": "djandre905"} | ||||
| 460 | +{"platform": "instagram", "handle": "rocswellradio"} | ||||
| 461 | +{"platform": "instagram", "handle": "dj.ftp"} | ||||
| 462 | +{"platform": "instagram", "handle": "topkatamazona"} | ||||
| 463 | +{"platform": "instagram", "handle": "godfather"} | ||||
| 464 | +{"platform": "instagram", "handle": "djfrankvinatra"} | ||||
| 465 | +{"platform": "instagram", "handle": "iamdjfusion"} | ||||
| 466 | +{"platform": "instagram", "handle": "icytouch"} | ||||
| 467 | +{"platform": "instagram", "handle": "djrychkydd"} | ||||
| 468 | +{"platform": "instagram", "handle": "lecolededansedequebec"} | ||||
| 469 | +{"platform": "instagram", "handle": "revuejeu"} | ||||
| 470 | +{"platform": "instagram", "handle": "enmoderythme"} | ||||
| 471 | +{"platform": "tiktok", "handle": "rythme105.7"} | ||||
| 472 | +{"platform": "youtube", "handle": "cogecomedia"} | ||||
| 473 | +{"platform": "x", "handle": "zaptele"} | ||||
| 474 | +{"platform": "instagram", "handle": "agence.m"} | ||||
| 475 | +{"platform": "instagram", "handle": "policy"} | ||||
| 476 | +{"platform": "instagram", "handle": "motelstudio"} | ||||
| 477 | +{"platform": "instagram", "handle": "moniteuracadien"} | ||||
| 478 | +{"platform": "tiktok", "handle": "jasonjouellette"} | ||||
| 479 | +{"platform": "youtube", "handle": "lemoniteuracadien"} | ||||
| 480 | +{"platform": "instagram", "handle": "onf_nfb"} | ||||
| 481 | +{"platform": "tiktok", "handle": "nfb_onf"} | ||||
| 482 | +{"platform": "x", "handle": "onf"} | ||||
| 483 | +{"platform": "instagram", "handle": "imdb"} | ||||
| 484 | +{"platform": "tiktok", "handle": "imdb"} | ||||
| 485 | +{"platform": "x", "handle": "imdb"} | ||||
| 486 | +{"platform": "instagram", "handle": "forteartists"} | ||||
| 487 | +{"platform": "instagram", "handle": "agence_ada"} | ||||
| 488 | +{"platform": "x", "handle": "adultes"} | ||||
| 489 | +{"platform": "x", "handle": "adolescents"} | ||||
| 490 | +{"platform": "x", "handle": "enfants"} | ||||
| 491 | +{"platform": "x", "handle": "voix"} | ||||
| 492 | +{"platform": "x", "handle": "variete"} | ||||
| 493 | +{"platform": "x", "handle": "agence"} | ||||
| 494 | +{"platform": "x", "handle": "ecole"} | ||||
| 495 | +{"platform": "x", "handle": "devenir"} | ||||
| 496 | +{"platform": "instagram", "handle": "agencechantalbrossard"} | ||||
| 497 | +{"platform": "instagram", "handle": "moffattariane"} | ||||
| 498 | +{"platform": "instagram", "handle": "anneelisabethbosse"} | ||||
| 499 | +{"platform": "instagram", "handle": "abeillegelinas"} | ||||
| 500 | +{"platform": "instagram", "handle": "emilybegin"} | ||||
| 501 | +{"platform": "instagram", "handle": "karinevanasse"} | ||||
| 502 | +{"platform": "instagram", "handle": "wonderwomanpicture"} | ||||
| 503 | +{"platform": "instagram", "handle": "magalielb"} | ||||
| 504 | +{"platform": "instagram", "handle": "julebreton"} | ||||
| 505 | +{"platform": "instagram", "handle": "mariloupwolfe"} | ||||
| 506 | +{"platform": "instagram", "handle": "mag_clindoeil"} | ||||
| 507 | +{"platform": "tiktok", "handle": "clindoeil.mag"} | ||||
| 508 | +{"platform": "instagram", "handle": "rebeccamakonnen"} | ||||
| 509 | +{"platform": "instagram", "handle": "sophiecads"} | ||||
| 510 | +{"platform": "instagram", "handle": "marieevelynelessard"} | ||||
| 511 | +{"platform": "instagram", "handle": "mariesoleildion"} | ||||
| 512 | +{"platform": "instagram", "handle": "kim_lizotte"} | ||||
| 513 | +{"platform": "instagram", "handle": "virginie_coossa"} | ||||
| 514 | +{"platform": "instagram", "handle": "waitresslacomediemusicale"} | ||||
| 515 | +{"platform": "instagram", "handle": "claudineprevost"} | ||||
| 516 | +{"platform": "instagram", "handle": "moniachokri"} | ||||
| 517 | +{"platform": "x", "handle": "cinemas"} | ||||
| 518 | +{"platform": "x", "handle": "activite"} | ||||
| 519 | +{"platform": "tiktok", "handle": "withnounna"} | ||||
| 520 | +{"platform": "instagram", "handle": "geneanet_officiel"} | ||||
| 521 | +{"platform": "tiktok", "handle": "geneanet"} | ||||
| 522 | +{"platform": "x", "handle": "geneanet"} | ||||
| 523 | +{"platform": "instagram", "handle": "bvachet"} | ||||
| 524 | +{"platform": "x", "handle": "bvachet"} | ||||
| 525 | +{"platform": "instagram", "handle": "maisondesparentsqc"} | ||||
| 526 | +{"platform": "instagram", "handle": "federationparentsacadiensne"} | ||||
| 527 | +{"platform": "youtube", "handle": "federationdesparentsacadie2075"} | ||||
| 528 | +{"platform": "instagram", "handle": "csap.officiel"} | ||||
| 529 | +{"platform": "x", "handle": "arsbfc"} | ||||
| 530 | +{"platform": "instagram", "handle": "ubereats"} | ||||
| 531 | +{"platform": "x", "handle": "ubereats"} | ||||
| 532 | +{"platform": "instagram", "handle": "santequebec.csmtl"} | ||||
| 533 | +{"platform": "youtube", "handle": "santequebec.csimtl"} | ||||
| 534 | +{"platform": "x", "handle": "montrealcc"} | ||||
| 535 | +{"platform": "x", "handle": "lacnpf"} | ||||
| 536 | +{"platform": "instagram", "handle": "fcfacanada"} | ||||
| 537 | +{"platform": "x", "handle": "fcfacanada"} | ||||
| 538 | +{"platform": "instagram", "handle": "samueltessierphotographe"} | ||||
| 539 | +{"platform": "youtube", "handle": "hellodarwin8652"} | ||||
| 540 | +{"platform": "instagram", "handle": "anniesimardphoto"} | ||||
| 541 | +{"platform": "instagram", "handle": "royaltonbavaroresort"} | ||||
| 542 | +{"platform": "instagram", "handle": "kaudet100"} | ||||
| 543 | +{"platform": "instagram", "handle": "fairmont"} | ||||
| 544 | +{"platform": "instagram", "handle": "fairmontfrontenac"} | ||||
| 545 | +{"platform": "instagram", "handle": "sparksmariages"} | ||||
| 546 | +{"platform": "instagram", "handle": "elodiefleuriste"} | ||||
| 547 | +{"platform": "instagram", "handle": "djkevinolsen"} | ||||
| 548 | +{"platform": "instagram", "handle": "lavieestunefete.ca"} | ||||
| 549 | +{"platform": "instagram", "handle": "groupeabp"} | ||||
| 550 | +{"platform": "instagram", "handle": "4elevation.ca"} | ||||
| 551 | +{"platform": "instagram", "handle": "manoirhovey"} | ||||
| 552 | +{"platform": "instagram", "handle": "alicemonnierphotographie"} | ||||
| 553 | +{"platform": "instagram", "handle": "anniegagnonphotographie"} | ||||
| 554 | +{"platform": "instagram", "handle": "highlightmarysebelanger"} | ||||
| 555 | +{"platform": "instagram", "handle": "madamealicefleuristestecath"} | ||||
| 556 | +{"platform": "instagram", "handle": "loccasion_dembellir"} | ||||
| 557 | +{"platform": "instagram", "handle": "highlight_maryse_belanger"} | ||||
| 558 | +{"platform": "instagram", "handle": "dreamityourselfmontreal"} | ||||
| 559 | +{"platform": "instagram", "handle": "montreal_bandindelloye"} | ||||
| 560 | +{"platform": "instagram", "handle": "mimosadesign.invitations"} | ||||
| 561 | +{"platform": "instagram", "handle": "lafleur_sucree"} | ||||
| 562 | +{"platform": "instagram", "handle": "justinequintaljewellery"} | ||||
| 563 | +{"platform": "instagram", "handle": "yasminerosedesigner"} | ||||
| 564 | +{"platform": "instagram", "handle": "meggie_lapointe"} | ||||
| 565 | +{"platform": "instagram", "handle": "maxalexleblanc"} | ||||
| 566 | +{"platform": "instagram", "handle": "missis101"} | ||||
| 567 | +{"platform": "instagram", "handle": "makeupbyalexandra.p"} | ||||
| 568 | +{"platform": "instagram", "handle": "marysewithlove"} | ||||
| 569 | +{"platform": "instagram", "handle": "aubergesaintantoine"} | ||||
| 570 | +{"platform": "instagram", "handle": "emiliesoprano"} | ||||
| 571 | +{"platform": "instagram", "handle": "cathylessardphoto"} | ||||
| 572 | +{"platform": "instagram", "handle": "so_lia"} | ||||
| 573 | +{"platform": "instagram", "handle": "helly819"} | ||||
| 574 | +{"platform": "instagram", "handle": "lamarieusesophiesamson"} | ||||
| 575 | +{"platform": "instagram", "handle": "sandosplayacar"} | ||||
| 576 | +{"platform": "instagram", "handle": "maebonnetphotographe"} | ||||
| 577 | +{"platform": "instagram", "handle": "alwaysplayingwithmakeup"} | ||||
| 578 | +{"platform": "instagram", "handle": "mart.menardimage"} | ||||
| 579 | +{"platform": "instagram", "handle": "karrelaubert"} | ||||
| 580 | +{"platform": "instagram", "handle": "erikaco.events"} | ||||
| 581 | +{"platform": "instagram", "handle": "robmalofilms"} | ||||
| 582 | +{"platform": "instagram", "handle": "club_atwater"} | ||||
| 583 | +{"platform": "instagram", "handle": "jacinthe.benoit"} | ||||
| 584 | +{"platform": "instagram", "handle": "ivoiremontreal"} | ||||
| 585 | +{"platform": "instagram", "handle": "montreal_blandindelloye"} | ||||
| 586 | +{"platform": "instagram", "handle": "anabelfrechettephotographe"} | ||||
| 587 | +{"platform": "instagram", "handle": "leplusbojour"} | ||||
| 588 | +{"platform": "instagram", "handle": "resort_entourage"} | ||||
| 589 | +{"platform": "instagram", "handle": "by_lemay"} | ||||
| 590 | +{"platform": "instagram", "handle": "fleurdeurope"} | ||||
| 591 | +{"platform": "instagram", "handle": "papeterieetconfetti"} | ||||
| 592 | +{"platform": "instagram", "handle": "cleobolduc"} | ||||
| 593 | +{"platform": "instagram", "handle": "chezmarcus"} | ||||
| 594 | +{"platform": "instagram", "handle": "xperience_applyrs"} | ||||
| 595 | +{"platform": "instagram", "handle": "mart.menard"} | ||||
| 596 | +{"platform": "instagram", "handle": "laurenceflortie"} | ||||
| 597 | +{"platform": "instagram", "handle": "paulinaco.events"} | ||||
| 598 | +{"platform": "instagram", "handle": "beyondthehearts"} | ||||
| 599 | +{"platform": "instagram", "handle": "annieli.mtl"} | ||||
| 600 | +{"platform": "instagram", "handle": "wang_dion"} | ||||
| 601 | +{"platform": "instagram", "handle": "kerstinhahnphotography"} | ||||
| 602 | +{"platform": "instagram", "handle": "myriammenardphoto"} | ||||
| 603 | +{"platform": "instagram", "handle": "chateausteagnes"} | ||||
| 604 | +{"platform": "instagram", "handle": "studio_ck_flowers"} | ||||
| 605 | +{"platform": "instagram", "handle": "blandindelloye.mariage"} | ||||
| 606 | +{"platform": "instagram", "handle": "nargessheed"} | ||||
| 607 | +{"platform": "instagram", "handle": "fulkoweddings"} | ||||
| 608 | +{"platform": "instagram", "handle": "loft.bijoux"} | ||||
| 609 | +{"platform": "instagram", "handle": "whitewillowpaperco"} | ||||
| 610 | +{"platform": "instagram", "handle": "letraiteurarcher"} | ||||
| 611 | +{"platform": "instagram", "handle": "buvette_mobile_lapero"} | ||||
| 612 | +{"platform": "instagram", "handle": "celebrationsgroup"} | ||||
| 613 | +{"platform": "instagram", "handle": "simplybeautifuldecor"} | ||||
| 614 | +{"platform": "instagram", "handle": "emilieviolon"} | ||||
| 615 | +{"platform": "instagram", "handle": "fairmontmanoir"} | ||||
| 616 | +{"platform": "instagram", "handle": "eclatprive.signature"} | ||||
| 617 | +{"platform": "instagram", "handle": "fetesgrenadine"} | ||||
| 618 | +{"platform": "instagram", "handle": "cvezinabride"} | ||||
| 619 | +{"platform": "instagram", "handle": "mepm"} | ||||
| 620 | +{"platform": "instagram", "handle": "joe_lbri"} | ||||
| 621 | +{"platform": "instagram", "handle": "christianlouboutin"} | ||||
| 622 | +{"platform": "instagram", "handle": "arvirestaurant"} | ||||
| 623 | +{"platform": "instagram", "handle": "cremesodaevenement"} | ||||
| 624 | +{"platform": "instagram", "handle": "cremesodaevenements"} | ||||
| 625 | +{"platform": "instagram", "handle": "maecaouette"} | ||||
| 626 | +{"platform": "instagram", "handle": "dior"} | ||||
| 627 | +{"platform": "instagram", "handle": "hiltonquebec"} | ||||
| 628 | +{"platform": "instagram", "handle": "agence.elegance"} | ||||
| 629 | +{"platform": "instagram", "handle": "mapatisserie.ca"} | ||||
| 630 | +{"platform": "instagram", "handle": "chateau.nadia"} | ||||
| 631 | +{"platform": "instagram", "handle": "catherinehardy_photographe"} | ||||
| 632 | +{"platform": "instagram", "handle": "dekoraalbum"} | ||||
| 633 | +{"platform": "instagram", "handle": "elisabethb_eb"} | ||||
| 634 | +{"platform": "instagram", "handle": "wed_vibes"} | ||||
| 635 | +{"platform": "instagram", "handle": "happy.moments.collector"} | ||||
| 636 | +{"platform": "instagram", "handle": "villapizzo"} | ||||
| 637 | +{"platform": "instagram", "handle": "sociallymichelleandco"} | ||||
| 638 | +{"platform": "instagram", "handle": "riccardociceri"} | ||||
| 639 | +{"platform": "instagram", "handle": "blunotteventi"} | ||||
| 640 | +{"platform": "instagram", "handle": "latinidesign"} | ||||
| 641 | +{"platform": "instagram", "handle": "tablesetrentals"} | ||||
| 642 | +{"platform": "instagram", "handle": "raraavis_group"} | ||||
| 643 | +{"platform": "instagram", "handle": "evgeniadragun"} | ||||
| 644 | +{"platform": "instagram", "handle": "jennymakeupland"} | ||||
| 645 | +{"platform": "instagram", "handle": "dadoallestimenti"} | ||||
| 646 | +{"platform": "instagram", "handle": "einpraegsam.co"} | ||||
| 647 | +{"platform": "instagram", "handle": "louska.v"} | ||||
| 648 | +{"platform": "instagram", "handle": "raphaelpalmeer"} | ||||
| 649 | +{"platform": "instagram", "handle": "coiffuredistinctiveqc"} | ||||
| 650 | +{"platform": "instagram", "handle": "wedding_chateaufrontenac"} | ||||
| 651 | +{"platform": "instagram", "handle": "magentastudiophoto"} | ||||
| 652 | +{"platform": "instagram", "handle": "photo_g.b"} | ||||
| 653 | +{"platform": "x", "handle": "blogue"} | ||||
| 654 | +{"platform": "x", "handle": "wp"} | ||||
| 655 | +{"platform": "instagram", "handle": "raavquebec"} | ||||
| 656 | +{"platform": "instagram", "handle": "francoisgaudet"} | ||||
| 657 | +{"platform": "instagram", "handle": "macbsp"} | ||||
| 658 | +{"platform": "instagram", "handle": "aaapnb"} | ||||
| 659 | +{"platform": "instagram", "handle": "leseloizes"} | ||||
| 660 | +{"platform": "instagram", "handle": "olyangertattoo"} | ||||
| 661 | +{"platform": "instagram", "handle": "tatouageroyal"} | ||||
| 662 | +{"platform": "instagram", "handle": "imagotattoo"} | ||||
| 663 | +{"platform": "instagram", "handle": "studioartease"} | ||||
| 664 | +{"platform": "instagram", "handle": "le.malandrin"} | ||||
| 665 | +{"platform": "instagram", "handle": "velours.studio"} | ||||
| 666 | +{"platform": "instagram", "handle": "velours.tattoo"} | ||||
| 667 | +{"platform": "instagram", "handle": "dominiquebodkintattoo"} | ||||
| 668 | +{"platform": "instagram", "handle": "arnostattoos"} | ||||
| 669 | +{"platform": "instagram", "handle": "e.a.tattoo"} | ||||
| 670 | +{"platform": "instagram", "handle": "christianlanouette"} | ||||
| 671 | +{"platform": "instagram", "handle": "tattoo.noirsurpeau"} | ||||
| 672 | +{"platform": "instagram", "handle": "phylotattoos"} | ||||
| 673 | +{"platform": "instagram", "handle": "lucitattoos"} | ||||
| 674 | +{"platform": "instagram", "handle": "lmariera"} | ||||
| 675 | +{"platform": "instagram", "handle": "softbrattattz"} | ||||
| 676 | +{"platform": "instagram", "handle": "mllealyx_tattoo"} | ||||
| 677 | +{"platform": "instagram", "handle": "piewchoquette"} | ||||
| 678 | +{"platform": "instagram", "handle": "murieldemai_tattoo"} | ||||
| 679 | +{"platform": "instagram", "handle": "laracailletattoo"} | ||||
| 680 | +{"platform": "instagram", "handle": "fredpokes"} | ||||
| 681 | +{"platform": "instagram", "handle": "b.hurricane"} | ||||
| 682 | +{"platform": "instagram", "handle": "lav4gurl"} | ||||
| 683 | +{"platform": "instagram", "handle": "steamboat_vinnie"} | ||||
| 684 | +{"platform": "instagram", "handle": "mllealyx"} | ||||
| 685 | +{"platform": "instagram", "handle": "murieldemai"} | ||||
| 686 | +{"platform": "instagram", "handle": "bb.hurricane"} | ||||
| 687 | +{"platform": "instagram", "handle": "steamboat"} | ||||
| 688 | +{"platform": "instagram", "handle": "lukalajoie"} | ||||
| 689 | +{"platform": "instagram", "handle": "christinastattoos"} | ||||
| 690 | +{"platform": "instagram", "handle": "ayako666"} | ||||
| 691 | +{"platform": "instagram", "handle": "maxxlemieux"} | ||||
| 692 | +{"platform": "instagram", "handle": "yannblacktattoo"} | ||||
| 693 | +{"platform": "instagram", "handle": "zema1"} | ||||
| 694 | +{"platform": "instagram", "handle": "ink.maude"} | ||||
| 695 | +{"platform": "instagram", "handle": "waynemcfarlane"} | ||||
| 696 | +{"platform": "instagram", "handle": "shaemotztattoos"} | ||||
| 697 | +{"platform": "instagram", "handle": "draworking"} | ||||
| 698 | +{"platform": "instagram", "handle": "getmooretattoos"} | ||||
| 699 | +{"platform": "instagram", "handle": "inkredible"} | ||||
| 700 | +{"platform": "instagram", "handle": "inkredible_shawn"} | ||||
| 701 | +{"platform": "instagram", "handle": "rebeccablairtattoos"} | ||||
| 702 | +{"platform": "instagram", "handle": "johnnynoirtattoo"} | ||||
| 703 | +{"platform": "instagram", "handle": "the_burning_jewel"} | ||||
| 704 | +{"platform": "instagram", "handle": "808byjack"} | ||||
| 705 | +{"platform": "instagram", "handle": "tattoomontreal"} | ||||
| 706 | +{"platform": "instagram", "handle": "montrealtattooguide"} | ||||
| 707 | +{"platform": "instagram", "handle": "monsieur.pitch"} | ||||
| 708 | +{"platform": "instagram", "handle": "lashopchaos"} | ||||
| 709 | +{"platform": "instagram", "handle": "velco.tattoo"} | ||||
| 710 | +{"platform": "instagram", "handle": "baroquebabetattoos"} | ||||
| 711 | +{"platform": "instagram", "handle": "chez.bebelala"} | ||||
| 712 | +{"platform": "instagram", "handle": "thedavidcote"} | ||||
| 713 | +{"platform": "instagram", "handle": "noirsurpeau"} | ||||
| 714 | +{"platform": "instagram", "handle": "studio.amormio"} | ||||
| 715 | +{"platform": "instagram", "handle": "brizz.amor"} | ||||
| 716 | +{"platform": "instagram", "handle": "dani.l.pokes"} | ||||
| 717 | +{"platform": "instagram", "handle": "passelebriquet"} | ||||
| 718 | +{"platform": "instagram", "handle": "isabelroseink"} | ||||
| 719 | +{"platform": "instagram", "handle": "industrial.inktattoo"} | ||||
| 720 | +{"platform": "instagram", "handle": "itslumibeauty"} | ||||
| 721 | +{"platform": "instagram", "handle": "permanence.pmu"} | ||||
| 722 | +{"platform": "instagram", "handle": "hayls.ink"} | ||||
| 723 | +{"platform": "instagram", "handle": "tattoobysoso"} | ||||
| 724 | +{"platform": "instagram", "handle": "saintpaul.tattoo"} | ||||
| 725 | +{"platform": "instagram", "handle": "subielachani.cs"} | ||||
| 726 | +{"platform": "instagram", "handle": "charlessimardcoiffeur"} | ||||
| 727 | +{"platform": "instagram", "handle": "hair_by_pk.t"} | ||||
| 728 | +{"platform": "instagram", "handle": "marcuuus"} | ||||
| 729 | +{"platform": "instagram", "handle": "cathesoe_hair"} | ||||
| 730 | +{"platform": "instagram", "handle": "kimmcgillis"} | ||||
| 731 | +{"platform": "instagram", "handle": "andree.anne.gagne"} | ||||
| 732 | +{"platform": "instagram", "handle": "hairbynathaliemichaud"} | ||||
| 733 | +{"platform": "instagram", "handle": "vikingmax.hair"} | ||||
| 734 | +{"platform": "instagram", "handle": "salonno1coiffure"} | ||||
| 735 | +{"platform": "instagram", "handle": "la_capillicultrice"} | ||||
| 736 | +{"platform": "instagram", "handle": "laurence_hairstylist"} | ||||
| 737 | +{"platform": "instagram", "handle": "sam.chab"} | ||||
| 738 | +{"platform": "instagram", "handle": "staellecolorful"} | ||||
| 739 | +{"platform": "instagram", "handle": "melagagn"} | ||||
| 740 | +{"platform": "instagram", "handle": "les_couloirs"} | ||||
| 741 | +{"platform": "instagram", "handle": "st_laurent_coiffure"} | ||||
| 742 | +{"platform": "instagram", "handle": "karianne_artistika"} | ||||
| 743 | +{"platform": "instagram", "handle": "eleganzaqc"} | ||||
| 744 | +{"platform": "instagram", "handle": "billie.qc"} | ||||
| 745 | +{"platform": "instagram", "handle": "luxetmusa"} | ||||
| 746 | +{"platform": "instagram", "handle": "zazzpareleganza"} | ||||
| 747 | +{"platform": "instagram", "handle": "salontestuvulallure"} | ||||
| 748 | +{"platform": "instagram", "handle": "alia_victoria_coiffure"} | ||||
| 749 | +{"platform": "instagram", "handle": "labelleetlatete"} | ||||
| 750 | +{"platform": "instagram", "handle": "parikart_"} | ||||
| 751 | +{"platform": "instagram", "handle": "litchicoiffure"} | ||||
| 752 | +{"platform": "instagram", "handle": "mcoupebeaute"} | ||||
| 753 | +{"platform": "instagram", "handle": "lakwaflevis"} | ||||
| 754 | +{"platform": "instagram", "handle": "hakima_matata"} | ||||
| 755 | +{"platform": "instagram", "handle": "matrix"} | ||||
| 756 | +{"platform": "instagram", "handle": "schwarzkopfpro"} | ||||
| 757 | +{"platform": "instagram", "handle": "babylissprousa"} | ||||
| 758 | +{"platform": "instagram", "handle": "neumabeauty"} | ||||
| 759 | +{"platform": "instagram", "handle": "joellienadeau"} | ||||
| 760 | +{"platform": "instagram", "handle": "goldwellca"} | ||||
| 761 | +{"platform": "instagram", "handle": "coiffure_le_saint"} | ||||
| 762 | +{"platform": "instagram", "handle": "hair_by_roxks"} | ||||
| 763 | +{"platform": "instagram", "handle": "carolabelleetlatete"} | ||||
| 764 | +{"platform": "instagram", "handle": "annieracine01"} | ||||
| 765 | +{"platform": "x", "handle": "jdequebec"} | ||||
| 766 | +{"platform": "instagram", "handle": "alexandrinepoirier"} | ||||
| 767 | +{"platform": "instagram", "handle": "maudegervais_"} | ||||
| 768 | +{"platform": "instagram", "handle": "lorealpro"} | ||||
| 769 | +{"platform": "instagram", "handle": "olaplex"} | ||||
| 770 | +{"platform": "instagram", "handle": "mutetienne"} | ||||
| 771 | +{"platform": "instagram", "handle": "gab.brulotte"} | ||||
| 772 | +{"platform": "instagram", "handle": "annepier"} | ||||
| 773 | +{"platform": "instagram", "handle": "klaudiaodeth"} | ||||
| 774 | +{"platform": "instagram", "handle": "biolage"} | ||||
| 775 | +{"platform": "instagram", "handle": "ruskhaircare"} | ||||
| 776 | +{"platform": "instagram", "handle": "ruskcanada"} | ||||
| 777 | +{"platform": "instagram", "handle": "aquagecanada"} | ||||
| 778 | +{"platform": "instagram", "handle": "aquagehaircare"} | ||||
| 779 | +{"platform": "instagram", "handle": "alexeloranger"} | ||||
| 780 | +{"platform": "instagram", "handle": "cath_marier"} | ||||
| 781 | +{"platform": "instagram", "handle": "fresha"} | ||||
| 782 | +{"platform": "instagram", "handle": "virginietrc"} | ||||
| 783 | +{"platform": "instagram", "handle": "clemencexchezmarcus"} | ||||
| 784 | +{"platform": "instagram", "handle": "kingperse"} | ||||
| 785 | +{"platform": "instagram", "handle": "annejuice10"} | ||||
| 786 | +{"platform": "instagram", "handle": "charlesxeda"} | ||||
| 787 | +{"platform": "instagram", "handle": "lau.gre"} | ||||
| 788 | +{"platform": "instagram", "handle": "cynth.haircolors"} | ||||
| 789 | +{"platform": "instagram", "handle": "kellyextensions"} | ||||
| 790 | +{"platform": "instagram", "handle": "sxmos_"} | ||||
| 791 | +{"platform": "instagram", "handle": "kateextensions"} | ||||
| 792 | +{"platform": "instagram", "handle": "est"} | ||||
| 793 | +{"platform": "instagram", "handle": "saloncoiffurelestudio"} | ||||
| 794 | +{"platform": "instagram", "handle": "conceptbeaute.esthetique"} | ||||
| 795 | +{"platform": "instagram", "handle": "institut.esthetique.qc"} | ||||
| 796 | +{"platform": "instagram", "handle": "skinandcoesthetique"} | ||||
| 797 | +{"platform": "tiktok", "handle": "skinco.esthtique"} | ||||
| 798 | +{"platform": "tiktok", "handle": "dermacureqc"} | ||||
| 799 | +{"platform": "instagram", "handle": "cfameriques"} | ||||
| 800 | +{"platform": "instagram", "handle": "icrml.cirlm"} | ||||
| 801 | +{"platform": "x", "handle": "icrml_cirlm"} | ||||
| 802 | +{"platform": "instagram", "handle": "nalyses"} | ||||
| 803 | +{"platform": "instagram", "handle": "gmc"} | ||||
| 804 | +{"platform": "instagram", "handle": "gmccanada"} | ||||
| 805 | +{"platform": "tiktok", "handle": "gmccanada"} | ||||
| 806 | +{"platform": "instagram", "handle": "triumphamerica"} | ||||
| 807 | +{"platform": "x", "handle": "triumphamerica"} | ||||
| 808 | +{"platform": "instagram", "handle": "motomontrealcycle"} | ||||
| 809 | +{"platform": "instagram", "handle": "motorcycleandpowersportshows"} | ||||
| 810 | +{"platform": "instagram", "handle": "bmwmotorradmontreal"} | ||||
| 811 | +{"platform": "instagram", "handle": "themotosocial"} | ||||
| 812 | +{"platform": "instagram", "handle": "idlegarageandcoffee"} | ||||
| 813 | +{"platform": "instagram", "handle": "cafelefalco"} | ||||
| 814 | +{"platform": "instagram", "handle": "hocheglace"} | ||||
| 815 | +{"platform": "instagram", "handle": "cantinova.cafe"} | ||||
| 816 | +{"platform": "instagram", "handle": "beausallnatural"} | ||||
| 817 | +{"platform": "instagram", "handle": "la_fille_au_casque_rouge_"} | ||||
| 818 | +{"platform": "instagram", "handle": "hawley_martin"} | ||||
| 819 | +{"platform": "instagram", "handle": "motor_cycle_bro"} | ||||
| 820 | +{"platform": "instagram", "handle": "nak_attaque"} | ||||
| 821 | +{"platform": "instagram", "handle": "vikpiccreative"} | ||||
| 822 | +{"platform": "instagram", "handle": "yamahamotorcanada"} | ||||
| 823 | +{"platform": "instagram", "handle": "mic"} | ||||
| 824 | +{"platform": "x", "handle": "enduro"} | ||||
| 825 | +{"platform": "instagram", "handle": "perrondesign"} | ||||
| 826 | +{"platform": "instagram", "handle": "adomicile_"} | ||||
| 827 | +{"platform": "instagram", "handle": "atelierzebulonperron"} | ||||
| 828 | +{"platform": "instagram", "handle": "atelierdansereau"} | ||||
| 829 | +{"platform": "instagram", "handle": "les"} | ||||
| 830 | +{"platform": "instagram", "handle": "bureautempo"} | ||||
| 831 | +{"platform": "instagram", "handle": "vivesstlaurent"} | ||||
| 832 | +{"platform": "instagram", "handle": "michaelgodmerstudio"} | ||||
| 833 | +{"platform": "instagram", "handle": "akbdesign"} | ||||
| 834 | +{"platform": "instagram", "handle": "bipede.design"} | ||||
| 835 | +{"platform": "instagram", "handle": "entrequatremurs"} | ||||
| 836 | +{"platform": "instagram", "handle": "entrepot_de_la_reno"} | ||||
| 837 | +{"platform": "instagram", "handle": "brookandpeony"} | ||||
| 838 | +{"platform": "instagram", "handle": "house_to_home.interiors"} | ||||
| 839 | +{"platform": "instagram", "handle": "rien_ne_se_perd"} | ||||
| 840 | +{"platform": "instagram", "handle": "alexandralarouche"} | ||||
| 841 | +{"platform": "instagram", "handle": "ashleyshaanan"} | ||||
| 842 | +{"platform": "x", "handle": "logisquebec"} | ||||
| 843 | +{"platform": "instagram", "handle": "davani_realtor"} | ||||
| 844 | +{"platform": "x", "handle": "behrooziani"} | ||||
| 845 | +{"platform": "instagram", "handle": "realtorpointca"} | ||||
| 846 | +{"platform": "x", "handle": "realtorpointca"} | ||||
| 847 | +{"platform": "instagram", "handle": "lespac"} | ||||
| 848 | +{"platform": "instagram", "handle": "royal_lepage"} | ||||
| 849 | +{"platform": "instagram", "handle": "remaxcanada"} | ||||
| 850 | +{"platform": "tiktok", "handle": "remax.canada"} | ||||
| 851 | +{"platform": "youtube", "handle": "remaxcanada_no1"} | ||||
| 852 | +{"platform": "x", "handle": "assets"} | ||||
| 853 | +{"platform": "x", "handle": "mex"} | ||||
| 854 | +{"platform": "instagram", "handle": "viacapitale"} | ||||
| 855 | +{"platform": "x", "handle": "viacapitale"} | ||||
| 856 | +{"platform": "instagram", "handle": "remaxquebec"} | ||||
| 857 | +{"platform": "tiktok", "handle": "remax.quebec"} | ||||
| 858 | +{"platform": "x", "handle": "notoriete"} | ||||
| 859 | +{"platform": "x", "handle": "formation"} | ||||
| 860 | +{"platform": "x", "handle": "contact"} | ||||
| 861 | +{"platform": "x", "handle": "remaxquebec"} | ||||
| 862 | +{"platform": "x", "handle": "default"} | ||||
| 863 | +{"platform": "youtube", "handle": "findevcanada"} | ||||
| 864 | +{"platform": "x", "handle": "findev_canada"} | ||||
| 865 | +{"platform": "instagram", "handle": "eycanada"} | ||||
| 866 | +{"platform": "instagram", "handle": "quebecintl"} | ||||
| 867 | +{"platform": "tiktok", "handle": "quebecintl"} | ||||
| 868 | +{"platform": "instagram", "handle": "yesmontreal"} | ||||
| 869 | +{"platform": "x", "handle": "yesmontreal"} | ||||
| 870 | +{"platform": "instagram", "handle": "fahdalhattab"} | ||||
| 871 | +{"platform": "youtube", "handle": "fahdalhattab"} | ||||
| 872 | +{"platform": "x", "handle": "fahdalhattab"} | ||||
| 873 | +{"platform": "instagram", "handle": "myriambariltessier_v4.jpg"} | ||||
| 874 | +{"platform": "instagram", "handle": "punctuatedesign"} | ||||
| 875 | +{"platform": "instagram", "handle": "startupfest"} | ||||
| 876 | +{"platform": "instagram", "handle": "inrsciences"} | ||||
| 877 | +{"platform": "x", "handle": "u_inrs"} | ||||
| 878 | +{"platform": "instagram", "handle": "fse_udem"} | ||||
| 879 | +{"platform": "instagram", "handle": "englishmtl"} | ||||
| 880 | +{"platform": "instagram", "handle": "hecmontreal"} | ||||
| 881 | +{"platform": "x", "handle": "hec_montreal"} | ||||
| 882 | +{"platform": "x", "handle": "recordingservic"} | ||||
| 883 | +{"platform": "instagram", "handle": "csf_cb"} | ||||
| 884 | +{"platform": "instagram", "handle": "bibliothequedequebec"} | ||||
| 885 | +{"platform": "youtube", "handle": "bibliotheque_quebec"} | ||||
| 886 | +{"platform": "instagram", "handle": "moongirlreads"} | ||||
| 887 | +{"platform": "instagram", "handle": "bookedj"} | ||||
| 888 | +{"platform": "instagram", "handle": "meemoreads"} | ||||
| 889 | +{"platform": "instagram", "handle": "thrillerbooklover"} | ||||
| 890 | +{"platform": "instagram", "handle": "literallyjohngreen"} | ||||
| 891 | +{"platform": "instagram", "handle": "thechloegong"} | ||||
| 892 | +{"platform": "instagram", "handle": "victoriaaveyard"} | ||||
| 893 | +{"platform": "instagram", "handle": "runwithskizzers"} | ||||
| 894 | +{"platform": "instagram", "handle": "michael.bjork"} | ||||
| 895 | +{"platform": "instagram", "handle": "penguin"} | ||||
| 896 | +{"platform": "tiktok", "handle": "girlyalex83"} | ||||
| 897 | +{"platform": "tiktok", "handle": "morgannbook"} | ||||
| 898 | +{"platform": "tiktok", "handle": "yabooktok"} | ||||
| 899 | +{"platform": "x", "handle": "ncbi"} | ||||
| 900 | +{"platform": "x", "handle": "nlm_nih"} | ||||
| 901 | +{"platform": "instagram", "handle": "daansbooks"} | ||||
| 902 | +{"platform": "instagram", "handle": "spinesvines"} | ||||
| 903 | +{"platform": "instagram", "handle": "spinesandvines"} | ||||
| 904 | +{"platform": "tiktok", "handle": "baker.reads"} | ||||
| 905 | +{"platform": "tiktok", "handle": "c15r5y4"} | ||||
| 906 | +{"platform": "tiktok", "handle": "ajunxx"} | ||||
| 907 | +{"platform": "tiktok", "handle": "iamstephanienoble"} | ||||
| 908 | +{"platform": "tiktok", "handle": "bigbooklady"} | ||||
| 909 | +{"platform": "tiktok", "handle": "thelibraryofdais"} | ||||
| 910 | +{"platform": "x", "handle": "culture"} | ||||
| 911 | +{"platform": "x", "handle": "exhaustdata"} | ||||
| 912 | +{"platform": "instagram", "handle": "booknet"} | ||||
| 913 | +{"platform": "instagram", "handle": "cbcbooks"} | ||||
| 914 | +{"platform": "instagram", "handle": "lat46publishing"} | ||||
| 915 | +{"platform": "instagram", "handle": "readflare"} | ||||
| 916 | +{"platform": "x", "handle": "pcitoyen"} | ||||
| 917 | +{"platform": "instagram", "handle": "msss_qc"} | ||||
| 918 | +{"platform": "x", "handle": "msss_qc"} | ||||
| 919 | +{"platform": "instagram", "handle": "acadianhealth"} | ||||
| 920 | +{"platform": "instagram", "handle": "creons_la_suite"} | ||||
| 921 | +{"platform": "x", "handle": "creonslasuite"} | ||||
| 922 | +{"platform": "x", "handle": "santefrancais"} | ||||
| 923 | +{"platform": "instagram", "handle": "lunayogamtl"} | ||||
| 924 | +{"platform": "instagram", "handle": "institutyogaessentiel"} | ||||
| 925 | +{"platform": "instagram", "handle": "yogashakmontreal"} | ||||
| 926 | +{"platform": "instagram", "handle": "naadayoga"} | ||||
| 927 | +{"platform": "x", "handle": "naadayoga"} | ||||
| 928 | +{"platform": "instagram", "handle": "sfvictoria.ca"} | ||||
| 929 | +{"platform": "x", "handle": "francophone_vic"} | ||||
| 930 | +{"platform": "x", "handle": "podkatt"} | ||||
| 931 | +{"platform": "instagram", "handle": "podkatt"} | ||||
| 932 | +{"platform": "instagram", "handle": "podthenorth"} | ||||
| 933 | +{"platform": "instagram", "handle": "labrigadepod.th"} | ||||
| 934 | +{"platform": "instagram", "handle": "jezebel.bardotsuivez"} | ||||
| 935 | +{"platform": "instagram", "handle": "celestelevisyoutube"} | ||||
| 936 | +{"platform": "instagram", "handle": "srnhasselaslinkedin"} | ||||
| 937 | +{"platform": "instagram", "handle": "makhena"} | ||||
| 938 | +{"platform": "instagram", "handle": "miquemichellesuivez"} | ||||
| 939 | +{"platform": "instagram", "handle": "leflofrancosite"} | ||||
| 940 | +{"platform": "instagram", "handle": "lexinemenard"} | ||||
| 941 | +{"platform": "instagram", "handle": "lexinephotographie"} | ||||
| 942 | +{"platform": "instagram", "handle": "lexiphotoboothsite"} | ||||
| 943 | +{"platform": "instagram", "handle": "lydiamariebpinstagram"} | ||||
| 944 | +{"platform": "instagram", "handle": "lydiamariebplinkedin"} | ||||
| 945 | +{"platform": "instagram", "handle": "monassemblee"} | ||||
| 946 | +{"platform": "instagram", "handle": "danieroy11"} | ||||
| 947 | +{"platform": "tiktok", "handle": "ledevoir"} | ||||
| 948 | +{"platform": "x", "handle": "ledevoir"} | ||||
| 949 | +{"platform": "instagram", "handle": "rubytdoll"} | ||||
| 950 | +{"platform": "instagram", "handle": "aleeranight"} | ||||
| 951 | +{"platform": "instagram", "handle": "verona_verushka"} | ||||
| 952 | +{"platform": "instagram", "handle": "madolamotte"} | ||||
| 953 | +{"platform": "instagram", "handle": "huffpost"} | ||||
| 954 | +{"platform": "instagram", "handle": "rainbow.drag"} | ||||
| 955 | +{"platform": "instagram", "handle": "ritabagaz"} | ||||
| 956 | +{"platform": "instagram", "handle": "gabryelledrag"} | ||||
| 957 | +{"platform": "instagram", "handle": "matante.alex"} | ||||
| 958 | +{"platform": "instagram", "handle": "gisele_lullaby"} | ||||
| 959 | +{"platform": "instagram", "handle": "kiara.qc.ca"} | ||||
| 960 | +{"platform": "instagram", "handle": "ladydeboomboom"} | ||||
| 961 | +{"platform": "instagram", "handle": "pythia.queen"} | ||||
| 962 | +{"platform": "instagram", "handle": "umagahd"} | ||||
| 963 | +{"platform": "instagram", "handle": "itsheavengenderfck"} | ||||
| 964 | +{"platform": "instagram", "handle": "selmagahd"} | ||||
| 965 | +{"platform": "x", "handle": "huffpost"} | ||||
| 966 | +{"platform": "x", "handle": "philippelepine"} | ||||
| 967 | +{"platform": "instagram", "handle": "sugarandspice"} | ||||
| 968 | +{"platform": "instagram", "handle": "callmespice"} | ||||
| 969 | +{"platform": "instagram", "handle": "sugar"} | ||||
| 970 | +{"platform": "instagram", "handle": "rc.ohdio"} | ||||
| 971 | +{"platform": "instagram", "handle": "she_laa9"} | ||||
| 972 | +{"platform": "tiktok", "handle": "samilandri"} | ||||
| 973 | +{"platform": "tiktok", "handle": "queenrosebeef"} | ||||
| 974 | +{"platform": "tiktok", "handle": "radpointca"} | ||||
| 975 | +{"platform": "tiktok", "handle": "she_laa9"} | ||||
| 976 | +{"platform": "tiktok", "handle": "danslebainaveccelin"} | ||||
| 977 | +{"platform": "tiktok", "handle": "rc.ohdio"} | ||||
| 978 | +{"platform": "tiktok", "handle": "sugarandspice"} | ||||
| 979 | +{"platform": "tiktok", "handle": "rainbow.drag"} | ||||
| 980 | +{"platform": "tiktok", "handle": "demone_lastrange"} | ||||
| 981 | +{"platform": "tiktok", "handle": "paspeufieres"} | ||||
| 982 | +{"platform": "tiktok", "handle": "rosiepetalsdrag"} | ||||
| 983 | +{"platform": "tiktok", "handle": "cityofquebec"} | ||||
| 984 | +{"platform": "tiktok", "handle": "scoobydoobydrew22"} | ||||
| 985 | +{"platform": "tiktok", "handle": "yap.mtl"} | ||||
| 986 | +{"platform": "tiktok", "handle": "ximena.do.santos"} | ||||
| 987 | +{"platform": "instagram", "handle": "samilandri"} | ||||
| 988 | +{"platform": "instagram", "handle": "queenrosebeef"} | ||||
| 989 | +{"platform": "instagram", "handle": "radpointca"} | ||||
| 990 | +{"platform": "instagram", "handle": "danslebainaveccelin"} | ||||
| 991 | +{"platform": "instagram", "handle": "agence.ludik"} | ||||
| 992 | +{"platform": "instagram", "handle": "barbada"} | ||||
| 993 | +{"platform": "instagram", "handle": "rita"} | ||||
| 994 | +{"platform": "instagram", "handle": "demone_lastrange"} | ||||
| 995 | +{"platform": "instagram", "handle": "paspeufieres"} | ||||
| 996 | +{"platform": "instagram", "handle": "chiquita"} | ||||
| 997 | +{"platform": "instagram", "handle": "rosiepetalsdrag"} | ||||
| 998 | +{"platform": "instagram", "handle": "cityofquebec"} | ||||
| 999 | +{"platform": "instagram", "handle": "scoobydoobydrew22"} | ||||
| 1000 | +{"platform": "instagram", "handle": "yap.mtl"} | ||||
| 1001 | +{"platform": "instagram", "handle": "ximena.do.santos"} | ||||
| 1002 | +{"platform": "instagram", "handle": "cult_mag_"} | ||||
| 1003 | +{"platform": "youtube", "handle": "cultmagazine"} | ||||
| 1004 | +{"platform": "youtube", "handle": "helpez-moi"} | ||||
| 1005 | +{"platform": "x", "handle": "cult_mag_"} | ||||
| 1006 | +{"platform": "instagram", "handle": "samilandri_"} | ||||
| 1007 | +{"platform": "instagram", "handle": "velma.johnny"} | ||||
| 1008 | +{"platform": "instagram", "handle": "chiquita.mere"} | ||||
| 1009 | +{"platform": "instagram", "handle": "queermtl"} | ||||
| 1010 | +{"platform": "instagram", "handle": "stefan"} | ||||
| 1011 | +{"platform": "instagram", "handle": "cclgbtqplus"} | ||||
| 1012 | +{"platform": "youtube", "handle": "bibliothequealivresouverts7986"} | ||||
| 1013 | +{"platform": "instagram", "handle": "barlestud"} | ||||
| 1014 | +{"platform": "instagram", "handle": "champs_montreal"} | ||||
| 1015 | +{"platform": "instagram", "handle": "motel_motel"} | ||||
| 1016 | +{"platform": "instagram", "handle": "bar_taboo_inc"} | ||||
| 1017 | +{"platform": "instagram", "handle": "ballroom4community"} | ||||
| 1018 | +{"platform": "instagram", "handle": "bareoke"} | ||||
| 1019 | +{"platform": "instagram", "handle": "violet_hour_lit"} | ||||
| 1020 | +{"platform": "instagram", "handle": "leclubdds"} | ||||
| 1021 | +{"platform": "instagram", "handle": "jontaemccrory"} | ||||
| 1022 | +{"platform": "instagram", "handle": "blackgxrlsesh"} | ||||
| 1023 | +{"platform": "instagram", "handle": "queerkaraokemtl"} | ||||
| 1024 | +{"platform": "instagram", "handle": "p10montreal"} | ||||
| 1025 | +{"platform": "instagram", "handle": "queerbodiesmontreal"} | ||||
| 1026 | +{"platform": "instagram", "handle": "bring_it_mtl"} | ||||
| 1027 | +{"platform": "instagram", "handle": "juke.collective"} | ||||
| 1028 | +{"platform": "instagram", "handle": "bmqs.mtl"} | ||||
| 1029 | +{"platform": "instagram", "handle": "dodgeball.ratons.chasseurs"} | ||||
| 1030 | +{"platform": "instagram", "handle": "out_runclub"} | ||||
| 1031 | +{"platform": "instagram", "handle": "queer_bloc"} | ||||
| 1032 | +{"platform": "instagram", "handle": "theunfitclub"} | ||||
| 1033 | +{"platform": "instagram", "handle": "justice.trans"} | ||||
| 1034 | +{"platform": "instagram", "handle": "audreyrivet"} | ||||
| 1035 | +{"platform": "instagram", "handle": "josianekonate"} | ||||
| 1036 | +{"platform": "instagram", "handle": "faulhaber.agency"} | ||||
| 1037 | +{"platform": "instagram", "handle": "trangreeny"} | ||||
| 1038 | +{"platform": "x", "handle": "faulhabercomm"} | ||||
| 1039 | +{"platform": "instagram", "handle": "legurky"} | ||||
| 1040 | +{"platform": "instagram", "handle": "adamparadisio"} | ||||
| 1041 | +{"platform": "instagram", "handle": "alexane"} | ||||
| 1042 | +{"platform": "instagram", "handle": "samanthaleclerc"} | ||||
| 1043 | +{"platform": "instagram", "handle": "emylalune"} | ||||
| 1044 | +{"platform": "instagram", "handle": "agenceoneway"} | ||||
| 1045 | +{"platform": "tiktok", "handle": "emylalune"} | ||||
| 1046 | +{"platform": "tiktok", "handle": "adamparadisio"} | ||||
| 1047 | +{"platform": "tiktok", "handle": "hydroquebec"} | ||||
| 1048 | +{"platform": "tiktok", "handle": "accouuu"} | ||||
| 1049 | +{"platform": "tiktok", "handle": "influencecreation"} | ||||
| 1050 | +{"platform": "instagram", "handle": "influencecreation"} | ||||
| 1051 | +{"platform": "instagram", "handle": "la.boite.dinfluence"} | ||||
| 1052 | +{"platform": "instagram", "handle": "nath.hebert"} | ||||
| 1053 | +{"platform": "instagram", "handle": "sarahmboily"} | ||||
| 1054 | +{"platform": "instagram", "handle": "samonthenews"} | ||||
| 1055 | +{"platform": "tiktok", "handle": "camilledufresne_"} | ||||
| 1056 | +{"platform": "instagram", "handle": "iamjahantea"} | ||||
| 1057 | +{"platform": "instagram", "handle": "aiequi"} | ||||
| 1058 | +{"platform": "tiktok", "handle": "sjbleauellington"} | ||||
| 1059 | +{"platform": "tiktok", "handle": "denyzee"} | ||||
| 1060 | +{"platform": "tiktok", "handle": "iamjahantea"} | ||||
| 1061 | +{"platform": "youtube", "handle": "denyzee"} | ||||
| 1062 | +{"platform": "youtube", "handle": "cocottee_"} | ||||
| 1063 | +{"platform": "instagram", "handle": "sjbleauellington"} | ||||
| 1064 | +{"platform": "instagram", "handle": "denyzee"} | ||||
| 1065 | +{"platform": "instagram", "handle": "felixdolci"} | ||||
| 1066 | +{"platform": "instagram", "handle": "nailzzbymyka"} | ||||
| 1067 | +{"platform": "instagram", "handle": "lasenza"} | ||||
| 1068 | +{"platform": "instagram", "handle": "quebecbroue"} | ||||
| 1069 | +{"platform": "instagram", "handle": "msfphotographie"} | ||||
| 1070 | +{"platform": "instagram", "handle": "calvinklein"} | ||||
| 1071 | +{"platform": "instagram", "handle": "tvanouvelles"} | ||||
| 1072 | +{"platform": "instagram", "handle": "salutbonjourofficiel"} | ||||
| 1073 | +{"platform": "instagram", "handle": "pascalerobitaille"} | ||||
| 1074 | +{"platform": "instagram", "handle": "upawasessions"} | ||||
| 1075 | +{"platform": "instagram", "handle": "soufiane"} | ||||
| 1076 | +{"platform": "instagram", "handle": "wherepaganoat"} | ||||
| 1077 | +{"platform": "instagram", "handle": "clatetu"} | ||||
| 1078 | +{"platform": "instagram", "handle": "killwilliamhennessey"} | ||||
| 1079 | +{"platform": "instagram", "handle": "d.rec.2"} | ||||
| 1080 | +{"platform": "instagram", "handle": "duber72_"} | ||||
| 1081 | +{"platform": "instagram", "handle": "bahoboxing"} | ||||
| 1082 | +{"platform": "instagram", "handle": "kayttykat"} | ||||
| 1083 | +{"platform": "instagram", "handle": "kaikupanda"} | ||||
| 1084 | +{"platform": "instagram", "handle": "yturcotte17"} | ||||
| 1085 | +{"platform": "instagram", "handle": "verolagachette"} | ||||
| 1086 | +{"platform": "instagram", "handle": "emiliebruncormier"} | ||||
| 1087 | +{"platform": "instagram", "handle": "laureantardif"} | ||||
| 1088 | +{"platform": "instagram", "handle": "ecoledecirquedequebec"} | ||||
| 1089 | +{"platform": "instagram", "handle": "speedbird3000"} | ||||
| 1090 | +{"platform": "instagram", "handle": "katiacuradeau"} | ||||
| 1091 | +{"platform": "instagram", "handle": "annagervaiss"} | ||||
| 1092 | +{"platform": "instagram", "handle": "kellyannturcot"} | ||||
| 1093 | +{"platform": "instagram", "handle": "juliette_painchaud"} | ||||
| 1094 | +{"platform": "tiktok", "handle": "emiliebruncormier"} | ||||
| 1095 | +{"platform": "tiktok", "handle": "juliettepainchaud"} | ||||
| 1096 | +{"platform": "instagram", "handle": "ledraguecabaretclub"} | ||||
| 1097 | +{"platform": "instagram", "handle": "unholyzipper"} | ||||
| 1098 | +{"platform": "instagram", "handle": "capitals"} | ||||
| 1099 | +{"platform": "instagram", "handle": "duber72"} | ||||
| 1100 | +{"platform": "instagram", "handle": "jecoursqc"} | ||||
| 1101 | +{"platform": "instagram", "handle": "lecoachingducoureur"} | ||||
| 1102 | +{"platform": "instagram", "handle": "yvesstlouis"} | ||||
| 1103 | +{"platform": "instagram", "handle": "lacliniqueducoureur"} | ||||
| 1104 | +{"platform": "instagram", "handle": "dioafitness"} | ||||
| 1105 | +{"platform": "instagram", "handle": "velocartel"} | ||||
| 1106 | +{"platform": "instagram", "handle": "kartelmusik"} | ||||
| 1107 | +{"platform": "instagram", "handle": "blackxlfc"} | ||||
| 1108 | +{"platform": "instagram", "handle": "goodjudy.ca"} | ||||
| 1109 | +{"platform": "instagram", "handle": "lunenoiretatouage"} | ||||
| 1110 | +{"platform": "instagram", "handle": "northerntattoosupply"} | ||||
| 1111 | +{"platform": "instagram", "handle": "bishoprotary"} | ||||
| 1112 | +{"platform": "instagram", "handle": "sportsexpertslaurier"} | ||||
| 1113 | +{"platform": "instagram", "handle": "julbocanada"} | ||||
| 1114 | +{"platform": "instagram", "handle": "krononutrition"} | ||||
| 1115 | +{"platform": "instagram", "handle": "heyheytiskenny"} | ||||
| 1116 | +{"platform": "instagram", "handle": "choco"} | ||||
| 1117 | +{"platform": "instagram", "handle": "photokurado"} | ||||
| 1118 | +{"platform": "instagram", "handle": "qbedshostel"} | ||||
| 1119 | +{"platform": "instagram", "handle": "elorouthe"} | ||||
| 1120 | +{"platform": "instagram", "handle": "skyvision.optometrie"} | ||||
| 1121 | +{"platform": "instagram", "handle": "lapetiteecoledeliledorleans"} | ||||
| 1122 | +{"platform": "instagram", "handle": "undz"} | ||||
| 1123 | +{"platform": "instagram", "handle": "audrey"} | ||||
| 1124 | +{"platform": "instagram", "handle": "spekoptics"} | ||||
| 1125 | +{"platform": "instagram", "handle": "popeyesquebec"} | ||||
| 1126 | +{"platform": "instagram", "handle": "lecoureurnordique"} | ||||
| 1127 | +{"platform": "instagram", "handle": "juliette"} | ||||
| 1128 | +{"platform": "instagram", "handle": "juliettepainchaud"} | ||||
| 1129 | +{"platform": "instagram", "handle": "eugeniemalenfant"} | ||||
| 1130 | +{"platform": "instagram", "handle": "pellandworkout"} | ||||
| 1131 | +{"platform": "instagram", "handle": "rachelledion"} | ||||
| 1132 | +{"platform": "instagram", "handle": "pcnphysio"} | ||||
| 1133 | +{"platform": "instagram", "handle": "kev"} | ||||
| 1134 | +{"platform": "instagram", "handle": "sim"} | ||||
| 1135 | +{"platform": "instagram", "handle": "elianne"} | ||||
| 1136 | +{"platform": "instagram", "handle": "jeannot.bou"} | ||||
| 1137 | +{"platform": "instagram", "handle": "srxproducts"} | ||||
| 1138 | +{"platform": "instagram", "handle": "supraathletique"} | ||||
| 1139 | +{"platform": "instagram", "handle": "vb.pod"} | ||||
| 1140 | +{"platform": "instagram", "handle": "tyrsport"} | ||||
| 1141 | +{"platform": "instagram", "handle": "ta.tristan"} | ||||
| 1142 | +{"platform": "instagram", "handle": "julieanneho"} | ||||
| 1143 | +{"platform": "instagram", "handle": "franceskafournier"} | ||||
| 1144 | +{"platform": "instagram", "handle": "marc"} | ||||
| 1145 | +{"platform": "instagram", "handle": "mikechabotfitness"} | ||||
| 1146 | +{"platform": "instagram", "handle": "claudiatihan"} | ||||
| 1147 | +{"platform": "instagram", "handle": "maudelavoie"} | ||||
| 1148 | +{"platform": "instagram", "handle": "emyjade.g"} | ||||
| 1149 | +{"platform": "instagram", "handle": "recklessxminds"} | ||||
| 1150 | +{"platform": "instagram", "handle": "rymnebbak"} | ||||
| 1151 | +{"platform": "instagram", "handle": "myriamlemaay"} | ||||
| 1152 | +{"platform": "instagram", "handle": "sousinfluencepc"} | ||||
| 1153 | +{"platform": "instagram", "handle": "essaimcollective"} | ||||
| 1154 | +{"platform": "instagram", "handle": "girlcrushgang"} | ||||
| 1155 | +{"platform": "instagram", "handle": "mariloublg_"} | ||||
| 1156 | +{"platform": "instagram", "handle": "milaydie"} | ||||
| 1157 | +{"platform": "instagram", "handle": "alanis.desilets"} | ||||
| 1158 | +{"platform": "instagram", "handle": "lacampagnedici"} | ||||
| 1159 | +{"platform": "instagram", "handle": "lajasette.co"} | ||||
| 1160 | +{"platform": "instagram", "handle": "fautquonsappelle"} | ||||
| 1161 | +{"platform": "instagram", "handle": "emmaverdeyt"} | ||||
| 1162 | +{"platform": "instagram", "handle": "lisahomsy"} | ||||
| 1163 | +{"platform": "instagram", "handle": "catherinepeachh"} | ||||
| 1164 | +{"platform": "instagram", "handle": "appy.secret"} | ||||
| 1165 | +{"platform": "instagram", "handle": "beatricebouchard"} | ||||
| 1166 | +{"platform": "instagram", "handle": "cath_belle"} | ||||
| 1167 | +{"platform": "instagram", "handle": "mahdiba"} | ||||
| 1168 | +{"platform": "instagram", "handle": "andreanec"} | ||||
| 1169 | +{"platform": "instagram", "handle": "audreyannej"} | ||||
| 1170 | +{"platform": "instagram", "handle": "alexcentomo"} | ||||
| 1171 | +{"platform": "instagram", "handle": "rise"} | ||||
| 1172 | +{"platform": "instagram", "handle": "hoaka_swimwear"} | ||||
| 1173 | +{"platform": "instagram", "handle": "hoaka_apparel"} | ||||
| 1174 | +{"platform": "instagram", "handle": "tastiofficial"} | ||||
| 1175 | +{"platform": "instagram", "handle": "mariloublg"} | ||||
| 1176 | +{"platform": "instagram", "handle": "cath"} | ||||
| 1177 | +{"platform": "instagram", "handle": "mariloubiz"} | ||||
| 1178 | +{"platform": "instagram", "handle": "boblechef"} | ||||
| 1179 | +{"platform": "instagram", "handle": "emilierossignolarts"} | ||||
| 1180 | +{"platform": "instagram", "handle": "antho.tran"} | ||||
| 1181 | +{"platform": "instagram", "handle": "carlarsenault"} | ||||
| 1182 | +{"platform": "instagram", "handle": "ricardocuisine"} | ||||
| 1183 | +{"platform": "instagram", "handle": "influenceursquebecois"} | ||||
| 1184 | +{"platform": "instagram", "handle": "justinebrouill"} | ||||
| 1185 | +{"platform": "instagram", "handle": "vivitowers"} | ||||
| 1186 | +{"platform": "instagram", "handle": "teachme"} | ||||
| 1187 | +{"platform": "instagram", "handle": "rcitystyle"} | ||||
| 1188 | +{"platform": "instagram", "handle": "winnspiration"} | ||||
| 1189 | +{"platform": "instagram", "handle": "pldetails"} | ||||
| 1190 | +{"platform": "instagram", "handle": "carli.vanheerden"} | ||||
| 1191 | +{"platform": "instagram", "handle": "toninabaratta"} | ||||
| 1192 | +{"platform": "instagram", "handle": "shayna"} | ||||
| 1193 | +{"platform": "instagram", "handle": "natalieast"} | ||||
| 1194 | +{"platform": "instagram", "handle": "struckblog"} | ||||
| 1195 | +{"platform": "instagram", "handle": "mylittlesecrets"} | ||||
| 1196 | +{"platform": "instagram", "handle": "leoniepelletier"} | ||||
| 1197 | +{"platform": "instagram", "handle": "mfpellerin"} | ||||
| 1198 | +{"platform": "instagram", "handle": "anacruz"} | ||||
| 1199 | +{"platform": "instagram", "handle": "working"} | ||||
| 1200 | +{"platform": "instagram", "handle": "mllegeri"} | ||||
| 1201 | +{"platform": "instagram", "handle": "thefitfatale"} | ||||
| 1202 | +{"platform": "tiktok", "handle": "thecordwlu"} | ||||
| 1203 | +{"platform": "x", "handle": "cordnews"} | ||||
| 1204 | +{"platform": "instagram", "handle": "festivalfranco"} | ||||
| 1205 | +{"platform": "instagram", "handle": "amys.clients"} | ||||
| 1206 | +{"platform": "instagram", "handle": "kyleandcodesign"} | ||||
| 1207 | +{"platform": "instagram", "handle": "sportsclubatelier"} | ||||
| 1208 | +{"platform": "instagram", "handle": "bartroveca"} | ||||
| 1209 | +{"platform": "instagram", "handle": "trovelivingca"} | ||||
| 1210 | +{"platform": "instagram", "handle": "crissycutz"} | ||||
| 1211 | +{"platform": "instagram", "handle": "iza.bee"} | ||||
| 1212 | +{"platform": "instagram", "handle": "narcityquebec"} | ||||
| 1213 | +{"platform": "instagram", "handle": "makeup"} | ||||
| 1214 | +{"platform": "instagram", "handle": "schulichmeddent"} | ||||
| 1215 | +{"platform": "instagram", "handle": "datcrusher"} | ||||
| 1216 | +{"platform": "instagram", "handle": "wearfigs"} | ||||
| 1217 | +{"platform": "instagram", "handle": "ashiamade"} | ||||
| 1218 | +{"platform": "instagram", "handle": "illkeepthese"} | ||||
| 1219 | +{"platform": "instagram", "handle": "trywhyte.ca"} | ||||
| 1220 | +{"platform": "instagram", "handle": "untilimdone"} | ||||
| 1221 | +{"platform": "instagram", "handle": "elite"} | ||||
| 1222 | +{"platform": "instagram", "handle": "style.withintention"} | ||||
| 1223 | +{"platform": "instagram", "handle": "boutiqueevolutionhomme"} | ||||
| 1224 | +{"platform": "instagram", "handle": "reneythemc"} | ||||
| 1225 | +{"platform": "instagram", "handle": "speke"} | ||||
| 1226 | +{"platform": "instagram", "handle": "sartoriameucci"} | ||||
| 1227 | +{"platform": "instagram", "handle": "giabymeucci"} | ||||
| 1228 | +{"platform": "instagram", "handle": "meuccifoundation"} | ||||
| 1229 | +{"platform": "instagram", "handle": "midnighthoopclub"} | ||||
| 1230 | +{"platform": "instagram", "handle": "carnetdyves"} | ||||
| 1231 | +{"platform": "instagram", "handle": "sj.mortgages"} | ||||
| 1232 | +{"platform": "instagram", "handle": "lapelinc"} | ||||
| 1233 | +{"platform": "instagram", "handle": "hellfiretattooco"} | ||||
| 1234 | +{"platform": "instagram", "handle": "heathenhandrecords"} | ||||
| 1235 | +{"platform": "instagram", "handle": "nikkarooo"} | ||||
| 1236 | +{"platform": "instagram", "handle": "forgatherfloralco"} | ||||
| 1237 | +{"platform": "instagram", "handle": "designingpolly"} | ||||
| 1238 | +{"platform": "instagram", "handle": "bluehavenwellness"} | ||||
| 1239 | +{"platform": "instagram", "handle": "livpilateswellness"} | ||||
| 1240 | +{"platform": "instagram", "handle": "pinklablondeclub"} | ||||
| 1241 | +{"platform": "instagram", "handle": "pinklablondeatelier"} | ||||
| 1242 | +{"platform": "instagram", "handle": "maurten"} | ||||
| 1243 | +{"platform": "instagram", "handle": "rouvyapp"} | ||||
| 1244 | +{"platform": "instagram", "handle": "bookishlifeofbrie"} | ||||
| 1245 | +{"platform": "instagram", "handle": "kindred.lindsay"} | ||||
| 1246 | +{"platform": "instagram", "handle": "kindred.bobcaygeon"} | ||||
| 1247 | +{"platform": "instagram", "handle": "dmilstein75"} | ||||
| 1248 | +{"platform": "instagram", "handle": "hrlexperience"} | ||||
| 1249 | +{"platform": "instagram", "handle": "arccommunity"} | ||||
| 1250 | +{"platform": "instagram", "handle": "okeanasretreats"} | ||||
| 1251 | +{"platform": "instagram", "handle": "thesoulslife"} | ||||
| 1252 | +{"platform": "instagram", "handle": "op.pfc"} | ||||
| 1253 | +{"platform": "instagram", "handle": "goldenheartcacao"} | ||||
| 1254 | +{"platform": "instagram", "handle": "sherisesfestival"} | ||||
| 1255 | +{"platform": "instagram", "handle": "cloudrealty"} | ||||
| 1256 | +{"platform": "instagram", "handle": "moresoona"} | ||||
| 1257 | +{"platform": "instagram", "handle": "thebarberszone.ca"} | ||||
| 1258 | +{"platform": "instagram", "handle": "dishwithjudy"} | ||||
| 1259 | +{"platform": "instagram", "handle": "lakeshoretattoocollective"} | ||||
| 1260 | +{"platform": "instagram", "handle": "clearcanvas.lasers"} | ||||
| 1261 | +{"platform": "instagram", "handle": "sandosmusic"} | ||||
| 1262 | +{"platform": "instagram", "handle": "amaaramaara"} | ||||
| 1263 | +{"platform": "instagram", "handle": "williamshirschtalent"} | ||||
| 1264 | +{"platform": "instagram", "handle": "chum1045"} | ||||
| 1265 | +{"platform": "instagram", "handle": "cynthiaandjosie"} | ||||
| 1266 | +{"platform": "instagram", "handle": "olivier.boyer"} | ||||
| 1267 | +{"platform": "instagram", "handle": "lovetunay"} | ||||
| 1268 | +{"platform": "instagram", "handle": "pineandpaisleyminiatures"} | ||||
| 1269 | +{"platform": "instagram", "handle": "drcindyhovington"} | ||||
| 1270 | +{"platform": "instagram", "handle": "thefeduppotter"} | ||||
| 1271 | +{"platform": "instagram", "handle": "cedricgrolet"} | ||||
modified
data/sources.json
+36 −0
@@ -283,6 +283,42 @@ | |||||
| 283 | "signal_identite": "—", | 283 | "signal_identite": "—", | ||
| 284 | "cadence": "hebdomadaire (rotation 7 j, lot <=200)", | 284 | "cadence": "hebdomadaire (rotation 7 j, lot <=200)", | ||
| 285 | "notes": "abonnés, bio, badge, compteurs de médias, avatar" | 285 | "notes": "abonnés, bio, badge, compteurs de médias, avatar" | ||
| 286 | + }, | ||||
| 287 | + { | ||||
| 288 | + "id": "tavily-seed", | ||||
| 289 | + "famille": "decouverte", | ||||
| 290 | + "palier": 3, | ||||
| 291 | + "acces": "dataset local moissonné par le Tavily scout (outils/creator-harvest.py) : handles extraits des annuaires/palmarès/agences QC", | ||||
| 292 | + "signal_identite": "listes_medias (0.85)", | ||||
| 293 | + "cadence": "par vague (re-moisson périodique)", | ||||
| 294 | + "notes": "expansion massive du bassin ; existence vérifiée ensuite par lenrichissement Apify" | ||||
| 295 | + }, | ||||
| 296 | + { | ||||
| 297 | + "id": "snowball-ig", | ||||
| 298 | + "famille": "decouverte", | ||||
| 299 | + "palier": 1, | ||||
| 300 | + "acces": "base interne : profils reliés Instagram (related_profiles) captés par instagram-apify", | ||||
| 301 | + "signal_identite": "mention (0.60) — à confirmer par enrichissement", | ||||
| 302 | + "cadence": "quotidienne (parcours en largeur, cap 4000/vague)", | ||||
| 303 | + "notes": "levier déchelle : chaque profil IG suggère ~10-20 comptes similaires" | ||||
| 304 | + }, | ||||
| 305 | + { | ||||
| 306 | + "id": "patreon-apify", | ||||
| 307 | + "famille": "enrichissement", | ||||
| 308 | + "palier": 3, | ||||
| 309 | + "acces": "acteur Apify maison ka-patreon (données embarquées de la page publique)", | ||||
| 310 | + "signal_identite": "—", | ||||
| 311 | + "cadence": "hebdomadaire (rotation 7 j)", | ||||
| 312 | + "notes": "patrons, publications, nom, avatar" | ||||
| 313 | + }, | ||||
| 314 | + { | ||||
| 315 | + "id": "discord-apify", | ||||
| 316 | + "famille": "enrichissement", | ||||
| 317 | + "palier": 2, | ||||
| 318 | + "acces": "acteur Apify maison ka-discord (API publique d'invitation, code sensible à la casse depuis l'URL)", | ||||
| 319 | + "signal_identite": "—", | ||||
| 320 | + "cadence": "hebdomadaire (rotation 7 j)", | ||||
| 321 | + "notes": "membres approximatifs, en ligne, boosts, nom/description du serveur" | ||||
| 286 | } | 322 | } | ||
| 287 | ] | 323 | ] | ||
| 288 | } | 324 | } | ||
| \ No newline at end of file | |||||
modified
docs/connecteurs/INDEX.md
+20 −16
@@ -1,21 +1,21 @@ | |||||
| 1 | # Créa-Ka — Index des connecteurs | 1 | # Créa-Ka — Index des connecteurs | ||
| 2 | 2 | ||||
| 3 | −_Généré automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Généré automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | −**31 sources au registre** · **9437 créateurs** et **10512 comptes** en BD. | 5 | +**35 sources au registre** · **9437 créateurs** et **10533 comptes** en BD. | ||
| 6 | 6 | ||||
| 7 | | Source | Famille | Palier | Type d'accès | Backend | Découverts | Comptes (plateforme) | État | Dernier passage | | 7 | | Source | Famille | Palier | Type d'accès | Backend | Découverts | Comptes (plateforme) | État | Dernier passage | | ||
| 8 | |---|---|---|---|---|---|---|---|---| | 8 | |---|---|---|---|---|---|---|---|---| | ||
| 9 | | [`listes-medias`](listes-medias.md) | decouverte | P3 | dataset local compilé (data/seed) | direct | 310 | — | actif | 2026-08-18T10:27… | | 9 | | [`listes-medias`](listes-medias.md) | decouverte | P3 | dataset local compilé (data/seed) | direct | 310 | — | actif | 2026-08-18T10:27… | | ||
| 10 | | [`wikidata-qc`](wikidata-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 73 | — | actif | 2026-08-18T10:36… | | 10 | | [`wikidata-qc`](wikidata-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 73 | — | actif | 2026-08-18T10:36… | | ||
| 11 | −| [`onlyqueb`](onlyqueb.md) | decouverte | P3 | sitemap XML + JSON-LD des pages profil (S… | direct | 253 | 248 (onlyfans) | actif | 2026-08-18T10:32… | | 11 | +| [`onlyqueb`](onlyqueb.md) | decouverte | P3 | sitemap XML + JSON-LD des pages profil (S… | direct | 253 | 250 (onlyfans) | actif | 2026-08-18T10:32… | | ||
| 12 | −| [`youtube-recherche`](youtube-recherche.md) | decouverte | P3 | API JSON | direct | 7876 | 8084 (youtube) | actif | 2026-08-18T17:05… | | 12 | +| [`youtube-recherche`](youtube-recherche.md) | decouverte | P3 | API JSON | direct | 7876 | 8086 (youtube) | actif | 2026-08-18T17:05… | | ||
| 13 | | [`wikipedia-qc`](wikipedia-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 84 | — | actif | 2026-08-18T14:44… | | 13 | | [`wikipedia-qc`](wikipedia-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 84 | — | actif | 2026-08-18T14:44… | | ||
| 14 | | [`palmares-apple`](palmares-apple.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 0 | 462 (podcast) | actif | 2026-08-18T10:35… | | 14 | | [`palmares-apple`](palmares-apple.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 0 | 462 (podcast) | actif | 2026-08-18T10:35… | | ||
| 15 | −| [`balados-itunes`](balados-itunes.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 460 | 462 (podcast) | actif | 2026-08-18T14:48… | | 15 | +| [`balados-itunes`](balados-itunes.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 460 | 462 (podcast) | actif | 2026-08-18T20:11… | | ||
| 16 | | [`instagram-profil`](instagram-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 495 (instagram) | actif | 2026-08-18T12:04… | | 16 | | [`instagram-profil`](instagram-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 495 (instagram) | actif | 2026-08-18T12:04… | | ||
| 17 | | [`tiktok-profil`](tiktok-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 224 (tiktok) | actif | 2026-08-18T13:25… | | 17 | | [`tiktok-profil`](tiktok-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 224 (tiktok) | actif | 2026-08-18T13:25… | | ||
| 18 | −| [`youtube`](youtube.md) | enrichissement | P2 | API JSON | direct | 0 | 8084 (youtube) | actif | 2026-08-18T17:21… | | 18 | +| [`youtube`](youtube.md) | enrichissement | P2 | API JSON | direct | 0 | 8086 (youtube) | actif | 2026-08-18T17:21… | | ||
| 19 | | [`twitch`](twitch.md) | enrichissement | P2 | API JSON | direct | 0 | 292 (twitch) | actif | 2026-08-18T17:05… | | 19 | | [`twitch`](twitch.md) | enrichissement | P2 | API JSON | direct | 0 | 292 (twitch) | actif | 2026-08-18T17:05… | | ||
| 20 | | [`link-in-bio`](link-in-bio.md) | enrichissement | P1 | pages HTML publiques | Firecrawl | 0 | — | actif | 2026-08-18T17:29… | | 20 | | [`link-in-bio`](link-in-bio.md) | enrichissement | P1 | pages HTML publiques | Firecrawl | 0 | — | actif | 2026-08-18T17:29… | | ||
| 21 | | [`balados-rss`](balados-rss.md) | enrichissement | P1 | flux RSS publics | direct | 0 | 462 (podcast) | actif | 2026-08-18T13:48… | | 21 | | [`balados-rss`](balados-rss.md) | enrichissement | P1 | flux RSS publics | direct | 0 | 462 (podcast) | actif | 2026-08-18T13:48… | | ||
@@ -25,15 +25,19 @@ _Généré automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14: | |||||
| 25 | | [`twitch-decouverte`](twitch-decouverte.md) | decouverte | P3 | pages HTML publiques | direct | 262 | — | actif | 2026-08-18T14:33… | | 25 | | [`twitch-decouverte`](twitch-decouverte.md) | decouverte | P3 | pages HTML publiques | direct | 262 | — | actif | 2026-08-18T14:33… | | ||
| 26 | | [`kick-decouverte`](kick-decouverte.md) | decouverte | P4 | pages HTML publiques | Scrapfly | 119 | — | actif | 2026-08-18T14:42… | | 26 | | [`kick-decouverte`](kick-decouverte.md) | decouverte | P4 | pages HTML publiques | Scrapfly | 119 | — | actif | 2026-08-18T14:42… | | ||
| 27 | | [`region-bio`](region-bio.md) | enrichissement | P1 | pages HTML publiques | direct | 0 | — | actif | 2026-08-18T17:29… | | 27 | | [`region-bio`](region-bio.md) | enrichissement | P1 | pages HTML publiques | direct | 0 | — | actif | 2026-08-18T17:29… | | ||
| 28 | −| [`instagram-apify`](instagram-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | 28 | +| [`instagram-apify`](instagram-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | 2026-08-18T19:58… | | ||
| 29 | −| [`tiktok-apify`](tiktok-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | 29 | +| [`tiktok-apify`](tiktok-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | 2026-08-18T20:05… | | ||
| 30 | −| [`x-apify`](x-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | — | | 30 | +| [`x-apify`](x-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | 2026-08-18T19:51… | | ||
| 31 | −| [`facebook-apify`](facebook-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | 31 | +| [`facebook-apify`](facebook-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | 2026-08-18T19:21… | | ||
| 32 | −| [`threads-apify`](threads-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | 32 | +| [`threads-apify`](threads-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | 2026-08-18T19:21… | | ||
| 33 | −| [`snapchat-apify`](snapchat-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | — | | 33 | +| [`snapchat-apify`](snapchat-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | 2026-08-18T19:21… | | ||
| 34 | | [`instagram-decouverte`](instagram-decouverte.md) | decouverte | P4 | API JSON | direct | 0 | — | actif | — | | 34 | | [`instagram-decouverte`](instagram-decouverte.md) | decouverte | P4 | API JSON | direct | 0 | — | actif | — | | ||
| 35 | −| [`youtube-apify`](youtube-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | — | | 35 | +| [`youtube-apify`](youtube-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | 2026-08-18T19:55… | | ||
| 36 | −| [`twitch-apify`](twitch-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | — | | 36 | +| [`twitch-apify`](twitch-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | 2026-08-18T19:21… | | ||
| 37 | −| [`kick-apify`](kick-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | 37 | +| [`kick-apify`](kick-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | 2026-08-18T19:21… | | ||
| 38 | | [`onlyfans-apify`](onlyfans-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | 38 | | [`onlyfans-apify`](onlyfans-apify.md) | enrichissement | P4 | — | — | 0 | — | actif | — | | ||
| 39 | −| [`fansly-apify`](fansly-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | — | | 39 | +| [`fansly-apify`](fansly-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | 2026-08-18T19:21… | | ||
| 40 | +| [`tavily-seed`](tavily-seed.md) | decouverte | P3 | dataset local compilé (data/seed) | direct | 0 | — | actif | — | | ||||
| 41 | +| [`snowball-ig`](snowball-ig.md) | decouverte | P1 | pages HTML publiques | direct | 0 | — | actif | — | | ||||
| 42 | +| [`patreon-apify`](patreon-apify.md) | enrichissement | P3 | — | — | 0 | — | actif | — | | ||||
| 43 | +| [`discord-apify`](discord-apify.md) | enrichissement | P2 | — | — | 0 | — | actif | — | | ||||
modified
docs/connecteurs/balados-itunes.md
+7 −7
@@ -1,6 +1,6 @@ | |||||
| 1 | # `balados-itunes` — connecteur decouverte (palier 2) | 1 | # `balados-itunes` — connecteur decouverte (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 460 · touchés : 460 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 460 · touchés : 460 | ||
| 6 | 6 | ||||
@@ -39,7 +39,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 39 | | `primary_platform` | Plateforme principale | 100 % | instagram | | 39 | | `primary_platform` | Plateforme principale | 100 % | instagram | | ||
| 40 | | `platforms` | Comptes sociaux (liste) | 100 % | instagram:@quebec_nostalgie, youtube:@UC10F7nTroeQocT2vqf2LoIw, podcast:@1741442896 | | 40 | | `platforms` | Comptes sociaux (liste) | 100 % | instagram:@quebec_nostalgie, youtube:@UC10F7nTroeQocT2vqf2LoIw, podcast:@1741442896 | | ||
| 41 | | `avatar_url` | Avatar | 100 % | https://is1-ssl.mzstatic.com/image/thumb/Podcasts211/v4/3a/5f/12/3a5f1256-74a6-f716-ffb8-… | | 41 | | `avatar_url` | Avatar | 100 % | https://is1-ssl.mzstatic.com/image/thumb/Podcasts211/v4/3a/5f/12/3a5f1256-74a6-f716-ffb8-… | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 0 % | 109744 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 1 % | 109741 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | https://linktr.ee/QuebecNostalgie | | 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | https://linktr.ee/QuebecNostalgie | | ||
| 44 | 44 | ||||
| 45 | Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (462 comptes en BD, confiance moyenne 0.98). | 45 | Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (462 comptes en BD, confiance moyenne 0.98). | ||
@@ -58,16 +58,16 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 58 | ## Fréquence & budget | 58 | ## Fréquence & budget | ||
| 59 | 59 | ||||
| 60 | - **Cadence déclarée (registre)** : quotidienne (watch) | 60 | - **Cadence déclarée (registre)** : quotidienne (watch) | ||
| 61 | −- **Cadence observée** (médiane sync_log) : ≈ 40 min | 61 | +- **Cadence observée** (médiane sync_log) : ≈ 47 min | ||
| 62 | −- **Dernier passage** : 2026-08-18T14:48:10Z — 460 créateurs, 460 comptes, +27 / ~433, 0 erreur(s), 241 s | 62 | +- **Dernier passage** : 2026-08-18T20:11:39Z — 460 créateurs, 460 comptes, +0 / ~460, 0 erreur(s), 224 s | ||
| 63 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | 63 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | ||
| 64 | 64 | ||||
| 65 | ## Volumétrie & complétude | 65 | ## Volumétrie & complétude | ||
| 66 | 66 | ||||
| 67 | - **Créateurs découverts par la source** (`doc.source`) : 460 · **fiches touchées** (`source_ids`) : 460 | 67 | - **Créateurs découverts par la source** (`doc.source`) : 460 · **fiches touchées** (`source_ids`) : 460 | ||
| 68 | −- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 0 % · région 8 % | 68 | +- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 1 % · région 8 % | ||
| 69 | −- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | 69 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T20:11:39Z | ||
| 70 | −- **Runs journalisés (60 derniers)** : 9, dont 0 avec erreurs | 70 | +- **Runs journalisés (60 derniers)** : 10, dont 0 avec erreurs | ||
| 71 | 71 | ||||
| 72 | ## Erreurs connues & dépannage | 72 | ## Erreurs connues & dépannage | ||
| 73 | 73 | ||||
modified
docs/connecteurs/balados-rss.md
+2 −2
@@ -1,6 +1,6 @@ | |||||
| 1 | # `balados-rss` — connecteur enrichissement (palier 1) | 1 | # `balados-rss` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | 51 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T20:11:39Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 6, dont 5 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 6, dont 5 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/bio-liens.md
+1 −1
@@ -1,6 +1,6 @@ | |||||
| 1 | # `bio-liens` — connecteur enrichissement (palier 1) | 1 | # `bio-liens` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
added
docs/connecteurs/discord-apify.md
+45 −0
@@ -0,0 +1,45 @@ | |||||
| 1 | +# `discord-apify` — connecteur enrichissement (palier 2) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +- **Notes (registre)** : membres approximatifs, en ligne, boosts, nom/description du serveur | ||||
| 10 | +- **Signal d'identité** : — (colonne `accounts.signal` / `confidence`) | ||||
| 11 | +- **Module** : introuvable (vérifier le registre) | ||||
| 12 | + | ||||
| 13 | +## Accès | ||||
| 14 | + | ||||
| 15 | +- **Accès (registre)** : acteur Apify maison ka-discord (API publique d'invitation, code sensible à la casse depuis l'URL) | ||||
| 16 | + | ||||
| 17 | +## Champs récupérés → schéma cible | ||||
| 18 | + | ||||
| 19 | +Aucune donnée attribuable à cette source en BD pour l'instant (clés manquantes ou source en attente) — schéma cible : `creators` + `accounts`. | ||||
| 20 | + | ||||
| 21 | +## Fréquence & budget | ||||
| 22 | + | ||||
| 23 | +- **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j) | ||||
| 24 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 25 | + | ||||
| 26 | +## Volumétrie & complétude | ||||
| 27 | + | ||||
| 28 | +- **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||||
| 29 | +- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | ||||
| 30 | + | ||||
| 31 | +## Erreurs connues & dépannage | ||||
| 32 | + | ||||
| 33 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 34 | + | ||||
| 35 | +Rejouer la source seule : `python3 run.py sync discord-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='discord-apify' ORDER BY ts DESC LIMIT 5;`). | ||||
| 36 | + | ||||
| 37 | +## Licence, attribution & conditions | ||||
| 38 | + | ||||
| 39 | +- **Cadre d'accès (registre)** : acteur Apify maison ka-discord (API publique d'invitation, code sensible à la casse depuis l'URL) | ||||
| 40 | +- **API publique** utilisée selon ses conditions (pas de clé détournée, throttling poli) ; données limitées aux profils publics. | ||||
| 41 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 42 | + | ||||
| 43 | +## Historique | ||||
| 44 | + | ||||
| 45 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
modified
docs/connecteurs/facebook-apify.md
+9 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `facebook-apify` — connecteur enrichissement (palier 4) | 1 | # `facebook-apify` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,20 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=100) | 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=100) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 9 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:21:41Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 0 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:21:41Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:03:59Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 38 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync facebook-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='facebook-apify' ORDER BY ts DESC LIMIT 5;`). | 39 | Rejouer la source seule : `python3 run.py sync facebook-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='facebook-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 40 | ||||
@@ -42,4 +46,5 @@ Rejouer la source seule : `python3 run.py sync facebook-apify` · vérifier `syn | |||||
| 42 | 46 | ||||
| 43 | ## Historique | 47 | ## Historique | ||
| 44 | 48 | ||||
| 49 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 50 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/fansly-apify.md
+9 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `fansly-apify` — connecteur enrichissement (palier 3) | 1 | # `fansly-apify` — connecteur enrichissement (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,20 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=200) | 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=200) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 9 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:21:41Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 0 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:21:41Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:03:58Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 38 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync fansly-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='fansly-apify' ORDER BY ts DESC LIMIT 5;`). | 39 | Rejouer la source seule : `python3 run.py sync fansly-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='fansly-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 40 | ||||
@@ -42,4 +46,5 @@ Rejouer la source seule : `python3 run.py sync fansly-apify` · vérifier `sync_ | |||||
| 42 | 46 | ||||
| 43 | ## Historique | 47 | ## Historique | ||
| 44 | 48 | ||||
| 49 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 50 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/instagram-apify.md
+10 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `instagram-apify` — connecteur enrichissement (palier 4) | 1 | # `instagram-apify` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,21 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=400) | 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=400) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 18 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:58:58Z — 276 créateurs, 767 comptes, +0 / ~276, 0 erreur(s), 182 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:29:35Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:21:42Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 38 | +| 2026-08-18T19:03:58Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 39 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync instagram-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='instagram-apify' ORDER BY ts DESC LIMIT 5;`). | 40 | Rejouer la source seule : `python3 run.py sync instagram-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='instagram-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 41 | ||||
@@ -42,4 +47,5 @@ Rejouer la source seule : `python3 run.py sync instagram-apify` · vérifier `sy | |||||
| 42 | 47 | ||||
| 43 | ## Historique | 48 | ## Historique | ||
| 44 | 49 | ||||
| 50 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 51 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/instagram-decouverte.md
+1 −1
@@ -1,6 +1,6 @@ | |||||
| 1 | # `instagram-decouverte` — connecteur decouverte (palier 4) | 1 | # `instagram-decouverte` — connecteur decouverte (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
modified
docs/connecteurs/instagram-profil.md
+6 −6
@@ -1,6 +1,6 @@ | |||||
| 1 | # `instagram-profil` — connecteur enrichissement (palier 4) | 1 | # `instagram-profil` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -31,12 +31,12 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `handle` | Handle | 100 % | catherinepaiz | | 32 | | `handle` | Handle | 100 % | catherinepaiz | | ||
| 33 | | `url` | URL du profil | 100 % | https://www.instagram.com/catherinepaiz/ | | 33 | | `url` | URL du profil | 100 % | https://www.instagram.com/catherinepaiz/ | | ||
| 34 | −| `followers` | Abonnés | 70 % | 7023251 | | 34 | +| `followers` | Abonnés | 73 % | 7022873 | | ||
| 35 | −| `verified` | Badge vérifié | 58 % | 1 | | 35 | +| `verified` | Badge vérifié | 62 % | 1 | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | base_publique | | 37 | | `signal` | Signal d'identité | 100 % | base_publique | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 58 % | {"following": 248, "posts": 667, "is_business": false} | | 38 | +| `metrics` | Métriques détaillées (JSON) | 62 % | {"following": 248, "posts": 667, "is_business": false, "highlight_reels": 22, "avg_likes"… | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T11:35:29Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T19:58:58Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `instagram` en BD** : 495 — abonnés 70 % · métriques 58 % · dernière vérification 2026-08-18T17:29:45Z | 51 | +- **Comptes `instagram` en BD** : 495 — abonnés 73 % · métriques 62 % · dernière vérification 2026-08-18T20:05:02Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 5, dont 0 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 5, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/kick-apify.md
+9 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `kick-apify` — connecteur enrichissement (palier 4) | 1 | # `kick-apify` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,20 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=120) | 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=120) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 9 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:21:40Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 0 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:21:40Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:03:58Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 38 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync kick-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='kick-apify' ORDER BY ts DESC LIMIT 5;`). | 39 | Rejouer la source seule : `python3 run.py sync kick-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='kick-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 40 | ||||
@@ -42,4 +46,5 @@ Rejouer la source seule : `python3 run.py sync kick-apify` · vérifier `sync_lo | |||||
| 42 | 46 | ||||
| 43 | ## Historique | 47 | ## Historique | ||
| 44 | 48 | ||||
| 49 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 50 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/kick-decouverte.md
+7 −7
@@ -1,6 +1,6 @@ | |||||
| 1 | # `kick-decouverte` — connecteur decouverte (palier 4) | 1 | # `kick-decouverte` — connecteur decouverte (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : Scrapfly · Créateurs découverts : 119 · touchés : 119 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : Scrapfly · Créateurs découverts : 119 · touchés : 119 | ||
| 6 | 6 | ||||
@@ -29,17 +29,17 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 29 | 29 | ||||
| 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | −| `display_name` | Nom public | 100 % | valquebrada | | 32 | +| `display_name` | Nom public | 100 % | juandemontreal | | ||
| 33 | −| `bio` | Bio | 25 % | Meu nome é Valmir Lima, tenho 32 anos de idade, curto jogar GTA RP. Vou mostrar um pouco … | | 33 | +| `bio` | Bio | 28 % | Gracias por seguirme hasta aqui tmb............ | | ||
| 34 | | `region` | Région | 0 % | — | | 34 | | `region` | Région | 0 % | — | | ||
| 35 | | `city` | Ville | 0 % | — | | 35 | | `city` | Ville | 0 % | — | | ||
| 36 | | `niches` | Niches (liste) | 100 % | gaming | | 36 | | `niches` | Niches (liste) | 100 % | gaming | | ||
| 37 | | `languages` | Langues (liste) | 100 % | fr | | 37 | | `languages` | Langues (liste) | 100 % | fr | | ||
| 38 | | `creator_type` | Type de créateur | 100 % | streamer | | 38 | | `creator_type` | Type de créateur | 100 % | streamer | | ||
| 39 | −| `primary_platform` | Plateforme principale | 100 % | twitch | | 39 | +| `primary_platform` | Plateforme principale | 100 % | tiktok | | ||
| 40 | −| `platforms` | Comptes sociaux (liste) | 100 % | twitch:@valquebrada, kick:@valquebrada, instagram:@val_quebrada | | 40 | +| `platforms` | Comptes sociaux (liste) | 100 % | tiktok:@juandemontrealoficial, instagram:@juandemontreal, kick:@juandemontreal | | ||
| 41 | −| `avatar_url` | Avatar | 40 % | https://files.kick.com/images/user/15480678/profile_image/conversion/f1cf1446-e43a-478d-8… | | 41 | +| `avatar_url` | Avatar | 40 % | https://files.kick.com/images/user/36432333/profile_image/conversion/2e63a30c-e041-4915-9… | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 56 % | 2772 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 56 % | 23455724 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | — | | 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | — | | ||
| 44 | 44 | ||||
| 45 | ## Fréquence & budget | 45 | ## Fréquence & budget | ||
modified
docs/connecteurs/link-in-bio.md
+1 −1
@@ -1,6 +1,6 @@ | |||||
| 1 | # `link-in-bio` — connecteur enrichissement (palier 1) | 1 | # `link-in-bio` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Firecrawl · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Firecrawl · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
modified
docs/connecteurs/listes-medias.md
+6 −6
@@ -1,6 +1,6 @@ | |||||
| 1 | # `listes-medias` — connecteur decouverte (palier 3) | 1 | # `listes-medias` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 310 · touchés : 310 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 310 · touchés : 310 | ||
| 6 | 6 | ||||
@@ -29,7 +29,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 29 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 29 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 30 | |---|---|---|---| | 30 | |---|---|---|---| | ||
| 31 | | `display_name` | Nom public | 100 % | Enola Bédard | | 31 | | `display_name` | Nom public | 100 % | Enola Bédard | | ||
| 32 | −| `bio` | Bio | 73 % | Énola Bédard (born September 14, 2000) is a Canadian dancer, singer, and social media per… | | 32 | +| `bio` | Bio | 76 % | Énola Bédard (born September 14, 2000) is a Canadian dancer, singer, and social media per… | | ||
| 33 | | `region` | Région | 51 % | Capitale-Nationale | | 33 | | `region` | Région | 51 % | Capitale-Nationale | | ||
| 34 | | `city` | Ville | 51 % | Québec | | 34 | | `city` | Ville | 51 % | Québec | | ||
| 35 | | `niches` | Niches (liste) | 100 % | danse, lifestyle | | 35 | | `niches` | Niches (liste) | 100 % | danse, lifestyle | | ||
@@ -37,9 +37,9 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 37 | | `creator_type` | Type de créateur | 100 % | createur-tiktok | | 37 | | `creator_type` | Type de créateur | 100 % | createur-tiktok | | ||
| 38 | | `primary_platform` | Plateforme principale | 100 % | tiktok | | 38 | | `primary_platform` | Plateforme principale | 100 % | tiktok | | ||
| 39 | | `platforms` | Comptes sociaux (liste) | 100 % | tiktok:@enola.bedard, youtube:@enola.bedard, instagram:@enola.bedard | | 39 | | `platforms` | Comptes sociaux (liste) | 100 % | tiktok:@enola.bedard, youtube:@enola.bedard, instagram:@enola.bedard | | ||
| 40 | −| `avatar_url` | Avatar | 75 % | https://scontent-lga3-2.cdninstagram.com/v/t51.82787-19/515154150_18510310135012441_32506… | | 40 | +| `avatar_url` | Avatar | 78 % | https://scontent-lga3-2.cdninstagram.com/v/t51.82787-19/515154150_18510310135012441_32506… | | ||
| 41 | −| `total_reach` | Portée totale (abonnés cumulés) | 90 % | 24917522 | | 41 | +| `total_reach` | Portée totale (abonnés cumulés) | 91 % | 24996097 | | ||
| 42 | −| `link_in_bio_url` | Lien-en-bio | 24 % | — | | 42 | +| `link_in_bio_url` | Lien-en-bio | 25 % | — | | ||
| 43 | 43 | ||||
| 44 | ## Fréquence & budget | 44 | ## Fréquence & budget | ||
| 45 | 45 | ||||
@@ -51,7 +51,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 51 | ## Volumétrie & complétude | 51 | ## Volumétrie & complétude | ||
| 52 | 52 | ||||
| 53 | - **Créateurs découverts par la source** (`doc.source`) : 310 · **fiches touchées** (`source_ids`) : 310 | 53 | - **Créateurs découverts par la source** (`doc.source`) : 310 · **fiches touchées** (`source_ids`) : 310 | ||
| 54 | −- **Complétude clé (découverts)** : niches 100 % · avatar 75 % · portée 90 % · région 51 % | 54 | +- **Complétude clé (découverts)** : niches 100 % · avatar 78 % · portée 91 % · région 51 % | ||
| 55 | - **Runs journalisés (60 derniers)** : 12, dont 0 avec erreurs | 55 | - **Runs journalisés (60 derniers)** : 12, dont 0 avec erreurs | ||
| 56 | 56 | ||||
| 57 | ## Erreurs connues & dépannage | 57 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/onlyfans-apify.md
+1 −1
@@ -1,6 +1,6 @@ | |||||
| 1 | # `onlyfans-apify` — connecteur enrichissement (palier 4) | 1 | # `onlyfans-apify` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
modified
docs/connecteurs/onlyqueb.md
+7 −7
@@ -1,6 +1,6 @@ | |||||
| 1 | # `onlyqueb` — connecteur decouverte (palier 3) | 1 | # `onlyqueb` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 253 · touchés : 253 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 253 · touchés : 253 | ||
| 6 | 6 | ||||
@@ -37,12 +37,12 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 37 | | `languages` | Langues (liste) | 100 % | fr | | 37 | | `languages` | Langues (liste) | 100 % | fr | | ||
| 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | ||
| 39 | | `primary_platform` | Plateforme principale | 100 % | instagram | | 39 | | `primary_platform` | Plateforme principale | 100 % | instagram | | ||
| 40 | −| `platforms` | Comptes sociaux (liste) | 100 % | instagram:@jadelavoie, x:@missjadelavoie, onlyfans:@misslavoie | | 40 | +| `platforms` | Comptes sociaux (liste) | 100 % | instagram:@jadelavoie, tiktok:@miss.jadelavoie, x:@missjadelavoie | | ||
| 41 | | `avatar_url` | Avatar | 100 % | https://storage.googleapis.com/onlyqueb/MQZBiXsbMQa31zxj9P_mabNxNITFBxa6 | | 41 | | `avatar_url` | Avatar | 100 % | https://storage.googleapis.com/onlyqueb/MQZBiXsbMQa31zxj9P_mabNxNITFBxa6 | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 20 % | 1571053 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 35 % | 2615987 | | ||
| 43 | −| `link_in_bio_url` | Lien-en-bio | 2 % | — | | 43 | +| `link_in_bio_url` | Lien-en-bio | 5 % | — | | ||
| 44 | 44 | ||||
| 45 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `onlyfans` (248 comptes en BD, confiance moyenne 0.90). | 45 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `onlyfans` (250 comptes en BD, confiance moyenne 0.90). | ||
| 46 | 46 | ||||
| 47 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 47 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 48 | |---|---|---|---| | 48 | |---|---|---|---| | ||
@@ -65,8 +65,8 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 65 | ## Volumétrie & complétude | 65 | ## Volumétrie & complétude | ||
| 66 | 66 | ||||
| 67 | - **Créateurs découverts par la source** (`doc.source`) : 253 · **fiches touchées** (`source_ids`) : 253 | 67 | - **Créateurs découverts par la source** (`doc.source`) : 253 · **fiches touchées** (`source_ids`) : 253 | ||
| 68 | −- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 20 % · région 2 % | 68 | +- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 35 % · région 2 % | ||
| 69 | −- **Comptes `onlyfans` en BD** : 248 — abonnés 0 % · métriques 0 % · dernière vérification 2026-08-18T17:29:45Z | 69 | +- **Comptes `onlyfans` en BD** : 250 — abonnés 0 % · métriques 0 % · dernière vérification 2026-08-18T19:58:58Z | ||
| 70 | - **Runs journalisés (60 derniers)** : 8, dont 0 avec erreurs | 70 | - **Runs journalisés (60 derniers)** : 8, dont 0 avec erreurs | ||
| 71 | 71 | ||||
| 72 | ## Erreurs connues & dépannage | 72 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/palmares-apple.md
+2 −2
@@ -1,6 +1,6 @@ | |||||
| 1 | # `palmares-apple` — connecteur decouverte (palier 2) | 1 | # `palmares-apple` — connecteur decouverte (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | 51 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T20:11:39Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
added
docs/connecteurs/patreon-apify.md
+45 −0
@@ -0,0 +1,45 @@ | |||||
| 1 | +# `patreon-apify` — connecteur enrichissement (palier 3) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +- **Notes (registre)** : patrons, publications, nom, avatar | ||||
| 10 | +- **Signal d'identité** : — (colonne `accounts.signal` / `confidence`) | ||||
| 11 | +- **Module** : introuvable (vérifier le registre) | ||||
| 12 | + | ||||
| 13 | +## Accès | ||||
| 14 | + | ||||
| 15 | +- **Accès (registre)** : acteur Apify maison ka-patreon (données embarquées de la page publique) | ||||
| 16 | + | ||||
| 17 | +## Champs récupérés → schéma cible | ||||
| 18 | + | ||||
| 19 | +Aucune donnée attribuable à cette source en BD pour l'instant (clés manquantes ou source en attente) — schéma cible : `creators` + `accounts`. | ||||
| 20 | + | ||||
| 21 | +## Fréquence & budget | ||||
| 22 | + | ||||
| 23 | +- **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j) | ||||
| 24 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 25 | + | ||||
| 26 | +## Volumétrie & complétude | ||||
| 27 | + | ||||
| 28 | +- **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||||
| 29 | +- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | ||||
| 30 | + | ||||
| 31 | +## Erreurs connues & dépannage | ||||
| 32 | + | ||||
| 33 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 34 | + | ||||
| 35 | +Rejouer la source seule : `python3 run.py sync patreon-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='patreon-apify' ORDER BY ts DESC LIMIT 5;`). | ||||
| 36 | + | ||||
| 37 | +## Licence, attribution & conditions | ||||
| 38 | + | ||||
| 39 | +- **Cadre d'accès (registre)** : acteur Apify maison ka-patreon (données embarquées de la page publique) | ||||
| 40 | +- **API publique** utilisée selon ses conditions (pas de clé détournée, throttling poli) ; données limitées aux profils publics. | ||||
| 41 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 42 | + | ||||
| 43 | +## Historique | ||||
| 44 | + | ||||
| 45 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
modified
docs/connecteurs/podcastindex.md
+2 −2
@@ -1,6 +1,6 @@ | |||||
| 1 | # `podcastindex` — connecteur enrichissement (palier 2) | 1 | # `podcastindex` — connecteur enrichissement (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : prêt — clés requises** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : prêt — clés requises** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -47,7 +47,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 47 | ## Volumétrie & complétude | 47 | ## Volumétrie & complétude | ||
| 48 | 48 | ||||
| 49 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 49 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 50 | −- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | 50 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T20:11:39Z | ||
| 51 | - **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 51 | - **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | ||
| 52 | 52 | ||||
| 53 | ## Erreurs connues & dépannage | 53 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/region-bio.md
+1 −1
@@ -1,6 +1,6 @@ | |||||
| 1 | # `region-bio` — connecteur enrichissement (palier 1) | 1 | # `region-bio` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
modified
docs/connecteurs/snapchat-apify.md
+9 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `snapchat-apify` — connecteur enrichissement (palier 3) | 1 | # `snapchat-apify` — connecteur enrichissement (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,20 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=60) | 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=60) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 9 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:21:40Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 0 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:21:40Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:03:59Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 38 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync snapchat-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='snapchat-apify' ORDER BY ts DESC LIMIT 5;`). | 39 | Rejouer la source seule : `python3 run.py sync snapchat-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='snapchat-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 40 | ||||
@@ -42,4 +46,5 @@ Rejouer la source seule : `python3 run.py sync snapchat-apify` · vérifier `syn | |||||
| 42 | 46 | ||||
| 43 | ## Historique | 47 | ## Historique | ||
| 44 | 48 | ||||
| 49 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 50 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
added
docs/connecteurs/snowball-ig.md
+54 −0
@@ -0,0 +1,54 @@ | |||||
| 1 | +# `snowball-ig` — connecteur decouverte (palier 1) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : decouverte (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +Connecteur DÉCOUVERTE par boule de neige — exploite les profils reliés (`related_profiles`) captés par l'enrichissement Instagram (instagram-apify) pour créer de nouvelles fiches. C'est le levier d'échelle : chaque profil IG suggère ~10-20 comptes similaires → parcours en largeur qui fait croître le bassin de dizaines de milliers au fil des vagues quotidiennes. Aucune requête réseau (lit la base). | ||||
| 10 | + | ||||
| 11 | +- **Notes (registre)** : levier déchelle : chaque profil IG suggère ~10-20 comptes similaires | ||||
| 12 | +- **Signal d'identité** : mention (0.60) — à confirmer par enrichissement (colonne `accounts.signal` / `confidence`) | ||||
| 13 | +- **Module** : `creaka/connectors/snowball.py` — classe `SnowballConnector` (`kind = "enrichment"`) | ||||
| 14 | + | ||||
| 15 | +## Accès | ||||
| 16 | + | ||||
| 17 | +- **Accès (registre)** : base interne : profils reliés Instagram (related_profiles) captés par instagram-apify | ||||
| 18 | +- **Type d'accès (code)** : pages HTML publiques | ||||
| 19 | +- **Endpoint de base** : — | ||||
| 20 | +- **Pagination** : réponse unique (pas de pagination) | ||||
| 21 | +- **Backend anti-bot / rendu** : requests direct | ||||
| 22 | +- **Politesse** : 0.8 s entre requêtes, timeout 30 s, UA `CreaKaBot/1.0 (+https://www.crea-ka.com/bot)` | ||||
| 23 | +- **Authentification** : aucune — contenu public / API anonyme | ||||
| 24 | + | ||||
| 25 | +## Champs récupérés → schéma cible | ||||
| 26 | + | ||||
| 27 | +Aucune donnée attribuable à cette source en BD pour l'instant (clés manquantes ou source en attente) — schéma cible : `creators` + `accounts`. | ||||
| 28 | + | ||||
| 29 | +## Fréquence & budget | ||||
| 30 | + | ||||
| 31 | +- **Cadence déclarée (registre)** : quotidienne (parcours en largeur, cap 4000/vague) | ||||
| 32 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 33 | +- **Throttling** : 0.8 s entre requêtes (`request_delay`) | ||||
| 34 | + | ||||
| 35 | +## Volumétrie & complétude | ||||
| 36 | + | ||||
| 37 | +- **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||||
| 38 | +- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | ||||
| 39 | + | ||||
| 40 | +## Erreurs connues & dépannage | ||||
| 41 | + | ||||
| 42 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 43 | + | ||||
| 44 | +Rejouer la source seule : `python3 run.py sync snowball-ig` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='snowball-ig' ORDER BY ts DESC LIMIT 5;`). | ||||
| 45 | + | ||||
| 46 | +## Licence, attribution & conditions | ||||
| 47 | + | ||||
| 48 | +- **Cadre d'accès (registre)** : base interne : profils reliés Instagram (related_profiles) captés par instagram-apify | ||||
| 49 | +- **Profils publics uniquement** : UA identifiable `CreaKaBot/1.0 (+https://www.crea-ka.com/bot; contact@spboucher.ai)`, throttling poli, respect des opt-out (`data/optout.json`) et du volet éthique (`creaka/ethics.py` — mineurs exclus via `is_minor`). | ||||
| 50 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 51 | + | ||||
| 52 | +## Historique | ||||
| 53 | + | ||||
| 54 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
added
docs/connecteurs/tavily-seed.md
+54 −0
@@ -0,0 +1,54 @@ | |||||
| 1 | +# `tavily-seed` — connecteur decouverte (palier 3) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +Connecteur DÉCOUVERTE à grande échelle — graines de créateurs québécois moissonnées par le Tavily scout (outils/creator-harvest.py du dépôt groupe-ka-connecteurs) : handles sociaux extraits des pages d'annuaires/palmarès/agences QC. Dataset local (aucune requête ici) : data/seed/qc_creator_seeds.jsonl. L'enrichissement (Apify) vérifie ensuite l'existence et remplit nom/abonnés/contenu. | ||||
| 10 | + | ||||
| 11 | +- **Notes (registre)** : expansion massive du bassin ; existence vérifiée ensuite par lenrichissement Apify | ||||
| 12 | +- **Signal d'identité** : listes_medias (0.85) (colonne `accounts.signal` / `confidence`) | ||||
| 13 | +- **Module** : `creaka/connectors/tavily_seed.py` — classe `TavilySeedConnector` (`kind = "discovery"`) | ||||
| 14 | + | ||||
| 15 | +## Accès | ||||
| 16 | + | ||||
| 17 | +- **Accès (registre)** : dataset local moissonné par le Tavily scout (outils/creator-harvest.py) : handles extraits des annuaires/palmarès/agences QC | ||||
| 18 | +- **Type d'accès (code)** : dataset local compilé (data/seed) | ||||
| 19 | +- **Endpoint de base** : — | ||||
| 20 | +- **Pagination** : réponse unique (pas de pagination) | ||||
| 21 | +- **Backend anti-bot / rendu** : requests direct | ||||
| 22 | +- **Politesse** : 0.8 s entre requêtes, timeout 30 s, UA `CreaKaBot/1.0 (+https://www.crea-ka.com/bot)` | ||||
| 23 | +- **Authentification** : aucune — contenu public / API anonyme | ||||
| 24 | + | ||||
| 25 | +## Champs récupérés → schéma cible | ||||
| 26 | + | ||||
| 27 | +Aucune donnée attribuable à cette source en BD pour l'instant (clés manquantes ou source en attente) — schéma cible : `creators` + `accounts`. | ||||
| 28 | + | ||||
| 29 | +## Fréquence & budget | ||||
| 30 | + | ||||
| 31 | +- **Cadence déclarée (registre)** : par vague (re-moisson périodique) | ||||
| 32 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 33 | +- **Throttling** : 0.8 s entre requêtes (`request_delay`) | ||||
| 34 | + | ||||
| 35 | +## Volumétrie & complétude | ||||
| 36 | + | ||||
| 37 | +- **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||||
| 38 | +- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | ||||
| 39 | + | ||||
| 40 | +## Erreurs connues & dépannage | ||||
| 41 | + | ||||
| 42 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 43 | + | ||||
| 44 | +Rejouer la source seule : `python3 run.py sync tavily-seed` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='tavily-seed' ORDER BY ts DESC LIMIT 5;`). | ||||
| 45 | + | ||||
| 46 | +## Licence, attribution & conditions | ||||
| 47 | + | ||||
| 48 | +- **Cadre d'accès (registre)** : dataset local moissonné par le Tavily scout (outils/creator-harvest.py) : handles extraits des annuaires/palmarès/agences QC | ||||
| 49 | +- **Données compilées** de listes et palmarès médias **publics** ; seuls des faits publics (nom, handle, audience approximative) sont conservés. | ||||
| 50 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 51 | + | ||||
| 52 | +## Historique | ||||
| 53 | + | ||||
| 54 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
modified
docs/connecteurs/threads-apify.md
+9 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `threads-apify` — connecteur enrichissement (palier 4) | 1 | # `threads-apify` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,20 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=60) | 23 | - **Cadence déclarée (registre)** : hebdomadaire (rotation 7 j, lot <=60) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 9 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:21:41Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 0 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:21:41Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:03:59Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 38 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync threads-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='threads-apify' ORDER BY ts DESC LIMIT 5;`). | 39 | Rejouer la source seule : `python3 run.py sync threads-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='threads-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 40 | ||||
@@ -42,4 +46,5 @@ Rejouer la source seule : `python3 run.py sync threads-apify` · vérifier `sync | |||||
| 42 | 46 | ||||
| 43 | ## Historique | 47 | ## Historique | ||
| 44 | 48 | ||||
| 49 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 50 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/tiktok-apify.md
+10 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `tiktok-apify` — connecteur enrichissement (palier 4) | 1 | # `tiktok-apify` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,21 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 31 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T20:05:02Z — 176 créateurs, 642 comptes, +0 / ~176, 38 erreur(s), 364 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 1 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T20:05:02Z | 38 | — | | ||||
| 37 | +| 2026-08-18T19:21:42Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 38 | +| 2026-08-18T19:03:58Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 39 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync tiktok-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='tiktok-apify' ORDER BY ts DESC LIMIT 5;`). | 40 | Rejouer la source seule : `python3 run.py sync tiktok-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='tiktok-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 41 | ||||
@@ -42,4 +47,5 @@ Rejouer la source seule : `python3 run.py sync tiktok-apify` · vérifier `sync_ | |||||
| 42 | 47 | ||||
| 43 | ## Historique | 48 | ## Historique | ||
| 44 | 49 | ||||
| 50 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 51 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/tiktok-profil.md
+10 −10
@@ -1,6 +1,6 @@ | |||||
| 1 | # `tiktok-profil` — connecteur enrichissement (palier 4) | 1 | # `tiktok-profil` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -29,14 +29,14 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | −| `handle` | Handle | 100 % | enola.bedard | | 32 | +| `handle` | Handle | 100 % | juandemontrealoficial | | ||
| 33 | −| `url` | URL du profil | 100 % | https://www.tiktok.com/@enola.bedard | | 33 | +| `url` | URL du profil | 100 % | https://www.tiktok.com/@juandemontrealoficial | | ||
| 34 | −| `followers` | Abonnés | 63 % | 17000000 | | 34 | +| `followers` | Abonnés | 84 % | 19810972 | | ||
| 35 | −| `verified` | Badge vérifié | 59 % | 1 | | 35 | +| `verified` | Badge vérifié | 83 % | 1 | | ||
| 36 | −| `confidence` | Confiance d'identité | 100 % | 0.85 | | 36 | +| `confidence` | Confiance d'identité | 100 % | 0.9 | | ||
| 37 | −| `signal` | Signal d'identité | 100 % | base_publique | | 37 | +| `signal` | Signal d'identité | 100 % | cross_link | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 59 % | {"following": 813, "likes": 438100000, "videos": 2847} | | 38 | +| `metrics` | Métriques détaillées (JSON) | 83 % | {"following": 3800, "likes": 686001479, "videos": 5366, "friends": 3637, "is_seller": fal… | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T14:44:09Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T20:05:02Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `tiktok` en BD** : 224 — abonnés 63 % · métriques 59 % · dernière vérification 2026-08-18T17:29:45Z | 51 | +- **Comptes `tiktok` en BD** : 224 — abonnés 84 % · métriques 83 % · dernière vérification 2026-08-18T20:05:02Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/twitch-apify.md
+9 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `twitch-apify` — connecteur enrichissement (palier 3) | 1 | # `twitch-apify` — connecteur enrichissement (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,20 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 9 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:21:40Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 0 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:21:40Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:03:58Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 38 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync twitch-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='twitch-apify' ORDER BY ts DESC LIMIT 5;`). | 39 | Rejouer la source seule : `python3 run.py sync twitch-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='twitch-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 40 | ||||
@@ -42,4 +46,5 @@ Rejouer la source seule : `python3 run.py sync twitch-apify` · vérifier `sync_ | |||||
| 42 | 46 | ||||
| 43 | ## Historique | 47 | ## Historique | ||
| 44 | 48 | ||||
| 49 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 50 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/twitch-decouverte.md
+2 −2
@@ -1,6 +1,6 @@ | |||||
| 1 | # `twitch-decouverte` — connecteur decouverte (palier 3) | 1 | # `twitch-decouverte` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 262 · touchés : 262 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 262 · touchés : 262 | ||
| 6 | 6 | ||||
@@ -38,7 +38,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 38 | | `primary_platform` | Plateforme principale | 100 % | twitch | | 38 | | `primary_platform` | Plateforme principale | 100 % | twitch | | ||
| 39 | | `platforms` | Comptes sociaux (liste) | 100 % | twitch:@plaqueboymax | | 39 | | `platforms` | Comptes sociaux (liste) | 100 % | twitch:@plaqueboymax | | ||
| 40 | | `avatar_url` | Avatar | 100 % | https://static-cdn.jtvnw.net/jtv_user_pictures/14f0fcfd-00d4-4004-9379-93e0c6336f5e-profi… | | 40 | | `avatar_url` | Avatar | 100 % | https://static-cdn.jtvnw.net/jtv_user_pictures/14f0fcfd-00d4-4004-9379-93e0c6336f5e-profi… | | ||
| 41 | −| `total_reach` | Portée totale (abonnés cumulés) | 74 % | 2841225 | | 41 | +| `total_reach` | Portée totale (abonnés cumulés) | 74 % | 2841236 | | ||
| 42 | | `link_in_bio_url` | Lien-en-bio | 0 % | — | | 42 | | `link_in_bio_url` | Lien-en-bio | 0 % | — | | ||
| 43 | 43 | ||||
| 44 | ## Fréquence & budget | 44 | ## Fréquence & budget | ||
modified
docs/connecteurs/twitch.md
+6 −6
@@ -1,6 +1,6 @@ | |||||
| 1 | # `twitch` — connecteur enrichissement (palier 2) | 1 | # `twitch` — connecteur enrichissement (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -31,12 +31,12 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `handle` | Handle | 100 % | xqc | | 32 | | `handle` | Handle | 100 % | xqc | | ||
| 33 | | `url` | URL du profil | 100 % | https://www.twitch.tv/xqc | | 33 | | `url` | URL du profil | 100 % | https://www.twitch.tv/xqc | | ||
| 34 | −| `followers` | Abonnés | 98 % | 12535878 | | 34 | +| `followers` | Abonnés | 98 % | 12535875 | | ||
| 35 | −| `verified` | Badge vérifié | 6 % | 1 | | 35 | +| `verified` | Badge vérifié | 96 % | 1 | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | base_publique | | 37 | | `signal` | Signal d'identité | 100 % | base_publique | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 79 % | {"last_stream": "2026-08-18T08:03:23.924661Z", "game": "Just Chatting"} | | 38 | +| `metrics` | Métriques détaillées (JSON) | 97 % | {"last_stream": "2026-08-18T08:03:23.924661Z", "game": "Just Chatting", "is_partner": tru… | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T17:05:24Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T19:10:08Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `twitch` en BD** : 292 — abonnés 98 % · métriques 79 % · dernière vérification 2026-08-18T17:28:20Z | 51 | +- **Comptes `twitch` en BD** : 292 — abonnés 98 % · métriques 97 % · dernière vérification 2026-08-18T20:05:02Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/wikidata-qc.md
+12 −12
@@ -1,6 +1,6 @@ | |||||
| 1 | # `wikidata-qc` — connecteur decouverte (palier 3) | 1 | # `wikidata-qc` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 73 · touchés : 73 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 73 · touchés : 73 | ||
| 6 | 6 | ||||
@@ -29,17 +29,17 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 29 | 29 | ||||
| 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | −| `display_name` | Nom public | 100 % | xQc | | 32 | +| `display_name` | Nom public | 100 % | Nigel Braun | | ||
| 33 | −| `bio` | Bio | 77 % | Félix Lengyel, mieux connu sous le pseudonyme « xQc » (Félix Québec), né le 12 novembre 1… | | 33 | +| `bio` | Bio | 78 % | Capturing the natural beauty of chemistry Find me on YouTube: @NileRed/@NileBlue | | ||
| 34 | −| `region` | Région | 18 % | Laval | | 34 | +| `region` | Région | 18 % | — | | ||
| 35 | −| `city` | Ville | 18 % | Laval | | 35 | +| `city` | Ville | 18 % | — | | ||
| 36 | −| `niches` | Niches (liste) | 100 % | gaming, lifestyle | | 36 | +| `niches` | Niches (liste) | 100 % | lifestyle | | ||
| 37 | −| `languages` | Langues (liste) | 100 % | en, fr | | 37 | +| `languages` | Langues (liste) | 100 % | fr | | ||
| 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | ||
| 39 | −| `primary_platform` | Plateforme principale | 100 % | twitch | | 39 | +| `primary_platform` | Plateforme principale | 100 % | youtube | | ||
| 40 | −| `platforms` | Comptes sociaux (liste) | 99 % | twitch:@xqc, youtube:@UCmDTrq0LNgPodDOFZiSbsww, x:@xqc | | 40 | +| `platforms` | Comptes sociaux (liste) | 99 % | youtube:@nilered, tiktok:@nilered, instagram:@nile.red | | ||
| 41 | −| `avatar_url` | Avatar | 73 % | https://scontent-yyz1-1.cdninstagram.com/v/t51.2885-19/387770319_137990486044045_21612287… | | 41 | +| `avatar_url` | Avatar | 75 % | https://scontent-yyz1-1.cdninstagram.com/v/t51.2885-19/441008830_1124225362150102_4410959… | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 64 % | 17219949 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 67 % | 22759897 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 19 % | — | | 43 | | `link_in_bio_url` | Lien-en-bio | 19 % | — | | ||
| 44 | 44 | ||||
| 45 | ## Fréquence & budget | 45 | ## Fréquence & budget | ||
@@ -52,7 +52,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 52 | ## Volumétrie & complétude | 52 | ## Volumétrie & complétude | ||
| 53 | 53 | ||||
| 54 | - **Créateurs découverts par la source** (`doc.source`) : 73 · **fiches touchées** (`source_ids`) : 73 | 54 | - **Créateurs découverts par la source** (`doc.source`) : 73 · **fiches touchées** (`source_ids`) : 73 | ||
| 55 | −- **Complétude clé (découverts)** : niches 100 % · avatar 73 % · portée 64 % · région 18 % | 55 | +- **Complétude clé (découverts)** : niches 100 % · avatar 75 % · portée 67 % · région 18 % | ||
| 56 | - **Runs journalisés (60 derniers)** : 10, dont 1 avec erreurs | 56 | - **Runs journalisés (60 derniers)** : 10, dont 1 avec erreurs | ||
| 57 | 57 | ||||
| 58 | ## Erreurs connues & dépannage | 58 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/wikipedia-qc.md
+4 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `wikipedia-qc` — connecteur decouverte (palier 3) | 1 | # `wikipedia-qc` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 84 · touchés : 84 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 84 · touchés : 84 | ||
| 6 | 6 | ||||
@@ -38,8 +38,8 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 38 | | `creator_type` | Type de créateur | 100 % | youtubeur | | 38 | | `creator_type` | Type de créateur | 100 % | youtubeur | | ||
| 39 | | `primary_platform` | Plateforme principale | 100 % | x | | 39 | | `primary_platform` | Plateforme principale | 100 % | x | | ||
| 40 | | `platforms` | Comptes sociaux (liste) | 100 % | x:@eviluno, instagram:@evil.uno, twitch:@eviluno | | 40 | | `platforms` | Comptes sociaux (liste) | 100 % | x:@eviluno, instagram:@evil.uno, twitch:@eviluno | | ||
| 41 | −| `avatar_url` | Avatar | 80 % | https://upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Unoenjoy.jpg/500px-Unoenjoy.jpg… | | 41 | +| `avatar_url` | Avatar | 83 % | https://upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Unoenjoy.jpg/500px-Unoenjoy.jpg… | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 12 % | 268165 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 17 % | 268180 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 5 % | http://linktr.ee/eviluno | | 43 | | `link_in_bio_url` | Lien-en-bio | 5 % | http://linktr.ee/eviluno | | ||
| 44 | 44 | ||||
| 45 | ## Fréquence & budget | 45 | ## Fréquence & budget | ||
@@ -52,7 +52,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 52 | ## Volumétrie & complétude | 52 | ## Volumétrie & complétude | ||
| 53 | 53 | ||||
| 54 | - **Créateurs découverts par la source** (`doc.source`) : 84 · **fiches touchées** (`source_ids`) : 84 | 54 | - **Créateurs découverts par la source** (`doc.source`) : 84 · **fiches touchées** (`source_ids`) : 84 | ||
| 55 | −- **Complétude clé (découverts)** : niches 100 % · avatar 80 % · portée 12 % · région 49 % | 55 | +- **Complétude clé (découverts)** : niches 100 % · avatar 83 % · portée 17 % · région 49 % | ||
| 56 | - **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | 56 | - **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | ||
| 57 | 57 | ||||
| 58 | ## Erreurs connues & dépannage | 58 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/x-apify.md
+12 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `x-apify` — connecteur enrichissement (palier 3) | 1 | # `x-apify` — connecteur enrichissement (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,23 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 8 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:51:07Z — 30 créateurs, 121 comptes, +0 / ~30, 2 erreur(s), 515 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 6, dont 1 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:51:07Z | 2 | — | | ||||
| 37 | +| 2026-08-18T19:39:57Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 38 | +| 2026-08-18T19:33:34Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 39 | +| 2026-08-18T19:25:32Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 40 | +| 2026-08-18T19:21:41Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 41 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync x-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='x-apify' ORDER BY ts DESC LIMIT 5;`). | 42 | Rejouer la source seule : `python3 run.py sync x-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='x-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 43 | ||||
@@ -42,4 +49,5 @@ Rejouer la source seule : `python3 run.py sync x-apify` · vérifier `sync_log` | |||||
| 42 | 49 | ||||
| 43 | ## Historique | 50 | ## Historique | ||
| 44 | 51 | ||||
| 52 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 53 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/x-profil.md
+6 −6
@@ -1,6 +1,6 @@ | |||||
| 1 | # `x-profil` — connecteur enrichissement (palier 3) | 1 | # `x-profil` — connecteur enrichissement (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -31,12 +31,12 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `handle` | Handle | 100 % | xqc | | 32 | | `handle` | Handle | 100 % | xqc | | ||
| 33 | | `url` | URL du profil | 100 % | https://x.com/xqc | | 33 | | `url` | URL du profil | 100 % | https://x.com/xqc | | ||
| 34 | −| `followers` | Abonnés | 18 % | 1598794 | | 34 | +| `followers` | Abonnés | 26 % | 1599135 | | ||
| 35 | −| `verified` | Badge vérifié | 0 % | — | | 35 | +| `verified` | Badge vérifié | 13 % | 1 | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.9 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.9 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | cross_link | | 37 | | `signal` | Signal d'identité | 100 % | cross_link | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 32 % | {"following": 526, "x_checked": "2026-08-18T06:14:55Z"} | | 38 | +| `metrics` | Métriques détaillées (JSON) | 39 % | {"following": 526, "x_checked": "2026-08-18T06:14:55Z", "tweets": 4328, "location": "", "… | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T14:44:09Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T19:58:58Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `x` en BD** : 228 — abonnés 18 % · métriques 32 % · dernière vérification 2026-08-18T17:29:45Z | 51 | +- **Comptes `x` en BD** : 228 — abonnés 26 % · métriques 39 % · dernière vérification 2026-08-18T19:58:58Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 6, dont 6 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 6, dont 6 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/youtube-apify.md
+12 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `youtube-apify` — connecteur enrichissement (palier 3) | 1 | # `youtube-apify` — connecteur enrichissement (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichissement) · Backend : — · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -21,16 +21,23 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 21 | ## Fréquence & budget | 21 | ## Fréquence & budget | ||
| 22 | 22 | ||||
| 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | 23 | - **Cadence déclarée (registre)** : quotidienne (rotation 5 j, lot <=300) | ||
| 24 | −- **Cadence observée** (médiane sync_log) : — | 24 | +- **Cadence observée** (médiane sync_log) : ≈ 8 min | ||
| 25 | +- **Dernier passage** : 2026-08-18T19:55:55Z — 1220 créateurs, 1352 comptes, +0 / ~1220, 0 erreur(s), 288 s | ||||
| 25 | 26 | ||||
| 26 | ## Volumétrie & complétude | 27 | ## Volumétrie & complétude | ||
| 27 | 28 | ||||
| 28 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 29 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 29 | −- **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 30 | +- **Runs journalisés (60 derniers)** : 6, dont 0 avec erreurs | ||
| 30 | 31 | ||||
| 31 | ## Erreurs connues & dépannage | 32 | ## Erreurs connues & dépannage | ||
| 32 | 33 | ||||
| 33 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 34 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 35 | +|---|---|---| | ||||
| 36 | +| 2026-08-18T19:42:16Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 37 | +| 2026-08-18T19:35:56Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 38 | +| 2026-08-18T19:27:33Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 39 | +| 2026-08-18T19:21:42Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 40 | +| 2026-08-18T19:03:58Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 34 | 41 | ||||
| 35 | Rejouer la source seule : `python3 run.py sync youtube-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='youtube-apify' ORDER BY ts DESC LIMIT 5;`). | 42 | Rejouer la source seule : `python3 run.py sync youtube-apify` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='youtube-apify' ORDER BY ts DESC LIMIT 5;`). | ||
| 36 | 43 | ||||
@@ -42,4 +49,5 @@ Rejouer la source seule : `python3 run.py sync youtube-apify` · vérifier `sync | |||||
| 42 | 49 | ||||
| 43 | ## Historique | 50 | ## Historique | ||
| 44 | 51 | ||||
| 52 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 45 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | 53 | - 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||
modified
docs/connecteurs/youtube-recherche.md
+5 −5
@@ -1,6 +1,6 @@ | |||||
| 1 | # `youtube-recherche` — connecteur decouverte (palier 3) | 1 | # `youtube-recherche` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 7876 · touchés : 7876 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 7876 · touchés : 7876 | ||
| 6 | 6 | ||||
@@ -42,7 +42,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 42 | | `total_reach` | Portée totale (abonnés cumulés) | 95 % | 1860000 | | 42 | | `total_reach` | Portée totale (abonnés cumulés) | 95 % | 1860000 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | — | | 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | — | | ||
| 44 | 44 | ||||
| 45 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `youtube` (8084 comptes en BD, confiance moyenne 0.98). | 45 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `youtube` (8086 comptes en BD, confiance moyenne 0.98). | ||
| 46 | 46 | ||||
| 47 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 47 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 48 | |---|---|---|---| | 48 | |---|---|---|---| | ||
@@ -52,8 +52,8 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 52 | | `verified` | Badge vérifié | 0 % | — | | 52 | | `verified` | Badge vérifié | 0 % | — | | ||
| 53 | | `confidence` | Confiance d'identité | 100 % | 0.9 | | 53 | | `confidence` | Confiance d'identité | 100 % | 0.9 | | ||
| 54 | | `signal` | Signal d'identité | 100 % | cross_link | | 54 | | `signal` | Signal d'identité | 100 % | cross_link | | ||
| 55 | −| `metrics` | Métriques détaillées (JSON) | 10 % | {"yt_checked": "2026-08-18T10:08:15Z", "videos": 400, "views": 4647638686, "last_video": … | | 55 | +| `metrics` | Métriques détaillées (JSON) | 18 % | {"yt_checked": "2026-08-18T10:08:15Z", "videos": 400, "views": 4647638686, "last_video": … | | ||
| 56 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T11:35:25Z | | 56 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T19:58:58Z | | ||
| 57 | 57 | ||||
| 58 | ## Fréquence & budget | 58 | ## Fréquence & budget | ||
| 59 | 59 | ||||
@@ -66,7 +66,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 66 | 66 | ||||
| 67 | - **Créateurs découverts par la source** (`doc.source`) : 7876 · **fiches touchées** (`source_ids`) : 7876 | 67 | - **Créateurs découverts par la source** (`doc.source`) : 7876 · **fiches touchées** (`source_ids`) : 7876 | ||
| 68 | - **Complétude clé (découverts)** : niches 100 % · avatar 98 % · portée 95 % · région 16 % | 68 | - **Complétude clé (découverts)** : niches 100 % · avatar 98 % · portée 95 % · région 16 % | ||
| 69 | −- **Comptes `youtube` en BD** : 8084 — abonnés 94 % · métriques 10 % · dernière vérification 2026-08-18T17:29:45Z | 69 | +- **Comptes `youtube` en BD** : 8086 — abonnés 94 % · métriques 18 % · dernière vérification 2026-08-18T20:05:02Z | ||
| 70 | - **Runs journalisés (60 derniers)** : 5, dont 0 avec erreurs | 70 | - **Runs journalisés (60 derniers)** : 5, dont 0 avec erreurs | ||
| 71 | 71 | ||||
| 72 | ## Erreurs connues & dépannage | 72 | ## Erreurs connues & dépannage | ||
modified
docs/connecteurs/youtube.md
+5 −5
@@ -1,6 +1,6 @@ | |||||
| 1 | # `youtube` — connecteur enrichissement (palier 2) | 1 | # `youtube` — connecteur enrichissement (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:47 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 16:14 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,7 +25,7 @@ Connecteur ENRICHISSEMENT YouTube — stats de chaîne par créateur. Mode d'acc | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `youtube` (8084 comptes en BD, confiance moyenne 0.98). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `youtube` (8086 comptes en BD, confiance moyenne 0.98). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
@@ -35,8 +35,8 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 35 | | `verified` | Badge vérifié | 0 % | — | | 35 | | `verified` | Badge vérifié | 0 % | — | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.9 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.9 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | cross_link | | 37 | | `signal` | Signal d'identité | 100 % | cross_link | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 10 % | {"yt_checked": "2026-08-18T10:08:15Z", "videos": 400, "views": 4647638686, "last_video": … | | 38 | +| `metrics` | Métriques détaillées (JSON) | 18 % | {"yt_checked": "2026-08-18T10:08:15Z", "videos": 400, "views": 4647638686, "last_video": … | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T11:35:25Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T19:58:58Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
@@ -48,7 +48,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `youtube` en BD** : 8084 — abonnés 94 % · métriques 10 % · dernière vérification 2026-08-18T17:29:45Z | 51 | +- **Comptes `youtube` en BD** : 8086 — abonnés 94 % · métriques 18 % · dernière vérification 2026-08-18T20:05:02Z | ||
| 52 | - **Runs journalisés (60 derniers)** : 5, dont 3 avec erreurs | 52 | - **Runs journalisés (60 derniers)** : 5, dont 3 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
modified
frontend/dist/index.html
+98 −14
@@ -722,12 +722,47 @@ select.f.active{background-color:var(--accent-soft);color:var(--ink);border-colo | |||||
| 722 | background:var(--surface);border:1.5px solid var(--ink);border-radius:var(--r-card); | 722 | background:var(--surface);border:1.5px solid var(--ink);border-radius:var(--r-card); | ||
| 723 | padding:13px 17px;box-shadow:var(--shadow-off-soft)} | 723 | padding:13px 17px;box-shadow:var(--shadow-off-soft)} | ||
| 724 | .sect-title{font-size:19px;margin:36px 0 15px;display:flex;align-items:center;gap:10px;text-transform:uppercase} | 724 | .sect-title{font-size:19px;margin:36px 0 15px;display:flex;align-items:center;gap:10px;text-transform:uppercase} | ||
| 725 | −.acc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:14px} | 725 | +.acc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px} | ||
| 726 | @media(max-width:640px){.acc-grid{grid-template-columns:1fr}} | 726 | @media(max-width:640px){.acc-grid{grid-template-columns:1fr}} | ||
| 727 | −.acc{display:flex;align-items:center;gap:13px;background:var(--surface); | 727 | +.acc-card{display:flex;flex-direction:column;background:var(--surface); | ||
| 728 | − border:1.5px solid var(--ink);border-radius:var(--r-card);padding:14px 16px; | 728 | + border:1.5px solid var(--ink);border-radius:var(--r-card); | ||
| 729 | − box-shadow:var(--shadow-off-soft);transition:transform .16s ease,box-shadow .16s ease;min-width:0} | 729 | + box-shadow:var(--shadow-off-soft);transition:transform .16s ease,box-shadow .16s ease; | ||
| 730 | −.acc:hover{transform:translate(-2px,-2px);box-shadow:var(--shadow-off)} | 730 | + min-width:0;overflow:hidden} | ||
| 731 | +.acc-card:hover{transform:translate(-2px,-2px);box-shadow:var(--shadow-off)} | ||||
| 732 | +.acc{display:flex;align-items:center;gap:13px;padding:14px 16px;min-width:0} | ||||
| 733 | +/* rangée de stats riches */ | ||||
| 734 | +.astat-row{display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 10px} | ||||
| 735 | +.astat{display:flex;flex-direction:column;background:var(--surface-2); | ||||
| 736 | + border:1px solid var(--line);border-radius:var(--r-ctl);padding:4px 9px;line-height:1.1} | ||||
| 737 | +.astat b{font-family:var(--font-display);font-size:13px;color:var(--ink);font-weight:700} | ||||
| 738 | +.astat span{font-family:var(--font-mono);font-size:8.5px;color:var(--ink-3); | ||||
| 739 | + text-transform:uppercase;letter-spacing:.05em;font-weight:700;margin-top:1px} | ||||
| 740 | +.abadge-row{display:flex;flex-wrap:wrap;gap:5px;padding:0 16px 12px} | ||||
| 741 | +.abadge{display:inline-flex;background:var(--lime-soft);color:var(--green-deep); | ||||
| 742 | + border:1px solid var(--line);border-radius:var(--r-ctl);padding:2px 8px; | ||||
| 743 | + font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.02em} | ||||
| 744 | +.abadge.live{background:#ffe3e0;color:#b0201a;border-color:#b0201a} | ||||
| 745 | +/* bande de contenu récent */ | ||||
| 746 | +.cstrip{border-top:1px dashed var(--line);padding:11px 0 13px} | ||||
| 747 | +.cstrip-h{font-family:var(--font-mono);font-size:9.5px;font-weight:700;color:var(--ink-3); | ||||
| 748 | + text-transform:uppercase;letter-spacing:.07em;padding:0 16px 8px} | ||||
| 749 | +.cstrip-scroll{display:flex;gap:9px;overflow-x:auto;padding:0 16px 3px;scroll-snap-type:x proximity} | ||||
| 750 | +.cstrip-scroll::-webkit-scrollbar{height:5px} | ||||
| 751 | +.cstrip-scroll::-webkit-scrollbar-thumb{background:var(--line);border-radius:3px} | ||||
| 752 | +.cstrip-item{flex:none;width:120px;scroll-snap-align:start;text-decoration:none;color:inherit; | ||||
| 753 | + display:flex;flex-direction:column;gap:4px} | ||||
| 754 | +.cstrip-thumb{position:relative;display:block;width:120px;height:120px;border-radius:9px; | ||||
| 755 | + background-size:cover;background-position:center;background-color:var(--surface-2); | ||||
| 756 | + border:1px solid var(--line);overflow:hidden} | ||||
| 757 | +.cstrip-thumb.noimg{display:flex;align-items:center;justify-content:center} | ||||
| 758 | +.cstrip-thumb.noimg svg{width:34px;height:34px;opacity:.35} | ||||
| 759 | +.cstrip-play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%); | ||||
| 760 | + color:#fff;font-size:20px;text-shadow:0 1px 4px rgba(0,0,0,.6)} | ||||
| 761 | +.cstrip-dur{position:absolute;right:5px;bottom:5px;background:rgba(0,0,0,.78);color:#fff; | ||||
| 762 | + font-family:var(--font-mono);font-size:9px;padding:1px 5px;border-radius:5px} | ||||
| 763 | +.cstrip-cap{font-size:11px;line-height:1.25;color:var(--ink-2);display:-webkit-box; | ||||
| 764 | + -webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden} | ||||
| 765 | +.cstrip-meta{font-family:var(--font-mono);font-size:9px;color:var(--ink-3);line-height:1.2} | ||||
| 731 | .acc .plat{width:44px;height:44px;border-radius:9px;flex:none} | 766 | .acc .plat{width:44px;height:44px;border-radius:9px;flex:none} | ||
| 732 | .acc .plat svg{width:20px;height:20px} | 767 | .acc .plat svg{width:20px;height:20px} | ||
| 733 | .acc-mid{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden} | 768 | .acc-mid{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden} | ||
@@ -1170,6 +1205,30 @@ async function reload(more){ | |||||
| 1170 | } | 1205 | } | ||
| 1171 | 1206 | ||||
| 1172 | /* ---------- page créateur ---------- */ | 1207 | /* ---------- page créateur ---------- */ | ||
| 1208 | +/* --- bande de contenu récent par compte (enrichissement Apify) --- */ | ||||
| 1209 | +const _relTime=ts=>{if(!ts)return"";if(typeof ts==="string"&&!/^\d+$/.test(ts))return esc(ts.slice(0,10)); | ||||
| 1210 | + const d=Math.floor((Date.now()/1000-Number(ts))/86400); | ||||
| 1211 | + return d<=0?"aujourd'hui":d===1?"hier":d<30?d+" j":d<365?Math.floor(d/30)+" mois":Math.floor(d/365)+" ans";}; | ||||
| 1212 | +function contentStrip(a){ | ||||
| 1213 | + const m=a.metrics||{}; | ||||
| 1214 | + const items=m.recent_posts||m.recent_videos||m.recent_tweets||[]; | ||||
| 1215 | + if(!items.length)return""; | ||||
| 1216 | + const cards=items.slice(0,8).map(it=>{ | ||||
| 1217 | + const img=it.display_url||it.thumbnail_url||""; | ||||
| 1218 | + const title=esc((it.caption||it.title||it.text||"").slice(0,90)); | ||||
| 1219 | + const stats=[ | ||||
| 1220 | + it.views!=null?fmt.format(it.views)+" vues":null, | ||||
| 1221 | + it.likes!=null?fmt.format(it.likes)+" ❤":null, | ||||
| 1222 | + it.comments!=null?fmt.format(it.comments)+" 💬":null, | ||||
| 1223 | + it.retweets!=null?fmt.format(it.retweets)+" ↻":null, | ||||
| 1224 | + ].filter(Boolean).join(" · "); | ||||
| 1225 | + const when=_relTime(it.timestamp||it.published_at||it.published||it.created_at); | ||||
| 1226 | + return `<a class="cstrip-item" href="${esc(it.url||a.url)}" target="_blank" rel="noopener" onclick="event.stopPropagation()"> | ||||
| 1227 | + ${img?`<span class="cstrip-thumb" style="background-image:url('${esc(img)}')">${it.type==="video"||it.type==="reel"||it.duration?'<span class="cstrip-play">▶</span>':""}${it.duration?`<span class="cstrip-dur">${esc(it.duration)}</span>`:""}</span>`:`<span class="cstrip-thumb noimg">${icon(a.platform)}</span>`} | ||||
| 1228 | + ${title?`<span class="cstrip-cap">${title}</span>`:""} | ||||
| 1229 | + <span class="cstrip-meta">${stats}${when?` · ${when}`:""}</span></a>`}).join(""); | ||||
| 1230 | + return `<div class="cstrip"><div class="cstrip-h">Contenu récent</div><div class="cstrip-scroll">${cards}</div></div>`; | ||||
| 1231 | +} | ||||
| 1173 | async function renderCreator(id){ | 1232 | async function renderCreator(id){ | ||
| 1174 | app.innerHTML=header()+`<div class="container"><div class="spin"></div></div>`+footer()+tabbar("");bindNav(); | 1233 | app.innerHTML=header()+`<div class="container"><div class="spin"></div></div>`+footer()+tabbar("");bindNav(); | ||
| 1175 | let c;try{c=await api("/api/creators/"+encodeURIComponent(id))} | 1234 | let c;try{c=await api("/api/creators/"+encodeURIComponent(id))} | ||
@@ -1179,18 +1238,43 @@ async function renderCreator(id){ | |||||
| 1179 | const verified=(c.platforms||[]).some(a=>a.verified); | 1238 | const verified=(c.platforms||[]).some(a=>a.verified); | ||
| 1180 | const niches=(c.niches||[]).map(n=>`<span class="mchip">${NICHE_LBL[n]||n}</span>`).join(""); | 1239 | const niches=(c.niches||[]).map(n=>`<span class="mchip">${NICHE_LBL[n]||n}</span>`).join(""); | ||
| 1181 | const M_LBL={following:"abonnements",posts:"publications",likes:"j'aime", | 1240 | const M_LBL={following:"abonnements",posts:"publications",likes:"j'aime", | ||
| 1182 | − views:"vues",videos:"vidéos",episodes:"épisodes"}; | 1241 | + views:"vues",videos:"vidéos",episodes:"épisodes",images:"photos", | ||
| 1242 | + friends:"amis",listed:"listes"}; | ||||
| 1183 | const accs=(c.platforms||[]).map(a=>{const p=PLAT[a.platform]||PLAT.autre; | 1243 | const accs=(c.platforms||[]).map(a=>{const p=PLAT[a.platform]||PLAT.autre; | ||
| 1184 | const conf=(a.confidence||0)>=0.75?["hi","confiance élevée"]:["mid","à confirmer"]; | 1244 | const conf=(a.confidence||0)>=0.75?["hi","confiance élevée"]:["mid","à confirmer"]; | ||
| 1185 | − const mx=Object.entries(a.metrics||{}).filter(([k,v])=>M_LBL[k]&&v!=null) | 1245 | + const m=a.metrics||{}; | ||
| 1246 | + const mx=Object.entries(m).filter(([k,v])=>M_LBL[k]&&v!=null) | ||||
| 1186 | .map(([k,v])=>`${fmt.format(v)} ${M_LBL[k]}`).join(" · "); | 1247 | .map(([k,v])=>`${fmt.format(v)} ${M_LBL[k]}`).join(" · "); | ||
| 1187 | − return `<a class="acc" href="${esc(a.url)}" target="_blank" rel="noopener"> | 1248 | + // rangée de statistiques riches (enrichissement Apify multi-plateforme) | ||
| 1188 | − <span class="plat" style="background:${p.color}">${icon(a.platform)}</span> | 1249 | + const stat=(v,l)=>v==null?"":`<span class="astat"><b>${typeof v==="number"?fmt.format(v):esc(v)}</b><span>${l}</span></span>`; | ||
| 1189 | − <span class="acc-mid"><span class="acc-name">${p.label}${a.verified?checkSvg:""}</span> | 1250 | + const stats=[ | ||
| 1190 | − <span class="acc-handle">@${esc(a.handle)}</span> | 1251 | + stat(m.engagement_rate_pct!=null?m.engagement_rate_pct+" %":null,"engagement"), | ||
| 1191 | − <span class="acc-handle" style="overflow:visible"><span class="conf ${conf[0]}" title="Score de rattachement ${Math.round((a.confidence||0)*100)} %">${conf[1]}</span>${mx?` <span style="font-size:11px">${mx}</span>`:""}</span></span> | 1252 | + stat(m.avg_likes,"j'aime/moy"), | ||
| 1192 | − <span class="acc-right">${a.followers?`<b>${fmt.format(a.followers)}</b><span>abonnés</span>`:`<span style="font-size:11px">voir le profil ↗</span>`}</span></a>`}).join(""); | 1253 | + stat(m.avg_views!=null?m.avg_views:m.avg_video_views,"vues/moy"), | ||
| 1193 | − const checked=(c.platforms||[]).map(a=>a.last_checked).filter(Boolean).sort().pop(); | 1254 | + stat(m.avg_retweets,"RT/moy"), | ||
| 1255 | + stat(m.posts_per_week!=null?m.posts_per_week:m.tweets_per_week,"/semaine"), | ||||
| 1256 | + ].filter(Boolean).join(""); | ||||
| 1257 | + const badges=[ | ||||
| 1258 | + m.is_partner?'<span class="abadge">Partenaire</span>':"", | ||||
| 1259 | + m.is_affiliate&&!m.is_partner?'<span class="abadge">Affilié</span>':"", | ||||
| 1260 | + m.is_live_now?'<span class="abadge live">● En direct</span>':"", | ||||
| 1261 | + m.is_seller?'<span class="abadge">Boutique</span>':"", | ||||
| 1262 | + m.is_free===true?'<span class="abadge">Gratuit</span>':"", | ||||
| 1263 | + m.has_story?'<span class="abadge">Story active</span>':"", | ||||
| 1264 | + (m.recent_games||[]).length?`<span class="abadge">${esc((m.recent_games||[])[0])}</span>`:"", | ||||
| 1265 | + (m.top_hashtags||[]).slice(0,2).map(h=>`<span class="abadge">#${esc(h)}</span>`).join(""), | ||||
| 1266 | + ].filter(Boolean).join(""); | ||||
| 1267 | + return `<div class="acc-card"> | ||||
| 1268 | + <a class="acc" href="${esc(a.url)}" target="_blank" rel="noopener"> | ||||
| 1269 | + <span class="plat" style="background:${p.color}">${icon(a.platform)}</span> | ||||
| 1270 | + <span class="acc-mid"><span class="acc-name">${p.label}${a.verified?checkSvg:""}</span> | ||||
| 1271 | + <span class="acc-handle">@${esc(a.handle)}</span> | ||||
| 1272 | + <span class="acc-handle" style="overflow:visible"><span class="conf ${conf[0]}" title="Score de rattachement ${Math.round((a.confidence||0)*100)} %">${conf[1]}</span>${mx?` <span style="font-size:11px">${mx}</span>`:""}</span></span> | ||||
| 1273 | + <span class="acc-right">${a.followers?`<b>${fmt.format(a.followers)}</b><span>abonnés</span>`:`<span style="font-size:11px">voir le profil ↗</span>`}</span></a> | ||||
| 1274 | + ${stats?`<div class="astat-row">${stats}</div>`:""} | ||||
| 1275 | + ${badges?`<div class="abadge-row">${badges}</div>`:""} | ||||
| 1276 | + ${contentStrip(a)}</div>`}).join(""); | ||||
| 1277 | + const checked=(c.platforms||[]).map(a=>(a.metrics||{}).instagram_apify_at||a.last_checked).filter(Boolean).sort().pop()||(c.platforms||[]).map(a=>a.last_checked).filter(Boolean).sort().pop(); | ||||
| 1194 | app.innerHTML=header()+` | 1278 | app.innerHTML=header()+` | ||
| 1195 | <div class="container cpage"> | 1279 | <div class="container cpage"> | ||
| 1196 | <a class="backlink" href="/" data-nav>← Tous les créateurs</a> | 1280 | <a class="backlink" href="/" data-nav>← Tous les créateurs</a> | ||
modified
frontend/src/index.template.html
+98 −14
@@ -264,12 +264,47 @@ select.f.active{background-color:var(--accent-soft);color:var(--ink);border-colo | |||||
| 264 | background:var(--surface);border:1.5px solid var(--ink);border-radius:var(--r-card); | 264 | background:var(--surface);border:1.5px solid var(--ink);border-radius:var(--r-card); | ||
| 265 | padding:13px 17px;box-shadow:var(--shadow-off-soft)} | 265 | padding:13px 17px;box-shadow:var(--shadow-off-soft)} | ||
| 266 | .sect-title{font-size:19px;margin:36px 0 15px;display:flex;align-items:center;gap:10px;text-transform:uppercase} | 266 | .sect-title{font-size:19px;margin:36px 0 15px;display:flex;align-items:center;gap:10px;text-transform:uppercase} | ||
| 267 | −.acc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:14px} | 267 | +.acc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px} | ||
| 268 | @media(max-width:640px){.acc-grid{grid-template-columns:1fr}} | 268 | @media(max-width:640px){.acc-grid{grid-template-columns:1fr}} | ||
| 269 | −.acc{display:flex;align-items:center;gap:13px;background:var(--surface); | 269 | +.acc-card{display:flex;flex-direction:column;background:var(--surface); | ||
| 270 | − border:1.5px solid var(--ink);border-radius:var(--r-card);padding:14px 16px; | 270 | + border:1.5px solid var(--ink);border-radius:var(--r-card); | ||
| 271 | − box-shadow:var(--shadow-off-soft);transition:transform .16s ease,box-shadow .16s ease;min-width:0} | 271 | + box-shadow:var(--shadow-off-soft);transition:transform .16s ease,box-shadow .16s ease; | ||
| 272 | −.acc:hover{transform:translate(-2px,-2px);box-shadow:var(--shadow-off)} | 272 | + min-width:0;overflow:hidden} | ||
| 273 | +.acc-card:hover{transform:translate(-2px,-2px);box-shadow:var(--shadow-off)} | ||||
| 274 | +.acc{display:flex;align-items:center;gap:13px;padding:14px 16px;min-width:0} | ||||
| 275 | +/* rangée de stats riches */ | ||||
| 276 | +.astat-row{display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 10px} | ||||
| 277 | +.astat{display:flex;flex-direction:column;background:var(--surface-2); | ||||
| 278 | + border:1px solid var(--line);border-radius:var(--r-ctl);padding:4px 9px;line-height:1.1} | ||||
| 279 | +.astat b{font-family:var(--font-display);font-size:13px;color:var(--ink);font-weight:700} | ||||
| 280 | +.astat span{font-family:var(--font-mono);font-size:8.5px;color:var(--ink-3); | ||||
| 281 | + text-transform:uppercase;letter-spacing:.05em;font-weight:700;margin-top:1px} | ||||
| 282 | +.abadge-row{display:flex;flex-wrap:wrap;gap:5px;padding:0 16px 12px} | ||||
| 283 | +.abadge{display:inline-flex;background:var(--lime-soft);color:var(--green-deep); | ||||
| 284 | + border:1px solid var(--line);border-radius:var(--r-ctl);padding:2px 8px; | ||||
| 285 | + font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.02em} | ||||
| 286 | +.abadge.live{background:#ffe3e0;color:#b0201a;border-color:#b0201a} | ||||
| 287 | +/* bande de contenu récent */ | ||||
| 288 | +.cstrip{border-top:1px dashed var(--line);padding:11px 0 13px} | ||||
| 289 | +.cstrip-h{font-family:var(--font-mono);font-size:9.5px;font-weight:700;color:var(--ink-3); | ||||
| 290 | + text-transform:uppercase;letter-spacing:.07em;padding:0 16px 8px} | ||||
| 291 | +.cstrip-scroll{display:flex;gap:9px;overflow-x:auto;padding:0 16px 3px;scroll-snap-type:x proximity} | ||||
| 292 | +.cstrip-scroll::-webkit-scrollbar{height:5px} | ||||
| 293 | +.cstrip-scroll::-webkit-scrollbar-thumb{background:var(--line);border-radius:3px} | ||||
| 294 | +.cstrip-item{flex:none;width:120px;scroll-snap-align:start;text-decoration:none;color:inherit; | ||||
| 295 | + display:flex;flex-direction:column;gap:4px} | ||||
| 296 | +.cstrip-thumb{position:relative;display:block;width:120px;height:120px;border-radius:9px; | ||||
| 297 | + background-size:cover;background-position:center;background-color:var(--surface-2); | ||||
| 298 | + border:1px solid var(--line);overflow:hidden} | ||||
| 299 | +.cstrip-thumb.noimg{display:flex;align-items:center;justify-content:center} | ||||
| 300 | +.cstrip-thumb.noimg svg{width:34px;height:34px;opacity:.35} | ||||
| 301 | +.cstrip-play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%); | ||||
| 302 | + color:#fff;font-size:20px;text-shadow:0 1px 4px rgba(0,0,0,.6)} | ||||
| 303 | +.cstrip-dur{position:absolute;right:5px;bottom:5px;background:rgba(0,0,0,.78);color:#fff; | ||||
| 304 | + font-family:var(--font-mono);font-size:9px;padding:1px 5px;border-radius:5px} | ||||
| 305 | +.cstrip-cap{font-size:11px;line-height:1.25;color:var(--ink-2);display:-webkit-box; | ||||
| 306 | + -webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden} | ||||
| 307 | +.cstrip-meta{font-family:var(--font-mono);font-size:9px;color:var(--ink-3);line-height:1.2} | ||||
| 273 | .acc .plat{width:44px;height:44px;border-radius:9px;flex:none} | 308 | .acc .plat{width:44px;height:44px;border-radius:9px;flex:none} | ||
| 274 | .acc .plat svg{width:20px;height:20px} | 309 | .acc .plat svg{width:20px;height:20px} | ||
| 275 | .acc-mid{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden} | 310 | .acc-mid{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden} | ||
@@ -712,6 +747,30 @@ async function reload(more){ | |||||
| 712 | } | 747 | } | ||
| 713 | 748 | ||||
| 714 | /* ---------- page créateur ---------- */ | 749 | /* ---------- page créateur ---------- */ | ||
| 750 | +/* --- bande de contenu récent par compte (enrichissement Apify) --- */ | ||||
| 751 | +const _relTime=ts=>{if(!ts)return"";if(typeof ts==="string"&&!/^\d+$/.test(ts))return esc(ts.slice(0,10)); | ||||
| 752 | + const d=Math.floor((Date.now()/1000-Number(ts))/86400); | ||||
| 753 | + return d<=0?"aujourd'hui":d===1?"hier":d<30?d+" j":d<365?Math.floor(d/30)+" mois":Math.floor(d/365)+" ans";}; | ||||
| 754 | +function contentStrip(a){ | ||||
| 755 | + const m=a.metrics||{}; | ||||
| 756 | + const items=m.recent_posts||m.recent_videos||m.recent_tweets||[]; | ||||
| 757 | + if(!items.length)return""; | ||||
| 758 | + const cards=items.slice(0,8).map(it=>{ | ||||
| 759 | + const img=it.display_url||it.thumbnail_url||""; | ||||
| 760 | + const title=esc((it.caption||it.title||it.text||"").slice(0,90)); | ||||
| 761 | + const stats=[ | ||||
| 762 | + it.views!=null?fmt.format(it.views)+" vues":null, | ||||
| 763 | + it.likes!=null?fmt.format(it.likes)+" ❤":null, | ||||
| 764 | + it.comments!=null?fmt.format(it.comments)+" 💬":null, | ||||
| 765 | + it.retweets!=null?fmt.format(it.retweets)+" ↻":null, | ||||
| 766 | + ].filter(Boolean).join(" · "); | ||||
| 767 | + const when=_relTime(it.timestamp||it.published_at||it.published||it.created_at); | ||||
| 768 | + return `<a class="cstrip-item" href="${esc(it.url||a.url)}" target="_blank" rel="noopener" onclick="event.stopPropagation()"> | ||||
| 769 | + ${img?`<span class="cstrip-thumb" style="background-image:url('${esc(img)}')">${it.type==="video"||it.type==="reel"||it.duration?'<span class="cstrip-play">▶</span>':""}${it.duration?`<span class="cstrip-dur">${esc(it.duration)}</span>`:""}</span>`:`<span class="cstrip-thumb noimg">${icon(a.platform)}</span>`} | ||||
| 770 | + ${title?`<span class="cstrip-cap">${title}</span>`:""} | ||||
| 771 | + <span class="cstrip-meta">${stats}${when?` · ${when}`:""}</span></a>`}).join(""); | ||||
| 772 | + return `<div class="cstrip"><div class="cstrip-h">Contenu récent</div><div class="cstrip-scroll">${cards}</div></div>`; | ||||
| 773 | +} | ||||
| 715 | async function renderCreator(id){ | 774 | async function renderCreator(id){ | ||
| 716 | app.innerHTML=header()+`<div class="container"><div class="spin"></div></div>`+footer()+tabbar("");bindNav(); | 775 | app.innerHTML=header()+`<div class="container"><div class="spin"></div></div>`+footer()+tabbar("");bindNav(); | ||
| 717 | let c;try{c=await api("/api/creators/"+encodeURIComponent(id))} | 776 | let c;try{c=await api("/api/creators/"+encodeURIComponent(id))} | ||
@@ -721,18 +780,43 @@ async function renderCreator(id){ | |||||
| 721 | const verified=(c.platforms||[]).some(a=>a.verified); | 780 | const verified=(c.platforms||[]).some(a=>a.verified); | ||
| 722 | const niches=(c.niches||[]).map(n=>`<span class="mchip">${NICHE_LBL[n]||n}</span>`).join(""); | 781 | const niches=(c.niches||[]).map(n=>`<span class="mchip">${NICHE_LBL[n]||n}</span>`).join(""); | ||
| 723 | const M_LBL={following:"abonnements",posts:"publications",likes:"j'aime", | 782 | const M_LBL={following:"abonnements",posts:"publications",likes:"j'aime", | ||
| 724 | − views:"vues",videos:"vidéos",episodes:"épisodes"}; | 783 | + views:"vues",videos:"vidéos",episodes:"épisodes",images:"photos", | ||
| 784 | + friends:"amis",listed:"listes"}; | ||||
| 725 | const accs=(c.platforms||[]).map(a=>{const p=PLAT[a.platform]||PLAT.autre; | 785 | const accs=(c.platforms||[]).map(a=>{const p=PLAT[a.platform]||PLAT.autre; | ||
| 726 | const conf=(a.confidence||0)>=0.75?["hi","confiance élevée"]:["mid","à confirmer"]; | 786 | const conf=(a.confidence||0)>=0.75?["hi","confiance élevée"]:["mid","à confirmer"]; | ||
| 727 | − const mx=Object.entries(a.metrics||{}).filter(([k,v])=>M_LBL[k]&&v!=null) | 787 | + const m=a.metrics||{}; | ||
| 788 | + const mx=Object.entries(m).filter(([k,v])=>M_LBL[k]&&v!=null) | ||||
| 728 | .map(([k,v])=>`${fmt.format(v)} ${M_LBL[k]}`).join(" · "); | 789 | .map(([k,v])=>`${fmt.format(v)} ${M_LBL[k]}`).join(" · "); | ||
| 729 | − return `<a class="acc" href="${esc(a.url)}" target="_blank" rel="noopener"> | 790 | + // rangée de statistiques riches (enrichissement Apify multi-plateforme) | ||
| 730 | − <span class="plat" style="background:${p.color}">${icon(a.platform)}</span> | 791 | + const stat=(v,l)=>v==null?"":`<span class="astat"><b>${typeof v==="number"?fmt.format(v):esc(v)}</b><span>${l}</span></span>`; | ||
| 731 | − <span class="acc-mid"><span class="acc-name">${p.label}${a.verified?checkSvg:""}</span> | 792 | + const stats=[ | ||
| 732 | − <span class="acc-handle">@${esc(a.handle)}</span> | 793 | + stat(m.engagement_rate_pct!=null?m.engagement_rate_pct+" %":null,"engagement"), | ||
| 733 | − <span class="acc-handle" style="overflow:visible"><span class="conf ${conf[0]}" title="Score de rattachement ${Math.round((a.confidence||0)*100)} %">${conf[1]}</span>${mx?` <span style="font-size:11px">${mx}</span>`:""}</span></span> | 794 | + stat(m.avg_likes,"j'aime/moy"), | ||
| 734 | − <span class="acc-right">${a.followers?`<b>${fmt.format(a.followers)}</b><span>abonnés</span>`:`<span style="font-size:11px">voir le profil ↗</span>`}</span></a>`}).join(""); | 795 | + stat(m.avg_views!=null?m.avg_views:m.avg_video_views,"vues/moy"), | ||
| 735 | − const checked=(c.platforms||[]).map(a=>a.last_checked).filter(Boolean).sort().pop(); | 796 | + stat(m.avg_retweets,"RT/moy"), | ||
| 797 | + stat(m.posts_per_week!=null?m.posts_per_week:m.tweets_per_week,"/semaine"), | ||||
| 798 | + ].filter(Boolean).join(""); | ||||
| 799 | + const badges=[ | ||||
| 800 | + m.is_partner?'<span class="abadge">Partenaire</span>':"", | ||||
| 801 | + m.is_affiliate&&!m.is_partner?'<span class="abadge">Affilié</span>':"", | ||||
| 802 | + m.is_live_now?'<span class="abadge live">● En direct</span>':"", | ||||
| 803 | + m.is_seller?'<span class="abadge">Boutique</span>':"", | ||||
| 804 | + m.is_free===true?'<span class="abadge">Gratuit</span>':"", | ||||
| 805 | + m.has_story?'<span class="abadge">Story active</span>':"", | ||||
| 806 | + (m.recent_games||[]).length?`<span class="abadge">${esc((m.recent_games||[])[0])}</span>`:"", | ||||
| 807 | + (m.top_hashtags||[]).slice(0,2).map(h=>`<span class="abadge">#${esc(h)}</span>`).join(""), | ||||
| 808 | + ].filter(Boolean).join(""); | ||||
| 809 | + return `<div class="acc-card"> | ||||
| 810 | + <a class="acc" href="${esc(a.url)}" target="_blank" rel="noopener"> | ||||
| 811 | + <span class="plat" style="background:${p.color}">${icon(a.platform)}</span> | ||||
| 812 | + <span class="acc-mid"><span class="acc-name">${p.label}${a.verified?checkSvg:""}</span> | ||||
| 813 | + <span class="acc-handle">@${esc(a.handle)}</span> | ||||
| 814 | + <span class="acc-handle" style="overflow:visible"><span class="conf ${conf[0]}" title="Score de rattachement ${Math.round((a.confidence||0)*100)} %">${conf[1]}</span>${mx?` <span style="font-size:11px">${mx}</span>`:""}</span></span> | ||||
| 815 | + <span class="acc-right">${a.followers?`<b>${fmt.format(a.followers)}</b><span>abonnés</span>`:`<span style="font-size:11px">voir le profil ↗</span>`}</span></a> | ||||
| 816 | + ${stats?`<div class="astat-row">${stats}</div>`:""} | ||||
| 817 | + ${badges?`<div class="abadge-row">${badges}</div>`:""} | ||||
| 818 | + ${contentStrip(a)}</div>`}).join(""); | ||||
| 819 | + const checked=(c.platforms||[]).map(a=>(a.metrics||{}).instagram_apify_at||a.last_checked).filter(Boolean).sort().pop()||(c.platforms||[]).map(a=>a.last_checked).filter(Boolean).sort().pop(); | ||||
| 736 | app.innerHTML=header()+` | 820 | app.innerHTML=header()+` | ||
| 737 | <div class="container cpage"> | 821 | <div class="container cpage"> | ||
| 738 | <a class="backlink" href="/" data-nav>← Tous les créateurs</a> | 822 | <a class="backlink" href="/" data-nav>← Tous les créateurs</a> | ||
| 739 | 823 | ||||