@danhachuel/thunderbolt 0.6.29 → 0.6.31
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.
|
@@ -48,6 +48,10 @@ def _render_instagram_bio(value: Any) -> None:
|
|
|
48
48
|
st.text(bio)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
def _profile_bio(profile: Mapping[str, Any]) -> str:
|
|
52
|
+
return normalize_instagram_bio(profile.get("bio")) or normalize_instagram_bio(profile.get("bio_raw"))
|
|
53
|
+
|
|
54
|
+
|
|
51
55
|
def _language_index(value: Any) -> int:
|
|
52
56
|
code = language_code(value)
|
|
53
57
|
return list(LANGUAGE_CODES).index(code) if code in LANGUAGE_CODES else list(LANGUAGE_CODES).index("pt")
|
|
@@ -299,7 +303,8 @@ def _save_public_profile(data: Mapping[str, Any], *, country: str, language: str
|
|
|
299
303
|
"name": name,
|
|
300
304
|
"url": url,
|
|
301
305
|
"handle": _clean(data.get("handle")),
|
|
302
|
-
"bio":
|
|
306
|
+
"bio": _profile_bio(data),
|
|
307
|
+
"bio_raw": _clean(data.get("bio_raw")),
|
|
303
308
|
"country": selected_country,
|
|
304
309
|
"language": language.strip(),
|
|
305
310
|
"post_count": data.get("post_count"),
|
|
@@ -314,7 +319,7 @@ def _save_public_profile(data: Mapping[str, Any], *, country: str, language: str
|
|
|
314
319
|
|
|
315
320
|
def _merge_instagram_refresh(existing: Mapping[str, Any], refreshed: Mapping[str, Any]) -> dict[str, Any]:
|
|
316
321
|
merged = dict(refreshed)
|
|
317
|
-
for field in ("subscriber_count", "following_count", "post_count", "bio", "avatar_url"):
|
|
322
|
+
for field in ("subscriber_count", "following_count", "post_count", "bio", "bio_raw", "avatar_url"):
|
|
318
323
|
if merged.get(field) in (None, "") and existing.get(field) not in (None, ""):
|
|
319
324
|
merged[field] = existing[field]
|
|
320
325
|
return merged
|
|
@@ -348,7 +353,7 @@ def _render_instagram_card(profile: dict[str, Any], characters: list[dict[str, A
|
|
|
348
353
|
with header_cols[1]:
|
|
349
354
|
st.write(f"**{_clean(profile.get('name')) or 'Sem nome'}**")
|
|
350
355
|
st.caption(f"{_clean(profile.get('handle')) or _clean(profile.get('url')) or 'sem handler'}")
|
|
351
|
-
_render_instagram_bio(profile
|
|
356
|
+
_render_instagram_bio(_profile_bio(profile))
|
|
352
357
|
st.caption(f"{_clean(profile.get('country')) or 'País não definido'} · {_clean(profile.get('language')) or 'Idioma não definido'}")
|
|
353
358
|
with header_cols[2]:
|
|
354
359
|
st.metric("posts", _metric(profile.get("post_count")))
|
|
@@ -362,6 +367,11 @@ def _render_instagram_card(profile: dict[str, Any], characters: list[dict[str, A
|
|
|
362
367
|
if st.button("↻", help="Actualizar posts, seguidores e seguindo", key=f"refresh_instagram_{profile_id}"):
|
|
363
368
|
refreshed_ok, refreshed_message, refreshed = _refresh_instagram_profile(profile)
|
|
364
369
|
if refreshed_ok:
|
|
370
|
+
posts_key = _instagram_posts_key(profile_id)
|
|
371
|
+
current_posts = st.session_state.get(posts_key, [])
|
|
372
|
+
posts_ok, _, refreshed_posts = _load_instagram_posts(refreshed, limit=max(10, len(current_posts)))
|
|
373
|
+
if posts_ok:
|
|
374
|
+
st.session_state[posts_key] = refreshed_posts
|
|
365
375
|
update_channel(profile_id, {**refreshed, "platform": "instagram", "country": profile.get("country", ""), "language": profile.get("language", ""), "character_id": profile.get("character_id", "")})
|
|
366
376
|
st.success("Métricas Instagram actualizadas.")
|
|
367
377
|
st.rerun()
|
|
@@ -397,7 +407,7 @@ def _render_instagram_card(profile: dict[str, Any], characters: list[dict[str, A
|
|
|
397
407
|
with edit_cols[0]:
|
|
398
408
|
name = st.text_input("Nome", value=_clean(profile.get("name")), key=f"instagram_edit_name_{profile_id}")
|
|
399
409
|
handle = st.text_input("handler", value=_clean(profile.get("handle")), key=f"instagram_edit_handle_{profile_id}")
|
|
400
|
-
bio = st.text_area("Bio", value=
|
|
410
|
+
bio = st.text_area("Bio", value=_profile_bio(profile), key=f"instagram_edit_bio_{profile_id}")
|
|
401
411
|
country = st.selectbox("País", _country_options(), index=_country_index(profile.get("country")), format_func=_country_label, key=f"instagram_edit_country_{profile_id}")
|
|
402
412
|
language = st.selectbox("Idioma", list(LANGUAGE_CODES), index=_language_index(profile.get("language")), format_func=language_label, key=f"instagram_edit_language_{profile_id}")
|
|
403
413
|
with edit_cols[1]:
|
|
@@ -406,7 +416,7 @@ def _render_instagram_card(profile: dict[str, Any], characters: list[dict[str, A
|
|
|
406
416
|
following = st.number_input("seguindo", min_value=0, value=_metric_input(profile.get("following_count")), placeholder="Não encontrado", key=f"instagram_edit_following_{profile_id}")
|
|
407
417
|
save_edit = st.form_submit_button("Guardar alterações", type="primary", use_container_width=True)
|
|
408
418
|
if save_edit:
|
|
409
|
-
update_channel(profile_id, {"name": name.strip(), "handle": handle.strip(), "bio": normalize_instagram_bio(bio), "country": country.strip(), "language": language, "post_count": _metric_input(posts), "subscriber_count": _metric_input(followers), "following_count": _metric_input(following)})
|
|
419
|
+
update_channel(profile_id, {"name": name.strip(), "handle": handle.strip(), "bio": normalize_instagram_bio(bio), "bio_raw": bio, "country": country.strip(), "language": language, "post_count": _metric_input(posts), "subscriber_count": _metric_input(followers), "following_count": _metric_input(following)})
|
|
410
420
|
st.session_state.pop(edit_key, None)
|
|
411
421
|
st.success("Conta Instagram actualizada.")
|
|
412
422
|
st.rerun()
|
|
@@ -466,7 +476,7 @@ def render_social_networks(settings: dict[str, Any]) -> None:
|
|
|
466
476
|
with preview_cols[1]:
|
|
467
477
|
st.write(f"**{_clean(data.get('name')) or _clean(data.get('username'))}**")
|
|
468
478
|
st.caption(_clean(data.get("handle")))
|
|
469
|
-
_render_instagram_bio(data
|
|
479
|
+
_render_instagram_bio(_profile_bio(data))
|
|
470
480
|
with preview_cols[2]:
|
|
471
481
|
st.metric("posts", _metric(data.get("post_count")))
|
|
472
482
|
with preview_cols[3]:
|
|
@@ -477,7 +487,7 @@ def render_social_networks(settings: dict[str, Any]) -> None:
|
|
|
477
487
|
form_cols = st.columns(2)
|
|
478
488
|
with form_cols[0]:
|
|
479
489
|
name = st.text_input("Nome", value=_clean(data.get("name")), key="social_instagram_result_name")
|
|
480
|
-
bio = st.text_area("Bio", value=
|
|
490
|
+
bio = st.text_area("Bio", value=_profile_bio(data), key="social_instagram_result_bio")
|
|
481
491
|
country = st.selectbox("País", _country_options(), index=_country_index(data.get("country")), format_func=_country_label, key="social_instagram_result_country")
|
|
482
492
|
language = st.selectbox("Idioma", list(LANGUAGE_CODES), index=_language_index(data.get("language")), format_func=language_label, key="social_instagram_result_language")
|
|
483
493
|
with form_cols[1]:
|
|
@@ -490,7 +500,7 @@ def render_social_networks(settings: dict[str, Any]) -> None:
|
|
|
490
500
|
save_profile = st.form_submit_button("Cadastrar conta Instagram", type="primary", use_container_width=True)
|
|
491
501
|
if save_profile:
|
|
492
502
|
profile_data = dict(data)
|
|
493
|
-
profile_data.update({"name": name, "bio": normalize_instagram_bio(bio), "post_count": _metric_input(posts), "subscriber_count": _metric_input(followers), "following_count": _metric_input(following)})
|
|
503
|
+
profile_data.update({"name": name, "bio": normalize_instagram_bio(bio), "bio_raw": bio, "post_count": _metric_input(posts), "subscriber_count": _metric_input(followers), "following_count": _metric_input(following)})
|
|
494
504
|
_save_public_profile(profile_data, country=country, language=language, character_id=selected_character)
|
|
495
505
|
st.success("Conta Instagram cadastrada em Redes Sociais.")
|
|
496
506
|
for key in ("social_instagram_result", "social_instagram_ok", "social_instagram_message"):
|
package/hermes_ui/domain.py
CHANGED
|
@@ -125,6 +125,8 @@ def _fetch_web_profile_user(username: str) -> dict[str, Any] | None:
|
|
|
125
125
|
[curl, '-L', '--max-time', '20', '-sS', '-A', headers['User-Agent'], '-H', f"x-ig-app-id: {headers['x-ig-app-id']}", '-H', 'Accept: application/json, text/plain, */*', endpoint],
|
|
126
126
|
capture_output=True,
|
|
127
127
|
text=True,
|
|
128
|
+
encoding='utf-8',
|
|
129
|
+
errors='replace',
|
|
128
130
|
timeout=25,
|
|
129
131
|
check=False,
|
|
130
132
|
)
|
|
@@ -154,11 +156,13 @@ def _profile_data_from_api(user: Mapping[str, Any], reference: Mapping[str, str]
|
|
|
154
156
|
followers = followers if followers is not None else _structured_metric_from_json(json.dumps(user), 'edge_followed_by', 'followers', 'follower_count', 'followerCount')
|
|
155
157
|
following = following if following is not None else _structured_metric_from_json(json.dumps(user), 'edge_follow', 'follows', 'following', 'following_count', 'followingCount')
|
|
156
158
|
media = ((user.get('edge_owner_to_timeline_media') or {}).get('count') if isinstance(user.get('edge_owner_to_timeline_media'), dict) else None)
|
|
159
|
+
biography = str(user.get('biography') or '').strip()
|
|
157
160
|
return {
|
|
158
161
|
'id': f"instagram_{reference['username']}",
|
|
159
162
|
**reference,
|
|
160
163
|
'name': str(user.get('full_name') or user.get('username') or reference['username']).strip(),
|
|
161
|
-
'bio': normalize_instagram_bio(
|
|
164
|
+
'bio': normalize_instagram_bio(biography),
|
|
165
|
+
'bio_raw': biography,
|
|
162
166
|
'avatar_url': str(user.get('profile_pic_url_hd') or user.get('profile_pic_url') or '').strip(),
|
|
163
167
|
'subscriber_count': followers,
|
|
164
168
|
'following_count': following,
|
|
@@ -220,7 +224,7 @@ def fetch_public_instagram_profile(source: str) -> IntegrationResult:
|
|
|
220
224
|
followers = metric((r'([\d,.]+)\s*(?:mil\s+)?(?:followers|seguidores)',)) or _structured_metric(response.text, 'edge_followed_by', 'followers', 'follower_count') or _structured_metric_from_json(response.text, 'edge_followed_by', 'followers', 'follower_count', 'followerCount')
|
|
221
225
|
following = metric((r'([\d,.]+)\s*(?:mil\s+)?(?:following|seguindo)',)) or _structured_metric(response.text, 'edge_follow', 'follows', 'following', 'following_count', 'followingCount') or _structured_metric_from_json(response.text, 'edge_follow', 'follows', 'following', 'following_count', 'followingCount')
|
|
222
226
|
posts = metric((r'([\d,.]+)\s*(?:mil\s+)?(?:posts|publicações|publications)',)) or _structured_metric(response.text, 'edge_owner_to_timeline_media', 'posts', 'post_count')
|
|
223
|
-
data = {'id': f"instagram_{reference['username']}", **reference, 'name': title.split('(')[0].strip() or reference['username'], 'bio': normalize_instagram_bio(description), 'avatar_url': avatar_url, 'subscriber_count': followers, 'following_count': following, 'post_count': posts, 'public_lookup': True, 'metrics_source': 'instagram_public_page', 'last_public_lookup_at': datetime.now(timezone.utc).isoformat()}
|
|
227
|
+
data = {'id': f"instagram_{reference['username']}", **reference, 'name': title.split('(')[0].strip() or reference['username'], 'bio': normalize_instagram_bio(description), 'bio_raw': description, 'avatar_url': avatar_url, 'subscriber_count': followers, 'following_count': following, 'post_count': posts, 'public_lookup': True, 'metrics_source': 'instagram_public_page', 'last_public_lookup_at': datetime.now(timezone.utc).isoformat()}
|
|
224
228
|
return IntegrationResult(True, 'Perfil Instagram encontrado publicamente.', data)
|
|
225
229
|
|
|
226
230
|
|
package/package.json
CHANGED