@danhachuel/thunderbolt 0.6.41 → 0.6.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/main.py +22 -0
- package/app/social_networks_ui.py +9 -1
- package/integrations/instagram_public.py +27 -0
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -39,6 +39,28 @@ import streamlit as st
|
|
|
39
39
|
ROOT = Path(__file__).resolve().parents[1]
|
|
40
40
|
if str(ROOT) not in sys.path:
|
|
41
41
|
sys.path.insert(0, str(ROOT))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _load_local_env() -> None:
|
|
45
|
+
for env_path in (ROOT / ".env", Path.cwd() / ".env"):
|
|
46
|
+
try:
|
|
47
|
+
if not env_path.is_file():
|
|
48
|
+
continue
|
|
49
|
+
for raw_line in env_path.read_text(encoding="utf-8").splitlines():
|
|
50
|
+
line = raw_line.strip()
|
|
51
|
+
if not line or line.startswith("#") or "=" not in line:
|
|
52
|
+
continue
|
|
53
|
+
key, value = line.split("=", 1)
|
|
54
|
+
key = key.strip()
|
|
55
|
+
value = value.strip().strip("'\"")
|
|
56
|
+
if key:
|
|
57
|
+
os.environ.setdefault(key, value)
|
|
58
|
+
except OSError as exc:
|
|
59
|
+
print(f"DEBUG: não foi possível ler {env_path}: {exc}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
_load_local_env()
|
|
63
|
+
|
|
42
64
|
try:
|
|
43
65
|
APP_VERSION = json.loads((ROOT / "package.json").read_text(encoding="utf-8")).get("version", "")
|
|
44
66
|
except (OSError, json.JSONDecodeError):
|
|
@@ -5,6 +5,7 @@ import re
|
|
|
5
5
|
import uuid
|
|
6
6
|
import zipfile
|
|
7
7
|
import unicodedata
|
|
8
|
+
import hashlib
|
|
8
9
|
from typing import Any, Callable, Mapping
|
|
9
10
|
|
|
10
11
|
import requests
|
|
@@ -130,6 +131,13 @@ def _clear_instagram_result_widget_state(profile: Mapping[str, Any]) -> None:
|
|
|
130
131
|
st.session_state.pop(f"social_instagram_result_{field}_{widget_id}", None)
|
|
131
132
|
|
|
132
133
|
|
|
134
|
+
def _instagram_result_widget_id(profile: Mapping[str, Any]) -> str:
|
|
135
|
+
base_id = _instagram_profile_storage_id(profile)
|
|
136
|
+
signature = "|".join(_clean(profile.get(key)) for key in ("bio", "bio_raw", "following_count", "subscriber_count", "post_count", "country"))
|
|
137
|
+
digest = hashlib.sha1(signature.encode("utf-8")).hexdigest()[:10]
|
|
138
|
+
return f"{base_id}_{digest}"
|
|
139
|
+
|
|
140
|
+
|
|
133
141
|
def _normalise_instagram_posts(value: Any) -> list[dict[str, Any]]:
|
|
134
142
|
if not isinstance(value, list):
|
|
135
143
|
return []
|
|
@@ -599,7 +607,7 @@ def render_social_networks(settings: dict[str, Any]) -> None:
|
|
|
599
607
|
data = st.session_state.get("social_instagram_result", {}) if st.session_state.get("social_instagram_ok") else {}
|
|
600
608
|
if data:
|
|
601
609
|
characters, _ = _characters(settings)
|
|
602
|
-
result_widget_id =
|
|
610
|
+
result_widget_id = _instagram_result_widget_id(data)
|
|
603
611
|
with st.container(border=True):
|
|
604
612
|
st.subheader("Conta Instagram encontrada")
|
|
605
613
|
preview_cols = st.columns([0.8, 2.2, 1.2, 1.2, 1.2])
|
|
@@ -520,6 +520,33 @@ def fetch_public_instagram_posts(source: str, limit: int = 10) -> IntegrationRes
|
|
|
520
520
|
break
|
|
521
521
|
if len(posts) >= max(1, int(limit)):
|
|
522
522
|
break
|
|
523
|
+
if not posts:
|
|
524
|
+
try:
|
|
525
|
+
from playwright.sync_api import sync_playwright
|
|
526
|
+
with sync_playwright() as playwright:
|
|
527
|
+
browser = playwright.chromium.launch(headless=True)
|
|
528
|
+
try:
|
|
529
|
+
page = browser.new_page(
|
|
530
|
+
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/131.0 Safari/537.36',
|
|
531
|
+
extra_http_headers={'x-ig-app-id': '936619743392459', 'Accept-Language': 'en-US,en;q=0.9'},
|
|
532
|
+
)
|
|
533
|
+
page.goto(reference['url'], wait_until='domcontentloaded', timeout=30000)
|
|
534
|
+
browser_document = page.content()
|
|
535
|
+
for document in _embedded_json_documents(browser_document):
|
|
536
|
+
for node in _walk_json(document):
|
|
537
|
+
post = _post_from_node(node)
|
|
538
|
+
if not post or post['id'] in seen:
|
|
539
|
+
continue
|
|
540
|
+
seen.add(post['id'])
|
|
541
|
+
posts.append(post)
|
|
542
|
+
if len(posts) >= max(1, int(limit)):
|
|
543
|
+
break
|
|
544
|
+
if len(posts) >= max(1, int(limit)):
|
|
545
|
+
break
|
|
546
|
+
finally:
|
|
547
|
+
browser.close()
|
|
548
|
+
except (ImportError, OSError, RuntimeError, TimeoutError):
|
|
549
|
+
pass
|
|
523
550
|
return IntegrationResult(bool(posts), 'Posts públicos encontrados.' if posts else 'Não foi possível encontrar posts públicos nesta página do Instagram.', reference | {'posts': posts[:max(1, int(limit))]})
|
|
524
551
|
|
|
525
552
|
|
package/package.json
CHANGED