Files
mmpSearch/pages/enviaProjeto.md
T

17 KiB
Executable File

layout, title, permalink
layout title permalink
default MMPSearch - Envie seu projeto /envie_seu_projeto/

  <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> para que outros possam estudar e remixar.
        </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 class="box p-5" 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

Atenção: Arquivos Faltando

Seu projeto usa samples externos!

Para que o projeto funcione para todos, precisamos dos seguintes arquivos:

  <div class="box">
      <ul id="missing-files-list" style="list-style: disc; margin-left: 20px; color: #d63031;">
          </ul>
  </div>

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

      <div class="field">
          <label class="label">Envie os arquivos listados acima:</label>
          <div class="file has-name is-fullwidth is-warning">
            <label class="file-label">
              <input class="file-input" type="file" name="sample_files" multiple required>
              <span class="file-cta">
                <span class="file-icon"><i class="fa-solid fa-upload"></i></span>
                <span class="file-label">Selecionar Samples...</span>
              </span>
              <span class="file-name" id="resolve-file-name">Nenhum selecionado</span>
            </label>
          </div>
      </div>

      <button type="submit" class="button is-warning is-fullwidth mt-4" id="resolve-btn">
          Enviar Arquivos e Finalizar
      </button>
  </form>
</section>
<style> /* Estilo do Dropzone */ .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; /* Deixa o clique passar para o input */ } /* Inputs customizados */ .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', () => { // --- ELEMENTOS GERAIS --- const dropZone = document.getElementById('drop-zone'); const fileInput = document.getElementById('project_file'); const fileNameDisplay = document.getElementById('file-name-display'); const dragTextTitle = dropZone.querySelector('.title'); // --- MODAIS --- const successModal = document.getElementById('success-modal'); const resolveModal = document.getElementById('resolve-modal'); const closeBtns = document.querySelectorAll('.delete, #close-success-modal, .modal-background'); // --- FORMULÁRIOS --- 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'); // 1. 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"; } }); // 2. INPUT DE ÁUDIO & RESOLVE (Nomes de arquivo) 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; } } }); }); // 3. FUNÇÃO DE FECHAR MODAIS closeBtns.forEach(btn => { btn.addEventListener('click', () => { successModal.classList.remove('is-active'); resolveModal.classList.remove('is-active'); document.documentElement.classList.remove('is-clipped'); }); }); // ============================================================ // 4. SUBMISSÃO PRINCIPAL (PROJETO) // ============================================================ mainForm.addEventListener('submit', async (e) => { e.preventDefault(); submitBtn.classList.add('is-loading'); const formData = new FormData(mainForm); try { // Rota principal de upload const response = await fetch('https://alice.ufsj.edu.br:33002/api/upload', { method: 'POST', body: formData }); // Parseamos o JSON independente do status para ler mensagens const result = await response.json(); submitBtn.classList.remove('is-loading'); if (response.status === 200) { // SUCESSO TOTAL (Status 200) mostrarSucesso(); mainForm.reset(); resetDropzone(); } else if (response.status === 202) { // SUCESSO PARCIAL (Status 202 - Faltam Samples) mostrarResolveModal(result); } else { // ERRO (400, 500) alert('Erro: ' + (result.error || 'Ocorreu um erro desconhecido.')); } } catch (error) { console.error('Erro:', error); alert('Erro de conexão com o servidor.'); submitBtn.classList.remove('is-loading'); } }); // ============================================================ // 5. SUBMISSÃO DE RESOLUÇÃO (SAMPLES FALTANDO) // ============================================================ resolveForm.addEventListener('submit', async (e) => { e.preventDefault(); resolveBtn.classList.add('is-loading'); const formData = new FormData(resolveForm); try { // Rota de resolução (envio dos samples faltantes) const response = await fetch('https://alice.ufsj.edu.br:33002/api/upload/resolve', { method: 'POST', body: formData }); const result = await response.json(); resolveBtn.classList.remove('is-loading'); if (response.ok) { // Agora sim, tudo certo! 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'); } }); // --- FUNÇÕES AUXILIARES --- function mostrarSucesso() { successModal.classList.add('is-active'); document.documentElement.classList.add('is-clipped'); } function mostrarResolveModal(data) { // 1. Preenche o input hidden com o nome do projeto (retornado pelo backend) document.getElementById('hidden-project-name').value = data.project_file; // 2. Preenche a lista visual de arquivos faltando const list = document.getElementById('missing-files-list'); list.innerHTML = ''; // Limpa lista anterior if (data.missing_files && data.missing_files.length > 0) { data.missing_files.forEach(file => { const li = document.createElement('li'); li.textContent = file; list.appendChild(li); }); } // 3. Abre o modal resolveModal.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>