diff --git a/.gitignore b/.gitignore index c8a6d38c..19775a60 100755 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ venv .gitea src assets/js/creations/server/data -_data diff --git a/_config.yml b/_config.yml index 5f715c59..fb0929e5 100755 --- a/_config.yml +++ b/_config.yml @@ -9,19 +9,19 @@ url: "https://alice.ufsj.edu.br/" # the base hostname & protocol for your site, theme: alice -#plugins: -# - jekyll-datapage-generator +plugins: + - jekyll-datapage-generator -#page_gen-dirs: true +page_gen-dirs: true -#page_gen: -# - data: all_leve -# template: projetos -# dir: projetos -# index_files: false -# title: file -# name: file -# debug: false +page_gen: + - data: all_leve + template: projetos + dir: projetos + index_files: false + title: file + name: file + debug: false # Configuração do datapage_gen: #page_gen: @@ -51,9 +51,9 @@ exclude: - Gemfile - Gemfile.lock - assets/js/creations/server/node_modules - - vendor/ # Ignora toda a pasta vendor de uma vez - - scripts/ # Seus scripts Python não vão para o HTML - - venv/ # Se você tiver um ambiente virtual Python aí dentro - # - "*.db" # Ignora bancos de dados do SQLite (como o users.db) + - vendor/ + - scripts/ + - venv/ + # - "*.db" - mmp/instruments/lmms/presets/ZynAddSubFX - - _data + #- _data diff --git a/_layouts/projetos.html b/_layouts/projetos.html index 9f692a2d..03265b55 100755 --- a/_layouts/projetos.html +++ b/_layouts/projetos.html @@ -1,119 +1,580 @@ --- layout: default -title: "Detalhes do Projeto" +title: "{{ page.file }}" --- -
-
- +
+
+
+ +
+ {% include sidebar.html %} +
+ +
+
+

+ {{ page.file }} +

+ {% if page.bpm %} + 🎵 {{ page.bpm }} + {% endif %} +
+ + {% if page.file %} +
+ {% assign creation_url = '/mmpSearch/creation.html?project=' | append: + page.file %} {% assign embed_url = creation_url | append: '&embed=true' + %} + + + +
+ +
+ Preview: +
+ {% assign audio_file_path = 'src_mmpSearch/wav/' | append: page.file + | append: '.ogg' %} + +
+
+
+ {% endif %} +
+ +
+
+ {% if page.tags %} {% assign tags_vazias = true %} {% for categoria in + page.tags %} {% if categoria[1] and categoria[1].size > 0 %}{% assign + tags_vazias = false %}{% endif %} {% endfor %} {% unless tags_vazias %} +
+ +

+ 🏷️ Tags do Projeto +

+ +
+
+ {% for categoria in page.tags %} {% if categoria[1] and + categoria[1].size > 0 %} +
+ {{ categoria[0] }}: +
+ {% for valor in categoria[1] %} {% if valor != "" %} {% assign + tag_slug = valor | replace: ' ', '+' %} {% if categoria[0] == + 'bassline' %} + {{ valor }} + {% elsif categoria[0] == 'sample' %} + {{ valor }} + {% elsif categoria[0] == 'plugin' %} + {{ valor }} + {% elsif categoria[0] == 'automation' %} + {{ valor }} + {% else %} + {{ valor }} + {% endif %} {% endif %} {% endfor %} +
+
+ {% endif %} {% endfor %} +
+
+ {% endunless %} {% endif %} {% if page.tracks and page.tracks.size > 0 + %} +
+ +

+ 🎚️ Instrumentos & Padrões +

+ +
+
+ {% for track in page.tracks %} {% if track.instruments and + track.instruments.size > 0 %} +
+
+ 📂 {{ track.bassline_name }} +
+ +
+ {% for instrument in track.instruments %} +
+ {% include _instrument_logic_inline.html %} +
+ {% endfor %} +
+ + {% elsif track.instrument_name %} {% assign instrument = track %} + +
+ {% include _instrument_logic_inline.html %} +
+ {% endif %} {% endfor %} +
+
+
+ {% endif %} +
+ +
+
+

+ 🛠️ Abra na Criação Colaborativa +

+ + {% assign creation_url = '/mmpSearch/creation.html?project=' | append: + page.file %} + + + Abrir no MMPCreator + + + +

