diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 2f516db..43f17bd 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -7,6 +7,28 @@ import { toast } from 'sonner'; import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from '@/lib/convertToGLB'; import { convertIFCtoGLB } from '@/lib/convertIFC'; +/** + * Normaliza URLs comuns para apontar ao binário direto. + * - Dropbox: força dl=1 + * - OneDrive (1drv.ms / onedrive.live.com): força download=1 + */ +function normalizeCloudUrl(input: string): string { + try { + const u = new URL(input); + if (/(^|\.)dropbox\.com$/.test(u.hostname)) { + u.searchParams.set('dl', '1'); + return u.toString(); + } + if (/(^|\.)1drv\.ms$|onedrive\.live\.com$/.test(u.hostname)) { + u.searchParams.set('download', '1'); + return u.toString(); + } + return input; + } catch { + return input; + } +} + const Index = () => { const navigate = useNavigate(); const fileInputRef = useRef(null); @@ -63,18 +85,47 @@ const Index = () => { }, [setModel]); const handleLoadCloud = useCallback(async () => { - const url = window.prompt('URL do modelo (GLB · OBJ · STL · IFC):', 'https://'); - if (!url) return; + const DEFAULT_URL = 'https://store.tracksteel.com.br/demo.ifc'; + const raw = window.prompt( + 'URL do modelo (GLB · OBJ · STL · IFC).\nDica: Dropbox use ?dl=1 · OneDrive ?download=1 · FileBrowser /api/raw/', + DEFAULT_URL, + ); + if (!raw) return; setLoadingCloud(true); try { + // Normalizações automáticas para hosts comuns + const url = normalizeCloudUrl(raw.trim()); const fileName = url.split('/').pop()?.split('?')[0] || 'modelo-cloud'; const ext = getSupportedExtension(fileName); if (!ext) { toast.error('URL deve apontar para .GLB, .OBJ, .STL ou .IFC'); return; } - const response = await fetch(url, { mode: 'cors' }); + + let response = await fetch(url, { mode: 'cors' }); if (!response.ok) throw new Error(`HTTP ${response.status}`); + + // Detecta servidores que retornam HTML em vez do binário (ex.: FileBrowser SPA) + let ct = response.headers.get('content-type') || ''; + if (ct.includes('text/html')) { + // Fallback: tenta endpoint /api/raw/ do FileBrowser + try { + const u = new URL(url); + if (!u.pathname.startsWith('/api/raw/')) { + const fbUrl = `${u.origin}/api/raw${u.pathname}${u.search}`; + const r2 = await fetch(fbUrl, { mode: 'cors' }); + if (r2.ok) { + response = r2; + ct = r2.headers.get('content-type') || ''; + } + } + } catch {} + } + if (ct.includes('text/html')) { + toast.error('O servidor devolveu uma página HTML, não o arquivo. Use o link DIRETO do arquivo (ex.: FileBrowser → /api/raw/arquivo.ifc).'); + return; + } + const buffer = await response.arrayBuffer(); let blob: Blob;