@danhachuel/thunderbolt 0.6.39 → 0.6.41

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.
@@ -124,6 +124,12 @@ def _instagram_profile_storage_id(profile: Mapping[str, Any]) -> str:
124
124
  return re.sub(r"[^A-Za-z0-9_.-]+", "_", value) or "unknown"
125
125
 
126
126
 
127
+ def _clear_instagram_result_widget_state(profile: Mapping[str, Any]) -> None:
128
+ widget_id = _instagram_profile_storage_id(profile)
129
+ for field in ("name", "bio", "country", "language", "posts", "followers", "following", "character"):
130
+ st.session_state.pop(f"social_instagram_result_{field}_{widget_id}", None)
131
+
132
+
127
133
  def _normalise_instagram_posts(value: Any) -> list[dict[str, Any]]:
128
134
  if not isinstance(value, list):
129
135
  return []
@@ -583,6 +589,8 @@ def render_social_networks(settings: dict[str, Any]) -> None:
583
589
  if search_clicked:
584
590
  result = fetch_public_instagram_profile(source)
585
591
  result_data = dict(result.data) if isinstance(result.data, dict) else {}
592
+ if result_data:
593
+ _clear_instagram_result_widget_state(result_data)
586
594
  st.session_state["social_instagram_result"] = result_data
587
595
  st.session_state["social_instagram_ok"] = result.ok
588
596
  st.session_state["social_instagram_message"] = result.message
@@ -140,7 +140,14 @@ def _fetch_web_profile_user(username: str) -> dict[str, Any] | None:
140
140
  f'https://i.instagram.com/api/v1/users/web_profile_info/?username={username}',
141
141
  )
142
142
  def profile_quality(user: Mapping[str, Any]) -> int:
143
- return sum(bool(user.get(key)) for key in ('biography', 'edge_follow', 'edge_followed_by', 'edge_owner_to_timeline_media', 'username'))
143
+ groups = (
144
+ ('biography', 'bio', 'description'),
145
+ ('edge_follow', 'following', 'following_count', 'followingCount', 'follows'),
146
+ ('edge_followed_by', 'followers', 'follower_count', 'followers_count', 'followerCount'),
147
+ ('edge_owner_to_timeline_media', 'posts', 'post_count', 'media_count'),
148
+ ('username', 'user_name', 'handle'),
149
+ )
150
+ return sum(any(user.get(key) not in (None, '', {}, []) for key in group) for group in groups)
144
151
 
145
152
  def merge_profile(base: dict[str, Any] | None, candidate: Mapping[str, Any]) -> dict[str, Any]:
146
153
  merged = dict(base or {})
@@ -152,6 +159,17 @@ def _fetch_web_profile_user(username: str) -> dict[str, Any] | None:
152
159
  merged[key] = value
153
160
  return merged
154
161
 
162
+ def extract_user(payload: Any) -> Mapping[str, Any] | None:
163
+ if not isinstance(payload, Mapping):
164
+ return None
165
+ candidates = [
166
+ payload.get('user'),
167
+ (payload.get('data') or {}).get('user') if isinstance(payload.get('data'), Mapping) else None,
168
+ (payload.get('graphql') or {}).get('user') if isinstance(payload.get('graphql'), Mapping) else None,
169
+ (payload.get('data') or {}).get('profile') if isinstance(payload.get('data'), Mapping) else None,
170
+ ]
171
+ return next((candidate for candidate in candidates if isinstance(candidate, Mapping)), None)
172
+
155
173
  request_headers = [
156
174
  headers,
157
175
  {**headers, 'User-Agent': 'Instagram 390.0.0.0.50 Android', 'Accept': 'application/json, text/plain, */*'},
@@ -169,7 +187,7 @@ def _fetch_web_profile_user(username: str) -> dict[str, Any] | None:
169
187
  if best_user:
170
188
  return best_user
171
189
  continue
172
- user = ((payload.get('data') or {}).get('user') if isinstance(payload, dict) else None)
190
+ user = extract_user(payload)
173
191
  if isinstance(user, dict):
174
192
  best_user = merge_profile(best_user, user)
175
193
  if profile_quality(best_user) >= 4:
@@ -189,7 +207,7 @@ def _fetch_web_profile_user(username: str) -> dict[str, Any] | None:
189
207
  check=False,
190
208
  )
