@danhachuel/thunderbolt 0.4.43 → 0.4.44

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.
Files changed (2) hide show
  1. package/app/main.py +53 -3
  2. package/package.json +1 -1
package/app/main.py CHANGED
@@ -1844,6 +1844,15 @@ def render_tiktok_prompt_masters():
1844
1844
  st.error(str(exc))
1845
1845
 
1846
1846
 
1847
+ def format_metric_number(value: Any) -> str:
1848
+ if value in (None, ""):
1849
+ return "—"
1850
+ try:
1851
+ return f"{int(value):,}".replace(",", ".")
1852
+ except (TypeError, ValueError):
1853
+ return str(value)
1854
+
1855
+
1847
1856
  def _tiktok_channel_records() -> list[dict[str, Any]]:
1848
1857
  return [channel for channel in read_json("channels.json", []) if isinstance(channel, dict) and channel.get("platform") == "tiktok"]
1849
1858
 
@@ -1862,15 +1871,56 @@ def render_tiktok_channels():
1862
1871
  import_tab, spreadsheet_tab, manual_tab = render_localized_tabs(["Importar do Tiktok", "Canais em lote Planilha", "Cadastro manual"])
1863
1872
  prompt_ids, prompt_labels = _tiktok_prompt_options()
1864
1873
  with import_tab:
1874
+ st.caption("A pesquisa consulta exclusivamente a página pública do TikTok. Não existe método alternativo nem utilização de API.")
1865
1875
  source = st.text_input("URL pública ou @handle", placeholder="https://www.tiktok.com/@conta", key="tiktok_channel_source")
1866
- if st.button("Buscar no Tiktok", type="primary", use_container_width=True, key="tiktok_channel_lookup"):
1867
- result = fetch_public_tiktok_profile(source)
1868
- st.session_state["tiktok_channel_import"] = {"ok": result.ok, "message": result.message, "data": result.data}
1876
+ lookup_cols = st.columns([1, 1])
1877
+ with lookup_cols[0]:
1878
+ if st.button("Buscar no Tiktok", type="primary", use_container_width=True, key="tiktok_channel_lookup"):
1879
+ result = fetch_public_tiktok_profile(source)
1880
+ st.session_state["tiktok_channel_import"] = {"ok": result.ok, "message": result.message, "data": result.data}
1881
+ with lookup_cols[1]:
1882
+ if st.button("Limpar importação", use_container_width=True, key="tiktok_channel_clear"):
1883
+ for key in ("tiktok_channel_import", "tiktok_import_language", "tiktok_import_niche", "tiktok_import_prompt", "tiktok_import_description"):
1884
+ st.session_state.pop(key, None)
1885
+ st.rerun()
1869
1886
  imported_state = st.session_state.get("tiktok_channel_import", {})
1870
1887
  if imported_state.get("message"):
1871
1888
  (st.success if imported_state.get("ok") else st.warning)(imported_state["message"])
1872
1889
  imported = imported_state.get("data") if imported_state.get("ok") else {}
1873
1890
  if imported:
1891
+ st.caption("Dados encontrados na página pública. Reveja os cartões e edite os campos antes de guardar.")
1892
+ with st.container(border=True):
1893
+ profile_cols = st.columns([0.8, 2.2, 1, 1, 1])
1894
+ with profile_cols[0]:
1895
+ avatar = imported.get("avatar_url") or imported.get("avatar")
1896
+ if avatar:
1897
+ st.image(avatar, width=82)
1898
+ else:
1899
+ st.markdown("### TT")
1900
+ with profile_cols[1]:
1901
+ st.markdown(f"### {imported.get('name') or imported.get('username') or 'Perfil TikTok'}")
1902
+ st.write(imported.get("handle") or f"@{imported.get('username', '')}")
1903
+ st.caption(imported.get("public_url") or imported.get("url") or "Página pública")
1904
+ with profile_cols[2]:
1905
+ st.metric("Seguidores", format_metric_number(imported.get("subscriber_count")))
1906
+ with profile_cols[3]:
1907
+ st.metric("Curtidas", format_metric_number(imported.get("likes_count")))
1908
+ with profile_cols[4]:
1909
+ st.metric("Vídeos", format_metric_number(imported.get("video_count")))
1910
+ if imported.get("bio"):
1911
+ st.caption(f"Descrição pública: {imported['bio']}")
1912
+ with st.container(border=True):
1913
+ st.markdown("**Dados do canal a cadastrar**")
1914
+ data_cols = st.columns(3)
1915
+ with data_cols[0]:
1916
+ st.write(f"**Nome:** {imported.get('name') or imported.get('username') or '—'}")
1917
+ st.write(f"**Handle:** {imported.get('handle') or '—'}")
1918
+ with data_cols[1]:
1919
+ st.write(f"**URL:** {imported.get('public_url') or imported.get('url') or '—'}")
1920
+ st.write(f"**Origem:** {imported.get('metrics_source') or 'tiktok_public_page'}")
1921
+ with data_cols[2]:
1922
+ st.write("**Formato:** Portrait 9:16")
1923
+ st.write("**Consulta:** Página pública")
1874
1924
  with st.form("tiktok_channel_import_form"):
1875
1925
  name = st.text_input("Nome canal", value=str(imported.get("name") or imported.get("username") or ""))
1876
1926
  url = st.text_input("URL canal", value=str(imported.get("public_url") or imported.get("url") or ""))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.4.43",
3
+ "version": "0.4.44",
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",