You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
12 KiB
Python

import os, time, zipfile
from pymxs import runtime as rt
try: from PySide6 import QtWidgets
except ImportError: from PySide2 import QtWidgets
import urllib.request
import urllib.parse
import json
def mock_connect_api(ui):
hash_txt = ui.e_hash.text().strip()
if len(hash_txt) < 5:
QtWidgets.QMessageBox.warning(ui, "Acesso Negado", "Hash inválida.")
return
ui.b_conn.setText("Conectando..."); QtWidgets.QApplication.processEvents()
# Faz chamada real para a API
url = "https://api.vr4life.com/public/listaCanais"
req_data = urllib.parse.urlencode({"tx_hash_login_externo": hash_txt}).encode('utf-8')
req = urllib.request.Request(url, data=req_data, headers={'Content-Type': 'application/x-www-form-urlencoded'})
try:
with urllib.request.urlopen(req, timeout=10) as response:
res_body = response.read().decode('utf-8')
canais = json.loads(res_body)
ui.c_chn.clear()
# Espera receber lista: [{"nm_canal": "...", "tx_hash_canal": "..."}, ...]
if isinstance(canais, list) and len(canais) > 0:
for c in canais:
n_c = str(c.get("nm_canal", "Canal Desconhecido"))
h_c = str(c.get("tx_hash_canal", ""))
ui.c_chn.addItem(n_c, h_c)
else:
raise Exception("Nenhum canal encontrado para este Hash.")
except Exception as e:
ui.b_conn.setText("🔄 Tentar Novamente")
QtWidgets.QMessageBox.critical(ui, "Erro de API", f"Falha ao conectar: {str(e)}")
return
# Ativa campos após sucesso
for w in [ui.c_chn, ui.rdo_add, ui.rdo_edt, ui.e_tit, ui.e_mp3, ui.b_mp3]:
w.setEnabled(True)
w.setStyleSheet("background: white; color: black; font-weight: bold;")
ui.b_up.setEnabled(True)
ui.b_conn.setText("✅ Conectado!"); ui.b_conn.setStyleSheet("background: #000; color: #0F0; font-weight: bold; border: 1px solid #0F0;")
# Auto-carrega postagens do primeiro canal
fetch_posts_for_channel(ui)
def fetch_posts_for_channel(ui):
ui.c_pst.blockSignals(True)
ui.c_pst.clear()
hash_txt = ui.e_hash.text().strip()
idx = ui.c_chn.currentIndex()
has_posts = False
if idx >= 0:
ch_hash = ui.c_chn.itemData(idx)
print(f"[DEBUG UI] Canal Index {idx}. Valor Extraído do ItemData: '{ch_hash}'")
if ch_hash and str(ch_hash).strip():
ch_hash = str(ch_hash).strip()
url = "https://api.vr4life.com/public/listaPostagemCanal"
dict_data = {"tx_hash_login_externo": hash_txt, "tx_hash_canal": ch_hash}
req_data = urllib.parse.urlencode(dict_data).encode('utf-8')
print(f"\n[DEBUG API] Chamando: {url}")
print(f"[DEBUG API] Payload (FormData): {dict_data}")
req = urllib.request.Request(url, data=req_data, headers={'Content-Type': 'application/x-www-form-urlencoded'})
try:
with urllib.request.urlopen(req, timeout=10) as response:
raw_res = response.read().decode('utf-8')
posts = json.loads(raw_res)
if isinstance(posts, list) and len(posts) > 0:
has_posts = True
for p in posts:
t_p = p.get('tx_titulo', 'Sem Título')
h_p = p.get('hash_postagem', '')
print(f"[DEBUG API] Encontrou Postagem: '{t_p}' | Hash: {h_p}")
ui.c_pst.addItem(t_p, h_p)
except urllib.error.HTTPError as e:
err_body = e.read().decode('utf-8')
QtWidgets.QMessageBox.critical(ui, f"Erro HTTP {e.code}", f"O Servidor RECUSOU a requisição.\n\nResposta:\n{err_body}")
except Exception as e:
QtWidgets.QMessageBox.warning(ui, "Aviso de Rede", f"Falha na comunicação ou falha lendo o JSON de postagens:\n\n{e}\n\n(A API pode ter retornado HTML ao invés de JSON puro?)")
else:
QtWidgets.QMessageBox.warning(ui, "Aviso", "O Hash deste canal não foi preenchido.")
ui.c_pst.blockSignals(False)
# Se não retornou posts, forçar modo "Novo" e bloquear edição
if not has_posts:
ui.rdo_add.setChecked(True)
ui.rdo_edt.setEnabled(False)
else:
ui.rdo_edt.setEnabled(True)
on_post_changed(ui)
def on_post_changed(ui):
if ui.rdo_add.isChecked():
ui.c_pst.setEnabled(False)
ui.c_pst.setStyleSheet("background: #CCC; color: black; font-weight: normal;")
ui.e_tit.setText(""); ui.e_tit.setPlaceholderText("Título do NOVO projeto...")
ui.b_tmb.setEnabled(False)
else:
ui.c_pst.setEnabled(True)
ui.c_pst.setStyleSheet("background: white; color: black; font-weight: bold;")
if ui.c_pst.count() > 0:
ui.e_tit.setText(ui.c_pst.currentText())
ui.b_tmb.setEnabled(True)
def finalize_export(ui, p_glb, f_name):
# Transição de abas após o término do Exportador V19
ui.tabs.setCurrentIndex(3)
def generate_thumbnail(ui):
p_glb = ui.edt_p_glb.text().replace("\\", "/")
if not p_glb.endswith("/"): p_glb += "/"
tgs = ui.get_processable_items()
if len(tgs) == 1: sn = f"{tgs[0]['name']}_Export"
else: sn = "VR4Life_Scene_Export"
tp = os.path.join(p_glb, f"{sn}_Thumb.jpg").replace("\\", "/")
ui.pb.setFormat("📸 Tirando Snapshot da Cena..."); QtWidgets.QApplication.processEvents()
rt.execute(f"""( local c = getActiveCamera(); if c == undefined do ( local ac = for cam in cameras where (classof cam != TargetObject) collect cam; if ac.count > 0 do c = ac[1] ); try ( if c != undefined then ( render camera:c outputwidth:1280 outputheight:720 outputfile:@"{tp}" vfb:false quiet:true ) else ( render outputwidth:1280 outputheight:720 outputfile:@"{tp}" vfb:false quiet:true ) ) catch() )""")
ui.pb.setFormat("✅ Thumbnail Gerado e Salvo!"); ui.pb.setValue(100)
try: os.startfile(p_glb)
except: pass
def upload_to_cloud(ui):
p_glb = ui.edt_p_glb.text().replace("\\", "/")
if not p_glb.endswith("/"): p_glb += "/"
tgs = ui.get_processable_items()
if len(tgs) == 1: sn = f"{tgs[0]['name']}_Export"
else: sn = "VR4Life_Scene_Export"
oz = os.path.join(p_glb, f"{sn}.zip").replace("\\", "/")
tp = os.path.join(p_glb, f"{sn}_Thumb.jpg").replace("\\", "/")
if not os.path.exists(oz):
try:
zip_files = [os.path.join(p_glb, f) for f in os.listdir(p_glb) if f.lower().endswith('.zip')]
if zip_files:
oz = max(zip_files, key=os.path.getmtime)
base_zip_name = os.path.basename(oz).replace(".zip", "")
alt_tp = os.path.join(p_glb, f"{base_zip_name}_Thumb.jpg")
if os.path.exists(alt_tp): tp = alt_tp
except Exception as e: print(f"Erro ao buscar zip recente: {e}")
if not os.path.exists(oz):
QtWidgets.QMessageBox.warning(ui, "Aviso", f"Nenhum arquivo ZIP encontrado na pasta:\n{p_glb}\n\nFaça o Bake primeiro!")
return
ui.pb.setFormat(f"📡 API: Sincronizando com a Nuvem..."); QtWidgets.QApplication.processEvents()
hx_login = ui.e_hash.text().strip()
ch_idx = ui.c_chn.currentIndex()
hx_canal = ui.c_chn.itemData(ch_idx) if ch_idx >= 0 else ""
titulo = ui.e_tit.text().strip()
hx_postagem = ""
if ui.rdo_edt.isChecked():
pst_idx = ui.c_pst.currentIndex()
if pst_idx >= 0: hx_postagem = ui.c_pst.itemData(pst_idx)
if not hx_login or not hx_canal or not titulo:
QtWidgets.QMessageBox.warning(ui, "Campos Inválidos", "Por favor conecte-se à API, selecione um Canal e digite um Título antes de enviar!")
ui.pb.setFormat("Pronto"); ui.pb.setValue(0)
return
import mimetypes
boundary = '----WebKitFormBoundaryVR4PluginX1A'
data_parts = []
def add_text_field(name, value):
data_parts.append(f'--{boundary}\r\n'.encode('utf-8'))
data_parts.append(f'Content-Disposition: form-data; name="{name}"\r\n\r\n'.encode('utf-8'))
data_parts.append(f'{value}\r\n'.encode('utf-8'))
def add_file_field(name, filename, filepath):
try:
mime_type = mimetypes.guess_type(filepath)[0] or 'application/octet-stream'
with open(filepath, 'rb') as f:
file_data = f.read()
data_parts.append(f'--{boundary}\r\n'.encode('utf-8'))
data_parts.append(f'Content-Disposition: form-data; name="{name}"; filename="{filename}"\r\n'.encode('utf-8'))
data_parts.append(f'Content-Type: {mime_type}\r\n\r\n'.encode('utf-8'))
data_parts.append(file_data)
data_parts.append(b'\r\n')
except Exception as e:
print(f"[DEBUG UPLOAD] Erro ao ler arquivo {filepath}: {e}")
add_text_field('tx_hash_login_externo', hx_login)
add_text_field('tx_hash_canal', hx_canal)
add_text_field('tx_titulo', titulo)
if ui.rdo_edt.isChecked() and hx_postagem:
add_text_field('tx_hash_postagem', hx_postagem)
if not os.path.exists(tp):
ui.pb.setFormat("📸 Tirando Snapshot Automático (Thumbnail)..."); QtWidgets.QApplication.processEvents()
rt.execute(f"""( local c = getActiveCamera(); if c == undefined do ( local ac = for cam in cameras where (classof cam != TargetObject) collect cam; if ac.count > 0 do c = ac[1] ); try ( if c != undefined then ( render camera:c outputwidth:1280 outputheight:720 outputfile:@"{tp}" vfb:false quiet:true ) else ( render outputwidth:1280 outputheight:720 outputfile:@"{tp}" vfb:false quiet:true ) ) catch() )""")
if os.path.exists(tp):
add_file_field('thumbnail', os.path.basename(tp), tp)
if os.path.exists(oz):
add_file_field('arquivo', os.path.basename(oz), oz)
data_parts.append(f'--{boundary}--\r\n'.encode('utf-8'))
body = b''.join(data_parts)
url = "https://api.vr4life.com/public/savePost"
req = urllib.request.Request(url, data=body)
req.add_header('Content-Type', f'multipart/form-data; boundary={boundary}')
req.add_header('Content-Length', str(len(body)))
print("\n" + "="*50)
print("📡 [DEBUG API UPLOAD] DADOS ENVIADOS NO FORM-DATA:")
print(f" -> tx_hash_login_externo: {hx_login}")
print(f" -> tx_hash_canal : {hx_canal}")
print(f" -> tx_titulo : {titulo}")
# Se campo não existe, printa vazio pra entender o contexto
if ui.rdo_edt.isChecked() and hx_postagem:
print(f" -> tx_hash_postagem : {hx_postagem}")
print(f" -> thumbnail (ARQUIVO) : {tp if os.path.exists(tp) else 'NAO ENVIADO'}")
print(f" -> arquivo (ARQUIVO) : {oz if os.path.exists(oz) else 'NAO ENVIADO'}")
print(f"--------------------------------------------------")
print(f"Disparando pacote de {len(body)} bytes para {url} ...")
print("="*50 + "\n")
ui.b_up.setEnabled(False); ui.b_up.setText("Upload em andamento...")
QtWidgets.QApplication.processEvents()
try:
with urllib.request.urlopen(req, timeout=120) as response:
raw_res = response.read().decode('utf-8')
print(f"[DEBUG API UPLOAD] Sucesso HTTP 200:\n{raw_res}")
QtWidgets.QMessageBox.information(ui, "Sincronização Cloud Concluída", f"O projeto foi enviado com sucesso para a plataforma!\n\nDados Retornados da API:\n{raw_res}")
except urllib.error.HTTPError as e:
err_body = e.read().decode('utf-8')
print(f"[DEBUG API UPLOAD] Erro HTTP {e.code}:\n{err_body}")
QtWidgets.QMessageBox.critical(ui, "Sincronização Falhou", f"O PHP Recusou o Arquivo (HTTP {e.code}).\n\nMotivo:\n{err_body}")
except Exception as e:
print(f"[DEBUG API UPLOAD] Exceção: {e}")
QtWidgets.QMessageBox.warning(ui, "Aviso de Rede", f"Não foi possível completar o envio do arquivo Zip para o servidor.\n\nDetalhes:\n{e}")
finally:
ui.b_up.setEnabled(True); ui.b_up.setText("☁️ Enviar para Nuvem")
ui.pb.setFormat("Pronto"); ui.pb.setValue(0)