Files
mmpSearch/pages/enviaProjeto.md
T
2025-12-09 18:38:55 -03:00

21 KiB
Executable File

layout, title, permalink
layout title permalink
default MMPSearch - Envie seu projeto /envie_seu_projeto/
{% include modal_login.html %}
  <div class="tabs is-centered is-boxed is-medium mb-6">
    {% include sidebar.html %}
  </div>

  <div class="columns is-centered">
    <div class="column is-8 has-text-centered">
        <h1 class="title is-3 has-text-grey-dark mb-3">
            <span class="icon has-text-info mr-2"><i class="fa-solid fa-cloud-arrow-up"></i></span>
            Enviar Projeto
        </h1>
        <p class="subtitle is-6 has-text-grey">
            Contribua com a comunidade! Envie seus arquivos <code>.mmp</code> ou <code>.mmpz</code>.
        </p>
        <div style="width: 60px; height: 4px; background-color: #3273dc; margin: 1rem auto; border-radius: 2px;"></div>
    </div>
  </div>

  <div class="columns is-centered">
    <div class="column is-8">

        <div id="auth-loading" class="box has-text-centered p-6">
            <span class="icon is-large has-text-info mb-3"><i class="fa-solid fa-circle-notch fa-spin fa-3x"></i></span>
            <p class="subtitle is-5">Verificando permissões...</p>
        </div>

        <div id="login-warning" class="box has-text-centered p-6 is-hidden" style="background-color: #fffdf5; border: 1px solid #ffe08a;">
            <span class="icon is-large has-text-warning mb-3"><i class="fa-solid fa-lock fa-3x"></i></span>
            <h3 class="title is-4 has-text-grey-dark">Login Necessário</h3>
            <p class="mb-5">Você precisa estar logado para enviar projetos e samples para a comunidade.</p>
            <div class="buttons is-centered">
                <a href="#" class="button is-info is-medium js-trigger-login">
                    <span class="icon"><i class="fa-solid fa-right-to-bracket"></i></span>
                    <span>Fazer Login / Cadastrar</span>
                </a>
            </div>
        </div>

        <div id="upload-content" class="box p-5 is-hidden" style="background-color: #f0f8ff; border: 1px solid #cfe8fc; border-radius: 12px;">
            <form id="upload-project-form">

                <div class="field mb-5">
                    <label class="label has-text-grey-dark">Arquivo do Projeto (LMMS)</label>
                    <div class="file-upload-wrapper" id="drop-zone">
                        <input class="file-upload-input" type="file" name="project_file" id="project_file" accept=".mmp, .mmpz" required>
                        <div class="drag-text has-text-centered">
                            <span class="icon is-large has-text-info mb-2"><i class="fa-solid fa-file-audio fa-3x"></i></span>
                            <h3 class="title is-5 has-text-grey-dark mb-1">Arraste e solte o arquivo aqui</h3>
                            <p class="is-size-7 has-text-grey">ou clique para selecionar (.mmp, .mmpz)</p>
                            <p id="file-name-display" class="tag is-info is-light mt-3 is-hidden"></p>
                        </div>
                    </div>
                </div>

                <div class="columns">
                    <div class="column is-6">
                        <div class="field">
                            <label class="label has-text-grey-dark">Nome do Projeto</label>
                            <div class="control has-icons-left">
                                <input class="input" type="text" placeholder="Ex: Manda a maladeza" required>
                                <span class="icon is-small is-left">
                                    <i class="fa-solid fa-music"></i>
                                </span>
                            </div>
                        </div>
                    </div>
                    <div class="column is-6">
                        <div class="field">
                            <label class="label has-text-grey-dark">Qual o seu vulgo?</label>
                            <div class="control has-icons-left">
                                <input class="input" type="text" placeholder="Seu nome ou nick" required>
                                <span class="icon is-small is-left">
                                    <i class="fa-solid fa-user"></i>
                                </span>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="columns">
                    <div class="column is-4">
                        <div class="field">
                            <label class="label has-text-grey-dark">BPM</label>
                            <div class="control has-icons-left">
                                <input class="input" type="number" placeholder="128" min="1" max="999">
                                <span class="icon is-small is-left">
                                    <i class="fa-solid fa-gauge-high"></i>
                                </span>
                            </div>
                        </div>
                    </div>
                    <div class="column is-8">
                        <div class="field">
                            <label class="label has-text-grey-dark">Tags (Opcional)</label>
                            <div class="control has-icons-left">
                                <input class="input" type="text" placeholder="Ex: rap, hip hop, boom bap, remix">
                                <span class="icon is-small is-left">
                                    <i class="fa-solid fa-tags"></i>
                                </span>
                            </div>
                            <p class="help">Separe por vírgulas.</p>
                        </div>
                    </div>
                </div>

                <div class="field">
                    <label class="label has-text-grey-dark">Descrição</label>
                    <div class="control">
                        <textarea class="textarea" placeholder="Conte um pouco sobre como você criou esse projeto, plugins usados, etc." rows="3"></textarea>
                    </div>
                </div>

                <div class="field mb-5">
                    <label class="label has-text-grey-dark">Preview de Áudio (Opcional)</label>
                    <div class="file has-name is-fullwidth">
                      <label class="file-label">
                        <input class="file-input" type="file" name="audio_preview" accept=".wav, .mp3, .ogg">
                        <span class="file-cta">
                          <span class="file-icon">
                            <i class="fa-solid fa-upload"></i>
                          </span>
                          <span class="file-label">
                            Escolher arquivo de áudio...
                          </span>
                        </span>
                        <span class="file-name has-text-grey-light">
                          Nenhum arquivo selecionado
                        </span>
                      </label>
                    </div>
                    <p class="help">Envie um .mp3 ou .wav para que as pessoas possam ouvir antes de baixar.</p>
                </div>

                <div class="field mt-5">
                    <div class="control">
                        <button type="submit" class="button is-info is-fullwidth is-medium shadow-sm" id="submit-btn">
                            <span class="icon"><i class="fa-solid fa-paper-plane"></i></span>
                            <span>Enviar Projeto</span>
                        </button>
                    </div>
                </div>

            </form>
        </div>
        </div>
  </div>

