@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.
- package/app/main.py +53 -1
- 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 =
|
|
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