Créa·Ka — annuaire public cross-plateforme des créateurs de contenu québécois (crea-ka.com)
Python 73.6%
HTML 13.2%
TypeScript 6%
JavaScript 4.5%
CSS 1.7%
Dockerfile 0.6%
1# ==============================================================================2# Author: Simon-Pierre Boucher <contact@spboucher.ai>3# File: tests/test_vague2.py4# Desc: Tests vague 2 — flux RSS des balados, nouvelles plateformes5# (spotify/discord/apple-podcasts), liaison bio-liens, compteurs X6# ==============================================================================7from pathlib import Path89from creaka.connectors.balados_rss import parse_feed, _parse_feed_regex10from creaka.connectors.bio_liens import extract_bio_accounts11from creaka.connectors.x_profil import parse_counts, parse_syndication12from creaka.normalize import canonical_url, normalize_platform, platform_from_url1314FIXTURE = (Path(__file__).parent / "fixtures" / "balado_sample.xml").read_bytes()151617# --- balados-rss ----------------------------------------------------------------1819def test_parse_feed_champs():20 feed = parse_feed(FIXTURE)21 assert feed["episodes"] == 322 assert feed["last_episode"].strftime("%Y-%m-%d") == "2026-08-01"23 assert feed["image"] == "https://exemple.qc.ca/pochette.jpg"24 assert feed["link"] == "https://www.balado-exemple.ca"25 assert "balado d'exemple" in feed["description"].lower()26 assert "Comedy" in feed["categories"]272829def test_parse_feed_repli_regex_flux_tronque():30 # flux coupé au milieu d'un item : le repli regex garde l'en-tête du canal31 trunc = FIXTURE.split(b"<item>")[0] + b"<item><title>coup"32 feed = _parse_feed_regex(trunc)33 assert feed is not None34 assert feed["image"] == "https://exemple.qc.ca/pochette.jpg"35 assert feed["link"] == "https://www.balado-exemple.ca"36 assert feed["episodes"] == 1373839def test_parse_feed_illisible():40 assert parse_feed(b"pas du xml") is None414243# --- nouvelles plateformes (normalize) --------------------------------------------4445def test_platform_from_url_spotify_discord_apple():46 assert platform_from_url(47 "https://open.spotify.com/show/4rOoJ6Egrf8K2IrywzwOMk") == \48 ("spotify", "4rooj6egrf8k2irywzwomk")49 assert platform_from_url(50 "https://open.spotify.com/intl-fr/artist/06HL4z0CvFAxyc27GXpf02") is not None51 assert platform_from_url("https://discord.gg/AbCd123") == ("discord", "abcd123")52 assert platform_from_url("https://discord.com/invite/AbCd123") == \53 ("discord", "abcd123")54 assert platform_from_url(55 "https://podcasts.apple.com/ca/podcast/mon-balado/id1502950331") == \56 ("podcast", "1502950331")575859def test_canonical_url_conserve_url_source():60 # IDs Spotify et invitations Discord : sensibles à la casse → on garde l'URL61 src = "https://open.spotify.com/show/4rOoJ6Egrf8K2IrywzwOMk"62 assert canonical_url("spotify", "4roo", fallback=src) == src63 assert normalize_platform("spotify") == "spotify"64 assert normalize_platform("discord") == "discord"65 assert normalize_platform("apple podcasts") == "podcast"666768# --- bio-liens --------------------------------------------------------------------6970def test_extract_bio_accounts_urls_completes_seulement():71 bio = ("Humoriste. Balado : https://open.spotify.com/show/4rOoJ6Egrf8K2Iryw "72 "· YouTube www.youtube.com/@moncompte · suivez @autretiktok !")73 accounts = extract_bio_accounts(bio, existing_keys=set())74 keys = {a.key for a in accounts}75 assert "youtube:moncompte" in keys76 assert any(k.startswith("spotify:") for k in keys)77 # « @autretiktok » textuel = ambigu → JAMAIS rattaché78 assert not any("autretiktok" in k for k in keys)79 assert all(a.signal == "cross_link" for a in accounts)808182def test_extract_bio_accounts_ignore_comptes_connus():83 bio = "Mon YouTube : https://youtube.com/@moncompte"84 assert extract_bio_accounts(bio, existing_keys={"youtube:moncompte"}) == []858687# --- x-profil ---------------------------------------------------------------------8889def test_parse_syndication_next_data():90 html = ('<html><script id="__NEXT_DATA__" type="application/json">'91 '{"props":{"pageProps":{"timeline":{"entries":[{"content":{"tweet":'92 '{"user":{"screen_name":"MonCompte","followers_count":4321,'93 '"friends_count":99,"verified":true,'94 '"profile_image_url_https":"https://pbs.twimg.com/x_normal.jpg"'95 '}}}}]}}}}</script></html>')96 info = parse_syndication(html, "moncompte")97 assert info["followers"] == 432198 assert info["following"] == 9999 assert info["verified"] is True100 assert info["avatar"].endswith("x_400x400.jpg")101 # autre handle dans la timeline (retweet) : JAMAIS pris pour le profil102 assert parse_syndication(html, "autrecompte") is None103104105def test_parse_counts_etat_integre():106 html = ('...t:VXNlcjo=:relationship_counts",__typename:'107 '"UserRelationshipCounts",followers:12068,following:847,...')108 assert parse_counts(html) == (12068, 847)109 assert parse_counts("<html>Se connecter</html>") is None110