@danhachuel/thunderbolt 0.4.85 → 0.4.86

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 -1
  2. package/package.json +1 -1
package/app/main.py CHANGED
@@ -4466,6 +4466,28 @@ def load_video_tasks_for_catalog() -> list[dict[str, Any]]:
4466
4466
  return [task for task in saved if isinstance(task, dict) and str(task.get("id") or "").strip()]
4467
4467
 
4468
4468
 
4469
+ def task_platform(task: dict[str, Any]) -> str:
4470
+ """Resolve a plataforma da tarefa, incluindo tarefas legadas sem platform."""
4471
+ explicit = str(task.get("platform") or "").strip().casefold()
4472
+ if explicit in {"youtube", "yt"}:
4473
+ return "youtube"
4474
+ if explicit in {"tiktok", "tik-tok", "tt"}:
4475
+ return "tiktok"
4476
+ channel_id = str(task.get("channel_id") or "")
4477
+ if channel_id:
4478
+ channel = next((item for item in read_json("channels.json", []) if isinstance(item, dict) and str(item.get("id")) == channel_id), None)
4479
+ if channel:
4480
+ return classify_channel_platform(channel)
4481
+ format_value = str(task.get("format") or "").strip().casefold()
4482
+ return "tiktok" if format_value in {"portrait", "portrait 9:16", "9:16"} else "youtube"
4483
+
4484
+
4485
+ def load_automation_tasks_for_platform(platform_name: str) -> list[dict[str, Any]]:
4486
+ """Return only automation/catalog tasks belonging to one publishing platform."""
4487
+ target = str(platform_name or "").strip().casefold()
4488
+ return [task for task in load_video_tasks_for_catalog() if task_platform(task) == target]
4489
+
4490
+
4469
4491
  def _task_thumbnail_path(task: dict[str, Any]) -> Path | None:
4470
4492
  """Resolve a generated thumbnail from current and legacy task fields."""
4471
4493
  artifacts = task.get("artifacts") if isinstance(task.get("artifacts"), dict) else {}
@@ -4968,6 +4990,36 @@ def render_tiktok_automation():
4968
4990
  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", "style_wide": "portrait", "avatar_url": avatar_url, "thumbnail_url": avatar_url})
4969
4991
  st.success("Automação TikTok guardada.")
4970
4992
  st.rerun()
4993
+ st.divider()
4994
+ st.subheader("Vídeos cadastrados TikTok")
4995
+ st.caption("Esta fila mostra exclusivamente tarefas associadas a canais TikTok.")
4996
+ tiktok_tasks = load_automation_tasks_for_platform("tiktok")
4997
+ if not tiktok_tasks:
4998
+ st.info("Ainda não existem vídeos TikTok cadastrados.")
4999
+ for task in tiktok_tasks:
5000
+ task_id = str(task["id"])
5001
+ with st.container(border=True):
5002
+ cols = st.columns([2.4, 1.4, 1.1, 1.6])
5003
+ with cols[0]:
5004
+ thumbnail_path = _task_thumbnail_path(task)
5005
+ if thumbnail_path:
5006
+ st.image(str(thumbnail_path), width=150, caption="Thumbnail")
5007
+ st.write(f"**{task.get('title') or task.get('topic') or 'Vídeo TikTok'}**")
5008
+ st.caption(f"{task.get('channel_name') or 'Canal TikTok'} · {task_id}")
5009
+ with cols[1]:
5010
+ _render_video_task_state(task)
5011
+ with cols[2]:
5012
+ st.caption("Plataforma")
5013
+ st.write("TikTok")
5014
+ st.caption("Portrait 9:16")
5015
+ with cols[3]:
5016
+ state = str(task.get("state") or "")
5017
+ if st.button("Start", key=f"tiktok_automation_start_{task_id}", disabled=state not in {"to_do", "blocked", "failed"}, use_container_width=True):
5018
+ retry_task_with_current_settings(task_id) if state in {"blocked", "failed"} else transition_task(task_id, "doing")
5019
+ st.rerun()
5020
+ if st.button("Stop", key=f"tiktok_automation_stop_{task_id}", disabled=state != "doing", use_container_width=True):
5021
+ stop_task_by_user(task_id)
5022
+ st.rerun()
4971
5023
 
4972
5024
 
4973
5025
  def render_automation():
@@ -5049,7 +5101,7 @@ def render_automation():
5049
5101
  st.divider()
5050
5102
  st.subheader("Vídeos cadastrados")
5051
5103
  st.caption("Start retoma as etapas já concluídas e só gera novamente o que ainda não estiver pronto. Em tarefas falhadas ou bloqueadas, a nova tentativa lê as chaves, prioridades e configurações actualmente guardadas. Apagar remove o card da fila após confirmação e preserva os artefactos locais.")
5052
- tasks = load_video_tasks_for_catalog()
5104
+ tasks = load_automation_tasks_for_platform("youtube")
5053
5105
  if not tasks:
5054
5106
  st.info("Ainda não existem vídeos cadastrados.")
5055
5107
  for task in tasks:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.4.85",
3
+ "version": "0.4.86",
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",