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
|
||||
- )screams(.wav
|
||||
- '- 7 is the answer (06.02.24).wav'
|
||||
- 2019Winter_Song.wav
|
||||
- 43yu.wav
|
||||
- 4r3st.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">
|
||||
<i class="fa-solid fa-house"></i>
|
||||
</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">
|
||||
<ul id="breadcrumb-list">
|
||||
<li class="is-active"><a href="#">Raiz</a></li>
|
||||
|
|
@ -164,6 +168,56 @@ permalink: /samples/
|
|||
</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>
|
||||
.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; }
|
||||
|
|
@ -440,5 +494,89 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
} catch(e){} });
|
||||
closeButtons.forEach(el => el.addEventListener('click', 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>
|
||||
|
|
@ -8,7 +8,7 @@ from werkzeug.utils import secure_filename
|
|||
from main import process_single_file, rebuild_indexes, generate_manifests
|
||||
|
||||
# 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__)
|
||||
CORS(app)
|
||||
|
|
@ -101,6 +101,62 @@ def upload_file():
|
|||
|
||||
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__":
|
||||
print("Iniciando Servidor de Upload MMP...")
|
||||
|
|
|
|||
Loading…
Reference in New Issue