@danhachuel/thunderbolt 0.4.58 → 0.4.59
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/MANUAL-INSTALACAO.md +2 -0
- package/app/main.py +2 -1
- package/hermes_ui/storage.py +1 -0
- package/integrations/upload_routing.py +18 -2
- package/package.json +1 -1
package/MANUAL-INSTALACAO.md
CHANGED
|
@@ -837,3 +837,5 @@ Quando o provider ainda não estiver conectado, use **Autorizar toolkit no Compo
|
|
|
837
837
|
Antes de clicar em **Enviar vídeo via Composio**, confirme o vídeo, o toolkit, o slug da ferramenta, o campo do ficheiro e os argumentos JSON. O resultado guarda apenas um registo local mínimo com o estado e, quando devolvido, o `log_id` do Composio. URLs presigned, tokens, headers e a API key não são guardados no histórico.
|
|
838
838
|
|
|
839
839
|
Na **Automação Youtube**, Composio é a rota padrão quando a integração está activa e tem API key, slug da ferramenta e campo do ficheiro configurados. A ordem automática passa a ser **Composio → API Oficial → Upload directo → Postiz**. Se Composio falhar ou não estiver configurado, o worker tenta os fallbacks disponíveis e mantém o comportamento de publicação existente.
|
|
840
|
+
|
|
841
|
+
Para garantir o canal correcto, configure também o **Campo do canal na ferramenta**. O worker lê o `youtube_channel_id` do canal associado à tarefa e substitui explicitamente esse campo nos argumentos enviados ao Composio. Se a tarefa não tiver um YouTube channel ID sincronizado, ou se os argumentos configurarem outro ID, o envio Composio é bloqueado e os fallbacks podem actuar; a publicação nunca é enviada silenciosamente para um canal diferente.
|
package/app/main.py
CHANGED
|
@@ -7173,6 +7173,7 @@ def render_settings():
|
|
|
7173
7173
|
composio_toolkit = st.text_input("Toolkit preferido (opcional)", value=str(settings.get("composio_toolkit") or ""), key="upload_composio_toolkit", help="Deixe vazio para descobrir ferramentas em todos os toolkits.")
|
|
7174
7174
|
composio_tool_slug = st.text_input("Slug da ferramenta para Automação Youtube", value=str(settings.get("composio_tool_slug") or ""), key="upload_composio_tool_slug", help="Depois de descobrir uma ferramenta em Upload via Composio, copie aqui o slug para a Automação Youtube.")
|
|
7175
7175
|
composio_file_field = st.text_input("Campo do ficheiro na ferramenta", value=str(settings.get("composio_file_field") or "file"), key="upload_composio_file_field")
|
|
7176
|
+
composio_channel_field = st.text_input("Campo do canal na ferramenta", value=str(settings.get("composio_channel_field") or "channel_id"), key="upload_composio_channel_field", help="O worker substitui este campo pelo YouTube channel ID do canal da tarefa, impedindo o envio para outro canal.")
|
|
7176
7177
|
composio_arguments_json = st.text_area("Argumentos JSON da Automação Youtube", value=str(settings.get("composio_arguments_json") or "{}"), key="upload_composio_arguments_json", height=120)
|
|
7177
7178
|
_render_credential_status(composio_api_key)
|
|
7178
7179
|
composio_action_cols = st.columns(2)
|
|
@@ -7181,7 +7182,7 @@ def render_settings():
|
|
|
7181
7182
|
with composio_action_cols[1]:
|
|
7182
7183
|
test_composio = st.button("Testar configuração", use_container_width=True, key="upload_composio_test")
|
|
7183
7184
|
if save_composio:
|
|
7184
|
-
settings.update({"composio_enabled": bool(composio_enabled), "composio_auto_upload": bool(composio_auto_upload), "composio_api_key": composio_api_key.strip(), "composio_user_id": composio_user_id.strip() or "thunderbolt-local", "composio_toolkit": composio_toolkit.strip(), "composio_tool_slug": composio_tool_slug.strip(), "composio_file_field": composio_file_field.strip() or "file", "composio_arguments_json": composio_arguments_json.strip() or "{}"})
|
|
7185
|
+
settings.update({"composio_enabled": bool(composio_enabled), "composio_auto_upload": bool(composio_auto_upload), "composio_api_key": composio_api_key.strip(), "composio_user_id": composio_user_id.strip() or "thunderbolt-local", "composio_toolkit": composio_toolkit.strip(), "composio_tool_slug": composio_tool_slug.strip(), "composio_file_field": composio_file_field.strip() or "file", "composio_channel_field": composio_channel_field.strip() or "channel_id", "composio_arguments_json": composio_arguments_json.strip() or "{}"})
|
|
7185
7186
|
write_json("settings.json", settings)
|
|
7186
7187
|
st.success("Configuração Composio guardada.")
|
|
7187
7188
|
st.rerun()
|
package/hermes_ui/storage.py
CHANGED
|
@@ -294,6 +294,7 @@ DEFAULTS: dict[str, Any] = {
|
|
|
294
294
|
"composio_toolkit": "",
|
|
295
295
|
"composio_tool_slug": "",
|
|
296
296
|
"composio_file_field": "file",
|
|
297
|
+
"composio_channel_field": "channel_id",
|
|
297
298
|
"composio_arguments_json": "{}",
|
|
298
299
|
"postiz_enabled": False,
|
|
299
300
|
"postiz_api_key": "",
|
|
@@ -106,6 +106,7 @@ def upload_with_default_route(
|
|
|
106
106
|
try:
|
|
107
107
|
composio_result = composio_publisher(
|
|
108
108
|
settings,
|
|
109
|
+
channel=channel,
|
|
109
110
|
video_path=video_path,
|
|
110
111
|
title=title,
|
|
111
112
|
description=description,
|
|
@@ -212,15 +213,30 @@ def upload_with_default_route(
|
|
|
212
213
|
return IntegrationResult(False, "Nenhum método de envio conseguiu publicar o vídeo.", {"attempts": attempts, "route": "none"})
|
|
213
214
|
|
|
214
215
|
|
|
215
|
-
def _composio_upload(settings: dict[str, Any], **kwargs: Any) -> IntegrationResult:
|
|
216
|
+
def _composio_upload(settings: dict[str, Any], *, channel: dict[str, Any], **kwargs: Any) -> IntegrationResult:
|
|
217
|
+
channel_id = str(channel.get("youtube_channel_id") or "").strip()
|
|
218
|
+
if not channel_id:
|
|
219
|
+
return IntegrationResult(False, "Composio não foi executado: o canal da tarefa não tem um YouTube channel ID sincronizado.", {"missing": ["youtube_channel_id"]})
|
|
220
|
+
channel_field = str(settings.get("composio_channel_field") or "channel_id").strip()
|
|
221
|
+
if not channel_field:
|
|
222
|
+
return IntegrationResult(False, "Composio não foi executado: configure o campo de canal da ferramenta.", {"missing": ["composio_channel_field"]})
|
|
216
223
|
try:
|
|
224
|
+
arguments = str(settings.get("composio_arguments_json") or "{}").strip() or "{}"
|
|
225
|
+
import json
|
|
226
|
+
parsed_arguments = json.loads(arguments)
|
|
227
|
+
if not isinstance(parsed_arguments, dict):
|
|
228
|
+
return IntegrationResult(False, "Composio não foi executado: os argumentos JSON devem ser um objecto.", {})
|
|
229
|
+
configured_channel = parsed_arguments.get(channel_field)
|
|
230
|
+
if configured_channel not in (None, "", channel_id):
|
|
231
|
+
return IntegrationResult(False, f"Composio bloqueado: o campo `{channel_field}` aponta para outro canal.", {"expected_channel_id": channel_id})
|
|
232
|
+
parsed_arguments[channel_field] = channel_id
|
|
217
233
|
result = execute_upload(
|
|
218
234
|
str(settings.get("composio_api_key") or ""),
|
|
219
235
|
str(settings.get("composio_user_id") or ""),
|
|
220
236
|
str(settings.get("composio_tool_slug") or ""),
|
|
221
237
|
str(kwargs.get("video_path") or ""),
|
|
222
238
|
str(settings.get("composio_file_field") or "file"),
|
|
223
|
-
|
|
239
|
+
json.dumps(parsed_arguments, ensure_ascii=False),
|
|
224
240
|
)
|
|
225
241
|
except ComposioUploadError as exc:
|
|
226
242
|
return IntegrationResult(False, str(exc), {})
|
package/package.json
CHANGED