Greasy Fork

Greasy Fork is available in English.

Popmundo Better Repertoire UI

28/09/2024, 00:38:02

当前为 2024-10-13 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Popmundo Better Repertoire UI
// @namespace   Violentmonkey Scripts
// @match       https://*.popmundo.com/World/Popmundo.aspx/Artist/Repertoire/*
// @grant       GM_setValue
// @grant       GM_getValue
// @license     M.I.T
// @version     1.4
// @description 28/09/2024, 00:38:02
// ==/UserScript==
const currentUrl = window.location.href;
const bandId = currentUrl.split('/').pop();
const urlDomain = window.location.hostname;
let grupos = GM_getValue('grupos', []);
const style = document.createElement('style');
style.innerHTML = `
  .accordion-header {
        background-image: url(Images/bgr-item-header.png);
        background-color: #56686f;
        background-repeat: repeat-x;
        color: #fff;
        font-weight: 500;
        padding: 16px;
        cursor: pointer;
        border-radius: 8px;
        font-size: 12px;
        transition: background-color 0.3s ease, transform 0.2s ease;
    }

    /* Efeito hover */
    .accordion-header:hover {
        background-color: #3c4b51;
        transform: translateY(-2px);
        box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
    }
    .accordion-content {
        padding: 10px;
        border: 1px solid #ccc;
        border-top: none;
        display: none;
        background-color:white;
    }
    .accordion-row {
        /* Define qualquer estilo adicional para as linhas accordion, se necessário */
    }
        .modal-dialog {
        width: 300px;
        height: auto;
    }
`;

document.head.appendChild(style);

function createDeleteGroupModal() {
    const overlay = jQuery('<div>', { class: 'modal-overlay' }).css({
        position: 'fixed',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        backgroundColor: 'rgba(0, 0, 0, 0.5)',
        zIndex: 999
    }).appendTo('body');

    const modal = jQuery('<div>', { class: 'modal-dialog' }).css({
        position: 'fixed',
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%)',
        backgroundColor: '#fff',
        padding: '20px',
        borderRadius: '12px',
        boxShadow: '0 6px 16px rgba(0, 0, 0, 0.15)',
        zIndex: 1000,
        width: '320px',
        textAlign: 'center',
        fontFamily: 'Arial, sans-serif'
    }).appendTo('body');

    // Título do modal
    const modalTitle = jQuery('<h3>').text('Deletar Grupo').css({
        marginBottom: '15px',
        fontSize: '18px',
        color: '#333',
        fontWeight: 'bold'
    }).appendTo(modal);

    // Select para escolher o grupo
    const selectGroup = jQuery('<select>').css({
        marginBottom: '15px',
        padding: '5px',
        width: '100%',
        fontSize: '14px',
        borderRadius: '6px',
        border: '1px solid #ccc'
    }).appendTo(modal);

    // Exibir grupos que começam com o bandId, exceto o grupo "default", e mostrar sem o prefixo
    grupos.forEach(grupo => {
        if (grupo !== `${bandId}_default` && grupo.startsWith(`${bandId}_`)) {
            selectGroup.append(jQuery('<option>', { value: grupo, text: grupo.replace(`${bandId}_`, '') }));
        }
    });

    // Botões de confirmação e cancelamento
    const confirmButton = jQuery('<button>').text('Confirmar').css({
        marginRight: '10px',
        padding: '8px 12px',
        backgroundColor: '#28a745',
        color: '#fff',
        border: 'none',
        borderRadius: '6px',
        cursor: 'pointer',
        fontSize: '14px',
    }).appendTo(modal);

    const cancelButton = jQuery('<button>').text('Cancelar').css({
        padding: '8px 12px',
        backgroundColor: '#dc3545',
        color: '#fff',
        border: 'none',
        borderRadius: '6px',
        cursor: 'pointer',
        fontSize: '14px'
    }).appendTo(modal);

    // Função para fechar o modal
    function closeModal() {
        modal.remove();
        overlay.remove();
    }

    // Evento de clique no botão de cancelamento
    cancelButton.on('click', function () {
        closeModal();
    });

    // Evento de clique no botão de confirmação
    confirmButton.on('click', function () {
        const selectedGroup = selectGroup.val();
        if (selectedGroup) {
            // Transfere as músicas do grupo deletado para o grupo "default"
            const tbody = jQuery('#tablesongs tbody');
            tbody.find('tr').each(function (index, row) {
                // Obter o grupo salvo para a música
                const currentGroup = GM_getValue(`${bandId}_song_${index}_group`, `${bandId}_default`);
                // Verifica se o grupo atual da música é o que está sendo deletado
                if (currentGroup === selectedGroup) {
                    GM_setValue(`${bandId}_song_${index}_group`, `${bandId}_default`); // Transfere para "default"
                }
            });

            // Remove o grupo do GM_store
            grupos = grupos.filter(grupo => grupo !== selectedGroup);
            GM_setValue('grupos', grupos);

            alert(`Grupo "${selectedGroup.replace(`${bandId}_`, '')}" foi deletado e todas as músicas foram transferidas para o grupo ${bandId}_default.`);
            closeModal();
            location.reload(); // Recarrega a página para atualizar os selects
        }
    });
}

