sockets funcionais
This commit is contained in:
1 parent
d38cd9e60f
commit
509c51b783
7 files changed
+1044
-134
No files matched your search
+2
-2
@@ -4,8 +4,8 @@ description: >- # this means to ignore newlines until "baseurl:"
|
|||||||
Write an awesome description for your new site here. You can edit this
|
Write an awesome description for your new site here. You can edit this
|
||||||
line in _config.yml. It will appear in your document head meta (for
|
line in _config.yml. It will appear in your document head meta (for
|
||||||
Google search results) and in your feed.xml site description.
|
Google search results) and in your feed.xml site description.
|
||||||
baseurl: "/mmpSearch/" # the subpath of your site, e.g. /blog
|
baseurl: "/~jotachina/mmpSearch/" # the subpath of your site, e.g. /blog
|
||||||
url: "https://alice.ufsj.edu.br" # the base hostname & protocol for your site, e.g. http://example.com
|
url: "https://alice.ufsj.edu.br/" # the base hostname & protocol for your site, e.g. http://example.com
|
||||||
|
|
||||||
theme: alice
|
theme: alice
|
||||||
|
|
||||||
|
|||||||
+155
-110
@@ -8,10 +8,8 @@ title: "{{ page.file }}"
|
|||||||
<main class="content">
|
<main class="content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<!-- Título -->
|
|
||||||
<h1 class="title is-3 mb-4"><code>{{ page.file }}</h1></code>
|
<h1 class="title is-3 mb-4"><code>{{ page.file }}</h1></code>
|
||||||
|
|
||||||
<!-- Metadados (Arquivo fonte + BPM) -->
|
|
||||||
{% if page.file or page.bpm %}
|
{% if page.file or page.bpm %}
|
||||||
<div class="mb-5">
|
<div class="mb-5">
|
||||||
<div class="columns is-mobile is-multiline is-vcentered">
|
<div class="columns is-mobile is-multiline is-vcentered">
|
||||||
@@ -29,114 +27,161 @@ title: "{{ page.file }}"
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Tags -->
|
<div class="columns">
|
||||||
{% if page.tags %}
|
|
||||||
{% assign tags_vazias = true %}
|
<div class="column is-two-thirds">
|
||||||
{% for categoria in page.tags %}
|
|
||||||
{% if categoria[1].size > 0 %}
|
{% if page.tags %}
|
||||||
{% assign tags_vazias = false %}
|
{% assign tags_vazias = true %}
|
||||||
{% endif %}
|
{% for categoria in page.tags %}
|
||||||
{% endfor %}
|
{% if categoria[1].size > 0 %}
|
||||||
|
{% assign tags_vazias = false %}
|
||||||
{% unless tags_vazias %}
|
|
||||||
<section class="tags-section mb-6">
|
|
||||||
<!-- Verificar se o arquivo .wav existe -->
|
|
||||||
{% assign audio_file = '/mmp/wav/' | append: page.file | append: '.wav' %}
|
|
||||||
|
|
||||||
<!-- Exibir player de áudio -->
|
|
||||||
{% if audio_file %}
|
|
||||||
<section class="audio-player-section mb-6">
|
|
||||||
<audio controls>
|
|
||||||
<source src="{{ audio_file | relative_url }}" type="audio/wav">
|
|
||||||
Seu navegador não suporta o elemento <code>audio</code>.
|
|
||||||
</audio>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h2 class="title is-5"><code>🏷️ Tags</code></h2>
|
|
||||||
{% for categoria in page.tags %}
|
|
||||||
{% if categoria[1].size > 0 %}
|
|
||||||
<div class="mb-4">
|
|
||||||
<strong><code>{{ categoria[0] }}:</strong></code>
|
|
||||||
<div class="tags mt-2">
|
|
||||||
{% for valor in categoria[1] %}
|
|
||||||
{% if valor != "" %}
|
|
||||||
{% assign tag_slug = valor | replace: ' ', '+' %}
|
|
||||||
|
|
||||||
<!-- Gerar link para filtro por categoria -->
|
|
||||||
{% if categoria[0] == 'bassline' %}
|
|
||||||
<a href="{{ '/bassline/?bassline=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
|
||||||
{% elsif categoria[0] == 'sample' %}
|
|
||||||
<a href="{{ '/sample/?sample=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
|
||||||
{% elsif categoria[0] == 'plugin' %}
|
|
||||||
<a href="{{ '/plugin/?plugin=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
|
||||||
{% elsif categoria[0] == 'automation' %}
|
|
||||||
<a href="{{ '/automation/?automation=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{{ '/' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</section>
|
|
||||||
{% endunless %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Instrumentos -->
|
|
||||||
{% if page.tracks and page.tracks.size > 0 %}
|
|
||||||
<section class="instruments-section">
|
|
||||||
<h2 class="title is-5"><code>🎚️ Instrumentos</h2></code>
|
|
||||||
<div class="content">
|
|
||||||
<ul style="list-style: none; padding-left: 0;">
|
|
||||||
{% for track in page.tracks %}
|
|
||||||
{% assign tem_instr = false %}
|
|
||||||
{% if track.instruments and track.instruments.size > 0 %}
|
|
||||||
{% assign tem_instr = true %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if track.bassline_name or tem_instr %}
|
|
||||||
<li class="mb-5">
|
|
||||||
{% if track.bassline_name %}
|
|
||||||
<p class="has-text-weight-bold mb-2">🎼 {{ track.bassline_name }}</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if tem_instr %}
|
|
||||||
<ul class="pl-4">
|
|
||||||
{% for instrument in track.instruments %}
|
|
||||||
{% if instrument.instrument_name %}
|
|
||||||
<li style="margin-bottom: 0.4rem;">
|
|
||||||
<!-- Gerar link para filtro por instrumento -->
|
|
||||||
{% assign instrument_slug = instrument.instrument_name | replace: ' ', '+' %}
|
|
||||||
<a href="{{ '/instruments/?instrument=' | append: instrument_slug | relative_url }}" class="tag is-info is-light">
|
|
||||||
<code>{{ instrument.instrument_name }}</code>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% if instrument.audiofileprocessor and instrument.audiofileprocessor.src %}
|
|
||||||
<!-- Exibir player de áudio para o instrumento -->
|
|
||||||
<div class="audio-player-section mt-3">
|
|
||||||
<audio controls>
|
|
||||||
<!-- O caminho, aparentemente, está correto. mas não está emitindo sons -->
|
|
||||||
<source src="{{ '/mmp/instruments/lmms/' | append: instrument.audiofileprocessor.src | relative_url }}" type="audio/wav">
|
|
||||||
<source src="{{ '/mmp/instruments/lmms/' | append: instrument.audiofileprocessor.src | relative_url }}" type="audio/ogg">
|
|
||||||
Seu navegador não suporta o elemento <code>audio</code>.
|
|
||||||
</audio>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
|
||||||
</div>
|
{% unless tags_vazias %}
|
||||||
</section>
|
<section class="tags-section mb-6">
|
||||||
{% endif %}
|
{% assign audio_file = '/mmp/wav/' | append: page.file | append: '.wav' %}
|
||||||
</div>
|
|
||||||
|
{% if audio_file %}
|
||||||
|
<section class="audio-player-section mb-6">
|
||||||
|
<audio controls>
|
||||||
|
<source src="{{ audio_file | relative_url }}" type="audio/wav">
|
||||||
|
Seu navegador não suporta o elemento <code>audio</code>.
|
||||||
|
</audio>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h2 class="title is-5"><code>🏷️ Tags</code></h2>
|
||||||
|
{% for categoria in page.tags %}
|
||||||
|
{% if categoria[1].size > 0 %}
|
||||||
|
<div class="mb-4">
|
||||||
|
<strong><code>{{ categoria[0] }}:</strong></code>
|
||||||
|
<div class="tags mt-2">
|
||||||
|
{% for valor in categoria[1] %}
|
||||||
|
{% if valor != "" %}
|
||||||
|
{% assign tag_slug = valor | replace: ' ', '+' %}
|
||||||
|
|
||||||
|
{% if categoria[0] == 'bassline' %}
|
||||||
|
<a href="{{ '/bassline/?bassline=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
||||||
|
{% elsif categoria[0] == 'sample' %}
|
||||||
|
<a href="{{ '/sample/?sample=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
||||||
|
{% elsif categoria[0] == 'plugin' %}
|
||||||
|
<a href="{{ '/plugin/?plugin=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
||||||
|
{% elsif categoria[0] == 'automation' %}
|
||||||
|
<a href="{{ '/automation/?automation=' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ '/' | append: tag_slug | relative_url }}" class="tag is-info is-light">{{ valor }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
{% endunless %}
|
||||||
|
{% endif %}
|
||||||
|
{% if page.tracks and page.tracks.size > 0 %}
|
||||||
|
<section class="instruments-section">
|
||||||
|
<h2 class="title is-5"><code>🎚️ Instrumentos</h2></code>
|
||||||
|
<div class="content">
|
||||||
|
<ul style="list-style: none; padding-left: 0;">
|
||||||
|
{% for track in page.tracks %}
|
||||||
|
{% assign tem_instr = false %}
|
||||||
|
{% if track.instruments and track.instruments.size > 0 %}
|
||||||
|
{% assign tem_instr = true %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if track.bassline_name or tem_instr %}
|
||||||
|
<li class="mb-5">
|
||||||
|
{% if track.bassline_name %}
|
||||||
|
<p class="has-text-weight-bold mb-2">🎼 {{ track.bassline_name }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if tem_instr %}
|
||||||
|
<ul class="pl-4">
|
||||||
|
{% for instrument in track.instruments %}
|
||||||
|
{% if instrument.instrument_name %}
|
||||||
|
<li style="margin-bottom: 0.4rem;">
|
||||||
|
{% assign instrument_slug = instrument.instrument_name | replace: ' ', '+' %}
|
||||||
|
<a href="{{ '/instruments/?instrument=' | append: instrument_slug | relative_url }}" class="tag is-info is-light">
|
||||||
|
<code>{{ instrument.instrument_name }}</code>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% if instrument.audiofileprocessor and instrument.audiofileprocessor.src %}
|
||||||
|
{% assign audio_filename_with_path = 'src/samples/' | append: instrument.audiofileprocessor.src %}
|
||||||
|
<div class="audio-player-section mt-3">
|
||||||
|
<audio controls>
|
||||||
|
<source
|
||||||
|
src="{{ audio_filename_with_path | relative_url }}"
|
||||||
|
type="audio/ogg"
|
||||||
|
>
|
||||||
|
|
||||||
|
{% assign wav_path = audio_filename_with_path | replace: '.ogg', '.wav' %}
|
||||||
|
<source
|
||||||
|
src="{{ wav_path | relative_url }}"
|
||||||
|
type="audio/wav"
|
||||||
|
>
|
||||||
|
|
||||||
|
Seu navegador não suporta o elemento <code>audio</code>.
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
</div> <div class="column is-one-third">
|
||||||
|
<div class="box p-4 has-background-info-light">
|
||||||
|
<h3 class="title is-6 has-text-info mb-3">🛠️ Abra na Criação Colaborativa</h3>
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
CONSTRUÇÃO DA URL:
|
||||||
|
1. Usa o arquivo fonte (`page.file`) como parâmetro `project`.
|
||||||
|
2. Assume que a plataforma de criação está em `/creations/`.
|
||||||
|
3. Abre em uma nova aba (`target="_blank"`).
|
||||||
|
{% endcomment %}
|
||||||
|
{% assign creation_url = '/creations/?project=' | append: page.file | relative_url %}
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="{{ creation_url }}"
|
||||||
|
target="_blank"
|
||||||
|
class="button is-info is-fullwidth is-medium mb-4"
|
||||||
|
>
|
||||||
|
<span class="icon"><i class="fa-solid fa-up-right-from-square"></i></span>
|
||||||
|
<span>Abrir no MMPCreator</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<p class="is-size-7 has-text-grey-dark">
|
||||||
|
O link abrirá o projeto em uma nova aba para edição.
|
||||||
|
<br>
|
||||||
|
Arquivo: <code>{{ page.file }}</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-4 is-hidden-mobile">
|
||||||
|
<h4 class="title is-7 has-text-grey-dark">Prévia (Embed)</h4>
|
||||||
|
{% comment %}
|
||||||
|
A prévia embutida é opcional e pode ser um pouco pesada.
|
||||||
|
Ajuste o caminho da URL e o estilo (altura) conforme necessário.
|
||||||
|
{% endcomment %}
|
||||||
|
<iframe
|
||||||
|
src="{{ creation_url }}"
|
||||||
|
title="Prévia do Projeto"
|
||||||
|
style="width: 100%; height: 300px; border: 1px solid #ccc; border-radius: 4px;"
|
||||||
|
>
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> </div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,6 +25,22 @@ import { sendAction, joinRoom, setUserName } from "./socket.js";
|
|||||||
const ROOM_NAME = new URLSearchParams(window.location.search).get("room");
|
const ROOM_NAME = new URLSearchParams(window.location.search).get("room");
|
||||||
window.ROOM_NAME = ROOM_NAME;
|
window.ROOM_NAME = ROOM_NAME;
|
||||||
|
|
||||||
|
const PROJECT_NAME = new URLSearchParams(window.location.search).get("project");
|
||||||
|
|
||||||
|
if (PROJECT_NAME) {
|
||||||
|
// O nome do projeto deve corresponder ao arquivo no servidor, por ex: "mmp/nome-do-seu-projeto-salvo.mmp"
|
||||||
|
// O arquivo 'file.js' já espera que loadProjectFromServer receba apenas o nome
|
||||||
|
// do arquivo dentro da pasta 'mmp/' (ex: 'nome-do-projeto.mmp').
|
||||||
|
console.log(`[MAIN] Carregando projeto do servidor: ${PROJECT_NAME}`);
|
||||||
|
// Adicione a extensão se ela não estiver no link
|
||||||
|
const filename = PROJECT_NAME.endsWith('.mmp') || PROJECT_NAME.endsWith('.mmpz')
|
||||||
|
? PROJECT_NAME
|
||||||
|
: `${PROJECT_NAME}.mmp`;
|
||||||
|
|
||||||
|
// Chama a função de file.js para carregar (que já envia a ação 'LOAD_PROJECT')
|
||||||
|
loadProjectFromServer(filename);
|
||||||
|
}
|
||||||
|
|
||||||
// ✅ NOVO: se tem sala na URL, entra já na sala (independe do áudio)
|
// ✅ NOVO: se tem sala na URL, entra já na sala (independe do áudio)
|
||||||
|
|
||||||
if (ROOM_NAME) {
|
if (ROOM_NAME) {
|
||||||
|
|||||||
@@ -518,6 +518,27 @@ io.on("connection", (socket) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- ENDPOINT DE NOTIFICAÇÃO EXTERNA ---
|
||||||
|
app.post("/notify-update", express.json(), (req, res) => {
|
||||||
|
const { updateType } = req.body;
|
||||||
|
|
||||||
|
if (updateType === "samples") {
|
||||||
|
// 1. Emitir o evento para TODAS as salas/clientes.
|
||||||
|
// O evento deve ser algo que seu ui.js entenda.
|
||||||
|
io.emit("system_update", {
|
||||||
|
type: "RELOAD_SAMPLES",
|
||||||
|
message: "Novo Sample/Project adicionado. Recarregando o navegador de arquivos...",
|
||||||
|
});
|
||||||
|
console.log(
|
||||||
|
"[Notificação] Evento 'RELOAD_SAMPLES' emitido para todos os clientes."
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({ success: true, message: "Notificação de Samples/Projetos enviada." });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(400).send({ success: false, message: "updateType inválido." });
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/", (req, res) => {
|
app.get("/", (req, res) => {
|
||||||
res.send(
|
res.send(
|
||||||
"Servidor Backend V6 (Logs Dinâmicos) da DAW colaborativa está no ar!"
|
"Servidor Backend V6 (Logs Dinâmicos) da DAW colaborativa está no ar!"
|
||||||
|
|||||||
@@ -165,6 +165,18 @@ socket.on("connect_error", (err) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("system_update", (data) => {
|
||||||
|
if (data.type === "RELOAD_SAMPLES") {
|
||||||
|
console.log(`[System Update] Recebida ordem para recarregar samples: ${data.message}`);
|
||||||
|
|
||||||
|
// Certifique-se de que esta função existe e faz o que é esperado:
|
||||||
|
// 1. Fetch dos novos manifestos (metadata/samples-manifest.json etc.)
|
||||||
|
// 2. Renderiza a interface do navegador de samples
|
||||||
|
loadAndRenderSampleBrowser();
|
||||||
|
}
|
||||||
|
// Se houver outras notificações, adicione-as aqui (ex: RELOAD_PROJECTS)
|
||||||
|
});
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// RECEBER ESTADO SALVO DA SALA
|
// RECEBER ESTADO SALVO DA SALA
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -803,4 +815,4 @@ async function handleActionBroadcast(action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXPORTS
|
// EXPORTS
|
||||||
export { socket };
|
export { socket };
|
||||||
@@ -0,0 +1,773 @@
|
|||||||
|
{
|
||||||
|
"basses": {
|
||||||
|
"bass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bass_acid01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bass_acid02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bass_hard01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bass_hard02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bass_punch01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"horror_bass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"matrix1000_pluck01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_bass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_bass02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_bass04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"synth_acid01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"synth_acid02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_synth01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bassloops": {
|
||||||
|
"briff01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_bass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_bass02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tb303_01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_bass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_bass02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_synth01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_synth02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_synth03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"techno_synth04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"beats": {
|
||||||
|
"909beat01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"break01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"break02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"break03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"electro_beat01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"electro_beat02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"house_loop01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"jungle01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_hihat01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_hihat02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_kick01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_kick02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_snare01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drums": {
|
||||||
|
"bassdrum01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bassdrum02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bassdrum03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bassdrum04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bassdrum_acoustic01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bassdrum_acoustic02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"clap01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"clap02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"clap03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"clap04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"clav01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"clav02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"crash01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"crash02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_closed01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_closed02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_closed03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_closed04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_closed05.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_foot_pedal01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_opened01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_opened02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hihat_opened03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_distorted01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_hard01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_hardcore01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_hiphop01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_long01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_soft01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"kick_soft02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"nasty_bass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"nasty_rim01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"nasty_snare01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"ride01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"ride02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rim01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"shaker01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"shaker02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"shaker03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"sidestick01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare05.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare06.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare07.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_acoustic01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_electro01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_harsh01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_hiphop01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_hiphop02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_muffled01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_muffled02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_rim01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snare_short01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom05.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom_hi01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom_low01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"tom_mid01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"wood01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"zap01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"zap02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"zap03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drumsynth": {
|
||||||
|
"acoustic": {},
|
||||||
|
"cr78": {},
|
||||||
|
"cr8000": {},
|
||||||
|
"effects": {},
|
||||||
|
"electro": {},
|
||||||
|
"farfisa": {},
|
||||||
|
"ferraro": {},
|
||||||
|
"instrument": {},
|
||||||
|
"jorgensohn": {},
|
||||||
|
"latin": {},
|
||||||
|
"linn": {},
|
||||||
|
"magnetboy": {},
|
||||||
|
"misc": {},
|
||||||
|
"misc_bass": {},
|
||||||
|
"misc_claps": {},
|
||||||
|
"misc_electro": {},
|
||||||
|
"misc_fx": {},
|
||||||
|
"misc_hats": {},
|
||||||
|
"misc_perc": {},
|
||||||
|
"misc_synth": {},
|
||||||
|
"r_n_b": {},
|
||||||
|
"tr606": {},
|
||||||
|
"tr77": {},
|
||||||
|
"tr808": {},
|
||||||
|
"tr909": {}
|
||||||
|
},
|
||||||
|
"effects": {
|
||||||
|
"chroma_sound_effect01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"explode01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"filter_sweep01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"scratch01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"start01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"start02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"stop01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"warp01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"warp02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"wind_chimes01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instruments": {
|
||||||
|
"bassslap01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bassslap02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"cello01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"church_organ01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"church_organ02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"church_organ03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"church_organ04.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"e_organ01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"e_piano_accord01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"e_piano_accord02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"flute01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"harpsichord01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"piano01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"piano02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"steel_guitar01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"steel_guitar_heavy_distorted01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"steel_guitar_medium_distorted01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"steel_guitar_slight_distorted01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"trumpet01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"violin_double_stop01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"violin_fingered01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"violin_pizzicato01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"latin": {
|
||||||
|
"latin_brass01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"latin_guitar01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"latin_guitar02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"latin_guitar03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"misc": {
|
||||||
|
"applause01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bass!.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"breath01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"buzz!.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"dong01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"dong02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"dong03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"electric_ping01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hit01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"hit02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"metalish_dong01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"metronome01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"metronome02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"raving_crowd01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"snaph01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"undefined01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"samples": {
|
||||||
|
"reuniao_funkwhale.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shapes": {
|
||||||
|
"additive.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"additive2.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist2.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist3.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist4.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist5.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist6.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist7.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist8.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bunglist9.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"harmonics.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"low_sine.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"micro.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"moog.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"roundbass.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"roundsaw.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"saw+sine.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"sine_dist.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"smooth_inv_saw.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"smooth_inv_saw2.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"smooth_inv_saw_dist.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technobass.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technosynth1.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technosynth2.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technosynth3.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technosynth4.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technosynth5.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"technosynth6.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"vowel_a.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"vowel_u.wav": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stringsnpads": {
|
||||||
|
"bell_choir01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"bell_choir02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"chorus01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"chorus02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"heaven_strings01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"juno_pad01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"korg_poly6_drone01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"nord_ambient01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"orion_string01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"rave_choir01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"space_strings01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"space_strings02.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"space_strings03.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"strings01.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"waveforms": {
|
||||||
|
"10saw.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"10sine.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"10sqr.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"10tri.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"analogsqr.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"fmsaw1.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"fmsine.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"fmsine2.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"halfsine.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"impulse.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_quarter.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_sawdecay_quarter.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_sinedecay_quarter.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_triplet_half.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_triplet_half_2.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_triplet_quarter.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_whole.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"lfo_trancegate_whole_2.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"modsqr.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"saw1.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"saw2.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"sinesaw.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_addsyn.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_angrysaw.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_hexagon.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_invsine.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_invsineabs.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_invsinehalf.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_noisy.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_rad.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_sawsine.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_sharp.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
|
"w2_w-wave.flac": {
|
||||||
|
"_isFile": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+64
-21
@@ -8,6 +8,9 @@ from werkzeug.utils import secure_filename
|
|||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from watchdog.observers import Observer
|
from watchdog.observers import Observer
|
||||||
from watchdog.events import FileSystemEventHandler
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
import requests
|
||||||
|
|
||||||
|
NODE_SERVER_URL = "https://127.0.0.1:33001"
|
||||||
|
|
||||||
# --- Configurações (sem alterações) ---
|
# --- Configurações (sem alterações) ---
|
||||||
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||||
@@ -27,13 +30,16 @@ CONFIGS = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
UPLOAD_FOLDER = os.path.join(PROJECT_ROOT, "src", "samples", "samples")
|
UPLOAD_FOLDER_SAMPLE = os.path.join(PROJECT_ROOT, "src", "samples", "samples")
|
||||||
WATCH_FOLDER = os.path.join(PROJECT_ROOT, "src", "samples") # Pasta a ser vigiada
|
WATCH_FOLDER_SAMPLE = UPLOAD_FOLDER_SAMPLE # Pasta a ser vigiada
|
||||||
|
UPLOAD_FOLDER_PROJECT = os.path.join(PROJECT_ROOT, "src", "samples", "projects")
|
||||||
|
WATCH_FOLDER_PROJECT = os.path.join(PROJECT_ROOT, "src", "upload_projects") # Pasta a ser vigiada
|
||||||
|
|
||||||
ALLOWED_EXTENSIONS = {'wav', 'ogg', 'flac', 'mp3'}
|
ALLOWED_EXTENSIONS = {'wav', 'ogg', 'flac', 'mp3'}
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app, origins=["https://alice.ufsj.edu.br", "http://localhost:8000", "http://127.0.0.1:5500"])
|
CORS(app, origins=["https://alice.ufsj.edu.br", "https://alice.ufsj.edu.br:33002"])
|
||||||
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
app.config['UPLOAD_FOLDER_SAMPLE'] = UPLOAD_FOLDER_SAMPLE
|
||||||
|
|
||||||
# --- Funções do Gerador de Manifesto (sem alterações) ---
|
# --- Funções do Gerador de Manifesto (sem alterações) ---
|
||||||
def scan_directory_tree(path):
|
def scan_directory_tree(path):
|
||||||
@@ -75,9 +81,27 @@ def run_jekyll_build():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERRO inesperado durante o Jekyll build: {e}")
|
print(f"ERRO inesperado durante o Jekyll build: {e}")
|
||||||
|
|
||||||
|
def notify_node_server(update_type):
|
||||||
|
"""Envia uma notificação HTTP para o servidor Node.js."""
|
||||||
|
try:
|
||||||
|
url = f"{NODE_SERVER_URL}/notify-update"
|
||||||
|
headers = {'Content-Type': 'application/json'}
|
||||||
|
payload = {"updateType": update_type}
|
||||||
|
|
||||||
|
# O argumento 'verify=False' é geralmente necessário ao usar 127.0.0.1
|
||||||
|
# com certificados Let's Encrypt (ou autoassinados) para evitar erros de SSL.
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
print(f"[Notificação] Sucesso ao notificar Node.js: {update_type}")
|
||||||
|
else:
|
||||||
|
print(f"[Notificação] ERRO ao notificar Node.js ({response.status_code}): {response.text}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Notificação] ERRO de conexão com o Node.js em {NODE_SERVER_URL}: {e}")
|
||||||
|
|
||||||
def generate_manifests():
|
def generate_manifests():
|
||||||
print("\nIniciando geração de arquivos de manifesto...")
|
print("\nIniciando geração de arquivos de manifesto...")
|
||||||
# ... (lógica interna sem alterações) ...
|
|
||||||
for config in CONFIGS:
|
for config in CONFIGS:
|
||||||
source_dir_abs = os.path.join(PROJECT_ROOT, config["source_dir"])
|
source_dir_abs = os.path.join(PROJECT_ROOT, config["source_dir"])
|
||||||
output_file_abs = os.path.join(PROJECT_ROOT, config["output_file"])
|
output_file_abs = os.path.join(PROJECT_ROOT, config["output_file"])
|
||||||
@@ -93,8 +117,10 @@ def generate_manifests():
|
|||||||
print(f"SUCESSO: Arquivo '{output_file_abs}' gerado!")
|
print(f"SUCESSO: Arquivo '{output_file_abs}' gerado!")
|
||||||
print("\nGeração de manifestos concluída.")
|
print("\nGeração de manifestos concluída.")
|
||||||
run_jekyll_build()
|
run_jekyll_build()
|
||||||
|
# 2. NOTIFICA O SERVIDOR NODE.JS (NOVO PASSO)
|
||||||
|
notify_node_server("samples")
|
||||||
|
|
||||||
# --- Lógica do Servidor Flask (sem alterações) ---
|
# --- Servidor Flask ---
|
||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
@@ -105,41 +131,58 @@ def upload_file():
|
|||||||
if file.filename == '': return jsonify({"error": "Nenhum arquivo selecionado"}), 400
|
if file.filename == '': return jsonify({"error": "Nenhum arquivo selecionado"}), 400
|
||||||
if file and allowed_file(file.filename):
|
if file and allowed_file(file.filename):
|
||||||
filename = secure_filename(file.filename)
|
filename = secure_filename(file.filename)
|
||||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
os.makedirs(app.config['UPLOAD_FOLDER_SAMPLE'], exist_ok=True)
|
||||||
save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
save_path = os.path.join(app.config['UPLOAD_FOLDER_SAMPLE'], filename)
|
||||||
try:
|
try:
|
||||||
file.save(save_path)
|
file.save(save_path)
|
||||||
generate_manifests()
|
return jsonify({"success": True, "message": f"Arquivo '{filename}' salvo!"}), 200
|
||||||
return jsonify({"success": True, "message": f"Arquivo '{filename}' salvo e site atualizado!"}), 200
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
return jsonify({"error": "Tipo de arquivo não permitido"}), 400
|
return jsonify({"error": "Tipo de arquivo não permitido"}), 400
|
||||||
|
|
||||||
# --- NOVO: LÓGICA DO "VIGIA" DE ARQUIVOS (WATCHDOG) ---
|
# --- LÓGICA DO "VIGIA" DE ARQUIVOS (WATCHDOG) ---
|
||||||
|
|
||||||
class ManifestEventHandler(FileSystemEventHandler):
|
class ManifestEventHandler(FileSystemEventHandler):
|
||||||
"""Um manipulador de eventos que gera os manifestos quando um arquivo muda."""
|
"""Um manipulador de eventos que gera os manifestos quando um arquivo muda."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
# Inicializa o timestamp da última execução
|
||||||
self.last_triggered = 0
|
self.last_triggered = 0
|
||||||
|
# Define o intervalo mínimo entre execuções (5 segundos)
|
||||||
|
self.debounce_interval = 5
|
||||||
|
|
||||||
def on_any_event(self, event):
|
def on_any_event(self, event):
|
||||||
# Desconsidera eventos em diretórios
|
# Ignora eventos em diretórios ou no arquivo de manifesto de saída (evita loop)
|
||||||
if event.is_directory:
|
if event.is_directory or "manifest" in event.src_path:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Mecanismo simples para evitar múltiplas execuções seguidas (debounce)
|
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
if current_time - self.last_triggered > 5: # Espera 5 segundos entre as atualizações
|
|
||||||
|
# Verifica se passou tempo suficiente desde o último acionamento
|
||||||
|
if current_time - self.last_triggered > self.debounce_interval:
|
||||||
print(f"\n[VIGIA] Mudança detectada: {event.src_path}")
|
print(f"\n[VIGIA] Mudança detectada: {event.src_path}")
|
||||||
generate_manifests()
|
|
||||||
|
# Executa a geração de manifestos (e o Jekyll build, se descomentado)
|
||||||
|
# É crucial que generate_manifests() seja rápido ou executado em outra thread separada
|
||||||
|
# para não bloquear o Watchdog por muito tempo.
|
||||||
|
Thread(target=generate_manifests).start()
|
||||||
|
|
||||||
self.last_triggered = current_time
|
self.last_triggered = current_time
|
||||||
|
else:
|
||||||
|
print(f"[VIGIA] Mudança ignorada devido ao debounce (Intervalo de {self.debounce_interval}s).")
|
||||||
|
|
||||||
def start_file_watcher():
|
def start_file_watcher():
|
||||||
"""Inicia o observador de arquivos em uma thread separada."""
|
"""Inicia o observador de arquivos para ambas as pastas em uma thread separada."""
|
||||||
print(f"\n[VIGIA] Iniciando monitoramento da pasta: {WATCH_FOLDER}")
|
|
||||||
event_handler = ManifestEventHandler()
|
event_handler = ManifestEventHandler()
|
||||||
observer = Observer()
|
observer = Observer()
|
||||||
observer.schedule(event_handler, WATCH_FOLDER, recursive=True)
|
|
||||||
|
# 1. Monitorar a pasta de Samples
|
||||||
|
print(f"\n[VIGIA] Monitorando Samples: {WATCH_FOLDER_SAMPLE}")
|
||||||
|
observer.schedule(event_handler, WATCH_FOLDER_SAMPLE, recursive=True)
|
||||||
|
|
||||||
|
# 2. Monitorar a pasta de Projetos
|
||||||
|
print(f"[VIGIA] Monitorando Projetos: {WATCH_FOLDER_PROJECT}")
|
||||||
|
observer.schedule(event_handler, WATCH_FOLDER_PROJECT, recursive=True)
|
||||||
|
|
||||||
observer.start()
|
observer.start()
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
@@ -160,4 +203,4 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# Inicia o servidor Flask (thread principal)
|
# Inicia o servidor Flask (thread principal)
|
||||||
print("\n[FLASK] Iniciando servidor de upload...")
|
print("\n[FLASK] Iniciando servidor de upload...")
|
||||||
app.run(host='0.0.0.0', port=5000, debug=False) # Debug mode deve ser False para evitar que rode duas vezes
|
app.run(host='0.0.0.0', port=33002, debug=True) # Debug mode deve ser False para evitar que rode duas vezes
|
||||||
Reference in new issue
Block a user