@danhachuel/thunderbolt 0.7.29 → 0.7.30
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 +128 -10
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -111,6 +111,7 @@ from hermes_ui.notifications import clear_notifications, list_notifications, mar
|
|
|
111
111
|
from hermes_ui.influencers import BACKEND_OPTIONS, DOCUMENT_EXTENSIONS, IMAGE_EXTENSIONS, backend_name, backend_status, get_repository, test_backend
|
|
112
112
|
from hermes_ui.logs import list_logs, logs_to_rows
|
|
113
113
|
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
|
|
114
|
+
from hermes_ui.countries import COUNTRY_OPTIONS
|
|
114
115
|
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
|
|
115
116
|
from hermes_ui.tutorials import tutorial_body, tutorial_caption, tutorial_title
|
|
116
117
|
from hermes_ui.update_manager import check_version, restart_current_process, update_to_latest
|
|
@@ -1558,6 +1559,9 @@ def render_channel_edit_form(channel: dict, youtube_account_ids: list[str], yout
|
|
|
1558
1559
|
edited_name = st.text_input("Nome do canal", value=str(channel.get("name") or ""))
|
|
1559
1560
|
edited_url = st.text_input("URL", value=str(channel.get("url") or ""))
|
|
1560
1561
|
edited_handle = st.text_input("Handle", value=str(channel.get("handle") or ""))
|
|
1562
|
+
country_options = [""] + list(COUNTRY_OPTIONS)
|
|
1563
|
+
current_country = str(channel.get("country") or "")
|
|
1564
|
+
edited_country = st.selectbox("País", country_options, index=country_options.index(current_country) if current_country in country_options else 0)
|
|
1561
1565
|
language_options = VIDEO_LANGUAGE_SELECTION_OPTIONS
|
|
1562
1566
|
edited_language = st.selectbox("Idioma do roteiro", language_options, index=language_options.index(normalize_video_language(channel.get("language") or "pt")) if normalize_video_language(channel.get("language") or "pt") in language_options else 0, format_func=video_language_label)
|
|
1563
1567
|
edited_style = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, index=WIDE_STYLE_OPTIONS.index(channel_video_source_value(channel.get("style_wide"))) if channel_video_source_value(channel.get("style_wide")) in WIDE_STYLE_OPTIONS else 0)
|
|
@@ -1588,7 +1592,7 @@ def render_channel_edit_form(channel: dict, youtube_account_ids: list[str], yout
|
|
|
1588
1592
|
update_channel(channel_id, {
|
|
1589
1593
|
"name": edited_name.strip(), "url": edited_url.strip(), "handle": edited_handle.strip(), "language": edited_language,
|
|
1590
1594
|
"style_wide": channel_video_source_storage(edited_style), "video_aspect_ratio": edited_aspect,
|
|
1591
|
-
"niche": edited_niche.strip(), "reference_channels": [item.strip() for item in re.split(r"[,|]", edited_niche) if item.strip()],
|
|
1595
|
+
"niche": edited_niche.strip(), "reference_channels": [item.strip() for item in re.split(r"[,|]", edited_niche) if item.strip()], "country": edited_country.strip(),
|
|
1592
1596
|
"default_blueprint_id": edited_blueprint.strip(), "blueprint_id": edited_blueprint.strip(),
|
|
1593
1597
|
"default_voice": edited_voice.strip(), "voice": edited_voice.strip(),
|
|
1594
1598
|
"google_account_id": edited_account.strip(), "google_account_email": str(youtube_accounts_by_id.get(edited_account, {}).get("email", "")),
|
|
@@ -2381,6 +2385,8 @@ def classify_channel_platform(channel: Any) -> str:
|
|
|
2381
2385
|
return "tiktok"
|
|
2382
2386
|
if value in {"instagram", "ig"}:
|
|
2383
2387
|
return "instagram"
|
|
2388
|
+
if value in {"facebook", "facebook_page", "facebook_pages", "fb"}:
|
|
2389
|
+
return "facebook"
|
|
2384
2390
|
def has_tiktok_marker(item: Any) -> bool:
|
|
2385
2391
|
if isinstance(item, dict):
|
|
2386
2392
|
return any(has_tiktok_marker(key) or has_tiktok_marker(value) for key, value in item.items())
|
|
@@ -2778,6 +2784,103 @@ def _tiktok_channel_url(channel: dict[str, Any]) -> str:
|
|
|
2778
2784
|
return source if source.startswith(("http://", "https://")) else ""
|
|
2779
2785
|
|
|
2780
2786
|
|
|
2787
|
+
def render_facebook_pages():
|
|
2788
|
+
st.title("Facebook Pages")
|
|
2789
|
+
st.caption("Cadastre páginas públicas do Facebook por URL. Esta área aceita apenas páginas Facebook e não perfis pessoais.")
|
|
2790
|
+
with st.form("facebook_page_form"):
|
|
2791
|
+
form_cols = st.columns(2)
|
|
2792
|
+
with form_cols[0]:
|
|
2793
|
+
name = st.text_input("Nome da página", key="facebook_page_name")
|
|
2794
|
+
url = st.text_input("URL pública da página", placeholder="https://www.facebook.com/suapagina", key="facebook_page_url")
|
|
2795
|
+
country_options = [""] + list(COUNTRY_OPTIONS)
|
|
2796
|
+
country = st.selectbox("País", country_options, key="facebook_page_country")
|
|
2797
|
+
with form_cols[1]:
|
|
2798
|
+
description = st.text_area("Descrição", key="facebook_page_description")
|
|
2799
|
+
niche = st.text_input("Nicho", key="facebook_page_niche")
|
|
2800
|
+
active = st.toggle("Activo", value=True, key="facebook_page_active")
|
|
2801
|
+
submitted = st.form_submit_button("Guardar página Facebook", type="primary", width="stretch")
|
|
2802
|
+
if submitted:
|
|
2803
|
+
normalized_url = url.strip()
|
|
2804
|
+
if not name.strip():
|
|
2805
|
+
st.error("Informe o nome da página.")
|
|
2806
|
+
elif not normalized_url.startswith(("https://www.facebook.com/", "https://facebook.com/", "http://www.facebook.com/", "http://facebook.com/")):
|
|
2807
|
+
st.error("Informe uma URL pública válida de uma página Facebook.")
|
|
2808
|
+
else:
|
|
2809
|
+
existing = [item for item in read_json("channels.json", []) if isinstance(item, dict)]
|
|
2810
|
+
duplicate = next((item for item in existing if classify_channel_platform(item) == "facebook" and str(item.get("url") or "").strip().casefold() == normalized_url.casefold()), None)
|
|
2811
|
+
if duplicate:
|
|
2812
|
+
st.warning("Esta página Facebook já está cadastrada.")
|
|
2813
|
+
else:
|
|
2814
|
+
page = create_channel(name.strip(), normalized_url, {
|
|
2815
|
+
"platform": "facebook",
|
|
2816
|
+
"social_network": "Facebook Pages",
|
|
2817
|
+
"country": country.strip(),
|
|
2818
|
+
"description": description.strip(),
|
|
2819
|
+
"niche": niche.strip(),
|
|
2820
|
+
"active": bool(active),
|
|
2821
|
+
"metrics_source": "public_url",
|
|
2822
|
+
})
|
|
2823
|
+
update_channel(page["id"], {"platform": "facebook", "social_network": "Facebook Pages"})
|
|
2824
|
+
st.success(f"Página {page['name']} guardada.")
|
|
2825
|
+
st.rerun()
|
|
2826
|
+
|
|
2827
|
+
pages = [item for item in read_json("channels.json", []) if isinstance(item, dict) and classify_channel_platform(item) == "facebook"]
|
|
2828
|
+
st.divider()
|
|
2829
|
+
st.subheader(f"Facebook Pages cadastradas ({len(pages)})")
|
|
2830
|
+
if not pages:
|
|
2831
|
+
st.info("Nenhuma página Facebook cadastrada.")
|
|
2832
|
+
return
|
|
2833
|
+
for page in pages:
|
|
2834
|
+
page_id = str(page.get("id") or "")
|
|
2835
|
+
with st.container(border=True):
|
|
2836
|
+
header_cols = st.columns([0.7, 2.75, 1.15, 1.1, 1.0, 1.35, 1.35])
|
|
2837
|
+
with header_cols[0]:
|
|
2838
|
+
st.markdown("### FB")
|
|
2839
|
+
with header_cols[1]:
|
|
2840
|
+
page_country = str(page.get("country") or "").strip()
|
|
2841
|
+
st.write(f"**{page.get('name', 'Sem nome')}**{f' · {page_country}' if page_country else ''}")
|
|
2842
|
+
st.caption(page.get("niche") or "SEM NICHO CONFIGURADO")
|
|
2843
|
+
st.caption(page.get("url") or "sem URL")
|
|
2844
|
+
with header_cols[2]:
|
|
2845
|
+
if page.get("url"):
|
|
2846
|
+
st.link_button("Abrir página", str(page["url"]), type="primary", width="content")
|
|
2847
|
+
with header_cols[3]:
|
|
2848
|
+
st.metric("País", page_country or "—")
|
|
2849
|
+
with header_cols[4]:
|
|
2850
|
+
st.metric("Estado", "Activo" if page.get("active", True) else "Inactivo")
|
|
2851
|
+
with header_cols[5]:
|
|
2852
|
+
st.caption("Facebook Page")
|
|
2853
|
+
with header_cols[6]:
|
|
2854
|
+
active_value = st.toggle("Activo", value=bool(page.get("active", True)), key=f"facebook_active_{page_id}")
|
|
2855
|
+
if active_value != bool(page.get("active", True)):
|
|
2856
|
+
update_channel(page_id, {"active": active_value})
|
|
2857
|
+
st.rerun()
|
|
2858
|
+
with st.expander("Detalhes e configuração da página", expanded=False):
|
|
2859
|
+
with st.form(f"facebook_page_edit_{page_id}"):
|
|
2860
|
+
edited_name = st.text_input("Nome da página", value=str(page.get("name") or ""))
|
|
2861
|
+
edited_url = st.text_input("URL pública", value=str(page.get("url") or ""))
|
|
2862
|
+
edit_country_options = [""] + list(COUNTRY_OPTIONS)
|
|
2863
|
+
current_page_country = str(page.get("country") or "")
|
|
2864
|
+
edited_country = st.selectbox("País", edit_country_options, index=edit_country_options.index(current_page_country) if current_page_country in edit_country_options else 0)
|
|
2865
|
+
edited_description = st.text_area("Descrição", value=str(page.get("description") or ""))
|
|
2866
|
+
edited_niche = st.text_input("Nicho", value=str(page.get("niche") or ""))
|
|
2867
|
+
save_page = st.form_submit_button("Guardar alterações", type="primary")
|
|
2868
|
+
action_cols = st.columns(2)
|
|
2869
|
+
with action_cols[0]:
|
|
2870
|
+
if save_page:
|
|
2871
|
+
if not edited_name.strip() or not edited_url.strip().startswith(("https://www.facebook.com/", "https://facebook.com/", "http://www.facebook.com/", "http://facebook.com/")):
|
|
2872
|
+
st.error("Informe o nome e uma URL pública válida de uma página Facebook.")
|
|
2873
|
+
else:
|
|
2874
|
+
update_channel(page_id, {"name": edited_name.strip(), "url": edited_url.strip(), "country": edited_country.strip(), "description": edited_description.strip(), "niche": edited_niche.strip()})
|
|
2875
|
+
st.success("Página Facebook actualizada.")
|
|
2876
|
+
st.rerun()
|
|
2877
|
+
with action_cols[1]:
|
|
2878
|
+
if st.button("Apagar", key=f"facebook_delete_{page_id}"):
|
|
2879
|
+
delete_channel(page_id)
|
|
2880
|
+
st.success("Página Facebook apagada.")
|
|
2881
|
+
st.rerun()
|
|
2882
|
+
|
|
2883
|
+
|
|
2781
2884
|
def render_channels():
|
|
2782
2885
|
st.title("Canais Youtube")
|
|
2783
2886
|
st.caption("Escolha entre importar dados públicos do YouTube ou preencher o canal manualmente.")
|
|
@@ -2849,6 +2952,8 @@ def render_channels():
|
|
|
2849
2952
|
url = st.text_input("URL", value=imported.get("url", source if source.startswith("http") else ""), key="yt_import_url")
|
|
2850
2953
|
handle = st.text_input("Handle", value=imported.get("handle", ""), key="yt_import_handle")
|
|
2851
2954
|
language = st.selectbox("Idioma do roteiro", VIDEO_LANGUAGE_SELECTION_OPTIONS, index=VIDEO_LANGUAGE_SELECTION_OPTIONS.index(normalize_video_language(imported.get("language") or "pt")) if normalize_video_language(imported.get("language") or "pt") in VIDEO_LANGUAGE_SELECTION_OPTIONS else 0, format_func=video_language_label, key="yt_import_language")
|
|
2955
|
+
import_country_options = [""] + list(COUNTRY_OPTIONS)
|
|
2956
|
+
import_country = st.selectbox("País", import_country_options, index=import_country_options.index(str(imported.get("country") or "")) if str(imported.get("country") or "") in import_country_options else 0, key="yt_import_country")
|
|
2852
2957
|
style = st.selectbox("Fonte do vídeo", WIDE_STYLE_OPTIONS, index=0, key="yt_import_style")
|
|
2853
2958
|
video_aspect_ratio = st.selectbox("Proporção do vídeo", CHANNEL_ASPECT_RATIO_OPTIONS, key="yt_import_aspect_ratio")
|
|
2854
2959
|
blueprint = st.selectbox("Blueprint Padrão", blueprint_ids, index=blueprint_ids.index(imported_blueprint) if imported_blueprint in blueprint_ids else 0, format_func=lambda item: blueprint_labels.get(item, item or "Sem Blueprint padrão"), key="yt_import_blueprint")
|
|
@@ -2879,7 +2984,7 @@ def render_channels():
|
|
|
2879
2984
|
"description": description.strip(),
|
|
2880
2985
|
"niche": niche.strip(),
|
|
2881
2986
|
"reference_channels": [item.strip() for item in re.split(r"[,|]", niche) if item.strip()],
|
|
2882
|
-
"language": language,
|
|
2987
|
+
"language": language, "country": import_country.strip(),
|
|
2883
2988
|
"style_wide": channel_video_source_storage(style), "video_aspect_ratio": video_aspect_ratio, "format": "wide",
|
|
2884
2989
|
"blueprint_id": blueprint.strip(),
|
|
2885
2990
|
"default_blueprint_id": blueprint.strip(),
|
|
@@ -3138,6 +3243,8 @@ def render_channels():
|
|
|
3138
3243
|
description = st.text_area("Descrição", key="manual_channel_description")
|
|
3139
3244
|
niche = st.text_input("Nicho", placeholder="Ex.: História militar, mistérios, ciência", key="manual_channel_niche")
|
|
3140
3245
|
language = st.selectbox("Idioma", list(LANGUAGE_CODES), index=list(LANGUAGE_CODES).index("pt"), format_func=language_label, key="manual_channel_language")
|
|
3246
|
+
manual_country_options = [""] + list(COUNTRY_OPTIONS)
|
|
3247
|
+
manual_country = st.selectbox("País", manual_country_options, key="manual_channel_country")
|
|
3141
3248
|
style = st.selectbox("Estilo wide", ["Pexels/Pixabay", "full_ia", "Apenas Música"], index=0, key="manual_channel_style")
|
|
3142
3249
|
manual_blueprint_items = blueprint_catalog()
|
|
3143
3250
|
manual_blueprint_ids = [item[0] for item in manual_blueprint_items]
|
|
@@ -3166,7 +3273,7 @@ def render_channels():
|
|
|
3166
3273
|
"description": description.strip(),
|
|
3167
3274
|
"niche": niche.strip(),
|
|
3168
3275
|
"reference_channels": [item.strip() for item in re.split(r"[,|]", niche) if item.strip()],
|
|
3169
|
-
"language": language,
|
|
3276
|
+
"language": language, "country": manual_country.strip(),
|
|
3170
3277
|
"style_wide": {"Pexels/Pixabay": "pexels", "full_ia": "full_ia", "Apenas Música": "music"}.get(style, style),
|
|
3171
3278
|
"blueprint_id": blueprint.strip(),
|
|
3172
3279
|
"default_blueprint_id": blueprint.strip(),
|
|
@@ -3228,7 +3335,8 @@ def render_channels():
|
|
|
3228
3335
|
else:
|
|
3229
3336
|
st.markdown("### YT")
|
|
3230
3337
|
with header_cols[1]:
|
|
3231
|
-
|
|
3338
|
+
country_label = str(channel.get("country") or "").strip()
|
|
3339
|
+
st.write(f"**{channel.get('name', 'Sem nome')}**{f' · {country_label}' if country_label else ''}")
|
|
3232
3340
|
st.caption(channel_niche_label(channel))
|
|
3233
3341
|
st.caption(f"{channel.get('handle') or channel.get('url') or 'sem URL'} · {channel.get('metrics_source', 'manual')}")
|
|
3234
3342
|
with header_cols[2]:
|
|
@@ -9552,12 +9660,13 @@ def main():
|
|
|
9552
9660
|
channel_profile_items = [
|
|
9553
9661
|
("Canais YouTube", ":material/ondemand_video:", "Canais YouTube"),
|
|
9554
9662
|
("Canais Tiktok", ":material/music_video:", "Canais Tiktok"),
|
|
9663
|
+
("Contas Instagram", ":material/share:", "Contas Instagram"),
|
|
9664
|
+
("Facebook Pages", ":material/public:", "Facebook Pages"),
|
|
9555
9665
|
("Blueprints Youtube", ":material/library_books:", "Blueprints Youtube"),
|
|
9556
9666
|
("Thumbnail Blueprints", ":material/image:", "Thumbnail Blueprints"),
|
|
9557
9667
|
("Brandings Youtube", ":material/brush:", "Brandings Youtube"),
|
|
9558
9668
|
("Contas TikTok", ":material/account_circle:", "Contas TikTok"),
|
|
9559
9669
|
("Prompt Masters", ":material/auto_awesome:", "Prompt Masters"),
|
|
9560
|
-
("Facebook Pages", ":material/public:", "Facebook Pages"),
|
|
9561
9670
|
]
|
|
9562
9671
|
music_items = [
|
|
9563
9672
|
("Criação de Músicas", ":material/music_note:", "Criação de Músicas"),
|
|
@@ -9570,7 +9679,6 @@ def main():
|
|
|
9570
9679
|
("Geração de Conteúdo IA", ":material/auto_awesome:", "Geração de Conteúdo IA"),
|
|
9571
9680
|
("Motion Control", ":material/motion_photos_on:", "Motion Control"),
|
|
9572
9681
|
("UGC Products", ":material/shopping_bag:", "UGC Products"),
|
|
9573
|
-
("Contas Instagram", ":material/share:", "Contas Instagram"),
|
|
9574
9682
|
]
|
|
9575
9683
|
growth_items = [
|
|
9576
9684
|
("Analista Growth Youtube", ":material/analytics:", "Analista Growth Youtube"),
|
|
@@ -9601,6 +9709,11 @@ def main():
|
|
|
9601
9709
|
automation_items = [
|
|
9602
9710
|
("Automação Youtube", ":material/schedule:", "Automação Youtube"),
|
|
9603
9711
|
("Automação Tiktok", ":material/schedule:", "Automação Tiktok"),
|
|
9712
|
+
("Automação Facebook", ":material/schedule:", "Automação Facebook"),
|
|
9713
|
+
("Automação Musicas", ":material/schedule:", "Automação Musicas"),
|
|
9714
|
+
("Automação UGC", ":material/schedule:", "Automação UGC"),
|
|
9715
|
+
("Automação Influencer Content", ":material/schedule:", "Automação Influencer Content"),
|
|
9716
|
+
("Automação Bilibili", ":material/schedule:", "Automação Bilibili"),
|
|
9604
9717
|
]
|
|
9605
9718
|
edition_items = [
|
|
9606
9719
|
("Limpador de Metadados", ":material/edit_note:", "Limpador de Metadados"),
|
|
@@ -9634,12 +9747,12 @@ def main():
|
|
|
9634
9747
|
"Configurações": settings_items,
|
|
9635
9748
|
}
|
|
9636
9749
|
nav_paths = {
|
|
9637
|
-
"Início": "/inicio", "Automação": "/automacao", "Automação Youtube": "/automacao/youtube", "Automação Tiktok": "/automacao/tiktok",
|
|
9750
|
+
"Início": "/inicio", "Automação": "/automacao", "Automação Youtube": "/automacao/youtube", "Automação Tiktok": "/automacao/tiktok", "Automação Facebook": "/automacao/facebook", "Automação Musicas": "/automacao/musicas", "Automação UGC": "/automacao/ugc", "Automação Influencer Content": "/automacao/influencer-content", "Automação Bilibili": "/automacao/bilibili",
|
|
9638
9751
|
"Niche Finder": "/niche-finder", "Niche Finder Kaggle": "/niche-finder/kaggle", "Niche Finder Apify": "/niche-finder/apify",
|
|
9639
9752
|
"Pipeline Vídeos": "/pipeline-videos", "Criação de Vídeos": "/pipeline-videos/criacao", "Criação de Shorts": "/pipeline-videos/shorts", "Backlog Vídeos": "/pipeline-videos/backlog", "Roteiros": "/pipeline-videos/roteiros", "Thumbnails": "/pipeline-videos/thumbnails", "Upload": "/pipeline-videos/upload", "Update Youtube Vídeos": "/pipeline-videos/update-youtube",
|
|
9640
9753
|
"Pipeline Música": "/pipeline-musica", "Criação de Músicas": "/pipeline-musica/criacao", "Music Backlog": "/pipeline-musica/backlog", "Vozes Personalizadas": "/pipeline-musica/vozes-personalizadas", "Upload Música": "/pipeline-musica/upload",
|
|
9641
|
-
"Canais/Perfis (Vídeos)": "/canais-perfis-videos", "Canais YouTube": "/canais-perfis-videos/canais-youtube", "Canais Tiktok": "/canais-perfis-videos/canais-tiktok", "Blueprints Youtube": "/canais-perfis-videos/blueprints-youtube", "Thumbnail Blueprints": "/canais-perfis-videos/thumbnail-blueprints", "Brandings Youtube": "/canais-perfis-videos/brandings-youtube", "Contas TikTok": "/canais-perfis-videos/contas-tiktok", "Prompt Masters": "/canais-perfis-videos/prompt-masters",
|
|
9642
|
-
"AI Influencers": "/ai-influencers", "Personagens": "/ai-influencers/personagens", "Geração de Conteúdo IA": "/ai-influencers/geracao-conteudo", "Motion Control": "/ai-influencers/motion-control", "UGC Products": "/ai-influencers/ugc-products",
|
|
9754
|
+
"Canais/Perfis (Vídeos)": "/canais-perfis-videos", "Canais YouTube": "/canais-perfis-videos/canais-youtube", "Canais Tiktok": "/canais-perfis-videos/canais-tiktok", "Contas Instagram": "/canais-perfis-videos/contas-instagram", "Facebook Pages": "/canais-perfis-videos/facebook-pages", "Blueprints Youtube": "/canais-perfis-videos/blueprints-youtube", "Thumbnail Blueprints": "/canais-perfis-videos/thumbnail-blueprints", "Brandings Youtube": "/canais-perfis-videos/brandings-youtube", "Contas TikTok": "/canais-perfis-videos/contas-tiktok", "Prompt Masters": "/canais-perfis-videos/prompt-masters",
|
|
9755
|
+
"AI Influencers": "/ai-influencers", "Personagens": "/ai-influencers/personagens", "Geração de Conteúdo IA": "/ai-influencers/geracao-conteudo", "Motion Control": "/ai-influencers/motion-control", "UGC Products": "/ai-influencers/ugc-products",
|
|
9643
9756
|
"Edição": "/edicao", "Limpador de Metadados": "/edicao/limpador-metadados", "Cortes": "/edicao/cortes", "Editor Python": "/edicao/editor-python", "Download Mídia": "/edicao/download-midia",
|
|
9644
9757
|
"Growth": "/growth", "Analista Growth Youtube": "/growth/youtube", "Analista Growth Tiktok": "/growth/tiktok", "Analista Growth Instagram": "/growth/instagram", "Analista Facebook Pages": "/growth/facebook-pages", "Analista Bilibili": "/growth/bilibili",
|
|
9645
9758
|
"Documentação": "/documentacao", "Tutorial Meta": "/documentacao/meta", "Tutorial Supabase": "/documentacao/supabase", "Tutorial Kaggle": "/documentacao/kaggle", "Tutorial Apify": "/documentacao/apify", "Tutorial YouTube Video-Upload Frontend": "/documentacao/youtube-video-upload-frontend", "Tutorial OAuth do Google": "/documentacao/oauth-google", "Tutorial YouTube Data API Key (Public Data)": "/documentacao/youtube-data-api-key",
|
|
@@ -9731,9 +9844,14 @@ def main():
|
|
|
9731
9844
|
"Canais YouTube": render_channels,
|
|
9732
9845
|
"Canais Tiktok": render_tiktok_channels,
|
|
9733
9846
|
"Contas TikTok": render_tiktok_accounts,
|
|
9734
|
-
"Facebook Pages":
|
|
9847
|
+
"Facebook Pages": render_facebook_pages,
|
|
9735
9848
|
"Automação Youtube": render_automation,
|
|
9736
9849
|
"Automação Tiktok": render_tiktok_automation,
|
|
9850
|
+
"Automação Facebook": lambda: None,
|
|
9851
|
+
"Automação Musicas": lambda: None,
|
|
9852
|
+
"Automação UGC": lambda: None,
|
|
9853
|
+
"Automação Influencer Content": lambda: None,
|
|
9854
|
+
"Automação Bilibili": lambda: None,
|
|
9737
9855
|
"Niche Finder Kaggle": render_niche_finder,
|
|
9738
9856
|
"Tutorial Kaggle": lambda: render_niche_tutorial("kaggle"),
|
|
9739
9857
|
"Niche Finder Apify": render_niche_finder_apify,
|
package/package.json
CHANGED