jQuery(document).ready(function () {
    // Create a div for color pickers
    const colorPickerDiv = jQuery('<div>', { class: 'box', css: { marginBottom: '10px', padding: '10px', border: '1px solid #ccc' } });
    const heading = jQuery('<h2>').text('Configuração das Cores').appendTo(colorPickerDiv);

    // Create color pickers
    const propriaColorPickerLabel = jQuery('<label>', { css: { marginRight: '20px' } }).text('Musica própria: ').appendTo(colorPickerDiv);
    const propriaColorPicker = jQuery('<input>', { type: 'color', value: GM_getValue('propriaColor', '#008000') }).appendTo(propriaColorPickerLabel);

    const naoPropriaColorPickerLabel = jQuery('<label>').text('Comprada/Cover: ').appendTo(colorPickerDiv);
    const naoPropriaColorPicker = jQuery('<input>', { type: 'color', value: GM_getValue('naoPropriaColor', '#FFFF00') }).appendTo(naoPropriaColorPickerLabel);
    const hr = jQuery('<hr>').appendTo(colorPickerDiv);

    // Create the submit button
    const submitButton = jQuery('<input>', { type: 'submit', value: 'Salvar Cores', class: 'cnf' }).appendTo(colorPickerDiv);
    const createGroup = jQuery('<input>', { type: 'button', value: 'Criar novo grupo', class: 'cnf' }).appendTo(colorPickerDiv);
    const deleteGroupButton = jQuery('<input>', { type: 'button', value: 'Deletar Grupos', class: 'cnf' }).appendTo(colorPickerDiv);

    // Save the selected colors in GM storage when changed
    propriaColorPicker.on('change', function () {
        GM_setValue('propriaColor', propriaColorPicker.val());
    });

    naoPropriaColorPicker.on('change', function () {
        GM_setValue('naoPropriaColor', naoPropriaColorPicker.val());
    });

    // Handle the submit button click
    submitButton.on('click', function () {
        alert('Cores atualizadas com sucesso!');
        location.reload(); // Refresh the page
    });
    deleteGroupButton.on('click', function () {
        createDeleteGroupModal();
    });

    createGroup.on('click', function () {
        let groupName = prompt("Nome do grupo que deseja criar:");
        if (groupName) {
            const uniqueGroupName = `${bandId}_${groupName}`; // Prefixa o nome do grupo com o bandId
            grupos.push(uniqueGroupName); // Adiciona o novo grupo com o bandId
            GM_setValue('grupos', grupos); // Salva a lista de grupos atualizada
            alert(`Grupo "${uniqueGroupName}" criado com sucesso!`);
            location.reload(); // Recarrega a página para atualizar os selects
        }
    });

    // Insert the color picker div above the table
    jQuery('#tablesongs').before(colorPickerDiv);

    // Cria um iframe único que será reutilizado para cada link e o oculta
    const iframe = jQuery('<iframe>', {
        id: 'songIframe',
        width: '0px',
        height: '0px',
        css: { display: 'none' } // Deixa o iframe oculto inicialmente
    }).appendTo('#ppm-wrapper');

    // Seleciona todos os links da tabela
    const links = jQuery('#tablesongs tbody tr td a');
    let currentIndex = 0;

    // Função para processar um link
    function processLink() {
        if (currentIndex >= links.length) {
            console.log('Processamento concluído para todos os links.');
            iframe.remove(); // Remove o iframe após concluir o processamento de todos os links
            return;
        }

        const currentLink = jQuery(links[currentIndex]);

        // Verifica se o link contém uma imagem <img>, se contiver, pula para o próximo
        if (currentLink.find('img').length > 0) {
            currentIndex++;
            processLink();
            return;
        }

        const songName = currentLink.text();
        const songData = GM_getValue(`${bandId}_${songName}`, null); // Verifica se a música já tem dados armazenados

        if (songData) {
            // Se os dados da música já estiverem salvos, exibe diretamente
            displaySongData(songData, currentLink);
            currentIndex++;
            processLink();
        } else {
            const currentLinkHref = currentLink.attr('href');
            const linkFormatted = "https://" + urlDomain + currentLinkHref;
            iframe.attr('src', linkFormatted);

            iframe.off('load').on('load', function () {
                const iframeContent = iframe.contents();
                let div1stBox = iframeContent.find('div.box').first();
                const bandHref = div1stBox.find('a[href^="/World/Popmundo.aspx/Artist/"]').attr('href');
                let bandaPropria = false;
                if (bandHref) {
                    const bandIdFromHref = bandHref.split('/').pop();
                    if (bandIdFromHref === bandId) {
                        bandaPropria = true;
                    }
                }

                let div2ndBox = iframeContent.find('div.box').eq(1);
                const melodiaTitle = div2ndBox.find('p a').eq(0).attr('title');
                const letraTitle = div2ndBox.find('p a').eq(1).attr('title');

                if (melodiaTitle && letraTitle) {
                    const notaMelodia = melodiaTitle.split('/')[0];
                    const notaLetra = letraTitle.split('/')[0];

                    const songData = {
                        songName,
                        notaMelodia,
                        notaLetra,
                        bandaPropria
                    };

                    // Salva os dados da música no GM_store
                    GM_setValue(`${bandId}_${songName}`, songData);

                    displaySongData(songData, currentLink);
                } else {
                    console.error('Não foi possível encontrar os títulos para as notas da melodia e da letra.');
                }

                currentIndex++;
                processLink();
            });
        }
    }

    // Função para exibir os dados da música
    function displaySongData(songData, linkElement) {
        let newText = `${songData.songName} (${songData.notaMelodia}/${songData.notaLetra})`;
        linkElement.text(newText);

        const propriaColor = GM_getValue('propriaColor', '#008000'); // Default green
        const naoPropriaColor = GM_getValue('naoPropriaColor', '#FFFF00'); // Default yellow

        if (songData.bandaPropria) {
            linkElement.css({ 'color': propriaColor });
        } else {
            linkElement.css({ 'color': naoPropriaColor });
        }
    }

    // Inicia o processamento do primeiro link
    processLink();


// Certifique-se de que o grupo bandId_default está sempre presente
const defaultGroup = `${bandId}_default`;
if (!grupos.includes(defaultGroup)) {
    grupos.push(defaultGroup);
    GM_setValue('grupos', grupos);
}

// Função para adicionar selectboxes em cada linha e salvar a seleção
function addSelectBoxesToRows(tbody, accordionMap) {
    const rows = tbody.querySelectorAll('tr');
    rows.forEach((row, index) => {
        // Verifica se a linha não é um accordion (verificamos se a linha contém um link de música)

        const songLink = row.querySelector('a');
        if (!songLink || songLink.textContent.includes('Grupo')) {
            return; // Pula esta linha, pois é um accordion
        }
            if (row.classList.contains('accordion-row')) {
            return; // Se for um accordion, pula essa linha
        }

        const songName = songLink.textContent.trim();
        const newCell = document.createElement('td');
        const select = createSelectBox(index, accordionMap, row, songName);
        newCell.appendChild(select);
        row.appendChild(newCell);

        const savedGroup = GM_getValue(`${bandId}_song_${index}_group`, defaultGroup); // Garantir que o padrão seja `${bandId}_default`
        if (accordionMap[savedGroup]) {
            accordionMap[savedGroup].appendChild(row);
        }
    });
}

// Função para inicializar a tabela e seus componentes
function initializeTable() {
    const table = document.getElementById('tablesongs');
    if (table) {
        const tbody = table.querySelector('tbody');
        const thead = table.querySelector('thead');
        if (thead) {
            addTableHeader(thead);
        }
        const accordionMap = createAccordions(tbody);
        addSelectBoxesToRows(tbody, accordionMap);
    }
}

// Função para adicionar o cabeçalho "Grupo" no thead
function addTableHeader(thead) {
    const headerRow = thead.querySelector('tr');
    const newHeader = document.createElement('th');
    newHeader.textContent = 'Grupo';
    headerRow.appendChild(newHeader);
}

// Função para criar os accordions apenas para os grupos que começam com o bandId
function createAccordions(tbody) {
    let accordionMap = {};

    // Filtra os grupos que começam com o bandId respectivo
    const filteredGroups = grupos.filter(grupo => grupo.startsWith(`${bandId}_`));

    filteredGroups.forEach(grupo => {
        const accordionRow = document.createElement('tr');
        accordionRow.classList.add('accordion-row'); // Adiciona uma classe para identificar que é um accordion

        const accordionCell = document.createElement('td');
        accordionCell.setAttribute('colspan', tbody.closest('table').querySelectorAll('th').length);

        const accordionHeader = createAccordionHeader(grupo);
        const accordionContent = createAccordionContent();

        accordionHeader.addEventListener('click', () => {
            toggleAccordionContent(accordionContent);
        });

        accordionCell.appendChild(accordionHeader);
        accordionCell.appendChild(accordionContent);
        accordionRow.appendChild(accordionCell);
        tbody.appendChild(accordionRow);

        accordionMap[grupo] = accordionContent;
    });

    return accordionMap;
}

// Função para criar o cabeçalho clicável do accordion
function createAccordionHeader(grupo) {
    const accordionHeader = document.createElement('div');
    accordionHeader.classList.add('accordion-header'); // Usa uma classe CSS para o cabeçalho do accordion

    // Exibe o grupo sem o prefixo bandId_ para visualização
    accordionHeader.textContent = `Grupo: ${grupo.replace(`${bandId}_`, '')}`;

    return accordionHeader;
}

// Função para criar o conteúdo do accordion
function createAccordionContent() {
    const accordionContent = document.createElement('div');
    accordionContent.classList.add('accordion-content'); // Usa uma classe CSS para o conteúdo do accordion
    accordionContent.style.display = 'none'; // Mantém o conteúdo oculto por padrão
    return accordionContent;
}

// Função para alternar a exibição do conteúdo do accordion
function toggleAccordionContent(content) {
    content.style.display = content.style.display === 'none' ? 'block' : 'none';
}

// Função para criar o selectbox e adicionar evento de mudança
function createSelectBox(index, accordionMap, row, songName) {
    const select = document.createElement('select');

    // Filtra os grupos que começam com o bandId respectivo
    const filteredGroups = grupos.filter(grupo => grupo.startsWith(`${bandId}_`));

    // Cria as opções de select, exibindo o nome do grupo sem o prefixo bandId_
    filteredGroups.forEach(grupo => {
        const option = document.createElement('option');
        option.value = grupo; // Mantém o valor completo para salvar
        option.textContent = grupo.replace(`${bandId}_`, ''); // Remove o prefixo apenas para exibição
        select.appendChild(option);
    });

    const savedGroup = GM_getValue(`${bandId}_song_${index}_group`, defaultGroup); // Usando o grupo padrão `${bandId}_default`
    select.value = savedGroup;

    select.addEventListener('change', () => {
        GM_setValue(`${bandId}_song_${index}_group`, select.value);
        console.log(`Salvando grupo: ${songName}, Grupo: ${select.value}`);

        const selectedGroup = select.value;
        if (accordionMap[selectedGroup]) {
            accordionMap[selectedGroup].appendChild(row);
        }
    });

    return select;
}


// Função principal que inicializa a tabela e seus componentes
function initializeTable() {
    const table = document.getElementById('tablesongs');
    if (table) {
        const tbody = table.querySelector('tbody');
        const thead = table.querySelector('thead');
        if (thead) {
            addTableHeader(thead);
        }
        const accordionMap = createAccordions(tbody);
        addSelectBoxesToRows(tbody, accordionMap);

    }
}

// Função para remover as linhas que não foram atribuídas a nenhum accordion


// Função principal que chama todas as outras
function main() {
    initializeTable();
}

// Chamada da função principal
main();
});