@danhachuel/thunderbolt 0.3.91 → 0.3.93
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
|
|
@@ -1969,10 +1969,17 @@ def render_channels():
|
|
|
1969
1969
|
channel_account_ids.append(current_channel_account_id)
|
|
1970
1970
|
youtube_account_labels[current_channel_account_id] = "Conta Google não configurada"
|
|
1971
1971
|
with st.expander("Upload directo — documento da conta deste canal", expanded=False):
|
|
1972
|
-
st.caption("O DELEGATED_SESSION_ID deste canal
|
|
1972
|
+
st.caption("O DELEGATED_SESSION_ID é individual deste canal. Guarde-o aqui; o valor fica no registo local do canal e não é copiado para o documento JSON partilhado da conta Google.")
|
|
1973
1973
|
with st.form(f"channel_direct_credentials_{channel_id}"):
|
|
1974
1974
|
channel_account_id = st.selectbox("Conta Google do documento deste canal", channel_account_ids, index=channel_account_ids.index(current_channel_account_id) if current_channel_account_id in channel_account_ids else 0, format_func=lambda item: youtube_account_labels.get(item, item or "Sem conta Google associada"), key=f"channel_account_{channel_id}")
|
|
1975
|
-
|
|
1975
|
+
channel_delegated_session_id = st.text_input(
|
|
1976
|
+
"DELEGATED_SESSION_ID deste canal",
|
|
1977
|
+
value=str(channel.get("delegated_session_id") or ""),
|
|
1978
|
+
type="password",
|
|
1979
|
+
key=f"channel_delegated_session_id_{channel_id}",
|
|
1980
|
+
help="Identificador individual usado pelo Upload directo deste canal. Não é partilhado com outros canais nem mostrado nos diagnósticos.",
|
|
1981
|
+
)
|
|
1982
|
+
save_channel_direct_credentials = st.form_submit_button("Guardar conta Google e DELEGATED_SESSION_ID", type="primary", use_container_width=True)
|
|
1976
1983
|
selected_channel_account = youtube_accounts_by_id.get(channel_account_id)
|
|
1977
1984
|
if selected_channel_account:
|
|
1978
1985
|
selected_account_status = document_status(STORAGE, selected_channel_account, channel, settings, channels)
|
|
@@ -1992,8 +1999,15 @@ def render_channels():
|
|
|
1992
1999
|
else:
|
|
1993
2000
|
st.info("Associe este canal a uma conta Google para validar o documento de credenciais.")
|
|
1994
2001
|
if save_channel_direct_credentials:
|
|
1995
|
-
update_channel(
|
|
1996
|
-
|
|
2002
|
+
update_channel(
|
|
2003
|
+
channel_id,
|
|
2004
|
+
{
|
|
2005
|
+
"google_account_id": channel_account_id.strip(),
|
|
2006
|
+
"google_account_email": str(youtube_accounts_by_id.get(channel_account_id, {}).get("email", "")),
|
|
2007
|
+
"delegated_session_id": channel_delegated_session_id.strip(),
|
|
2008
|
+
},
|
|
2009
|
+
)
|
|
2010
|
+
st.success("Conta Google e DELEGATED_SESSION_ID individual do canal guardados.")
|
|
1997
2011
|
st.rerun()
|
|
1998
2012
|
|
|
1999
2013
|
render_channel_videos(channel)
|
|
@@ -5204,6 +5218,12 @@ def render_google_accounts():
|
|
|
5204
5218
|
key="global_innertube_api_key",
|
|
5205
5219
|
help="Chave global usada pelo Upload directo para todas as contas Google/YouTube. Guarde-a na configuração global, separada dos documentos de cookies.",
|
|
5206
5220
|
)
|
|
5221
|
+
_render_api_test_control(
|
|
5222
|
+
settings,
|
|
5223
|
+
"innertube",
|
|
5224
|
+
lambda: test_innertube_api_key(innertube_api_key_value),
|
|
5225
|
+
widget_key="api_test_innertube",
|
|
5226
|
+
)
|
|
5207
5227
|
save_innertube_api_key = st.form_submit_button("Guardar INNERTUBE_API_KEY global", type="primary", use_container_width=True)
|
|
5208
5228
|
if save_innertube_api_key:
|
|
5209
5229
|
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",
|
|
@@ -363,6 +363,9 @@ def merge_credentials_document(
|
|
|
363
363
|
|
|
364
364
|
|
|
365
365
|
def delegated_session_id(document: dict[str, Any], channel: dict[str, Any]) -> str:
|
|
366
|
+
channel_value = str(channel.get("delegated_session_id") or "").strip() if isinstance(channel, dict) else ""
|
|
367
|
+
if channel_value:
|
|
368
|
+
return channel_value
|
|
366
369
|
mapping = document.get("delegated_session_ids", {}) if isinstance(document, dict) else {}
|
|
367
370
|
if not isinstance(mapping, dict):
|
|
368
371
|
return ""
|
package/package.json
CHANGED