@danhachuel/thunderbolt 0.5.69 → 0.5.71

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 CHANGED
@@ -6799,26 +6799,14 @@ def render_google_accounts(*, include_innertube: bool = True):
6799
6799
  st.rerun()
6800
6800
 
6801
6801
  st.divider()
6802
- st.subheader("Configuração Global: YouTube Data API v3 (API Key) + YouTube Analytics API (OAuth 2.0)")
6803
- st.caption("1. YouTube Data API v3: Metadados públicos (títulos, views, likes) Via MCP integrado.\n\n2. YouTube Analytics API: Métricas internas (CTR, retenção, RPM, tráfego, demografia) Via OAuth 2.0")
6802
+ youtube_global_cols = st.columns([3.2, 1.2])
6803
+ with youtube_global_cols[0]:
6804
+ st.subheader("Configuração Global: YouTube Data API v3 (API Key)")
6805
+ with youtube_global_cols[1]:
6806
+ _render_credential_status(settings.get("youtube_api_key"), required=True)
6807
+ st.caption("1. YouTube Data API v3: Metadados públicos (títulos, views, likes) Via MCP integrado.\n\n2. YouTube Analytics API: Métricas internas (CTR, retenção, RPM, tráfego, demografia) Via OAuth 2.0 (Directamente via OAuth das Contas Google/YouTube cadastradas)")
6804
6808
  with st.form("google_global_api_settings_form"):