</div>

Sucesso!

Projeto Enviado!

Obrigado por contribuir. Seu projeto está sendo processado e em breve aparecerá na lista.

Ver Projetos Enviar Outro

Arquivos Externos Detectados

<section class="modal-card-body">
  <div class="content is-small mb-4">
    <p>Este projeto utiliza samples que não são nativos do LMMS. Para que o som saia correto, precisamos que você envie os arquivos correspondentes.</p>
  </div>

  <form id="resolve-form">
      <input type="hidden" name="project_file" id="hidden-project-name">

      <div class="table-container">
          <table class="table is-fullwidth is-striped is-hoverable">
              <thead>
                  <tr>
                      <th>Arquivo Faltante (XML)</th>
                      <th style="width: 50px;">Status</th>
                      <th style="width: 120px;">Ação</th>
                  </tr>
              </thead>
              <tbody id="missing-files-table-body">
                  </tbody>
          </table>
      </div>

      <div class="notification is-danger is-light is-hidden" id="resolve-error-msg"></div>

      <button type="submit" class="button is-success is-fullwidth mt-4" id="resolve-btn" disabled>
          <span class="icon"><i class="fa-solid fa-check"></i></span>
          <span>Enviar Todos e Processar</span>
      </button>
  </form>
</section>
<style> .file-upload-wrapper { position: relative; width: 100%; height: 200px; border: 2px dashed #3273dc; border-radius: 8px; background-color: #fff; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; cursor: pointer; } .file-upload-wrapper:hover, .file-upload-wrapper.dragover { background-color: #eef6fc; border-color: #205081; } .file-upload-input { position: absolute; width: 100%; height: 100%; top: 0; left: 0; opacity: 0; cursor: pointer; } .drag-text { pointer-events: none; } .input:focus, .textarea:focus { border-color: #3273dc; box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } </style> <script> document.addEventListener('DOMContentLoaded', async () => { // --- VERIFICAÇÃO DE LOGIN (NOVO) --- const loadingDiv = document.getElementById('auth-loading'); const warningDiv = document.getElementById('login-warning'); const contentDiv = document.getElementById('upload-content'); try { // Usa caminho relativo graças ao Apache Proxy const authRes = await fetch('/api/check_auth'); const authData = await authRes.json(); loadingDiv.classList.add('is-hidden'); if (authData.logged_in) { // Se logado: Mostra o formulário contentDiv.classList.remove('is-hidden'); } else { // Se não logado: Mostra aviso warningDiv.classList.remove('is-hidden'); } } catch (e) { console.error("Erro ao verificar auth:", e); loadingDiv.innerHTML = "

Erro ao conectar com servidor.

"; } // ------------------------------------ const dropZone = document.getElementById('drop-zone'); const fileInput = document.getElementById('project_file'); const fileNameDisplay = document.getElementById('file-name-display'); const dragTextTitle = dropZone.querySelector('.title'); const successModal = document.getElementById('success-modal'); const resolveModal = document.getElementById('resolve-modal'); const closeBtns = document.querySelectorAll('.delete, #close-success-modal, .modal-background'); const mainForm = document.getElementById('upload-project-form'); const resolveForm = document.getElementById('resolve-form'); const submitBtn = document.getElementById('submit-btn'); const resolveBtn = document.getElementById('resolve-btn'); // Visual do Dropzone ['dragenter', 'dragover'].forEach(evt => dropZone.addEventListener(evt, (e) => { e.preventDefault(); dropZone.classList.add('dragover'); })); ['dragleave', 'drop'].forEach(evt => dropZone.addEventListener(evt, (e) => { dropZone.classList.remove('dragover'); })); fileInput.addEventListener('change', () => { if (fileInput.files.length > 0) { fileNameDisplay.textContent = fileInput.files[0].name; fileNameDisplay.classList.remove('is-hidden'); dragTextTitle.textContent = "Arquivo Pronto!"; dropZone.style.borderColor = "#4caf50"; dropZone.style.backgroundColor = "#f0fff4"; } }); document.querySelectorAll('.file-input').forEach(input => { input.addEventListener('change', () => { if (input.files.length > 0) { const nameContainer = input.parentElement.querySelector('.file-name'); if (nameContainer) { nameContainer.textContent = input.files.length > 1 ? `${input.files.length} arquivos selecionados` : input.files[0].name; } } }); }); closeBtns.forEach(btn => { btn.addEventListener('click', () => { successModal.classList.remove('is-active'); resolveModal.classList.remove('is-active'); document.documentElement.classList.remove('is-clipped'); }); }); // SUBMISSÃO PRINCIPAL mainForm.addEventListener('submit', async (e) => { e.preventDefault(); submitBtn.classList.add('is-loading'); const formData = new FormData(mainForm); try { // FIX: Usando caminho relativo (/api/upload) em vez da porta 33002 const response = await fetch('/api/upload', { method: 'POST', body: formData }); const result = await response.json(); submitBtn.classList.remove('is-loading'); if (response.status === 200) { mostrarSucesso(); mainForm.reset(); resetDropzone(); } else if (response.status === 202) { mostrarResolveModal(result); } else { alert('Erro: ' + (result.error || result.message || 'Ocorreu um erro desconhecido.')); } } catch (error) { console.error('Erro:', error); alert('Erro de conexão com o servidor.'); submitBtn.classList.remove('is-loading'); } }); // SUBMISSÃO RESOLVE resolveForm.addEventListener('submit', async (e) => { e.preventDefault(); resolveBtn.classList.add('is-loading'); const formData = new FormData(resolveForm); try { // FIX: Usando caminho relativo const response = await fetch('/api/upload/resolve', { method: 'POST', body: formData }); const result = await response.json(); resolveBtn.classList.remove('is-loading'); if (response.ok) { resolveModal.classList.remove('is-active'); mostrarSucesso(); mainForm.reset(); resetDropzone(); } else { alert('Erro ao enviar samples: ' + (result.error || 'Erro desconhecido')); } } catch (error) { console.error(error); alert('Erro ao enviar samples.'); resolveBtn.classList.remove('is-loading'); } }); function mostrarSucesso() { successModal.classList.add('is-active'); document.documentElement.classList.add('is-clipped'); } function mostrarResolveModal(data) { document.getElementById('hidden-project-name').value = data.project_file; const tbody = document.getElementById('missing-files-table-body'); tbody.innerHTML = ''; const resolveBtn = document.getElementById('resolve-btn'); resolveBtn.disabled = true; let totalFiles = data.missing_files.length; let filledFiles = 0; data.missing_files.forEach((originalName, index) => { const tr = document.createElement('tr'); const tdName = document.createElement('td'); tdName.style.verticalAlign = "middle"; tdName.innerHTML = `${originalName}`; const tdStatus = document.createElement('td'); tdStatus.style.verticalAlign = "middle"; tdStatus.style.textAlign = "center"; tdStatus.innerHTML = ``; const tdAction = document.createElement('td'); tdAction.style.textAlign = "right"; const fileInput = document.createElement('input'); fileInput.type = 'file'; fileInput.name = originalName; fileInput.style.display = 'none'; fileInput.accept = ".wav, .mp3, .ogg, .flac, .ds"; const uploadLabel = document.createElement('label'); uploadLabel.className = 'button is-small is-info is-outlined'; uploadLabel.innerHTML = ``; uploadLabel.addEventListener('click', (e) => { e.preventDefault(); fileInput.click(); }); fileInput.addEventListener('change', () => { if (fileInput.files.length > 0) { uploadLabel.className = 'button is-small is-success'; uploadLabel.innerHTML = ``; const icon = tdStatus.querySelector('.status-icon'); icon.innerHTML = ``; icon.classList.remove('has-text-grey-light'); icon.classList.add('has-text-success'); if (!fileInput.dataset.filled) { fileInput.dataset.filled = "true"; filledFiles++; } if (filledFiles >= totalFiles) { resolveBtn.disabled = false; resolveBtn.classList.remove('is-outlined'); } } }); tdAction.appendChild(fileInput); tdAction.appendChild(uploadLabel); tr.appendChild(tdName); tr.appendChild(tdStatus); tr.appendChild(tdAction); tbody.appendChild(tr); }); document.getElementById('resolve-modal').classList.add('is-active'); document.documentElement.classList.add('is-clipped'); } function resetDropzone() { fileNameDisplay.classList.add('is-hidden'); dragTextTitle.textContent = "Arraste e solte o arquivo aqui"; dropZone.style.borderColor = "#3273dc"; dropZone.style.backgroundColor = "#fff"; } }); </script>