Atualização automática: 2026-05-18 17:10:08

This commit is contained in:
Hermes
2026-05-18 17:10:08 +00:00
parent 8ac0979c67
commit 700c47277d
4 changed files with 155 additions and 34 deletions
+133 -23
View File
@@ -38,6 +38,11 @@ app.use(express.static(path.join(__dirname, 'public'), {
app.use((req, res, next) => {
if (!req.path.startsWith('/api') && req.path !== '/' && req.path !== '/old') {
let urlPath = req.path;
// Remover prefixo /cloned-sites se existir para buscar corretamente no disco
if (urlPath.startsWith('/cloned-sites/')) {
urlPath = urlPath.replace('/cloned-sites/', '/');
}
if (!urlPath.match(/\.[a-zA-Z0-9]+$/)) {
if (!urlPath.endsWith('/')) urlPath += '/';
urlPath += 'index.html';
@@ -54,10 +59,12 @@ app.use((req, res, next) => {
(function() {
try {
const originalPathname = Object.getOwnPropertyDescriptor(Location.prototype, 'pathname').get;
const originalHref = Object.getOwnPropertyDescriptor(Location.prototype, 'href').get;
Object.defineProperty(Location.prototype, 'pathname', {
get: function() {
const path = originalPathname.call(this);
if (path !== '/' && path !== '/index.html') {
if (path !== '/' && path !== '/index.html' && (path.includes('_202') || path.includes('/cloned-sites/'))) {
return '/';
}
return path;
@@ -66,7 +73,29 @@ app.use((req, res, next) => {
window.location.assign(val);
}
});
console.log('🚀 [CloneWeb] SPA Router fix initialized. Simulating root pathname /');
Object.defineProperty(Location.prototype, 'href', {
get: function() {
const href = originalHref.call(this);
if (href.includes('_202') || href.includes('/cloned-sites/')) {
const url = new URL(href);
return url.protocol + '//' + url.host + '/';
}
return href;
}
});
const OriginalURL = window.URL;
window.URL = function(url, base) {
if (typeof url === 'string' && (url.includes('_202') || url.includes('/cloned-sites/'))) {
url = url.replace(/\\/cloned-sites\\/[^/]+/gi, '').replace(/\\/[^/]+_202[0-9-_T:.]+(\\/index\\.html)?/gi, '/');
}
return new OriginalURL(url, base);
};
window.URL.prototype = OriginalURL.prototype;
Object.assign(window.URL, OriginalURL);
console.log('🚀 [CloneWeb] Ultimate SPA Router fix initialized. Simulating root pathname /');
} catch(e) {
console.error('❌ [CloneWeb] Failed to initialize router fix:', e);
}
@@ -257,7 +286,102 @@ app.get('/api/health', async (req, res) => {
}
});
// Abrir pasta do clone
// Rota de visualização de arquivos da pasta clonada (Gerenciador de Arquivos Web Embutido)
app.get('/api/browse/:folder', (req, res) => {
try {
const folderName = req.params.folder;
const folderPath = path.join(__dirname, '..', 'cloned-sites', folderName);
if (!fs.existsSync(folderPath)) {
return res.status(404).send('<h1>Pasta não encontrada</h1><p>A pasta solicitada não existe no servidor.</p>');
}
const items = fs.readdirSync(folderPath);
let filesHtml = '';
items.forEach(item => {
const itemPath = path.join(folderPath, item);
const stat = fs.statSync(itemPath);
const isDir = stat.isDirectory();
const size = isDir ? '-' : (stat.size / 1024).toFixed(2) + ' KB';
const date = new Date(stat.mtime).toLocaleString('pt-BR');
const icon = isDir ? 'fa-folder' : (item.endsWith('.html') ? 'fa-file-code' : (item.endsWith('.json') ? 'fa-file-alt' : 'fa-file'));
const link = isDir ? `#` : `/${folderName}/${item}`;
filesHtml += `
<tr>
<td><i class="fas ${icon}" style="color: #4f46e5; margin-right: 10px;"></i> <a href="${link}" target="_blank" style="color: #1f2937; text-decoration: none; font-weight: 500;">${item}</a></td>
<td style="color: #6b7280;">${size}</td>
<td style="color: #6b7280;">${date}</td>
<td>
${!isDir ? `<a href="${link}" target="_blank" class="btn btn-secondary btn-sm" style="background: #e0e7ff; color: #4f46e5; padding: 5px 10px; border-radius: 6px; text-decoration: none; font-size: 14px;">Visualizar</a>` : ''}
${!isDir ? `<a href="${link}" download="${item}" class="btn btn-secondary btn-sm" style="background: #fee2e2; color: #ef4444; padding: 5px 10px; border-radius: 6px; text-decoration: none; font-size: 14px; margin-left: 5px;">Baixar</a>` : ''}
</td>
</tr>
`;
});
const html = `
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Arquivos Clonados - ${folderName}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Inter', sans-serif; background: #f3f4f6; margin: 0; padding: 40px 20px; color: #1f2937; }
.container { max-width: 1000px; margin: 0 auto; background: white; border-radius: 16px; box-shadow: 0 10px 25px rgba(0,0,0,0.05); overflow: hidden; padding: 30px; }
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e5e7eb; padding-bottom: 20px; margin-bottom: 25px; }
.header h1 { font-size: 24px; margin: 0; color: #111827; display: flex; align-items: center; gap: 12px; }
.actions { display: flex; gap: 12px; }
.btn { padding: 10px 20px; border-radius: 8px; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; font-size: 14px; transition: all 0.2s; }
.btn-primary { background: #4f46e5; color: white; }
.btn-primary:hover { background: #4338ca; }
.btn-secondary { background: #f3f4f6; color: #374151; }
.btn-secondary:hover { background: #e5e7eb; }
table { width: 100%; border-collapse: collapse; text-align: left; }
th { padding: 16px; background: #f9fafb; font-weight: 600; color: #374151; border-bottom: 1px solid #e5e7eb; font-size: 14px; }
td { padding: 16px; border-bottom: 1px solid #e5e7eb; font-size: 15px; }
tr:hover { background: #f9fafb; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1><i class="fas fa-folder-open" style="color: #4f46e5;"></i> ${folderName}</h1>
<div class="actions">
<a href="/${folderName}/index.html" target="_blank" class="btn btn-primary"><i class="fas fa-external-link-alt"></i> Abrir Site Clonado</a>
<a href="/" class="btn btn-secondary"><i class="fas fa-arrow-left"></i> Voltar ao Dashboard</a>
</div>
</div>
<table>
<thead>
<tr>
<th>Nome do Ficheiro</th>
<th>Tamanho</th>
<th>Modificado em</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
${filesHtml}
</tbody>
</table>
</div>
</body>
</html>
`;
res.send(html);
} catch (error) {
console.error('Erro ao listar pasta:', error);
res.status(500).send('<h1>Erro interno do servidor</h1>');
}
});
// Abrir pasta do clone (mantém compatibilidade legada e retorna a URL do Web Browse)
app.post('/api/open-folder', (req, res) => {
try {
const { path: folderPath } = req.body;
@@ -265,14 +389,10 @@ app.post('/api/open-folder', (req, res) => {
return res.status(400).json({ error: 'Caminho da pasta é obrigatório' });
}
// Abrir pasta no gerenciador de ficheiros
exec(`xdg-open "${folderPath}"`, (error) => {
if (error) {
console.error('Erro ao abrir pasta:', error);
return res.status(500).json({ error: 'Não foi possível abrir a pasta' });
}
res.json({ success: true, message: 'Pasta aberta com sucesso' });
});
const folderName = path.basename(folderPath);
const browseUrl = `/api/browse/${folderName}`;
res.json({ success: true, message: 'Pasta acessível via Web', url: browseUrl });
} catch (error) {
console.error('Erro ao abrir pasta:', error);
res.status(500).json({ error: 'Erro interno do servidor' });
@@ -287,20 +407,10 @@ app.post('/api/open-site', (req, res) => {
return res.status(400).json({ error: 'Caminho do site é obrigatório' });
}
// Extrair apenas o nome da pasta (último segmento do caminho)
const folderName = path.basename(sitePath);
const siteUrl = `http://localhost:${PORT}/${folderName}/index.html`;
const siteUrl = `/${folderName}/index.html`;
console.log(`🌍 Opening site via HTTP: ${siteUrl}`);
// Abrir URL no navegador padrão (Linux)
exec(`xdg-open "${siteUrl}"`, (error) => {
if (error) {
console.error('Erro ao abrir site:', error);
return res.status(500).json({ error: 'Não foi possível abrir o site via HTTP' });
}
res.json({ success: true, message: 'Site aberto via HTTP com sucesso', url: siteUrl });
});
res.json({ success: true, message: 'Site aberto com sucesso', url: siteUrl });
} catch (error) {
console.error('Erro ao abrir site:', error);
res.status(500).json({ error: 'Erro interno do servidor' });