@danhachuel/thunderbolt 0.3.90 → 0.3.92
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
|
@@ -47,7 +47,7 @@ from hermes_ui.notifications import clear_notifications, list_notifications, mar
|
|
|
47
47
|
from hermes_ui.influencers import BACKEND_OPTIONS, DOCUMENT_EXTENSIONS, IMAGE_EXTENSIONS, backend_name, backend_status, get_repository, test_backend
|
|
48
48
|
from hermes_ui.logs import list_logs, logs_to_rows
|
|
49
49
|
from hermes_ui.languages import LANGUAGE_CODES, VIDEO_LANGUAGE_CODES, LANGUAGE_FLAG_DATA_URIS, language_code, language_label, ui_language_menu_label, ui_text, video_language_label, video_language_options
|
|
50
|
-
from hermes_ui.api_key_tests import test_apify_credentials, test_influencer_database, test_kaggle_credentials, test_material_source_credentials, test_media_provider_card, test_nano_banana_credentials, test_postiz_credentials, test_telegram_credentials, test_tiktok_credentials, test_upload_post_credentials, test_voice_provider
|
|
50
|
+
from hermes_ui.api_key_tests import test_apify_credentials, test_influencer_database, test_innertube_api_key, test_kaggle_credentials, test_material_source_credentials, test_media_provider_card, test_nano_banana_credentials, test_postiz_credentials, test_telegram_credentials, test_tiktok_credentials, test_upload_post_credentials, test_voice_provider
|
|
51
51
|
from hermes_ui.tutorials import tutorial_body, tutorial_caption, tutorial_title
|
|
52
52
|
|
|
53
53
|
from hermes_ui.script_documents import list_script_documents, read_script_document, save_script_document, script_storage_path
|
|
@@ -5066,6 +5066,22 @@ def render_google_accounts():
|
|
|
5066
5066
|
key=f"batch_session_info_{account_id}",
|
|
5067
5067
|
help="Token sessionInfo usado pelo Upload directo. É guardado por conta e sincronizado no credentials.json; os cookies e restantes valores continuam exclusivamente no documento.",
|
|
5068
5068
|
)
|
|
5069
|
+
captured_at_value = str(
|
|
5070
|
+
session_health.captured_at
|
|
5071
|
+
or batch_account.get("sessionInfoCapturedAt")
|
|
5072
|
+
or batch_account.get("session_info_captured_at")
|
|
5073
|
+
or ""
|
|
5074
|
+
).strip()
|
|
5075
|
+
try:
|
|
5076
|
+
account_session_info_captured_at = datetime.fromisoformat(captured_at_value.replace("Z", "+00:00")).date() if captured_at_value else None
|
|
5077
|
+
except ValueError:
|
|
5078
|
+
account_session_info_captured_at = None
|
|
5079
|
+
account_session_info_captured_at = st.date_input(
|
|
5080
|
+
"Data de Captura",
|
|
5081
|
+
value=account_session_info_captured_at,
|
|
5082
|
+
key=f"batch_session_info_captured_at_{account_id}",
|
|
5083
|
+
help="Data em que o sessionInfo token foi capturado. É usada para calcular o alerta de expiração e não revela o token.",
|
|
5084
|
+
)
|
|
5069
5085
|
save_account = st.form_submit_button("Guardar dados da conta Google", type="primary", use_container_width=True)
|
|
5070
5086
|
|
|
5071
5087
|
st.markdown("**Documento de cookies/credenciais desta conta Google**")
|
|
@@ -5119,8 +5135,14 @@ def render_google_accounts():
|
|
|
5119
5135
|
credentials_changed = any(existing.get(field, "") != value for field, value in (("email", account_email.strip()), ("client_id", account_client_id.strip()), ("client_secret", account_client_secret.strip())))
|
|
5120
5136
|
if credentials_changed:
|
|
5121
5137
|
delete_youtube_batch_token(existing, STORAGE)
|
|
5122
|
-
|
|
5123
|
-
|
|
5138
|
+
captured_at_iso = account_session_info_captured_at.isoformat() if isinstance(account_session_info_captured_at, date) else ""
|
|
5139
|
+
existing.update({"label": account_label.strip() or "Canais YouTube", "email": account_email.strip(), "client_id": account_client_id.strip(), "client_secret": account_client_secret.strip(), "sessionInfo": account_session_info.strip(), "sessionInfoCapturedAt": captured_at_iso})
|
|
5140
|
+
update_credentials_document_session_info(
|
|
5141
|
+
STORAGE,
|
|
5142
|
+
existing,
|
|
5143
|
+
account_session_info.strip(),
|
|
5144
|
+
captured_at=captured_at_iso,
|
|
5145
|
+
)
|
|
5124
5146
|
ensure_credentials_document(STORAGE, existing, settings, channel_state)
|
|
5125
5147
|
settings["youtube_batch_accounts"] = batch_accounts
|
|
5126
5148
|
write_json("settings.json", settings)
|
|
@@ -5182,6 +5204,12 @@ def render_google_accounts():
|
|
|
5182
5204
|
key="global_innertube_api_key",
|
|
5183
5205
|
help="Chave global usada pelo Upload directo para todas as contas Google/YouTube. Guarde-a na configuração global, separada dos documentos de cookies.",
|
|
5184
5206
|
)
|
|
5207
|
+
_render_api_test_control(
|
|
5208
|
+
settings,
|
|
5209
|
+
"innertube",
|
|
5210
|
+
lambda: test_innertube_api_key(innertube_api_key_value),
|
|
5211
|
+
widget_key="api_test_innertube",
|
|
5212
|
+
)
|
|
5185
5213
|
save_innertube_api_key = st.form_submit_button("Guardar INNERTUBE_API_KEY global", type="primary", use_container_width=True)
|
|
5186
5214
|
if save_innertube_api_key:
|
|
5187
5215
|
settings["direct_innertube_api_key"] = innertube_api_key_value.strip()
|
|
@@ -95,6 +95,24 @@ def test_apify_credentials(api_token: str) -> dict[str, Any]:
|
|
|
95
95
|
return _get(f"{APIFY_API_BASE}/users/me", headers={"Authorization": f"Bearer {api_token}"})
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
def test_innertube_api_key(api_key: str) -> dict[str, Any]:
|
|
99
|
+
"""Validate a global InnerTube key with a public, read-only guide request."""
|
|
100
|
+
api_key = str(api_key or "").strip()
|
|
101
|
+
if not api_key:
|
|
102
|
+
return _missing("Introduza a INNERTUBE_API_KEY antes de testar.")
|
|
103
|
+
return _post(
|
|
104
|
+
f"https://www.youtube.com/youtubei/v1/guide?key={quote(api_key, safe='')}",
|
|
105
|
+
json={
|
|
106
|
+
"context": {
|
|
107
|
+
"client": {
|
|
108
|
+
"clientName": "WEB",
|
|
109
|
+
"clientVersion": "2.20250305.01.00",
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
98
116
|
def test_nano_banana_credentials(api_key: str, model: str) -> dict[str, Any]:
|
|
99
117
|
"""Validate the configured Gemini image model metadata without generating an image."""
|
|
100
118
|
api_key = str(api_key or "").strip()
|
|
@@ -307,6 +325,7 @@ __all__ = [
|
|
|
307
325
|
"test_apify_credentials",
|
|
308
326
|
"test_azure_speech_credentials",
|
|
309
327
|
"test_elevenlabs_credentials",
|
|
328
|
+
"test_innertube_api_key",
|
|
310
329
|
"test_kaggle_credentials",
|
|
311
330
|
"test_influencer_database",
|
|
312
331
|
"test_material_source_credentials",
|
|
@@ -242,8 +242,14 @@ def save_credentials_document(storage_root: Path, account: dict[str, Any], docum
|
|
|
242
242
|
return destination
|
|
243
243
|
|
|
244
244
|
|
|
245
|
-
def update_credentials_document_session_info(
|
|
246
|
-
|
|
245
|
+
def update_credentials_document_session_info(
|
|
246
|
+
storage_root: Path,
|
|
247
|
+
account: dict[str, Any],
|
|
248
|
+
session_info: str,
|
|
249
|
+
*,
|
|
250
|
+
captured_at: str | None = None,
|
|
251
|
+
) -> Path | None:
|
|
252
|
+
"""Save sessionInfo and an optional user-confirmed capture date without exposing the token."""
|
|
247
253
|
path = credentials_document_path(storage_root, account)
|
|
248
254
|
if path.exists():
|
|
249
255
|
raw = _read_json_document(path) or {}
|
|
@@ -251,7 +257,12 @@ def update_credentials_document_session_info(storage_root: Path, account: dict[s
|
|
|
251
257
|
raw = load_credentials_document(storage_root, {**account, "sessionInfo": session_info}, create=True)
|
|
252
258
|
document = _normalise_document(raw, {**account, "sessionInfo": session_info})
|
|
253
259
|
document["sessionInfo"] = str(session_info or "").strip()
|
|
254
|
-
|
|
260
|
+
if not document["sessionInfo"]:
|
|
261
|
+
document["sessionInfoCapturedAt"] = ""
|
|
262
|
+
elif captured_at is None:
|
|
263
|
+
document["sessionInfoCapturedAt"] = _session_info_now()
|
|
264
|
+
else:
|
|
265
|
+
document["sessionInfoCapturedAt"] = str(captured_at).strip()
|
|
255
266
|
return save_credentials_document(storage_root, account, document)
|
|
256
267
|
|
|
257
268
|
|
package/package.json
CHANGED