6805
- google_api_cols = st.columns(2)
6806
- with google_api_cols[0]:
6807
- youtube_client_id = st.text_input(
6808
- "YouTube OAuth Client ID",
6809
- value=str(settings.get("youtube_client_id", "") or ""),
6810
- key="google_page_youtube_client_id",
6811
- help="Client ID OAuth 2.0 criado no Google Cloud para autorizar a conta YouTube.",
6812
- )
6813
- with google_api_cols[1]:
6814
- youtube_client_secret = st.text_input(
6815
- "YouTube OAuth Client Secret",
6816
- value=str(settings.get("youtube_client_secret", "") or ""),
6817
- type="password",
6818
- key="google_page_youtube_client_secret",
6819
- help="Client Secret do mesmo cliente OAuth 2.0. Não é uma API Key.",
6820
- )
6821
- st.caption(f"OAuth local: use um cliente do tipo Desktop app. Se o Google Cloud pedir uma URI autorizada, registe exactamente `{loopback_redirect_uri()}`.")
6809
+ st.caption("A autorização OAuth 2.0 é gerida por cada Conta Google/YouTube cadastrada e associada ao canal.")
6822
6810
  youtube_api_key = st.text_input(
6823
6811
  "YouTube Data API Key (opcional)",
6824
6812
  value=str(settings.get("youtube_api_key", "") or ""),
@@ -6829,10 +6817,10 @@ def render_google_accounts(*, include_innertube: bool = True):
6829
6817
  save_google_global = st.form_submit_button("Guardar configuração global do YouTube", type="primary", use_container_width=True)
6830
6818
  if save_google_global:
6831
6819
  settings.update({
6832
- "youtube_client_id": youtube_client_id.strip(),
6833
- "youtube_client_secret": youtube_client_secret.strip(),
6834
6820
  "youtube_api_key": youtube_api_key.strip(),
6835
6821
  })
6822
+ settings.pop("youtube_client_id", None)
6823
+ settings.pop("youtube_client_secret", None)
6836
6824
  write_json("settings.json", settings)
6837
6825
  st.success("Configuração global do YouTube guardada em Contas Google.")
6838
6826
  st.rerun()
@@ -7864,6 +7852,9 @@ def render_settings():
7864
7852
  with st.expander("API Tiktok", expanded=False):
7865
7853
  render_tiktok_api_cards(settings)
7866
7854
  with st.expander("API Bilibili", expanded=False):
7855
+ bilibili_cards = settings.get("bilibili_api_cards") if isinstance(settings.get("bilibili_api_cards"), list) else []
7856
+ bilibili_ready = any(bool(card.get("active", True) and card.get("sessdata") and card.get("bili_jct") and card.get("buvid3")) for card in bilibili_cards if isinstance(card, dict))
7857
+ _api_status_badge("Configured" if bilibili_ready else "Missing configuration", "ready" if bilibili_ready else "missing")
7867
7858
  render_bilibili_api_cards(settings)
7868
7859
  with st.expander("Composio", expanded=False):
7869
7860
  st.caption("A API key é guardada apenas no storage local. O slug da ferramenta e o provider são descobertos no Upload via Composio; a autenticação da conta é feita pelo Connect Link do Composio.")
@@ -7903,6 +7894,7 @@ def render_settings():
7903
7894
  upload_post_user_upload = st.text_input("Upload-Post username", value=str(settings.get("upload_post_username") or ""), key="upload_tab_upload_post_user")
7904
7895
  upload_post_platforms_upload = st.text_input("Plataformas Upload-Post", value=str(settings.get("upload_post_platforms") or "youtube,tiktok"), key="upload_tab_upload_post_platforms")
7905
7896
  upload_post_auto_upload = st.checkbox("Publicar automaticamente após gerar", bool(settings.get("upload_post_auto_upload", False)), key="upload_tab_upload_post_auto")
7897
+ _render_credential_status(upload_post_key_upload, required=True)
7906
7898
  if st.button("Guardar Upload-Post", type="primary", use_container_width=True, key="upload_tab_save_upload_post"):
7907
7899
  settings.update({"upload_post_enabled": bool(upload_post_enabled_upload), "upload_post_api_key": upload_post_key_upload.strip(), "upload_post_username": upload_post_user_upload.strip(), "upload_post_platforms": upload_post_platforms_upload.strip(), "upload_post_auto_upload": bool(upload_post_auto_upload)})
7908
7900
  write_json("settings.json", settings)
@@ -7915,6 +7907,7 @@ def render_settings():
7915
7907
  postiz_mcp_upload = st.text_input("Postiz MCP URL", value=str(settings.get("postiz_mcp_url") or "https://api.postiz.com/mcp"), key="upload_tab_postiz_mcp")
7916
7908
  postiz_integration_upload = st.text_input("Postiz integração padrão", value=str(settings.get("postiz_integration_id") or ""), key="upload_tab_postiz_integration")
7917
7909
  postiz_auto_upload = st.checkbox("Permitir publicação imediata no Postiz", bool(settings.get("postiz_auto_publish", False)), key="upload_tab_postiz_auto")
7910
+ _render_credential_status(postiz_key_upload, required=True)
7918
7911
  if st.button("Guardar Postiz", type="primary", use_container_width=True, key="upload_tab_save_postiz"):
7919
7912
  settings.update({"postiz_enabled": bool(postiz_enabled_upload), "postiz_api_key": postiz_key_upload.strip(), "postiz_base_url": postiz_base_upload.strip(), "postiz_mcp_url": postiz_mcp_upload.strip(), "postiz_integration_id": postiz_integration_upload.strip(), "postiz_auto_publish": bool(postiz_auto_upload)})
7920
7913
  write_json("settings.json", settings)
@@ -10,7 +10,10 @@ from typing import Any
10
10
 
11
11
  from integrations.platforms import IntegrationResult
12
12
 
13
- BATCH_SCOPES = ["https://www.googleapis.com/auth/youtube.readonly"]
13
+ BATCH_SCOPES = [
14
+ "https://www.googleapis.com/auth/youtube.readonly",
15
+ "https://www.googleapis.com/auth/yt-analytics.readonly",
16
+ ]
14
17
  DEFAULT_LOOPBACK_HOST = "127.0.0.1"
15
18
  DEFAULT_LOOPBACK_PORT = 8765
16
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.5.69",
3
+ "version": "0.5.71",
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",