+ O link abrirá o projeto em uma nova aba para edição. +
+ Arquivo: {{ page.file }} +

+ +
+
+

Prévia do Editor:

+ {% assign embed_url = creation_url | append: '&embed=true' %} + +
+
+
+
+ +
+{% capture instrument_logic %} {% assign plugin_name = +instrument.instrument_name | downcase %} {% assign is_sample = false %} {% +assign sample_src = "" %} {% if plugin_name == 'audiofileprocessor' or +instrument.audiofileprocessor %} {% assign is_sample = true %} {% assign +sample_src = instrument.audiofileprocessor.src | default: "" | strip %} {% endif +%} {% assign should_open = false %} {% if is_sample == false %} {% assign +should_open = true %} {% elsif is_sample == true and sample_src != "" %} {% +assign should_open = true %} {% endif %} + +
+
  • +
    + +
    + {% assign display_name = instrument.instrument_name %} {% if is_sample + %} {% if display_name contains "audiofileprocessor" and + instrument.patterns %} {% assign first_pattern_name = + instrument.patterns | map: 'name' | first %} {% if first_pattern_name + and first_pattern_name != empty %} {% assign display_name = + first_pattern_name | remove: ".ogg" | remove: ".ogg" | remove: ".flac" + | remove: ".mp3" %} {% elsif instrument.audiofileprocessor.src %} {% + assign src_parts = instrument.audiofileprocessor.src | split: '/' %} + {% assign file_name = src_parts | last %} {% assign display_name = + file_name | remove: ".ogg" | remove: ".ogg" | remove: ".flac" | + remove: ".mp3" %} {% endif %} {% endif %} {% endif %} {% assign + instrument_slug = display_name | replace: ' ', '+' %} + + {{ display_name }} + {% unless is_sample %} + (Synth 🎹){% + endunless %} + +
    +
    + + {% for pattern in instrument.patterns %} {% assign pattern_steps = + pattern.steps %} {% if pattern_steps and pattern_steps.size > 0 %} +
    + {% assign bassline_index = forloop.index | minus: 1 %} {% if + track.bassline_name %} + {{ bassline_index }}: + {% endif %} + +
    + {% assign total_steps = pattern_steps.size %} {% assign chunk_size = 4 + %} {% assign num_chunks = total_steps | divided_by: chunk_size %} {% + assign remainder = total_steps | modulo: chunk_size %} {% if remainder + > 0 %}{% assign num_chunks = num_chunks | plus: 1 %}{% endif %} {% for + i in (0..num_chunks) %} {% assign start_index = i | times: chunk_size + %} {% assign current_chunk_array = pattern_steps | slice: start_index, + chunk_size %} {% if current_chunk_array.size > 0 %} {% assign + chunk_string = "" %} {% for step in current_chunk_array %} {% if step + == true or step == 'true' or step == 1 %} {% assign chunk_string = + chunk_string | append: '1' %} {% else %} {% assign chunk_string = + chunk_string | append: '0' %} {% endif %} {% endfor %} {% assign + search_url = '/pattern/?p=' | append: chunk_string | relative_url %} + +
    + {% for step_active in current_chunk_array %} {% assign step_color + = '#e0e0e0' %} {% if step_active == true or step_active == 'true' + or step_active == 1 %} {% assign step_color = '#4caf50' %} {% + endif %} +
    + {% endfor %} +
    +
    + {% endif %} {% endfor %} +
    +
    + {% endif %} {% endfor %} +
    + +
    + {% if is_sample %} {% if sample_src != "" %} {% assign + audio_filename_with_path = 'src/samples/' | append: sample_src %} + + {% else %} +

    O sample **não foi enviado** 😢

    + {% endif %} {% else %} + + Via Web Audio API + {% endif %} +
    +
  • +
    +{% endcapture %} + + + + + diff --git a/pages/projetos.html b/pages/projetos.html index c6777858..1acb26ee 100755 --- a/pages/projetos.html +++ b/pages/projetos.html @@ -4,321 +4,1056 @@ title: MMPSearch - Projetos permalink: /projetos/ --- +{% assign list_bpm = "" %} +{% assign list_plugins = "" %} +{% assign list_instruments = "" %} +{% assign list_samples = "" %} +{% assign list_bassline = "" %} +{% assign list_automation = "" %} + +{% for p in site.data.all %} + {% assign raw_bpm = p.bpm | append: "" %} + {% if raw_bpm != "" and raw_bpm != "N/A" and raw_bpm != "nil" %} + {% assign list_bpm = list_bpm | append: raw_bpm | append: "|||" %} + {% endif %} + + {% for item in p.tags.plugin %}{% if item != "" %}{% assign list_plugins = list_plugins | append: item | append: "|||" %}{% endif %}{% endfor %} + {% if p.tags.bassline %}{% for item in p.tags.bassline %}{% if item != "" %}{% assign list_bassline = list_bassline | append: item | append: "|||" %}{% endif %}{% endfor %}{% endif %} + {% if p.tags.automation %}{% for item in p.tags.automation %}{% if item != "" %}{% assign list_automation = list_automation | append: item | append: "|||" %}{% endif %}{% endfor %}{% endif %} + + {% for track in p.tracks %} + {% if track.instruments %}{% for inst in track.instruments %}{% if inst.instrument_name %}{% assign list_instruments = list_instruments | append: inst.instrument_name | append: "|||" %}{% endif %}{% endfor %} + {% elsif track.instrument_name %}{% assign list_instruments = list_instruments | append: track.instrument_name | append: "|||" %}{% endif %} + {% if track.sample %}{% for smp in track.sample %}{% assign list_samples = list_samples | append: smp.sample_name | append: "|||" %}{% endfor %} + {% elsif track.sample_name %}{% assign list_samples = list_samples | append: track.sample_name | append: "|||" %}{% endif %} + {% endfor %} +{% endfor %} + +{% assign unique_bpm_array = list_bpm | split: "|||" | uniq | sort %} +{% assign unique_plugins = list_plugins | split: "|||" | uniq | sort %} +{% assign unique_instruments = list_instruments | split: "|||" | uniq | sort %} +{% assign unique_samples = list_samples | split: "|||" | uniq | sort %} +{% assign unique_bassline = list_bassline | split: "|||" | uniq | sort %} +{% assign unique_automation = list_automation | split: "|||" | uniq | sort %} + +{% assign min_limit = 0 %} +{% assign max_limit = 300 %} +{% if unique_bpm_array.size > 0 %} + {% assign last_bpm = unique_bpm_array | last | plus: 0 %} + {% if last_bpm > max_limit %}{% assign max_limit = last_bpm %}{% endif %} +{% endif %} +

    +
    {% include sidebar.html %}
    -
    -

    📁 Projetos Disponíveis

    -
    -
    -
    -
    -
    - -
    -
    -
    - -
    +
    +

    📁 Projetos Disponíveis

    +

    + Utilize os filtros laterais para refinar sua busca. +

    +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    + +
    +
    -
    +
    -
    -
    - -
    - - -
    +
    + +
    + +
    + + + + + +
    +
    +
    + +
    + 🥁 Pattern Rítmico +
    + +
    +
    +

    Desenhe o ritmo:

    + +

    Clique para ativar steps

    +
    +
    +
    +
    + Gêneros (IA) +
    + +
    + +
    +
    + +
    + Tom / Key +
    + +
    +
    + {% assign keys_list = "C,Cm,C#,C#m,Db,Dm,D,D#m,Eb,E,Em,F,Fm,F#,F#m,Gb,G,Gm,G#,Ab,A,Am,Bb,B,Bm" | split: "," %} + {% for key in keys_list %} + + {% endfor %} +
    +
    +
    + +
    + Faixa de BPM +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    + + {% assign filter_groups = "instruments|Instrumentos,plugins|Plugins,bassline|Bassline,automation|Automação,samples|Samples" | split: "," %} + {% for group in filter_groups %} + {% assign parts = group | split: "|" %} + {% assign cat_key = parts[0] %} + {% assign cat_label = parts[1] %} + +
    + {{ cat_label }} +
    + +
    +
    + {% assign current_list = "" %} + {% if cat_key == 'instruments' %}{% assign current_list = unique_instruments %} + {% elsif cat_key == 'plugins' %}{% assign current_list = unique_plugins %} + {% elsif cat_key == 'bassline' %}{% assign current_list = unique_bassline %} + {% elsif cat_key == 'automation' %}{% assign current_list = unique_automation %} + {% elsif cat_key == 'samples' %}{% assign current_list = unique_samples %} + {% endif %} + + {% for item in current_list %}{% if item != "" %} + + {% endif %}{% endfor %} +
    +
    +
    + {% endfor %} +
    -
    -
    - - 🥁 Pattern Rítmico - - -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    - Encontrados - 0 - projetos. -
    -
    - + + + +
    + {% assign project_pages = site.pages | where_exp: "page", "page.path contains 'projetos/'" | sort: "title" %} + {% for page in project_pages %} + {% if page.url != '/projetos/' %} + + {% assign raw_bpm = page.bpm | append: "" %} + {% if raw_bpm == "" or raw_bpm == "N/A" or raw_bpm == "nil" %}{% assign p_bpm = 0 %}{% else %}{% assign p_bpm = raw_bpm | plus: 0 %}{% endif %} + + {% assign p_insts_array = "" | split: "," %} + + {% assign project_patterns_flat = "" | split: "," %} + {% for track in page.tracks %} + {% if track.instruments %}{% for inst in track.instruments %}{% if inst.instrument_name %}{% assign p_insts_array = p_insts_array | push: inst.instrument_name %}{% endif %} + {% if inst.patterns %} + {% for pattern in inst.patterns %} + {% assign pattern_steps = pattern.steps %} + {% if pattern_steps and pattern_steps.size > 0 %} + {% assign chunk_string = "" %} + {% assign step_count = 0 %} + {% for step in pattern_steps %} + {% if step == true or step == 'true' or step == 1 %}{% assign chunk_string = chunk_string | append: '1' %}{% else %}{% assign chunk_string = chunk_string | append: '0' %}{% endif %} + {% assign step_count = step_count | plus: 1 %} + {% if step_count == 4 %} + {% unless project_patterns_flat contains chunk_string %} + {% assign project_patterns_flat = project_patterns_flat | push: chunk_string %} + {% endunless %} + {% assign chunk_string = "" %} + {% assign step_count = 0 %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% elsif track.instrument_name %}{% assign p_insts_array = p_insts_array | push: track.instrument_name %}{% endif %} + {% endfor %} + + {% assign p_patterns_str = project_patterns_flat | join: ',' %} + {% assign p_instruments_str = p_insts_array | uniq | join: ',' %} + {% assign p_plugins = page.tags.plugin | join: ',' %} + {% assign p_bassline = page.tags.bassline | join: ',' %} + {% assign p_automation = page.tags.automation | join: ',' %} + {% assign p_samples = page.tags.sample | join: ',' %} + {% assign p_name = page.title | default: page.name | downcase %} + +
    + +
    + +{% assign matching_beat = nil %} +{% if site.data.beats %} + {% assign proj_slug = page.file | slugify %} + {% for filename in site.data.beats %} + {% assign beat_slug = filename | remove: '.ogg' | remove: '.mp3' | slugify %} + {% if beat_slug == proj_slug %} + {% assign matching_beat = filename %} + {% break %} + {% endif %} + {% endfor %} +{% endif %} + + +
    + +
    + +
    + +

    +{{ page.title | default: page.name | replace: '.html', '' }} +

    + +
    +{% if p_bpm > 0 %} +🎵 {{ p_bpm }} BPM +{% else %} +⚠️ BPM N/A +{% endif %} +
    + +{% if matching_beat %} +
    + +
    +{% endif %} + +
    + +
    +{% assign unique_insts_page = p_insts_array | uniq | sort %} +{% if unique_insts_page.size > 0 %} +
    +
    🎸 INSTRUMENTS
    +
    +
    +{% endif %} + +{% assign has_patterns_display = false %} +{% capture patterns_html_content %} +
    + {% for track in page.tracks %} + {% if track.instruments %} + {% for inst in track.instruments %} + {% if inst.patterns %} + {% assign current_inst_patterns = "" | split: "," %} + {% for pattern in inst.patterns %} + {% assign p_steps = pattern.steps %} + {% if p_steps and p_steps.size > 0 %} + {% assign total_s = p_steps.size %} + {% assign n_chunks = total_s | divided_by: 4 %} + {% for i in (0..n_chunks) %} + {% assign idx = i | times: 4 %} + {% assign chunk = p_steps | slice: idx, 4 %} + {% if chunk.size > 0 %} + {% assign c_str = "" %} + {% for s in chunk %} + {% if s == true or s == 1 or s == 'true' %}{% assign c_str = c_str | append: "1" %}{% else %}{% assign c_str = c_str | append: "0" %}{% endif %} + {% endfor %} + {% if c_str != "0000" %} + {% unless current_inst_patterns contains c_str %} + {% assign current_inst_patterns = current_inst_patterns | push: c_str %} + {% endunless %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + + {% if current_inst_patterns.size > 0 %} + {% assign has_patterns_display = true %} +
    + + {{ inst.instrument_name | truncate: 12 }} + +
    + {% for pat in current_inst_patterns %} +
    + {% assign bits = pat | split: '' %} + {% for bit in bits %} +
    + {% endfor %} +
    + {% endfor %} +
    +
    + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} +
    +{% endcapture %} + +{% if has_patterns_display %} +
    + +
    🥁 RITMO
    + +
    +
    + {{ patterns_html_content }} +
    +
    +{% endif %} +{% if page.tags.plugin.size > 0 %} +
    +
    🔌 PLUGINS
    +
    +{% for tag in page.tags.plugin %}{% if tag != "" %} +{{ tag | truncate: 18 }} +{% endif %}{% endfor %} +
    +
    +{% endif %} + +{% if page.tags.bassline.size > 0 %} +
    +
    🎹 BASSLINE
    +
    +{% for tag in page.tags.bassline %}{% if tag != "" %} +{{ tag | truncate: 18 }} +{% endif %}{% endfor %} +
    +
    +{% endif %} + +{% if page.tags.automation.size > 0 %} +
    +
    🎚️ AUTOMATION
    +
    +{% for tag in page.tags.automation %}{% if tag != "" %} +{{ tag | truncate: 18 }} +{% endif %}{% endfor %} +
    +
    +{% endif %} + +{% if page.tags.sample.size > 0 %} +
    +
    🎤 SAMPLES
    +
    +{% for tag in page.tags.sample %}{% if tag != "" %} +{{ tag | truncate: 18 }} +{% endif %}{% endfor %} +
    +
    +{% endif %} +
    +
    + + +
    +Prévia +{% assign creation_url = '/mmpSearch/creation.html?project=' | append: page.file %} +{% assign embed_url = creation_url | append: '&embed=true' %} +Prévia do Editor +
    + +
    +
    +{% endif %} +{% endfor %} +
    + + +
    +{% include preview-modal.html %} + + // Checkboxes Init + checkboxes.forEach(cb => cb.addEventListener('change', updateActiveSidebar)); + + // Inputs de Busca + searchInput.addEventListener('input', (e) => { searchText = e.target.value.toLowerCase().trim(); applyGlobalFilters(); }); + clearInputBtn.addEventListener('click', () => { searchInput.value = ""; searchText = ""; applyGlobalFilters(); }); + + if(starFilterSelect) starFilterSelect.addEventListener('change', (e) => { currentMinStars = e.target.value; applyGlobalFilters(); }); + + if(sortSelect) sortSelect.addEventListener('change', (e) => { + const crit = e.target.value; + const cols = Array.from(projectsContainer.children); + cols.sort((a, b) => { + const getVal = (el, k) => parseFloat(el.getAttribute(k) || 0); + if(crit === 'stars_desc') return getVal(b, 'data-stars') - getVal(a, 'data-stars'); + if(crit === 'stars_asc') return getVal(a, 'data-stars') - getVal(b, 'data-stars'); + if(crit === 'bpm_desc') return getVal(b, 'data-bpm-real') - getVal(a, 'data-bpm-real'); + if(crit === 'intensity_desc') return getVal(b, 'data-intensity') - getVal(a, 'data-intensity'); + if(crit === 'intensity_asc') return getVal(a, 'data-intensity') - getVal(b, 'data-intensity'); + return a.getAttribute('data-title').localeCompare(b.getAttribute('data-title')); + }); + cols.forEach(c => projectsContainer.appendChild(c)); + }); + + // Botões Limpar Grupo + clearGroupBtns.forEach(btn => { + btn.addEventListener('click', (e) => { + e.preventDefault(); e.stopPropagation(); + const target = btn.dataset.target; + if(target === 'bpm') { + sliderMin.value = sliderMin.min; sliderMax.value = sliderMax.max; updateSlider(); + } else if (target === 'pattern') { + searchSteps.forEach(s => s.classList.remove('is-active')); + updatePatternChunks(); + applyGlobalFilters(); + } else { + document.querySelectorAll(`.filter-checkbox[data-category="${target}"]`).forEach(cb => { + cb.checked = false; + if(cb.parentElement.classList.contains('tag')) cb.parentElement.classList.remove('is-checked'); + }); + updateActiveSidebar(); + } + }); + }); + + resetBtn.addEventListener('click', () => { + document.querySelectorAll('.filter-checkbox').forEach(cb => { cb.checked = false; cb.parentElement.classList.remove('is-checked'); }); + searchInput.value = ""; searchText = ""; + searchSteps.forEach(s => s.classList.remove('is-active')); + updatePatternChunks(); + sliderMin.value = sliderMin.min; sliderMax.value = sliderMax.max; updateSlider(); + starFilterSelect.value = 'all'; currentMinStars = 'all'; sortSelect.value = 'default'; + updateActiveSidebar(); + }); + + + // --- 4. ENRIQUECIMENTO DOS CARDS COM JSON (FETCH) --- + const JSON_URL = '/mmpSearch/src_mmpSearch/saida_analises/db_final_completo.json'; + + fetch(JSON_URL) + .then(r => r.ok ? r.json() : []) + .then(data => { + enrichCards(data); + createGenreCheckboxes(data); + + // Recalcula limites de BPM com base no JSON + const bpms = data.map(i => parseFloat(i.analise_tecnica?.bpm || 0)).filter(b => b > 0); + if(bpms.length > 0) { + const maxData = Math.ceil(Math.max(...bpms)); + if(maxData > parseInt(sliderMax.max)) { + sliderMax.max = maxData; + inputMax.max = maxData; + sliderMin.max = maxData; + inputMin.max = maxData; + } + } + // Aplica filtros pela primeira vez APÓS carregar dados + applyGlobalFilters(); + }) + .catch(console.warn); + + function normalizarChaveJS(str) { + if (!str) return ""; + return str.toString().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, ""); + } + + function renderizarDificuldade(num) { + const n = Math.round(num) || 1; + let label = "Básico", icon = "fa-leaf", color = "is-success"; + if (n >= 4.5) { label = "Expert"; icon = "fa-fire"; color = "is-danger"; } + else if (n >= 3.5) { label = "Avançado"; icon = "fa-bolt"; color = "is-warning"; } + else if (n >= 2.5) { label = "Médio"; icon = "fa-layer-group"; color = "is-info"; } + return ` ${label}`; + } + + function enrichCards(data) { + const mapDados = {}; + data.forEach(item => { + if(item.arquivo) mapDados[normalizarChaveJS(item.arquivo.replace('.ogg','').replace('.mp3',''))] = item; + if(item.dados_projeto?.titulo) mapDados[normalizarChaveJS(item.dados_projeto.titulo)] = item; + }); + + document.querySelectorAll('.project-item').forEach(item => { + const card = item.querySelector('.project-card'); + const titleKey = normalizarChaveJS(item.getAttribute('data-title')); + const info = mapDados[titleKey]; + + let genero = "Unknown", subgeneros = [], estrelas = 0, intensidade = -100, bpm = 0, tomHtml = "", tomRaw = "all", subTagsHTML = ""; + + if (info) { + if (info.analise_ia) { + genero = info.analise_ia.genero_macro || "Unknown"; + if (Array.isArray(info.analise_ia.nuvem_tags)) { + info.analise_ia.nuvem_tags.forEach(t => { if(t.tag) subgeneros.push(t.tag); }); + info.analise_ia.nuvem_tags.slice(0, 2).forEach(t => { + subTagsHTML += `#${t.tag}`; + }); + } + } + if (info.analise_tecnica) { + intensidade = parseFloat(info.analise_tecnica.intensidade_db || -100); + bpm = parseFloat(info.analise_tecnica.bpm || 0); + estrelas = Math.round(info.analise_tecnica.complexidade?.estrelas || 0); + if (info.analise_tecnica.tom) { + const t = info.analise_tecnica.tom; + const e = info.analise_tecnica.escala === 'minor' ? 'm' : ''; + tomRaw = t + e; + tomHtml = `🎹 ${tomRaw}`; + } + } + } + + item.setAttribute('data-genre', genero); + item.setAttribute('data-subgenres', subgeneros.join(',').toLowerCase()); + item.setAttribute('data-stars', estrelas); + item.setAttribute('data-intensity', intensidade); + item.setAttribute('data-key', tomRaw); + + if(bpm > 0) { + item.setAttribute('data-bpm-real', bpm); + if(item.getAttribute('data-bpm') == "0") item.setAttribute('data-bpm', Math.round(bpm)); + } + + const bpmContainer = card.querySelector('.bpm-container'); + if(bpmContainer) { + let bpmDisplay = ""; + if(bpm > 0) { + bpmDisplay = `🎵 ${Math.round(bpm)} BPM`; + } else if (item.getAttribute('data-bpm') != "0") { + bpmDisplay = bpmContainer.innerHTML; + } else { + bpmDisplay = `⚠️ BPM N/A`; + } + + let newHtml = `
    `; + newHtml += `
    ${renderizarDificuldade(estrelas)}
    `; + newHtml += `
    `; + if(genero !== "Unknown") { + let c = 'is-primary'; + if(genero === 'Electronic') c = 'is-info'; + if(genero === 'Hip Hop') c = 'is-warning'; + if(genero === 'Rock') c = 'is-danger'; + newHtml += `🤖 ${genero}`; + } + newHtml += tomHtml; + newHtml += `
    `; + if(subTagsHTML) newHtml += `
    ${subTagsHTML}
    `; + newHtml += `
    `; + + bpmContainer.innerHTML = bpmDisplay + newHtml; + } + }); + } + + function createGenreCheckboxes(data) { + const genres = new Set(); + data.forEach(i => { + if(i.analise_ia?.genero_macro && i.analise_ia.genero_macro !== "Unknown") genres.add(i.analise_ia.genero_macro); + if(Array.isArray(i.analise_ia?.nuvem_tags)) i.analise_ia.nuvem_tags.forEach(t => genres.add(t.tag)); + }); + + sidebarGenreContainer.innerHTML = ""; + Array.from(genres).sort().forEach(g => { + const label = document.createElement('label'); + label.className = "checkbox is-block mb-1 is-size-7"; + label.innerHTML = ` ${g}`; + sidebarGenreContainer.appendChild(label); + }); + + document.querySelectorAll('#sidebar-genres .filter-checkbox').forEach(cb => { + cb.addEventListener('change', updateActiveSidebar); + }); + } + + // Modal + const modal = document.getElementById('preview-modal'); + const iframe = document.getElementById('preview-iframe'); + const modalTitle = document.getElementById('modal-title'); + const fullEditBtn = document.getElementById('full-edit-btn'); + const closeButtons = document.querySelectorAll('.modal-background, .modal-card-head .delete, #close-modal-btn'); + function openModal(url, title, btnText, btnLink) { + if(!modal) return; modalTitle.textContent = title; iframe.src = url; fullEditBtn.textContent = btnText; fullEditBtn.href = btnLink; + modal.classList.add('is-active'); document.documentElement.classList.add('is-clipped'); + } + function closeModal() { + if(!modal) return; modal.classList.remove('is-active'); document.documentElement.classList.remove('is-clipped'); iframe.src = ""; + } + document.querySelectorAll('.js-open-modal').forEach(btn => { + btn.addEventListener('click', (e) => { e.preventDefault(); openModal(btn.dataset.targetUrl, btn.dataset.modalTitle, btn.dataset.fullBtnText, btn.dataset.fullBtnLink); }); + }); + if(iframe) { iframe.addEventListener('load', () => { try { + const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; + const style = iframeDoc.createElement('style'); + style.textContent = `.tabs, .navbar, .sidebar-wrapper, .main-header { display: none !important; } .publication { padding-top: 0 !important; } body { background-color: #fff !important; }`; + iframeDoc.head.appendChild(style); } catch(e){} }); + } + closeButtons.forEach(el => el.addEventListener('click', closeModal)); + document.addEventListener('keydown', (e) => { if (e.key === "Escape") closeModal(); }); +}); + \ No newline at end of file