upload de samples
Deploy / Deploy (push) Successful in 1m29s
Details
Deploy / Deploy (push) Successful in 1m29s
Details
This commit is contained in:
parent
229f09883d
commit
20dff13a0b
File diff suppressed because it is too large
Load Diff
684416
_data/all.yml
684416
_data/all.yml
File diff suppressed because it is too large
Load Diff
|
|
@ -20,6 +20,7 @@
|
||||||
- (lo-fi beat) bubblegum.wav
|
- (lo-fi beat) bubblegum.wav
|
||||||
- )screams(.wav
|
- )screams(.wav
|
||||||
- '- 7 is the answer (06.02.24).wav'
|
- '- 7 is the answer (06.02.24).wav'
|
||||||
|
- 2019Winter_Song.wav
|
||||||
- 43yu.wav
|
- 43yu.wav
|
||||||
- 4r3st.wav
|
- 4r3st.wav
|
||||||
- '@prod.plue_Trap_Beat.wav'
|
- '@prod.plue_Trap_Beat.wav'
|
||||||
|
|
|
||||||
138
pages/samples.md
138
pages/samples.md
|
|
@ -28,6 +28,10 @@ permalink: /samples/
|
||||||
<button id="btn-home" class="button is-small is-info is-light mr-3" title="Voltar ao início">
|
<button id="btn-home" class="button is-small is-info is-light mr-3" title="Voltar ao início">
|
||||||
<i class="fa-solid fa-house"></i>
|
<i class="fa-solid fa-house"></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="btn-open-upload" class="button is-small is-success is-light mr-3" title="Enviar novo Sample">
|
||||||
|
<span class="icon"><i class="fa-solid fa-cloud-arrow-up"></i></span>
|
||||||
|
<span>Enviar Sample</span>
|
||||||
|
</button>
|
||||||
<nav class="breadcrumb is-small mb-0" aria-label="breadcrumbs">
|
<nav class="breadcrumb is-small mb-0" aria-label="breadcrumbs">
|
||||||
<ul id="breadcrumb-list">
|
<ul id="breadcrumb-list">
|
||||||
<li class="is-active"><a href="#">Raiz</a></li>
|
<li class="is-active"><a href="#">Raiz</a></li>
|
||||||
|
|
@ -164,6 +168,56 @@ permalink: /samples/
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="upload-sample-modal" class="modal">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">Enviar Sample</p>
|
||||||
|
<button class="delete" aria-label="close" id="close-upload-modal"></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
|
||||||
|
<form id="sample-upload-form">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Arquivo de Áudio</label>
|
||||||
|
<div class="control">
|
||||||
|
<div class="file has-name is-fullwidth">
|
||||||
|
<label class="file-label">
|
||||||
|
<input class="file-input" type="file" name="sample_file" accept=".wav,.mp3,.ogg,.flac" required>
|
||||||
|
<span class="file-cta">
|
||||||
|
<span class="file-icon"><i class="fa-solid fa-upload"></i></span>
|
||||||
|
<span class="file-label">Escolher arquivo...</span>
|
||||||
|
</span>
|
||||||
|
<span class="file-name" id="upload-filename-display">Nenhum arquivo selecionado</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Salvar na Pasta</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input class="input" type="text" name="subfolder" placeholder="Ex: Drums/Kicks (Vazio = Raiz)" id="upload-subfolder">
|
||||||
|
<span class="icon is-small is-left"><i class="fa-solid fa-folder-open"></i></span>
|
||||||
|
</div>
|
||||||
|
<p class="help">Você pode criar pastas usando barras, ex: <code>Percussion/Hats</code></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<progress id="upload-progress" class="progress is-small is-primary is-hidden" max="100"></progress>
|
||||||
|
<p id="upload-status" class="help is-hidden"></p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<footer class="modal-card-foot" style="justify-content: flex-end;">
|
||||||
|
<button class="button" id="cancel-upload">Cancelar</button>
|
||||||
|
<button class="button is-success" id="confirm-upload-btn">
|
||||||
|
<span class="icon"><i class="fa-solid fa-check"></i></span>
|
||||||
|
<span>Enviar</span>
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.browser-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 15px; }
|
.browser-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 15px; }
|
||||||
.browser-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 15px; border: 1px solid transparent; border-radius: 8px; cursor: pointer; transition: all 0.2s; }
|
.browser-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 15px; border: 1px solid transparent; border-radius: 8px; cursor: pointer; transition: all 0.2s; }
|
||||||
|
|
@ -440,5 +494,89 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
} catch(e){} });
|
} catch(e){} });
|
||||||
closeButtons.forEach(el => el.addEventListener('click', closeModal));
|
closeButtons.forEach(el => el.addEventListener('click', closeModal));
|
||||||
document.addEventListener('keydown', (e) => { if (e.key === "Escape") closeModal(); });
|
document.addEventListener('keydown', (e) => { if (e.key === "Escape") closeModal(); });
|
||||||
|
|
||||||
|
// === LÓGICA DE UPLOAD ===
|
||||||
|
const uploadModal = document.getElementById('upload-sample-modal');
|
||||||
|
const btnOpenUpload = document.getElementById('btn-open-upload');
|
||||||
|
const btnCloseUpload = document.getElementById('close-upload-modal');
|
||||||
|
const btnCancelUpload = document.getElementById('cancel-upload');
|
||||||
|
const fileInput = document.querySelector('#sample-upload-form input[type="file"]');
|
||||||
|
const fileNameDisplay = document.getElementById('upload-filename-display');
|
||||||
|
const subfolderInput = document.getElementById('upload-subfolder');
|
||||||
|
const confirmUploadBtn = document.getElementById('confirm-upload-btn');
|
||||||
|
const uploadProgress = document.getElementById('upload-progress');
|
||||||
|
const uploadStatus = document.getElementById('upload-status');
|
||||||
|
|
||||||
|
// Abrir/Fechar Modal
|
||||||
|
function toggleUploadModal(show) {
|
||||||
|
if(show) {
|
||||||
|
uploadModal.classList.add('is-active');
|
||||||
|
// Tenta preencher a pasta atual automaticamente baseado na navegação
|
||||||
|
const currentPath = currentPathStack.join('/');
|
||||||
|
subfolderInput.value = currentPath;
|
||||||
|
} else {
|
||||||
|
uploadModal.classList.remove('is-active');
|
||||||
|
uploadStatus.classList.add('is-hidden');
|
||||||
|
uploadProgress.classList.add('is-hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(btnOpenUpload) btnOpenUpload.onclick = () => toggleUploadModal(true);
|
||||||
|
if(btnCloseUpload) btnCloseUpload.onclick = () => toggleUploadModal(false);
|
||||||
|
if(btnCancelUpload) btnCancelUpload.onclick = () => toggleUploadModal(false);
|
||||||
|
|
||||||
|
// Atualizar nome do arquivo no input
|
||||||
|
fileInput.onchange = () => {
|
||||||
|
if (fileInput.files.length > 0) {
|
||||||
|
fileNameDisplay.textContent = fileInput.files[0].name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enviar Formulário
|
||||||
|
confirmUploadBtn.onclick = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (fileInput.files.length === 0) {
|
||||||
|
alert("Selecione um arquivo primeiro.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData(document.getElementById('sample-upload-form'));
|
||||||
|
|
||||||
|
// UI de Carregamento
|
||||||
|
confirmUploadBtn.classList.add('is-loading');
|
||||||
|
uploadProgress.classList.remove('is-hidden');
|
||||||
|
uploadStatus.classList.remove('is-hidden');
|
||||||
|
uploadStatus.textContent = "Enviando e atualizando biblioteca (pode demorar)...";
|
||||||
|
uploadStatus.className = "help has-text-info";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// URL do seu servidor Python (ajuste a porta/domínio se necessário)
|
||||||
|
// Se estiver rodando localmente no navegador, use a URL pública
|
||||||
|
const response = await fetch('https://alice.ufsj.edu.br:33002/api/upload/sample', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
uploadStatus.textContent = "Sucesso! Recarregando...";
|
||||||
|
uploadStatus.className = "help has-text-success";
|
||||||
|
|
||||||
|
// Aguarda um pouco e recarrega a página para pegar o novo manifesto
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1500);
|
||||||
|
} else {
|
||||||
|
throw new Error(result.error || "Erro desconhecido");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
uploadStatus.textContent = "Erro: " + error.message;
|
||||||
|
uploadStatus.className = "help has-text-danger";
|
||||||
|
confirmUploadBtn.classList.remove('is-loading');
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -8,7 +8,7 @@ from werkzeug.utils import secure_filename
|
||||||
from main import process_single_file, rebuild_indexes, generate_manifests
|
from main import process_single_file, rebuild_indexes, generate_manifests
|
||||||
|
|
||||||
# 2. ADICIONE BASE_PATH ABAIXO (Assume que utils tem o caminho raiz do projeto)
|
# 2. ADICIONE BASE_PATH ABAIXO (Assume que utils tem o caminho raiz do projeto)
|
||||||
from utils import MMP_FOLDER, MMPZ_FOLDER, CERT_PATH, KEY_PATH, BASE_DATA, SRC_MMPSEARCH
|
from utils import MMP_FOLDER, MMPZ_FOLDER, CERT_PATH, KEY_PATH, BASE_DATA, SRC_MMPSEARCH, SAMPLE_SRC
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
|
@ -101,6 +101,62 @@ def upload_file():
|
||||||
|
|
||||||
return jsonify({"error": "Tipo de arquivo não permitido"}), 400
|
return jsonify({"error": "Tipo de arquivo não permitido"}), 400
|
||||||
|
|
||||||
|
ALLOWED_SAMPLE_EXTENSIONS = {'wav', 'mp3', 'ogg', 'flac'}
|
||||||
|
|
||||||
|
def allowed_sample(filename):
|
||||||
|
return '.' in filename and \
|
||||||
|
filename.rsplit('.', 1)[1].lower() in ALLOWED_SAMPLE_EXTENSIONS
|
||||||
|
|
||||||
|
@app.route('/api/upload/sample', methods=['POST'])
|
||||||
|
def upload_sample():
|
||||||
|
if 'sample_file' not in request.files:
|
||||||
|
return jsonify({'error': 'Nenhum arquivo enviado'}), 400
|
||||||
|
|
||||||
|
file = request.files['sample_file']
|
||||||
|
# Pega a subpasta (opcional), ex: "Drums/Kicks"
|
||||||
|
subfolder = request.form.get('subfolder', '').strip()
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Nome do arquivo vazio'}), 400
|
||||||
|
|
||||||
|
if file and allowed_sample(file.filename):
|
||||||
|
filename = secure_filename(file.filename)
|
||||||
|
|
||||||
|
# Define o caminho final (Raiz de samples + Subpasta)
|
||||||
|
# Evita "directory traversal" removendo ..
|
||||||
|
safe_subfolder = subfolder.replace('..', '').strip('/')
|
||||||
|
target_dir = os.path.join(SAMPLE_SRC, safe_subfolder)
|
||||||
|
|
||||||
|
# Cria a pasta se não existir
|
||||||
|
if not os.path.exists(target_dir):
|
||||||
|
try:
|
||||||
|
os.makedirs(target_dir, exist_ok=True)
|
||||||
|
# Garante permissão para o grupo www-data
|
||||||
|
os.system(f"chmod -R 775 {target_dir}")
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'error': f"Erro ao criar pasta: {str(e)}"}), 500
|
||||||
|
|
||||||
|
save_path = os.path.join(target_dir, filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
file.save(save_path)
|
||||||
|
# Garante permissão do arquivo
|
||||||
|
os.chmod(save_path, 0o664)
|
||||||
|
print(f"Sample salvo em: {save_path}")
|
||||||
|
|
||||||
|
# 1. Regenerar o manifesto (samples-manifest.json)
|
||||||
|
# Passamos SRC_MMPSEARCH pois o generate_manifests espera a raiz do projeto
|
||||||
|
generate_manifests(SRC_MMPSEARCH)
|
||||||
|
|
||||||
|
# 2. Reconstruir o site (para o Jekyll ler o novo JSON)
|
||||||
|
run_jekyll_build()
|
||||||
|
|
||||||
|
return jsonify({'message': 'Sample enviado e biblioteca atualizada!'}), 200
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'error': f"Falha ao processar: {str(e)}"}), 500
|
||||||
|
|
||||||
|
return jsonify({'error': 'Tipo de arquivo não permitido (apenas wav, mp3, ogg, flac)'}), 400
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Iniciando Servidor de Upload MMP...")
|
print("Iniciando Servidor de Upload MMP...")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue