@danhachuel/thunderbolt 0.4.44 → 0.4.45

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
@@ -1931,7 +1931,7 @@ def render_tiktok_channels():
1931
1931
  description = st.text_area("Descrição", value=str(imported.get("bio") or ""), key="tiktok_import_description")
1932
1932
  if st.form_submit_button("Cadastrar canal TikTok", type="primary"):
1933
1933
  channel = create_channel(name.strip(), url.strip(), {"platform": "tiktok", "handle": handle.strip(), "language": language, "niche": niche.strip(), "description": description.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "style_wide": "portrait", "video_aspect_ratio": "Portrait 9:16", "metrics_source": "tiktok_public_page", "subscriber_count": imported.get("subscriber_count"), "video_count": imported.get("video_count")})
1934
- update_channel(channel["id"], {"platform": "tiktok", "default_prompt_master": prompt, "prompt_master": prompt})
1934
+ update_channel(channel["id"], {"platform": "tiktok", "default_prompt_master": prompt, "prompt_master": prompt, "avatar_url": imported.get("avatar_url") or imported.get("avatar") or "", "thumbnail_url": imported.get("avatar_url") or imported.get("avatar") or ""})
1935
1935
  st.session_state.pop("tiktok_channel_import", None)
1936
1936
  st.success(f"Canal {channel['name']} cadastrado.")
1937
1937
  st.rerun()
@@ -4589,7 +4589,13 @@ def render_thumbnails():
4589
4589
 
4590
4590
  def render_tiktok_automation():
4591
4591
  st.title("Automação Tiktok")
4592
- st.caption("Fila exclusiva de Shorts TikTok em Portrait 9:16, usando Prompt Master em vez de Blueprint.")
4592
+ st.caption("Agendamento diário da geração por canal. A fila TikTok usa Prompt Master e mantém exclusivamente o formato Portrait 9:16.")
4593
+ worker_status = load_worker_status()
4594
+ local_now = datetime.now().astimezone()
4595
+ if worker_status.get("alive"):
4596
+ st.success(f"Worker activo · relógio local: {local_now.strftime('%d/%m/%Y %H:%M:%S %Z')}")
4597
+ else:
4598
+ st.warning("Worker de automação não está activo. Inicie o Thunderbolt pelo launcher (`npx.cmd --yes @danhachuel/thunderbolt`) para activar as verificações horárias.")
4593
4599
  channels = _tiktok_channel_records()
4594
4600
  prompt_ids, prompt_labels = _tiktok_prompt_options()
4595
4601
  if not channels:
@@ -4598,18 +4604,43 @@ def render_tiktok_automation():
4598
4604
  for channel in channels:
4599
4605
  channel_id = str(channel["id"])
4600
4606
  with st.container(border=True):
4601
- st.write(f"**{channel.get('name', 'Sem nome')}** · {channel.get('handle', '')}")
4602
- enabled = st.toggle("Automação ligada", value=bool(channel.get("automation_on", False)), key=f"tiktok_automation_on_{channel_id}")
4603
- schedule_time = st.text_input("Horário diário (HH:MM)", value=channel.get("automation_time", "00:00"), key=f"tiktok_automation_time_{channel_id}")
4604
- prompt = st.selectbox("Prompt Master padrão", prompt_ids, index=prompt_ids.index(channel.get("default_prompt_master", "")) if channel.get("default_prompt_master", "") in prompt_ids else 0, format_func=lambda item: prompt_labels.get(item, item), key=f"tiktok_automation_prompt_{channel_id}")
4605
- st.caption("Formato da fila: Portrait 9:16 · Pool de vídeo: TikTok")
4606
- if st.button("Guardar automação TikTok", key=f"tiktok_automation_save_{channel_id}", type="primary"):
4607
- if not valid_hhmm(schedule_time):
4608
- st.error("Use o formato HH:MM, por exemplo 08:30.")
4607
+ header_cols = st.columns([0.55, 2.35, 1.35, 1.5, 1.35])
4608
+ with header_cols[0]:
4609
+ profile_image = channel.get("avatar_url") or channel.get("thumbnail_url")
4610
+ if profile_image:
4611
+ st.image(profile_image, width=48)
4609
4612
  else:
4610
- update_channel(channel_id, {"automation_on": bool(enabled), "automation_time": schedule_time.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "platform": "tiktok", "video_aspect_ratio": "Portrait 9:16"})
4611
- st.success("Automação TikTok guardada.")
4612
- st.rerun()
4613
+ st.markdown("### TT")
4614
+ with header_cols[1]:
4615
+ st.write(f"**{channel.get('name', 'Sem nome')}**")
4616
+ st.caption(channel.get("handle") or channel.get("url") or "sem URL")
4617
+ with header_cols[2]:
4618
+ enabled = st.toggle("Automação ligada", value=bool(channel.get("automation_on", False)), key=f"tiktok_automation_on_{channel_id}")
4619
+ with header_cols[3]:
4620
+ schedule_time = st.text_input("Horário (HH:MM)", value=channel.get("automation_time", "00:00"), key=f"tiktok_automation_time_{channel_id}")
4621
+ default_cols = st.columns([1.0, 1.0, 1.35, 1.45, 1.55, 1.0], gap="small")
4622
+ with default_cols[0]:
4623
+ st.markdown("**Idioma Padrão**")
4624
+ st.caption(language_label(channel.get("language") or "pt"))
4625
+ with default_cols[1]:
4626
+ st.markdown("**Nicho Padrão**")
4627
+ st.caption(channel_niche_label(channel))
4628
+ with default_cols[2]:
4629
+ st.markdown("**Formato da fila**")
4630
+ st.caption("Portrait 9:16")
4631
+ with default_cols[3]:
4632
+ prompt = st.selectbox("Prompt Master Padrão", prompt_ids, index=prompt_ids.index(channel.get("default_prompt_master", "")) if channel.get("default_prompt_master", "") in prompt_ids else 0, format_func=lambda item: prompt_labels.get(item, item), key=f"tiktok_automation_prompt_{channel_id}")
4633
+ with default_cols[4]:
4634
+ st.markdown("**Pool de vídeos**")
4635
+ st.caption("TikTok / Shorts")
4636
+ with default_cols[5]:
4637
+ if st.button("Guardar", key=f"tiktok_automation_save_{channel_id}", use_container_width=True, type="primary"):
4638
+ if not valid_hhmm(schedule_time):
4639
+ st.error("Use o formato HH:MM, por exemplo 08:30.")
4640
+ else:
4641
+ update_channel(channel_id, {"automation_on": bool(enabled), "automation_time": schedule_time.strip(), "default_prompt_master": prompt, "prompt_master": prompt, "platform": "tiktok", "video_aspect_ratio": "Portrait 9:16"})
4642
+ st.success("Automação TikTok guardada.")
4643
+ st.rerun()
4613
4644
 
4614
4645
 
4615
4646
  def render_automation():
@@ -39,6 +39,7 @@ def create_channel(name: str, url: str = "", metadata: dict[str, Any] | None = N
39
39
  "niche": "",
40
40
  "reference_channels": [],
41
41
  "thumbnail_url": "",
42
+ "avatar_url": "",
42
43
  "subscriber_count": None,
43
44
  "video_count": None,
44
45
  "view_count": None,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.4.44",
3
+ "version": "0.4.45",
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",