@danhachuel/thunderbolt 0.6.76 → 0.6.78

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
@@ -4970,10 +4970,11 @@ def _task_artifact_path(task: dict[str, Any], *names: str) -> Path | None:
4970
4970
 
4971
4971
 
4972
4972
  def _download_title(task: dict[str, Any]) -> str:
4973
- """Return a filesystem-safe title for automation downloads."""
4974
- raw_title = str(task.get("title") or task.get("topic") or task.get("name") or "Vídeo").strip()
4975
- cleaned = re.sub(r'[<>:"/\\|?*\\x00-\\x1f]+', "_", raw_title)
4976
- cleaned = " ".join(cleaned.split()).strip(" ._")
4973
+ """Return the original video name, safely normalised for downloaded files."""
4974
+ raw_title = str(task.get("topic") or task.get("title") or task.get("name") or "Vídeo").strip()
4975
+ cleaned = re.sub(r'[<>:"/\\|?*\x00-\x1f]+', "_", raw_title)
4976
+ cleaned = re.sub(r"\s+", "_", cleaned)
4977
+ cleaned = re.sub(r"_+", "_", cleaned).strip(" ._")
4977
4978
  return cleaned or "Vídeo"
4978
4979
 
4979
4980
 
@@ -5713,7 +5714,7 @@ def _render_youtube_automation_cards():
5713
5714
  st.download_button(
5714
5715
  "Baixar Thumbnail",
5715
5716
  data=thumbnail_path.read_bytes() if thumbnail_path else b"",
5716
- file_name=_automation_download_name("Thumbnail9:16", task, thumbnail_path, ".png"),
5717
+ file_name=_automation_download_name("Thumbnail", task, thumbnail_path, ".png"),
5717
5718
  mime="image/png",
5718
5719
  key=f"automation_download_thumbnail_{task['id']}",
5719
5720
  use_container_width=True,
@@ -5761,7 +5762,7 @@ def _render_youtube_automation_cards():
5761
5762
  st.download_button(
5762
5763
  "Baixar Vídeo",
5763
5764
  data=video_path.read_bytes() if video_path else b"",
5764
- file_name=_automation_download_name("Vídeo9:16", task, video_path, ".mp4"),
5765
+ file_name=_automation_download_name("Vídeo", task, video_path, ".mp4"),
5765
5766
  mime="video/mp4",
5766
5767
  key=f"automation_download_video_{task['id']}",
5767
5768
  use_container_width=True,
@@ -41,6 +41,7 @@ PIPELINE_LOG_FILENAME = "pipeline_worker.json"
41
41
  VIDEO_TIMEOUT_SECONDS = 20 * 60
42
42
  LONG_STOCK_VIDEO_TIMEOUT_SECONDS = 90 * 60
43
43
  VIDEO_IDLE_TIMEOUT_SECONDS = 10 * 60
44
+ STOCK_VIDEO_IDLE_TIMEOUT_SECONDS = 30 * 60
44
45
  STALE_TASK_SECONDS = VIDEO_TIMEOUT_SECONDS + 5 * 60
45
46
  WORKER_HEARTBEAT_TIMEOUT_SECONDS = 15
46
47
  CASCADE_STAGE_ORDER = ("topic", "script", "title", "keywords", "video", "thumbnail_prompt", "thumbnail", "upload")
@@ -726,6 +727,18 @@ def _video_timeout_seconds(task: dict[str, Any], settings: dict[str, Any] | None
726
727
  return VIDEO_TIMEOUT_SECONDS
727
728
 
728
729
 
730
+ def _video_idle_timeout_seconds(task: dict[str, Any], settings: dict[str, Any] | None = None) -> int:
731
+ """Allow slow stock downloads to stay quiet without treating them as hung."""
732
+ configured = VIDEO_IDLE_TIMEOUT_SECONDS
733
+ if configured <= 0:
734
+ return configured
735
+ effective_settings = settings if isinstance(settings, dict) else _settings()
736
+ route = _normalise_video_route(task, effective_settings)
737
+ if route in {"pexels", "pixabay"}:
738
+ return max(configured, STOCK_VIDEO_IDLE_TIMEOUT_SECONDS)
739
+ return configured
740
+
741
+
729
742
  def _task_stale_timeout_seconds(task: dict[str, Any]) -> int:
730
743
  """Keep stale-task recovery aligned with the actual execution budget."""
731
744
  if str(task.get("stage") or "").strip().casefold() == "video":
@@ -1032,6 +1045,7 @@ def _run_video_helper_once(
1032
1045
  line_queue: queue.Queue[str | None] = queue.Queue()
1033
1046
  started_at = time.monotonic()
1034
1047
  timeout_seconds = _video_timeout_seconds(task, settings)
1048
+ idle_timeout_seconds = _video_idle_timeout_seconds(task, settings)
1035
1049
  process: subprocess.Popen[str] | None = None
1036
1050
 
1037
1051
  def _read_output() -> None:
@@ -1125,11 +1139,11 @@ def _run_video_helper_once(
1125
1139
  failure_metadata=metadata,
1126
1140
  fallback_eligible=True,
1127
1141
  )
1128
- if time.monotonic() - last_activity_at >= VIDEO_IDLE_TIMEOUT_SECONDS:
1142
+ if time.monotonic() - last_activity_at >= idle_timeout_seconds:
1129
1143
  _stop_process(process)
1130
1144
  message = (
1131
1145
  "A etapa Vídeo não apresentou actividade comprovada do motor durante "
1132
- f"{VIDEO_IDLE_TIMEOUT_SECONDS // 60} minutos e foi encerrada."
1146
+ f"{idle_timeout_seconds // 60} minutos e foi encerrada."
1133
1147
  )
1134
1148
  metadata = _failure_attribution(task, settings, "video", error=message)
1135
1149
  raise PipelineError(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.6.76",
3
+ "version": "0.6.78",
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",