191
209
  payload = json.loads(completed.stdout) if completed.returncode == 0 and completed.stdout else None
192
- user = ((payload.get('data') or {}).get('user') if isinstance(payload, dict) else None)
210
+ user = extract_user(payload)
193
211
  if isinstance(user, dict):
194
212
  best_user = merge_profile(best_user, user)
195
213
  if profile_quality(best_user) >= 4:
@@ -215,7 +233,7 @@ def _fetch_web_profile_user(username: str) -> dict[str, Any] | None:
215
233
  if response is None or response.status >= 400:
216
234
  continue
217
235
  payload = json.loads(page.locator('body').inner_text(timeout=5000))
218
- user = ((payload.get('data') or {}).get('user') if isinstance(payload, dict) else None)
236
+ user = extract_user(payload)
219
237
  if isinstance(user, dict):
220
238
  best_user = merge_profile(best_user, user)
221
239
  if profile_quality(best_user) >= 4:
@@ -289,12 +307,13 @@ def _profile_data_from_api(user: Mapping[str, Any], reference: Mapping[str, str]
289
307
  followers = followers if followers is not None else _structured_metric_from_json(json.dumps(user), 'edge_followed_by', 'followers', 'follower_count', 'followerCount')
290
308
  following = following if following is not None else _structured_metric_from_json(json.dumps(user), 'edge_follow', 'follows', 'following', 'following_count', 'followingCount')
291
309
  media = ((user.get('edge_owner_to_timeline_media') or {}).get('count') if isinstance(user.get('edge_owner_to_timeline_media'), dict) else None)
292
- biography = str(user.get('biography') or '').strip()
310
+ media = media if media is not None else _profile_metric(user, 'posts', 'post_count', 'media_count')
311
+ biography = str(user.get('biography') or user.get('bio') or user.get('description') or '').strip()
293
312
  country = extract_public_instagram_country(user) or _fetch_instagram_about_country(user.get('id') or user.get('pk'))
294
313
  return {
295
314
  'id': f"instagram_{reference['username']}",
296
315
  **reference,
297
- 'name': str(user.get('full_name') or user.get('username') or reference['username']).strip(),
316
+ 'name': str(user.get('full_name') or user.get('name') or user.get('username') or reference['username']).strip(),
298
317
  'bio': normalize_instagram_bio(biography),
299
318
  'bio_raw': biography,
300
319
  'country': country,
@@ -306,7 +325,7 @@ def _profile_data_from_api(user: Mapping[str, Any], reference: Mapping[str, str]
306
325
  'public_lookup': True,
307
326
  'metrics_source': 'instagram_web_profile_info',
308
327
  'last_public_lookup_at': datetime.now(timezone.utc).isoformat(),
309
- '_api_posts': (((user.get('edge_owner_to_timeline_media') or {}).get('edges') or []) if isinstance(user.get('edge_owner_to_timeline_media'), dict) else []),
328
+ '_api_posts': (((user.get('edge_owner_to_timeline_media') or {}).get('edges') or []) if isinstance(user.get('edge_owner_to_timeline_media'), dict) else (user.get('posts') if isinstance(user.get('posts'), list) else [])),
310
329
  }
311
330
 
312
331
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.6.39",
3
+ "version": "0.6.41",
4
4
  "description": "Thunderbolt — interface local para operação de canais faceless e motor MoneyPrinterTurbo",
5
5
  "license": "MIT",
6
6
  "main": "scripts/cli.mjs",