@danhachuel/thunderbolt 0.6.77 → 0.6.79
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 +127 -125
- package/hermes_ui/pipeline_worker.py +16 -2
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -5633,57 +5633,58 @@ def render_tiktok_automation():
|
|
|
5633
5633
|
if not channels:
|
|
5634
5634
|
st.info("Cadastre primeiro um canal TikTok.")
|
|
5635
5635
|
return
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
st.markdown("### TT")
|
|
5646
|
-
with header_cols[1]:
|
|
5647
|
-
st.write(f"**{channel.get('name', 'Sem nome')}**")
|
|
5648
|
-
st.caption(channel.get("handle") or channel.get("url") or "sem URL")
|
|
5649
|
-
with header_cols[2]:
|
|
5650
|
-
enabled = st.toggle("Automação ligada", value=bool(channel.get("automation_on", False)), key=f"tiktok_automation_on_{channel_id}")
|
|
5651
|
-
with header_cols[3]:
|
|
5652
|
-
schedule_time = st.text_input("Horário (HH:MM)", value=channel.get("automation_time", "00:00"), key=f"tiktok_automation_time_{channel_id}")
|
|
5653
|
-
with header_cols[4]:
|
|
5654
|
-
prompt_file = TIKTOK_PROMPT_MASTERS / str(channel.get("default_prompt_master") or channel.get("prompt_master") or "")
|
|
5655
|
-
prompt_content = load_prompt_master_file(prompt_file) if prompt_file.is_file() else ""
|
|
5656
|
-
calculated_time, calculated_source, calculated_words = _channel_average_video_time(channel, prompt_master=prompt_content)
|
|
5657
|
-
average_video_time = st.text_input("Tempo Medio de Video", value=channel_video_time_value(channel), key=f"tiktok_average_video_time_{channel_id}", help=f"Referência média: {calculated_words or 0} palavras · fonte: {calculated_source}.")
|
|
5658
|
-
default_cols = st.columns([1.0, 1.0, 1.35, 1.45, 1.55, 1.0], gap="small")
|
|
5659
|
-
with default_cols[0]:
|
|
5660
|
-
st.markdown("**Idioma do roteiro**")
|
|
5661
|
-
st.caption(video_language_label(normalize_video_language(channel.get("language") or "pt")))
|
|
5662
|
-
with default_cols[1]:
|
|
5663
|
-
st.markdown("**Nicho Padrão**")
|
|
5664
|
-
st.caption(channel_niche_label(channel))
|
|
5665
|
-
with default_cols[2]:
|
|
5666
|
-
st.markdown("**Fonte do vídeo**")
|
|
5667
|
-
st.caption(channel_video_source_value(channel.get("style_wide")))
|
|
5668
|
-
st.markdown("**Proporção do vídeo**")
|
|
5669
|
-
st.caption(str(channel.get("video_aspect_ratio") or "Portrait 9:16"))
|
|
5670
|
-
st.markdown("**Formato**")
|
|
5671
|
-
st.caption(str(channel.get("format") or "Shorts"))
|
|
5672
|
-
with default_cols[3]:
|
|
5673
|
-
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}")
|
|
5674
|
-
with default_cols[4]:
|
|
5675
|
-
automation_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=CHANNEL_FORMAT_OPTIONS.index(str(channel.get("format") or "Shorts")) if str(channel.get("format") or "Shorts") in CHANNEL_FORMAT_OPTIONS else 1, key=f"tiktok_automation_format_{channel_id}")
|
|
5676
|
-
with default_cols[5]:
|
|
5677
|
-
if st.button("Guardar", key=f"tiktok_automation_save_{channel_id}", use_container_width=True, type="primary"):
|
|
5678
|
-
if not valid_hhmm(schedule_time):
|
|
5679
|
-
st.error("Use o formato HH:MM, por exemplo 08:30.")
|
|
5680
|
-
elif not valid_hhmm(average_video_time):
|
|
5681
|
-
st.error("O Tempo Medio de Video deve estar no formato MM:SS, por exemplo 12:00.")
|
|
5636
|
+
with st.expander("Canais cadastrados", expanded=False):
|
|
5637
|
+
for channel in channels:
|
|
5638
|
+
channel_id = str(channel["id"])
|
|
5639
|
+
with st.container(border=True):
|
|
5640
|
+
header_cols = st.columns([0.55, 2.35, 1.25, 0.82, 0.92, 1.2])
|
|
5641
|
+
with header_cols[0]:
|
|
5642
|
+
profile_image = _tiktok_avatar_url(channel)
|
|
5643
|
+
if profile_image:
|
|
5644
|
+
st.image(profile_image, width=48)
|
|
5682
5645
|
else:
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5646
|
+
st.markdown("### TT")
|
|
5647
|
+
with header_cols[1]:
|
|
5648
|
+
st.write(f"**{channel.get('name', 'Sem nome')}**")
|
|
5649
|
+
st.caption(channel.get("handle") or channel.get("url") or "sem URL")
|
|
5650
|
+
with header_cols[2]:
|
|
5651
|
+
enabled = st.toggle("Automação ligada", value=bool(channel.get("automation_on", False)), key=f"tiktok_automation_on_{channel_id}")
|
|
5652
|
+
with header_cols[3]:
|
|
5653
|
+
schedule_time = st.text_input("Horário (HH:MM)", value=channel.get("automation_time", "00:00"), key=f"tiktok_automation_time_{channel_id}")
|
|
5654
|
+
with header_cols[4]:
|
|
5655
|
+
prompt_file = TIKTOK_PROMPT_MASTERS / str(channel.get("default_prompt_master") or channel.get("prompt_master") or "")
|
|
5656
|
+
prompt_content = load_prompt_master_file(prompt_file) if prompt_file.is_file() else ""
|
|
5657
|
+
calculated_time, calculated_source, calculated_words = _channel_average_video_time(channel, prompt_master=prompt_content)
|
|
5658
|
+
average_video_time = st.text_input("Tempo Medio de Video", value=channel_video_time_value(channel), key=f"tiktok_average_video_time_{channel_id}", help=f"Referência média: {calculated_words or 0} palavras · fonte: {calculated_source}.")
|
|
5659
|
+
default_cols = st.columns([1.0, 1.0, 1.35, 1.45, 1.55, 1.0], gap="small")
|
|
5660
|
+
with default_cols[0]:
|
|
5661
|
+
st.markdown("**Idioma do roteiro**")
|
|
5662
|
+
st.caption(video_language_label(normalize_video_language(channel.get("language") or "pt")))
|
|
5663
|
+
with default_cols[1]:
|
|
5664
|
+
st.markdown("**Nicho Padrão**")
|
|
5665
|
+
st.caption(channel_niche_label(channel))
|
|
5666
|
+
with default_cols[2]:
|
|
5667
|
+
st.markdown("**Fonte do vídeo**")
|
|
5668
|
+
st.caption(channel_video_source_value(channel.get("style_wide")))
|
|
5669
|
+
st.markdown("**Proporção do vídeo**")
|
|
5670
|
+
st.caption(str(channel.get("video_aspect_ratio") or "Portrait 9:16"))
|
|
5671
|
+
st.markdown("**Formato**")
|
|
5672
|
+
st.caption(str(channel.get("format") or "Shorts"))
|
|
5673
|
+
with default_cols[3]:
|
|
5674
|
+
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}")
|
|
5675
|
+
with default_cols[4]:
|
|
5676
|
+
automation_format = st.selectbox("Formato", CHANNEL_FORMAT_OPTIONS, index=CHANNEL_FORMAT_OPTIONS.index(str(channel.get("format") or "Shorts")) if str(channel.get("format") or "Shorts") in CHANNEL_FORMAT_OPTIONS else 1, key=f"tiktok_automation_format_{channel_id}")
|
|
5677
|
+
with default_cols[5]:
|
|
5678
|
+
if st.button("Guardar", key=f"tiktok_automation_save_{channel_id}", use_container_width=True, type="primary"):
|
|
5679
|
+
if not valid_hhmm(schedule_time):
|
|
5680
|
+
st.error("Use o formato HH:MM, por exemplo 08:30.")
|
|
5681
|
+
elif not valid_hhmm(average_video_time):
|
|
5682
|
+
st.error("O Tempo Medio de Video deve estar no formato MM:SS, por exemplo 12:00.")
|
|
5683
|
+
else:
|
|
5684
|
+
avatar_url = _tiktok_avatar_url(channel)
|
|
5685
|
+
update_channel(channel_id, {"automation_on": bool(enabled), "automation_time": schedule_time.strip(), "average_video_time": average_video_time.strip() or DEFAULT_AVERAGE_VIDEO_TIME, "average_video_word_count": words_from_channel_time(average_video_time), "default_prompt_master": prompt, "prompt_master": prompt, "platform": "tiktok", "format": automation_format, "video_aspect_ratio": "Portrait 9:16", "style_wide": "portrait", "avatar_url": avatar_url, "thumbnail_url": avatar_url})
|
|
5686
|
+
st.success("Automação TikTok guardada.")
|
|
5687
|
+
st.rerun()
|
|
5687
5688
|
_render_tiktok_automation_cards()
|
|
5688
5689
|
|
|
5689
5690
|
@st.fragment(run_every=5.0)
|
|
@@ -5807,82 +5808,83 @@ def render_automation():
|
|
|
5807
5808
|
channels = [channel for channel in read_json("channels.json", []) if is_youtube_channel_record(channel)]
|
|
5808
5809
|
if not channels:
|
|
5809
5810
|
st.info("Nenhum canal cadastrado para configurar.")
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
st.markdown("### YT")
|
|
5824
|
-
with header_cols[1]:
|
|
5825
|
-
st.write(f"**{channel.get('name', 'Sem nome')}**")
|
|
5826
|
-
st.caption(channel.get("handle") or channel.get("url") or "sem URL")
|
|
5827
|
-
with header_cols[2]:
|
|
5828
|
-
st.markdown("**Thumbnail Blueprint**")
|
|
5829
|
-
st.caption(str(paired_thumbnail.get("name") or "Generic_Thumbnail_Blueprint"))
|
|
5830
|
-
with header_cols[3]:
|
|
5831
|
-
st.markdown("**Idioma do roteiro**")
|
|
5832
|
-
st.caption(video_language_label(normalize_video_language(channel.get("language") or "pt")))
|
|
5833
|
-
with header_cols[4]:
|
|
5834
|
-
st.markdown("**Nicho Padrão**")
|
|
5835
|
-
st.caption(channel_niche_label(channel))
|
|
5836
|
-
with header_cols[5]:
|
|
5837
|
-
st.markdown("**Fonte do vídeo**")
|
|
5838
|
-
st.caption(channel_video_source_value(channel.get("style_wide")))
|
|
5839
|
-
st.markdown("**Proporção do vídeo**")
|
|
5840
|
-
st.caption(str(channel.get("video_aspect_ratio") or "Landscape 16:9"))
|
|
5841
|
-
with header_cols[6]:
|
|
5842
|
-
schedule_time = st.text_input("Horário (HH:MM)", value=channel.get("automation_time", "00:00"), key=f"automation_time_{channel_id}")
|
|
5843
|
-
with header_cols[7]:
|
|
5844
|
-
calculated_time, calculated_source, calculated_words = _channel_average_video_time(channel)
|
|
5845
|
-
average_video_time = st.text_input("Tempo Medio de Video", value=channel_video_time_value(channel), key=f"average_video_time_{channel_id}", help=f"Referência média: {calculated_words or 0} palavras · fonte: {calculated_source}.")
|
|
5846
|
-
|
|
5847
|
-
control_cols = st.columns([1.8, 1.8, 1.35, 1.2], gap="small")
|
|
5848
|
-
with control_cols[0]:
|
|
5849
|
-
automation_blueprint = st.selectbox(
|
|
5850
|
-
"Blueprint Padrão",
|
|
5851
|
-
blueprint_ids,
|
|
5852
|
-
index=blueprint_ids.index(current_blueprint) if current_blueprint in blueprint_ids else 0,
|
|
5853
|
-
format_func=lambda item: blueprint_labels.get(item, item or "Sem Blueprint padrão"),
|
|
5854
|
-
key=f"automation_blueprint_{channel_id}",
|
|
5855
|
-
)
|
|
5856
|
-
paired_thumbnail = thumbnail_blueprint_for_blueprint(automation_blueprint)
|
|
5857
|
-
with control_cols[1]:
|
|
5858
|
-
automation_voice = st.selectbox(
|
|
5859
|
-
"Narrador/Voz Padrão",
|
|
5860
|
-
voice_options,
|
|
5861
|
-
index=voice_options.index(current_voice) if current_voice in voice_options else 0,
|
|
5862
|
-
format_func=lambda item: item or "Sem voz padrão",
|
|
5863
|
-
key=f"automation_voice_{channel_id}",
|
|
5864
|
-
)
|
|
5865
|
-
with control_cols[2]:
|
|
5866
|
-
enabled = st.toggle("Automação ligada", value=bool(channel.get("automation_on", False)), key=f"automation_on_{channel_id}")
|
|
5867
|
-
with control_cols[3]:
|
|
5868
|
-
if st.button("Guardar", key=f"automation_save_{channel_id}", use_container_width=True, type="primary"):
|
|
5869
|
-
if not valid_hhmm(schedule_time):
|
|
5870
|
-
st.error("Use o formato HH:MM, por exemplo 08:30.")
|
|
5871
|
-
elif not valid_hhmm(average_video_time):
|
|
5872
|
-
st.error("O Tempo Medio de Video deve estar no formato MM:SS, por exemplo 12:00.")
|
|
5811
|
+
with st.expander("Canais cadastrados", expanded=False):
|
|
5812
|
+
for channel in channels:
|
|
5813
|
+
channel_id = channel["id"]
|
|
5814
|
+
with st.container(border=True):
|
|
5815
|
+
blueprint_ids, blueprint_labels, current_blueprint, voice_options, current_voice = channel_default_options(channel)
|
|
5816
|
+
automation_blueprint = current_blueprint
|
|
5817
|
+
automation_voice = current_voice
|
|
5818
|
+
paired_thumbnail = thumbnail_blueprint_for_blueprint(automation_blueprint)
|
|
5819
|
+
automation_format = str(channel.get("format") or "wide")
|
|
5820
|
+
header_cols = st.columns([0.58, 2.15, 1.4, 1.15, 1.15, 1.25, 0.82, 0.92], gap="small")
|
|
5821
|
+
with header_cols[0]:
|
|
5822
|
+
if channel.get("thumbnail_url"):
|
|
5823
|
+
st.image(channel["thumbnail_url"], width=48)
|
|
5873
5824
|
else:
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5825
|
+
st.markdown("### YT")
|
|
5826
|
+
with header_cols[1]:
|
|
5827
|
+
st.write(f"**{channel.get('name', 'Sem nome')}**")
|
|
5828
|
+
st.caption(channel.get("handle") or channel.get("url") or "sem URL")
|
|
5829
|
+
with header_cols[2]:
|
|
5830
|
+
st.markdown("**Thumbnail Blueprint**")
|
|
5831
|
+
st.caption(str(paired_thumbnail.get("name") or "Generic_Thumbnail_Blueprint"))
|
|
5832
|
+
with header_cols[3]:
|
|
5833
|
+
st.markdown("**Idioma do roteiro**")
|
|
5834
|
+
st.caption(video_language_label(normalize_video_language(channel.get("language") or "pt")))
|
|
5835
|
+
with header_cols[4]:
|
|
5836
|
+
st.markdown("**Nicho Padrão**")
|
|
5837
|
+
st.caption(channel_niche_label(channel))
|
|
5838
|
+
with header_cols[5]:
|
|
5839
|
+
st.markdown("**Fonte do vídeo**")
|
|
5840
|
+
st.caption(channel_video_source_value(channel.get("style_wide")))
|
|
5841
|
+
st.markdown("**Proporção do vídeo**")
|
|
5842
|
+
st.caption(str(channel.get("video_aspect_ratio") or "Landscape 16:9"))
|
|
5843
|
+
with header_cols[6]:
|
|
5844
|
+
schedule_time = st.text_input("Horário (HH:MM)", value=channel.get("automation_time", "00:00"), key=f"automation_time_{channel_id}")
|
|
5845
|
+
with header_cols[7]:
|
|
5846
|
+
calculated_time, calculated_source, calculated_words = _channel_average_video_time(channel)
|
|
5847
|
+
average_video_time = st.text_input("Tempo Medio de Video", value=channel_video_time_value(channel), key=f"average_video_time_{channel_id}", help=f"Referência média: {calculated_words or 0} palavras · fonte: {calculated_source}.")
|
|
5848
|
+
|
|
5849
|
+
control_cols = st.columns([1.8, 1.8, 1.35, 1.2], gap="small")
|
|
5850
|
+
with control_cols[0]:
|
|
5851
|
+
automation_blueprint = st.selectbox(
|
|
5852
|
+
"Blueprint Padrão",
|
|
5853
|
+
blueprint_ids,
|
|
5854
|
+
index=blueprint_ids.index(current_blueprint) if current_blueprint in blueprint_ids else 0,
|
|
5855
|
+
format_func=lambda item: blueprint_labels.get(item, item or "Sem Blueprint padrão"),
|
|
5856
|
+
key=f"automation_blueprint_{channel_id}",
|
|
5857
|
+
)
|
|
5858
|
+
paired_thumbnail = thumbnail_blueprint_for_blueprint(automation_blueprint)
|
|
5859
|
+
with control_cols[1]:
|
|
5860
|
+
automation_voice = st.selectbox(
|
|
5861
|
+
"Narrador/Voz Padrão",
|
|
5862
|
+
voice_options,
|
|
5863
|
+
index=voice_options.index(current_voice) if current_voice in voice_options else 0,
|
|
5864
|
+
format_func=lambda item: item or "Sem voz padrão",
|
|
5865
|
+
key=f"automation_voice_{channel_id}",
|
|
5866
|
+
)
|
|
5867
|
+
with control_cols[2]:
|
|
5868
|
+
enabled = st.toggle("Automação ligada", value=bool(channel.get("automation_on", False)), key=f"automation_on_{channel_id}")
|
|
5869
|
+
with control_cols[3]:
|
|
5870
|
+
if st.button("Guardar", key=f"automation_save_{channel_id}", use_container_width=True, type="primary"):
|
|
5871
|
+
if not valid_hhmm(schedule_time):
|
|
5872
|
+
st.error("Use o formato HH:MM, por exemplo 08:30.")
|
|
5873
|
+
elif not valid_hhmm(average_video_time):
|
|
5874
|
+
st.error("O Tempo Medio de Video deve estar no formato MM:SS, por exemplo 12:00.")
|
|
5875
|
+
else:
|
|
5876
|
+
update_channel(channel_id, {
|
|
5877
|
+
"automation_on": bool(enabled),
|
|
5878
|
+
"automation_time": schedule_time.strip(),
|
|
5879
|
+
"average_video_time": average_video_time.strip() or DEFAULT_AVERAGE_VIDEO_TIME,
|
|
5880
|
+
"average_video_word_count": words_from_channel_time(average_video_time),
|
|
5881
|
+
"format": automation_format,
|
|
5882
|
+
})
|
|
5883
|
+
set_channel_defaults(channel_id, automation_blueprint, automation_voice)
|
|
5884
|
+
paired_id = str(paired_thumbnail.get("id") or "Generic_Thumbnail_Blueprint")
|
|
5885
|
+
update_channel(channel_id, {"thumbnail_blueprint_id": paired_id, "default_thumbnail_blueprint_id": paired_id})
|
|
5886
|
+
st.success("Agendamento guardado.")
|
|
5887
|
+
st.rerun()
|
|
5886
5888
|
|
|
5887
5889
|
_render_youtube_automation_cards()
|
|
5888
5890
|
|
|
@@ -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 >=
|
|
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"{
|
|
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